暂存
This commit is contained in:
Binary file not shown.
86
1.6/Defs/PsychicRitualDefs/WULA_FallenEmpire_Rituals.xml
Normal file
86
1.6/Defs/PsychicRitualDefs/WULA_FallenEmpire_Rituals.xml
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<WulaFallenEmpire.PsychicRitual_TechOffering>
|
||||||
|
<defName>WULA_Ritual_TechOffering</defName>
|
||||||
|
<label>帝国技术献祭</label>
|
||||||
|
<description>乌拉帝国用于交换失落技术的灵能仪式。通过献上高价值的科技产品,帝国可以从时空的裂隙中获得罕见的武器或工具。</description>
|
||||||
|
<durationTicks>1800</durationTicks>
|
||||||
|
<cooldownDays>15</cooldownDays>
|
||||||
|
<researchPrerequisite>BasicPsychicRituals</researchPrerequisite>
|
||||||
|
<iconPath>UI/PsychicRituals/PsychicRitual_Default</iconPath>
|
||||||
|
|
||||||
|
<requiredOffering>
|
||||||
|
<filter>
|
||||||
|
<thingDefs>
|
||||||
|
<li>TechprofSubpersonaCore</li>
|
||||||
|
</thingDefs>
|
||||||
|
</filter>
|
||||||
|
<count>1</count>
|
||||||
|
</requiredOffering>
|
||||||
|
|
||||||
|
<extraOfferings>
|
||||||
|
<li>
|
||||||
|
<thingDef>Gold</thingDef>
|
||||||
|
<power>0.005</power>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<thingDef>Plasteel</thingDef>
|
||||||
|
<power>0.01</power>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<thingDef>Uranium</thingDef>
|
||||||
|
<power>0.015</power>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<thingDef>ComponentSpacer</thingDef>
|
||||||
|
<power>0.05</power>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<thingDef>TechprofSubpersonaCore</thingDef>
|
||||||
|
<power>0.2</power>
|
||||||
|
</li>
|
||||||
|
</extraOfferings>
|
||||||
|
|
||||||
|
<rewardWeaponPool>
|
||||||
|
<li>WULA_MW_Breaker_Bar</li>
|
||||||
|
<li>WULA_MW_Charge_Mace</li>
|
||||||
|
<li>WULA_MW_Lance</li>
|
||||||
|
<li>WULA_MW_ChainSword</li>
|
||||||
|
<li>WULA_MW_Glaive</li>
|
||||||
|
<li>WULA_RW_Fractal_AR</li>
|
||||||
|
<li>WULA_RW_StarDrift_SG</li>
|
||||||
|
<li>WULA_RW_Sphene_MG</li>
|
||||||
|
<li>WULA_RW_Handle_Cannon</li>
|
||||||
|
<li>WULA_RW_AutoCannon</li>
|
||||||
|
<li>WULA_RW_Auto_GL</li>
|
||||||
|
<li>WULA_RW_DM_AR</li>
|
||||||
|
<li>WULA_RW_DM_Cannon</li>
|
||||||
|
</rewardWeaponPool>
|
||||||
|
|
||||||
|
<qualityThresholds>
|
||||||
|
<li>
|
||||||
|
<threshold>1.0</threshold>
|
||||||
|
<quality>Legendary</quality>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<threshold>0.8</threshold>
|
||||||
|
<quality>Masterwork</quality>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<threshold>0.5</threshold>
|
||||||
|
<quality>Excellent</quality>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<threshold>0.2</threshold>
|
||||||
|
<quality>Normal</quality>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<threshold>0.0</threshold>
|
||||||
|
<quality>Poor</quality>
|
||||||
|
</li>
|
||||||
|
</qualityThresholds>
|
||||||
|
|
||||||
|
</WulaFallenEmpire.PsychicRitual_TechOffering>
|
||||||
|
|
||||||
|
</Defs>
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<Defs>
|
||||||
|
|
||||||
|
<ThingDef ParentName="BuildingBase">
|
||||||
|
<defName>WULA_OfferingPedestal</defName>
|
||||||
|
<label>帝国献祭基座</label>
|
||||||
|
<description>一个用于进行灵能献祭的华丽基座。它可以作为灵能的冥想焦点,并能通过附近的灵能设施获得强化。它是启动帝国科技献祭仪式的关键建筑。</description>
|
||||||
|
<tickerType>Normal</tickerType>
|
||||||
|
<passability>Standable</passability>
|
||||||
|
<scatterableOnMapGen>false</scatterableOnMapGen>
|
||||||
|
<building>
|
||||||
|
<sowTag>SupportPlantsOnly</sowTag>
|
||||||
|
<canPlaceOverImpassablePlant>false</canPlaceOverImpassablePlant>
|
||||||
|
<ai_chillDestination>false</ai_chillDestination>
|
||||||
|
<wakeDormantPawnsOnConstruction>false</wakeDormantPawnsOnConstruction>
|
||||||
|
<artificialForMeditationPurposes>false</artificialForMeditationPurposes>
|
||||||
|
<buildingTags>
|
||||||
|
<li>Anomaly</li>
|
||||||
|
</buildingTags>
|
||||||
|
</building>
|
||||||
|
<uiOrder>200</uiOrder>
|
||||||
|
<graphicData>
|
||||||
|
<texPath>Things/Building/PsychicRitualSpot</texPath>
|
||||||
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<drawSize>(3, 3)</drawSize>
|
||||||
|
</graphicData>
|
||||||
|
<size>(3, 3)</size>
|
||||||
|
<terrainAffordanceNeeded>Light</terrainAffordanceNeeded>
|
||||||
|
<researchPrerequisites>
|
||||||
|
<li>PsychicRituals</li>
|
||||||
|
</researchPrerequisites>
|
||||||
|
<inspectorTabs>
|
||||||
|
<li>ITab_Entity</li>
|
||||||
|
</inspectorTabs>
|
||||||
|
<designationCategory>Misc</designationCategory>
|
||||||
|
<altitudeLayer>FloorEmplacement</altitudeLayer>
|
||||||
|
<selectable>true</selectable>
|
||||||
|
<rotatable>false</rotatable>
|
||||||
|
<statBases>
|
||||||
|
<WorkToBuild>0</WorkToBuild>
|
||||||
|
<MeditationFocusStrength>0.08</MeditationFocusStrength>
|
||||||
|
</statBases>
|
||||||
|
<useHitPoints>false</useHitPoints>
|
||||||
|
<placeWorkers>
|
||||||
|
<li>PlaceWorker_NeverAdjacentUnstandableRadial</li>
|
||||||
|
</placeWorkers>
|
||||||
|
<drawPlaceWorkersWhileSelected>True</drawPlaceWorkersWhileSelected>
|
||||||
|
<comps>
|
||||||
|
<li Class="CompProperties_PsychicRitualSpot">
|
||||||
|
<ritualDef>WULA_FallenEmpire_TechOffering</ritualDef>
|
||||||
|
<maxDistance>10</maxDistance>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_AffectedByFacilities">
|
||||||
|
<linkableFacilities>
|
||||||
|
<li>ShardBeacon</li>
|
||||||
|
<li>VoidSculpture</li>
|
||||||
|
</linkableFacilities>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_MeditationFocus">
|
||||||
|
<statDef>MeditationFocusStrength</statDef>
|
||||||
|
<focusTypes>
|
||||||
|
<li>Void</li>
|
||||||
|
</focusTypes>
|
||||||
|
<offsets>
|
||||||
|
<li Class="FocusStrengthOffset_BuildingDefs">
|
||||||
|
<defs>
|
||||||
|
<li>ShardBeacon</li>
|
||||||
|
</defs>
|
||||||
|
<offsetPerBuilding>0.02</offsetPerBuilding>
|
||||||
|
<radius>9.9</radius>
|
||||||
|
<maxBuildings>4</maxBuildings>
|
||||||
|
<explanationKey>MeditationFocusPerBuilding</explanationKey>
|
||||||
|
<explanationKeyAbstract>MeditationFocusPerBuildingAbstract</explanationKeyAbstract>
|
||||||
|
</li>
|
||||||
|
<li Class="FocusStrengthOffset_BuildingDefs">
|
||||||
|
<defs>
|
||||||
|
<li>VoidSculpture</li>
|
||||||
|
</defs>
|
||||||
|
<offsetPerBuilding>0.02</offsetPerBuilding>
|
||||||
|
<radius>9.9</radius>
|
||||||
|
<maxBuildings>6</maxBuildings>
|
||||||
|
<explanationKey>MeditationFocusPerBuilding</explanationKey>
|
||||||
|
<explanationKeyAbstract>MeditationFocusPerBuildingAbstract</explanationKeyAbstract>
|
||||||
|
</li>
|
||||||
|
</offsets>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
|
</Defs>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<LanguageData>
|
||||||
|
|
||||||
|
<WULA_RitualReward_Label>献祭的回报</WULA_RitualReward_Label>
|
||||||
|
<WULA_RitualReward_Description>你们的献祭得到了回应。虚空吐出了一件物品作为奖赏:{0} (品质: {1})。</WULA_RitualReward_Description>
|
||||||
|
|
||||||
|
<WULA_ExtraOfferings>额外祭品</WULA_ExtraOfferings>
|
||||||
|
<WULA_ExtraOfferings_Tooltip>在仪式中心附近放置的贵重物品提升了仪式的品质。这些物品将在仪式完成时被消耗。</WULA_ExtraOfferings_Tooltip>
|
||||||
|
|
||||||
|
</LanguageData>
|
||||||
188
Source/WulaFallenEmpire/PsychicRitual_TechOffering.cs
Normal file
188
Source/WulaFallenEmpire/PsychicRitual_TechOffering.cs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI.Group;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
// 用于在XML中定义祭品
|
||||||
|
public class OfferingItem
|
||||||
|
{
|
||||||
|
public ThingDef thingDef;
|
||||||
|
public float power;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QualityThreshold
|
||||||
|
{
|
||||||
|
public float threshold;
|
||||||
|
public QualityCategory quality;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PsychicRitual_TechOffering : PsychicRitualDef_InvocationCircle
|
||||||
|
{
|
||||||
|
// 从XML加载的额外祭品列表
|
||||||
|
public List<OfferingItem> extraOfferings = new List<OfferingItem>();
|
||||||
|
|
||||||
|
// 从XML加载的奖励池
|
||||||
|
public List<ThingDef> rewardWeaponPool = new List<ThingDef>();
|
||||||
|
|
||||||
|
// 从XML加载的品质阈值
|
||||||
|
public List<QualityThreshold> qualityThresholds = new List<QualityThreshold>();
|
||||||
|
|
||||||
|
// 重写计算最大能量的方法
|
||||||
|
public override void CalculateMaxPower(PsychicRitualRoleAssignments assignments, List<QualityFactor> powerFactorsOut, out float power)
|
||||||
|
{
|
||||||
|
// 首先调用基类方法
|
||||||
|
base.CalculateMaxPower(assignments, powerFactorsOut, out power);
|
||||||
|
|
||||||
|
IntVec3 center = assignments.Target.Cell;
|
||||||
|
Map map = assignments.Target.Map;
|
||||||
|
float offeringRadius = 8f;
|
||||||
|
|
||||||
|
float extraPowerFromOfferings = 0f;
|
||||||
|
if (!extraOfferings.NullOrEmpty())
|
||||||
|
{
|
||||||
|
var offeringThings = new Dictionary<ThingDef, float>();
|
||||||
|
foreach(var offering in extraOfferings)
|
||||||
|
{
|
||||||
|
offeringThings[offering.thingDef] = offering.power;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Thing thing in GenRadial.RadialDistinctThingsAround(center, map, offeringRadius, useCenter: true))
|
||||||
|
{
|
||||||
|
if (offeringThings.TryGetValue(thing.def, out float value))
|
||||||
|
{
|
||||||
|
extraPowerFromOfferings += value * thing.stackCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extraPowerFromOfferings > 0)
|
||||||
|
{
|
||||||
|
powerFactorsOut?.Add(new QualityFactor
|
||||||
|
{
|
||||||
|
label = "WULA_ExtraOfferings".Translate(),
|
||||||
|
positive = true,
|
||||||
|
quality = extraPowerFromOfferings,
|
||||||
|
toolTip = "WULA_ExtraOfferings_Tooltip".Translate()
|
||||||
|
});
|
||||||
|
power += extraPowerFromOfferings;
|
||||||
|
}
|
||||||
|
|
||||||
|
power = UnityEngine.Mathf.Clamp01(power);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重写创建仪式步骤的方法
|
||||||
|
public override List<PsychicRitualToil> CreateToils(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||||
|
{
|
||||||
|
// 获取基类的仪式步骤
|
||||||
|
List<PsychicRitualToil> toils = base.CreateToils(psychicRitual, parent);
|
||||||
|
|
||||||
|
// 在最后添加我们自定义的奖励步骤
|
||||||
|
toils.Add(new PsychicRitualToil_TechOfferingOutcome(psychicRitual, this));
|
||||||
|
|
||||||
|
return toils;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义的仪式步骤,用于处理奖励
|
||||||
|
public class PsychicRitualToil_TechOfferingOutcome : PsychicRitualToil
|
||||||
|
{
|
||||||
|
private PsychicRitual psychicRitual;
|
||||||
|
private PsychicRitualDef def;
|
||||||
|
|
||||||
|
public PsychicRitualToil_TechOfferingOutcome(PsychicRitual psychicRitual, PsychicRitualDef def)
|
||||||
|
{
|
||||||
|
this.psychicRitual = psychicRitual;
|
||||||
|
this.def = def;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Tick(PsychicRitual psychicRitual, PsychicRitualGraph parent)
|
||||||
|
{
|
||||||
|
float power = psychicRitual.power;
|
||||||
|
|
||||||
|
// 消耗祭品
|
||||||
|
IntVec3 center = psychicRitual.assignments.Target.Cell;
|
||||||
|
Map map = psychicRitual.assignments.Target.Map;
|
||||||
|
float offeringRadius = 8f;
|
||||||
|
|
||||||
|
PsychicRitual_TechOffering ritualDef = (PsychicRitual_TechOffering)def;
|
||||||
|
|
||||||
|
if (!ritualDef.extraOfferings.NullOrEmpty())
|
||||||
|
{
|
||||||
|
var offeringThings = new Dictionary<ThingDef, float>();
|
||||||
|
foreach(var offering in ritualDef.extraOfferings)
|
||||||
|
{
|
||||||
|
offeringThings[offering.thingDef] = offering.power;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Thing thing in GenRadial.RadialDistinctThingsAround(center, map, offeringRadius, useCenter: true))
|
||||||
|
{
|
||||||
|
if (offeringThings.ContainsKey(thing.def))
|
||||||
|
{
|
||||||
|
thing.Destroy(DestroyMode.Vanish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从奖励池中随机选择一个武器
|
||||||
|
if (ritualDef.rewardWeaponPool.NullOrEmpty())
|
||||||
|
{
|
||||||
|
Log.Error($"[WulaFallenEmpire] Reward weapon pool is empty for {def.defName}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ThingDef weaponDef = ritualDef.rewardWeaponPool.RandomElement();
|
||||||
|
if (weaponDef == null)
|
||||||
|
{
|
||||||
|
Log.Error($"[WulaFallenEmpire] Could not find weapon Def: {weaponDef.defName}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据能量值决定物品品质
|
||||||
|
QualityCategory quality = QualityCategory.Awful; // 默认最低品质
|
||||||
|
if (!ritualDef.qualityThresholds.NullOrEmpty())
|
||||||
|
{
|
||||||
|
// 对阈值列表按阈值从高到低排序
|
||||||
|
var sortedThresholds = ritualDef.qualityThresholds.OrderByDescending(t => t.threshold).ToList();
|
||||||
|
foreach (var threshold in sortedThresholds)
|
||||||
|
{
|
||||||
|
if (power >= threshold.threshold)
|
||||||
|
{
|
||||||
|
quality = threshold.quality;
|
||||||
|
break; // 找到第一个满足的阈值就跳出
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // 如果XML中没有定义,则使用硬编码的默认值
|
||||||
|
{
|
||||||
|
if (power >= 1.0f) { quality = QualityCategory.Legendary; }
|
||||||
|
else if (power >= 0.8f) { quality = QualityCategory.Masterwork; }
|
||||||
|
else if (power >= 0.5f) { quality = QualityCategory.Excellent; }
|
||||||
|
else if (power >= 0.2f) { quality = QualityCategory.Normal; }
|
||||||
|
else { quality = QualityCategory.Poor; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建物品并设置品质
|
||||||
|
Thing reward = ThingMaker.MakeThing(weaponDef);
|
||||||
|
CompQuality compQuality = reward.TryGetComp<CompQuality>();
|
||||||
|
if (compQuality != null)
|
||||||
|
{
|
||||||
|
compQuality.SetQuality(quality, ArtGenerationContext.Colony);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在仪式中心点生成奖励物品
|
||||||
|
GenPlace.TryPlaceThing(reward, psychicRitual.assignments.Target.Cell, map, ThingPlaceMode.Near);
|
||||||
|
|
||||||
|
// 发送消息通知玩家
|
||||||
|
Find.LetterStack.ReceiveLetter(
|
||||||
|
"WULA_RitualReward_Label".Translate(),
|
||||||
|
"WULA_RitualReward_Description".Translate(reward.Label, quality.GetLabel()),
|
||||||
|
LetterDefOf.PositiveEvent,
|
||||||
|
new LookTargets(psychicRitual.assignments.Target.Cell, map)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,27 +94,26 @@ namespace WulaFallenEmpire
|
|||||||
protected void MakeExplosion()
|
protected void MakeExplosion()
|
||||||
{
|
{
|
||||||
Pawn casterPawn = this.CasterPawn;
|
Pawn casterPawn = this.CasterPawn;
|
||||||
bool spawned = casterPawn.Spawned;
|
if (!casterPawn.Spawned || this.Props == null)
|
||||||
bool flag11 = spawned;
|
|
||||||
if (flag11)
|
|
||||||
{
|
{
|
||||||
Thing targetThing = this.currentTarget.Thing;
|
return;
|
||||||
bool flag = targetThing != null && this.IsTargetImmobile(this.currentTarget) && casterPawn.skills != null;
|
|
||||||
bool flag12 = flag;
|
|
||||||
if (flag12)
|
|
||||||
{
|
|
||||||
casterPawn.skills.Learn(SkillDefOf.Shooting, 250f * this.verbProps.AdjustedFullCycleTime(this, casterPawn), false, false);
|
|
||||||
}
|
}
|
||||||
bool flag2 = this.Props != null;
|
|
||||||
bool flag13 = flag2;
|
// 技能学习逻辑 (只在目标是站立Pawn时)
|
||||||
if (flag13)
|
if (this.currentTarget.Thing is Pawn targetPawn && !targetPawn.Downed && targetPawn.GetPosture() == PawnPosture.Standing && casterPawn.skills != null)
|
||||||
{
|
{
|
||||||
List<IntVec3> cells = Verb_ShootArc.circularSectorCellsStartedCaster(casterPawn.Position, casterPawn.Map, this.currentTarget.Cell, this.Props.range, this.Props.affectedAngle, false).ToList<IntVec3>();
|
casterPawn.skills.Learn(SkillDefOf.Shooting, 250f * verbProps.AdjustedFullCycleTime(this, casterPawn), false, false);
|
||||||
HashSet<IntVec3> hashSet = this.HashSetConverter(cells);
|
}
|
||||||
this.pawnConduct.Add(casterPawn);
|
|
||||||
float weaponDamageMultiplier = base.EquipmentSource.GetStatValue(StatDefOf.RangedWeapon_DamageMultiplier, true, -1);
|
float weaponDamageMultiplier = base.EquipmentSource.GetStatValue(StatDefOf.RangedWeapon_DamageMultiplier, true, -1);
|
||||||
int damageMultiplier = this.GetDamageAmount(weaponDamageMultiplier, null);
|
int damageMultiplier = this.GetDamageAmount(weaponDamageMultiplier, null);
|
||||||
float armorPenetrationMultiplier = this.GetArmorPenetration(weaponDamageMultiplier, null);
|
float armorPenetrationMultiplier = this.GetArmorPenetration(weaponDamageMultiplier, null);
|
||||||
|
|
||||||
|
// 总是先收集范围内的Pawn,为后续决策做准备
|
||||||
|
List<IntVec3> cells = Verb_ShootArc.circularSectorCellsStartedCaster(casterPawn.Position, casterPawn.Map, this.currentTarget.Cell, this.Props.range, this.Props.affectedAngle, false).ToList<IntVec3>();
|
||||||
|
HashSet<IntVec3> hashSet = this.HashSetConverter(cells);
|
||||||
|
this.pawnConduct.Add(casterPawn);
|
||||||
|
|
||||||
foreach (IntVec3 cell in hashSet)
|
foreach (IntVec3 cell in hashSet)
|
||||||
{
|
{
|
||||||
List<Thing> list = casterPawn.Map.thingGrid.ThingsListAt(cell);
|
List<Thing> list = casterPawn.Map.thingGrid.ThingsListAt(cell);
|
||||||
@@ -122,20 +121,12 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
if (list[num] is Pawn p)
|
if (list[num] is Pawn p)
|
||||||
{
|
{
|
||||||
// 新增友方过滤逻辑
|
bool isFriendly = p.Faction != null && casterPawn.Faction != null && !p.Faction.HostileTo(casterPawn.Faction);
|
||||||
bool isFriendly = p.Faction != null
|
if (!this.Props.conductFriendly && isFriendly)
|
||||||
&& casterPawn.Faction != null
|
|
||||||
&& !p.Faction.HostileTo(casterPawn.Faction);
|
|
||||||
|
|
||||||
if (!Props.conductFriendly && isFriendly)
|
|
||||||
{
|
{
|
||||||
continue; // 跳过友方目标
|
continue;
|
||||||
}
|
}
|
||||||
|
bool isInvalidPosture = p.GetPosture() != PawnPosture.Standing && this.currentTarget.Thing != p;
|
||||||
// 原有姿势检查
|
|
||||||
bool isInvalidPosture = p.GetPosture() != PawnPosture.Standing
|
|
||||||
&& this.currentTarget.Thing != p;
|
|
||||||
|
|
||||||
if (!isInvalidPosture)
|
if (!isInvalidPosture)
|
||||||
{
|
{
|
||||||
this.pawnConduct.Add(p);
|
this.pawnConduct.Add(p);
|
||||||
@@ -143,178 +134,83 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool isConductible = this.Props.isConductible;
|
|
||||||
bool flag17 = isConductible;
|
// 决策:如果设为导电模式且有至少一个传导目标,则进行链式攻击
|
||||||
if (flag17)
|
if (this.Props.isConductible && this.pawnConduct.Count > 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < this.Props.conductNum; i++)
|
for (int i = 0; i < this.Props.conductNum && i < this.pawnConduct.Count - 1; i++)
|
||||||
{
|
{
|
||||||
bool flag6 = i > this.pawnConduct.Count - 2;
|
if (this.Props.EMPDamageAmount > 0f)
|
||||||
bool flag18 = flag6;
|
|
||||||
if (flag18)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bool flag7 = this.Props.EMPDamageAmount > 0f;
|
|
||||||
bool flag19 = flag7;
|
|
||||||
if (flag19)
|
|
||||||
{
|
{
|
||||||
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f);
|
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f);
|
||||||
}
|
}
|
||||||
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], this.Props.damageDef, (float)damageMultiplier, armorPenetrationMultiplier);
|
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], this.Props.damageDef, (float)damageMultiplier, armorPenetrationMultiplier);
|
||||||
bool flag8 = this.verbProps.beamMoteDef != null;
|
if (this.verbProps.beamMoteDef != null)
|
||||||
bool flag20 = flag8;
|
|
||||||
if (flag20)
|
|
||||||
{
|
{
|
||||||
MoteMaker.MakeInteractionOverlay(this.verbProps.beamMoteDef, new TargetInfo(this.pawnConduct[i].Position, this.caster.Map, false), new TargetInfo(this.pawnConduct[i + 1].Position, this.caster.Map, false));
|
MoteMaker.MakeInteractionOverlay(this.verbProps.beamMoteDef, new TargetInfo(this.pawnConduct[i].Position, this.caster.Map, false), new TargetInfo(this.pawnConduct[i + 1].Position, this.caster.Map, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 否则(非导电模式,或没有传导目标),执行一次普通的单体攻击
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
IntVec3 position = this.caster.Position;
|
Thing primaryTarget = this.currentTarget.Thing;
|
||||||
float num2 = Mathf.Atan2(-(float)(this.currentTarget.Cell.z - position.z), (float)(this.currentTarget.Cell.x - position.x)) * 57.29578f;
|
if (primaryTarget != null)
|
||||||
bool flag9 = num2 - this.Props.affectedAngle < -180f || num2 + this.Props.affectedAngle > 180f;
|
|
||||||
bool flag21 = flag9;
|
|
||||||
if (flag21)
|
|
||||||
{
|
{
|
||||||
FloatRange? affectedAngle = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(num2 - this.Props.affectedAngle), 180f));
|
float angle = (primaryTarget.Position - this.caster.Position).AngleFlat;
|
||||||
// 修正后的爆炸调用(参数通过命名对齐)
|
DamageInfo dinfo = new DamageInfo(this.Props.damageDef, (float)damageMultiplier, armorPenetrationMultiplier, angle, this.caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing);
|
||||||
GenExplosion.DoExplosion(
|
primaryTarget.TakeDamage(dinfo);
|
||||||
center: casterPawn.Position,
|
}
|
||||||
map: this.caster.MapHeld,
|
|
||||||
radius: this.verbProps.range,
|
|
||||||
damType: this.Props.damageDef,
|
|
||||||
instigator: null,
|
|
||||||
damAmount: damageMultiplier,
|
|
||||||
armorPenetration: armorPenetrationMultiplier,
|
|
||||||
explosionSound: null,
|
|
||||||
weapon: this.CasterPawn.equipment.Primary.def,
|
|
||||||
projectile: null,
|
|
||||||
intendedTarget: null,
|
|
||||||
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
|
||||||
postExplosionSpawnChance: 0f,
|
|
||||||
postExplosionSpawnThingCount: 1,
|
|
||||||
postExplosionGasType: null,
|
|
||||||
postExplosionGasRadiusOverride: null,
|
|
||||||
postExplosionGasAmount: 0,
|
|
||||||
applyDamageToExplosionCellsNeighbors: false,
|
|
||||||
preExplosionSpawnThingDef: null,
|
|
||||||
preExplosionSpawnChance: 0f,
|
|
||||||
preExplosionSpawnThingCount: 1,
|
|
||||||
chanceToStartFire: 0f,
|
|
||||||
damageFalloff: false,
|
|
||||||
direction: null,
|
|
||||||
ignoredThings: null,
|
|
||||||
affectedAngle: affectedAngle,
|
|
||||||
doVisualEffects: true,
|
|
||||||
propagationSpeed: 0.6f,
|
|
||||||
excludeRadius: 0f,
|
|
||||||
doSoundEffects: false,
|
|
||||||
postExplosionSpawnThingDefWater: null,
|
|
||||||
screenShakeFactor: 1f,
|
|
||||||
flammabilityChanceCurve: null,
|
|
||||||
overrideCells: null,
|
|
||||||
postExplosionSpawnSingleThingDef: null,
|
|
||||||
preExplosionSpawnSingleThingDef: null
|
|
||||||
);
|
|
||||||
|
|
||||||
affectedAngle = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(num2 + this.Props.affectedAngle)));
|
// 无论是否命中,都显示视觉效果
|
||||||
// 第二次爆炸调用(参数结构相同)
|
if (this.verbProps.beamMoteDef != null)
|
||||||
GenExplosion.DoExplosion(
|
|
||||||
center: casterPawn.Position,
|
|
||||||
map: this.caster.MapHeld,
|
|
||||||
radius: this.verbProps.range,
|
|
||||||
damType: this.Props.damageDef,
|
|
||||||
instigator: null,
|
|
||||||
damAmount: damageMultiplier,
|
|
||||||
armorPenetration: armorPenetrationMultiplier,
|
|
||||||
explosionSound: null,
|
|
||||||
weapon: this.CasterPawn.equipment.Primary.def,
|
|
||||||
projectile: null,
|
|
||||||
intendedTarget: null,
|
|
||||||
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
|
||||||
postExplosionSpawnChance: 0f,
|
|
||||||
postExplosionSpawnThingCount: 1,
|
|
||||||
postExplosionGasType: null,
|
|
||||||
postExplosionGasRadiusOverride: null,
|
|
||||||
postExplosionGasAmount: 0,
|
|
||||||
applyDamageToExplosionCellsNeighbors: false,
|
|
||||||
preExplosionSpawnThingDef: null,
|
|
||||||
preExplosionSpawnChance: 0f,
|
|
||||||
preExplosionSpawnThingCount: 1,
|
|
||||||
chanceToStartFire: 0f,
|
|
||||||
damageFalloff: false,
|
|
||||||
direction: null,
|
|
||||||
ignoredThings: null,
|
|
||||||
affectedAngle: affectedAngle,
|
|
||||||
doVisualEffects: true,
|
|
||||||
propagationSpeed: 0.6f,
|
|
||||||
excludeRadius: 0f,
|
|
||||||
doSoundEffects: false,
|
|
||||||
postExplosionSpawnThingDefWater: null,
|
|
||||||
screenShakeFactor: 1f,
|
|
||||||
flammabilityChanceCurve: null,
|
|
||||||
overrideCells: null,
|
|
||||||
postExplosionSpawnSingleThingDef: null,
|
|
||||||
preExplosionSpawnSingleThingDef: null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(num2 - this.Props.affectedAngle, num2 + this.Props.affectedAngle));
|
MoteMaker.MakeInteractionOverlay(this.verbProps.beamMoteDef, new TargetInfo(this.caster.Position, this.caster.Map, false), new TargetInfo(this.currentTarget.Cell, this.caster.Map, false));
|
||||||
GenExplosion.DoExplosion(
|
|
||||||
center: casterPawn.Position,
|
|
||||||
map: this.caster.MapHeld,
|
|
||||||
radius: this.verbProps.range,
|
|
||||||
damType: this.Props.damageDef,
|
|
||||||
instigator: null,
|
|
||||||
damAmount: damageMultiplier,
|
|
||||||
armorPenetration: armorPenetrationMultiplier,
|
|
||||||
explosionSound: null,
|
|
||||||
weapon: this.CasterPawn.equipment.Primary.def,
|
|
||||||
projectile: null,
|
|
||||||
intendedTarget: null,
|
|
||||||
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
|
||||||
postExplosionSpawnChance: 0f,
|
|
||||||
postExplosionSpawnThingCount: 1,
|
|
||||||
postExplosionGasType: null,
|
|
||||||
postExplosionGasRadiusOverride: null,
|
|
||||||
postExplosionGasAmount: 0,
|
|
||||||
applyDamageToExplosionCellsNeighbors: false,
|
|
||||||
preExplosionSpawnThingDef: null,
|
|
||||||
preExplosionSpawnChance: 0f,
|
|
||||||
preExplosionSpawnThingCount: 1,
|
|
||||||
chanceToStartFire: 0f,
|
|
||||||
damageFalloff: false,
|
|
||||||
direction: null,
|
|
||||||
ignoredThings: null,
|
|
||||||
affectedAngle: affectedAngle2,
|
|
||||||
doVisualEffects: true,
|
|
||||||
propagationSpeed: 0.6f,
|
|
||||||
excludeRadius: 0f,
|
|
||||||
doSoundEffects: false,
|
|
||||||
postExplosionSpawnThingDefWater: null,
|
|
||||||
screenShakeFactor: 1f,
|
|
||||||
flammabilityChanceCurve: null,
|
|
||||||
overrideCells: null,
|
|
||||||
postExplosionSpawnSingleThingDef: null,
|
|
||||||
preExplosionSpawnSingleThingDef: null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (int j = 1; j < this.pawnConduct.Count<Pawn>(); j++)
|
|
||||||
{
|
|
||||||
bool flag10 = this.Props.EMPDamageAmount > 0f;
|
|
||||||
bool flag22 = flag10;
|
|
||||||
if (flag22)
|
|
||||||
{
|
|
||||||
this.TargetTakeDamage(casterPawn, this.pawnConduct[j], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.pawnConduct.Clear();
|
this.pawnConduct.Clear();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void DoExplosion(Pawn casterPawn, int damAmount, float armorPenetration, FloatRange? affectedAngle)
|
||||||
|
{
|
||||||
|
GenExplosion.DoExplosion(
|
||||||
|
center: casterPawn.Position,
|
||||||
|
map: this.caster.MapHeld,
|
||||||
|
radius: this.verbProps.range,
|
||||||
|
damType: this.Props.damageDef,
|
||||||
|
instigator: casterPawn, // Corrected
|
||||||
|
damAmount: damAmount,
|
||||||
|
armorPenetration: armorPenetration,
|
||||||
|
explosionSound: null,
|
||||||
|
weapon: this.CasterPawn.equipment?.Primary?.def, // Safety check
|
||||||
|
projectile: null,
|
||||||
|
intendedTarget: this.currentTarget.Thing, // Corrected
|
||||||
|
postExplosionSpawnThingDef: null, // Simplified
|
||||||
|
postExplosionSpawnChance: 0f,
|
||||||
|
postExplosionSpawnThingCount: 1,
|
||||||
|
postExplosionGasType: null,
|
||||||
|
postExplosionGasRadiusOverride: null,
|
||||||
|
postExplosionGasAmount: 0,
|
||||||
|
applyDamageToExplosionCellsNeighbors: false,
|
||||||
|
preExplosionSpawnThingDef: null,
|
||||||
|
preExplosionSpawnChance: 0f,
|
||||||
|
preExplosionSpawnThingCount: 1,
|
||||||
|
chanceToStartFire: 0f,
|
||||||
|
damageFalloff: false,
|
||||||
|
direction: null,
|
||||||
|
ignoredThings: null,
|
||||||
|
affectedAngle: affectedAngle,
|
||||||
|
doVisualEffects: true,
|
||||||
|
propagationSpeed: 0.6f,
|
||||||
|
excludeRadius: 0f,
|
||||||
|
doSoundEffects: false,
|
||||||
|
postExplosionSpawnThingDefWater: null,
|
||||||
|
screenShakeFactor: 1f,
|
||||||
|
flammabilityChanceCurve: null,
|
||||||
|
overrideCells: null,
|
||||||
|
postExplosionSpawnSingleThingDef: null,
|
||||||
|
preExplosionSpawnSingleThingDef: null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -118,6 +118,7 @@
|
|||||||
<Compile Include="Verb\Trackingbullet.cs" />
|
<Compile Include="Verb\Trackingbullet.cs" />
|
||||||
<Compile Include="Verb\Projectile_ConfigurableHellsphereCannon.cs" />
|
<Compile Include="Verb\Projectile_ConfigurableHellsphereCannon.cs" />
|
||||||
<Compile Include="TimedExplosion.cs" />
|
<Compile Include="TimedExplosion.cs" />
|
||||||
|
<Compile Include="PsychicRitual_TechOffering.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
<!-- 自定义清理任务,删除obj文件夹中的临时文件 -->
|
||||||
|
|||||||
486
美术与文本源文件/故障的arc代码之扇形攻击.txt
Normal file
486
美术与文本源文件/故障的arc代码之扇形攻击.txt
Normal file
@@ -0,0 +1,486 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using RimWorld;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
using Verse.Sound;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class VerbProperties_Arc : VerbProperties
|
||||||
|
{
|
||||||
|
public DamageDef damageDef;
|
||||||
|
|
||||||
|
public float EMPDamageAmount = -1f;
|
||||||
|
|
||||||
|
public int damageAmount = -1;
|
||||||
|
|
||||||
|
public float armorPenetration = -1f;
|
||||||
|
|
||||||
|
public float affectedAngle;
|
||||||
|
|
||||||
|
public bool isConductible = false;
|
||||||
|
|
||||||
|
public int conductNum;
|
||||||
|
|
||||||
|
public bool conductFriendly = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Verb_ShootArc : Verb
|
||||||
|
{
|
||||||
|
private VerbProperties_Arc Props
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (VerbProperties_Arc)this.verbProps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int damageAmount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (this.Props.damageAmount > 0) ? this.Props.damageAmount : this.verbProps.beamDamageDef.defaultDamage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float armorPenetration
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (this.Props.armorPenetration > 0f) ? this.Props.armorPenetration : this.verbProps.beamDamageDef.defaultArmorPenetration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WarmupComplete()
|
||||||
|
{
|
||||||
|
this.TryCastShot();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryCastShot()
|
||||||
|
{
|
||||||
|
this.MakeExplosion();
|
||||||
|
bool flag = this.verbProps.soundCast != null;
|
||||||
|
bool flag3 = flag;
|
||||||
|
if (flag3)
|
||||||
|
{
|
||||||
|
this.verbProps.soundCast.PlayOneShot(new TargetInfo(this.caster.Position, this.caster.MapHeld, false));
|
||||||
|
}
|
||||||
|
bool flag2 = this.verbProps.soundCastTail != null;
|
||||||
|
bool flag4 = flag2;
|
||||||
|
if (flag4)
|
||||||
|
{
|
||||||
|
this.verbProps.soundCastTail.PlayOneShotOnCamera(this.caster.Map);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsTargetImmobile(LocalTargetInfo target)
|
||||||
|
{
|
||||||
|
Thing thing = target.Thing;
|
||||||
|
Pawn pawn = thing as Pawn;
|
||||||
|
return pawn != null && !pawn.Downed && pawn.GetPosture() == PawnPosture.Standing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanHitTarget(LocalTargetInfo targ)
|
||||||
|
{
|
||||||
|
bool flag = this.caster == null || !this.caster.Spawned;
|
||||||
|
bool flag2 = flag;
|
||||||
|
return !flag2 && (targ == this.caster || this.CanHitTargetFrom(this.caster.Position, targ));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void MakeExplosion()
|
||||||
|
{
|
||||||
|
Pawn casterPawn = this.CasterPawn;
|
||||||
|
bool spawned = casterPawn.Spawned;
|
||||||
|
bool flag11 = spawned;
|
||||||
|
if (flag11)
|
||||||
|
{
|
||||||
|
Thing targetThing = this.currentTarget.Thing;
|
||||||
|
bool flag = targetThing != null && this.IsTargetImmobile(this.currentTarget) && casterPawn.skills != null;
|
||||||
|
bool flag12 = flag;
|
||||||
|
if (flag12)
|
||||||
|
{
|
||||||
|
casterPawn.skills.Learn(SkillDefOf.Shooting, 250f * this.verbProps.AdjustedFullCycleTime(this, casterPawn), false, false);
|
||||||
|
}
|
||||||
|
bool flag2 = this.Props != null;
|
||||||
|
bool flag13 = flag2;
|
||||||
|
if (flag13)
|
||||||
|
{
|
||||||
|
List<IntVec3> cells = Verb_ShootArc.circularSectorCellsStartedCaster(casterPawn.Position, casterPawn.Map, this.currentTarget.Cell, this.Props.range, this.Props.affectedAngle, false).ToList<IntVec3>();
|
||||||
|
HashSet<IntVec3> hashSet = this.HashSetConverter(cells);
|
||||||
|
this.pawnConduct.Add(casterPawn);
|
||||||
|
float weaponDamageMultiplier = base.EquipmentSource.GetStatValue(StatDefOf.RangedWeapon_DamageMultiplier, true, -1);
|
||||||
|
int damageMultiplier = this.GetDamageAmount(weaponDamageMultiplier, null);
|
||||||
|
float armorPenetrationMultiplier = this.GetArmorPenetration(weaponDamageMultiplier, null);
|
||||||
|
foreach (IntVec3 cell in hashSet)
|
||||||
|
{
|
||||||
|
List<Thing> list = casterPawn.Map.thingGrid.ThingsListAt(cell);
|
||||||
|
for (int num = list.Count - 1; num >= 0; num--)
|
||||||
|
{
|
||||||
|
if (list[num] is Pawn p)
|
||||||
|
{
|
||||||
|
// 新增友方过滤逻辑
|
||||||
|
bool isFriendly = p.Faction != null
|
||||||
|
&& casterPawn.Faction != null
|
||||||
|
&& !p.Faction.HostileTo(casterPawn.Faction);
|
||||||
|
|
||||||
|
if (!Props.conductFriendly && isFriendly)
|
||||||
|
{
|
||||||
|
continue; // 跳过友方目标
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原有姿势检查
|
||||||
|
bool isInvalidPosture = p.GetPosture() != PawnPosture.Standing
|
||||||
|
&& this.currentTarget.Thing != p;
|
||||||
|
|
||||||
|
if (!isInvalidPosture)
|
||||||
|
{
|
||||||
|
this.pawnConduct.Add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool isConductible = this.Props.isConductible;
|
||||||
|
bool flag17 = isConductible;
|
||||||
|
if (flag17)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.Props.conductNum; i++)
|
||||||
|
{
|
||||||
|
bool flag6 = i > this.pawnConduct.Count - 2;
|
||||||
|
bool flag18 = flag6;
|
||||||
|
if (flag18)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bool flag7 = this.Props.EMPDamageAmount > 0f;
|
||||||
|
bool flag19 = flag7;
|
||||||
|
if (flag19)
|
||||||
|
{
|
||||||
|
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f);
|
||||||
|
}
|
||||||
|
this.TargetTakeDamage(casterPawn, this.pawnConduct[i + 1], this.Props.damageDef, (float)damageMultiplier, armorPenetrationMultiplier);
|
||||||
|
bool flag8 = this.verbProps.beamMoteDef != null;
|
||||||
|
bool flag20 = flag8;
|
||||||
|
if (flag20)
|
||||||
|
{
|
||||||
|
MoteMaker.MakeInteractionOverlay(this.verbProps.beamMoteDef, new TargetInfo(this.pawnConduct[i].Position, this.caster.Map, false), new TargetInfo(this.pawnConduct[i + 1].Position, this.caster.Map, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IntVec3 position = this.caster.Position;
|
||||||
|
float num2 = Mathf.Atan2(-(float)(this.currentTarget.Cell.z - position.z), (float)(this.currentTarget.Cell.x - position.x)) * 57.29578f;
|
||||||
|
bool flag9 = num2 - this.Props.affectedAngle < -180f || num2 + this.Props.affectedAngle > 180f;
|
||||||
|
bool flag21 = flag9;
|
||||||
|
if (flag21)
|
||||||
|
{
|
||||||
|
FloatRange? affectedAngle = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(num2 - this.Props.affectedAngle), 180f));
|
||||||
|
// 修正后的爆炸调用(参数通过命名对齐)
|
||||||
|
GenExplosion.DoExplosion(
|
||||||
|
center: casterPawn.Position,
|
||||||
|
map: this.caster.MapHeld,
|
||||||
|
radius: this.verbProps.range,
|
||||||
|
damType: this.Props.damageDef,
|
||||||
|
instigator: null,
|
||||||
|
damAmount: damageMultiplier,
|
||||||
|
armorPenetration: armorPenetrationMultiplier,
|
||||||
|
explosionSound: null,
|
||||||
|
weapon: this.CasterPawn.equipment.Primary.def,
|
||||||
|
projectile: null,
|
||||||
|
intendedTarget: null,
|
||||||
|
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
||||||
|
postExplosionSpawnChance: 0f,
|
||||||
|
postExplosionSpawnThingCount: 1,
|
||||||
|
postExplosionGasType: null,
|
||||||
|
postExplosionGasRadiusOverride: null,
|
||||||
|
postExplosionGasAmount: 0,
|
||||||
|
applyDamageToExplosionCellsNeighbors: false,
|
||||||
|
preExplosionSpawnThingDef: null,
|
||||||
|
preExplosionSpawnChance: 0f,
|
||||||
|
preExplosionSpawnThingCount: 1,
|
||||||
|
chanceToStartFire: 0f,
|
||||||
|
damageFalloff: false,
|
||||||
|
direction: null,
|
||||||
|
ignoredThings: null,
|
||||||
|
affectedAngle: affectedAngle,
|
||||||
|
doVisualEffects: true,
|
||||||
|
propagationSpeed: 0.6f,
|
||||||
|
excludeRadius: 0f,
|
||||||
|
doSoundEffects: false,
|
||||||
|
postExplosionSpawnThingDefWater: null,
|
||||||
|
screenShakeFactor: 1f,
|
||||||
|
flammabilityChanceCurve: null,
|
||||||
|
overrideCells: null,
|
||||||
|
postExplosionSpawnSingleThingDef: null,
|
||||||
|
preExplosionSpawnSingleThingDef: null
|
||||||
|
);
|
||||||
|
|
||||||
|
affectedAngle = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(num2 + this.Props.affectedAngle)));
|
||||||
|
// 第二次爆炸调用(参数结构相同)
|
||||||
|
GenExplosion.DoExplosion(
|
||||||
|
center: casterPawn.Position,
|
||||||
|
map: this.caster.MapHeld,
|
||||||
|
radius: this.verbProps.range,
|
||||||
|
damType: this.Props.damageDef,
|
||||||
|
instigator: null,
|
||||||
|
damAmount: damageMultiplier,
|
||||||
|
armorPenetration: armorPenetrationMultiplier,
|
||||||
|
explosionSound: null,
|
||||||
|
weapon: this.CasterPawn.equipment.Primary.def,
|
||||||
|
projectile: null,
|
||||||
|
intendedTarget: null,
|
||||||
|
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
||||||
|
postExplosionSpawnChance: 0f,
|
||||||
|
postExplosionSpawnThingCount: 1,
|
||||||
|
postExplosionGasType: null,
|
||||||
|
postExplosionGasRadiusOverride: null,
|
||||||
|
postExplosionGasAmount: 0,
|
||||||
|
applyDamageToExplosionCellsNeighbors: false,
|
||||||
|
preExplosionSpawnThingDef: null,
|
||||||
|
preExplosionSpawnChance: 0f,
|
||||||
|
preExplosionSpawnThingCount: 1,
|
||||||
|
chanceToStartFire: 0f,
|
||||||
|
damageFalloff: false,
|
||||||
|
direction: null,
|
||||||
|
ignoredThings: null,
|
||||||
|
affectedAngle: affectedAngle,
|
||||||
|
doVisualEffects: true,
|
||||||
|
propagationSpeed: 0.6f,
|
||||||
|
excludeRadius: 0f,
|
||||||
|
doSoundEffects: false,
|
||||||
|
postExplosionSpawnThingDefWater: null,
|
||||||
|
screenShakeFactor: 1f,
|
||||||
|
flammabilityChanceCurve: null,
|
||||||
|
overrideCells: null,
|
||||||
|
postExplosionSpawnSingleThingDef: null,
|
||||||
|
preExplosionSpawnSingleThingDef: null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(num2 - this.Props.affectedAngle, num2 + this.Props.affectedAngle));
|
||||||
|
GenExplosion.DoExplosion(
|
||||||
|
center: casterPawn.Position,
|
||||||
|
map: this.caster.MapHeld,
|
||||||
|
radius: this.verbProps.range,
|
||||||
|
damType: this.Props.damageDef,
|
||||||
|
instigator: null,
|
||||||
|
damAmount: damageMultiplier,
|
||||||
|
armorPenetration: armorPenetrationMultiplier,
|
||||||
|
explosionSound: null,
|
||||||
|
weapon: this.CasterPawn.equipment.Primary.def,
|
||||||
|
projectile: null,
|
||||||
|
intendedTarget: null,
|
||||||
|
postExplosionSpawnThingDef: ThingDefOf.Filth_FlammableBile,
|
||||||
|
postExplosionSpawnChance: 0f,
|
||||||
|
postExplosionSpawnThingCount: 1,
|
||||||
|
postExplosionGasType: null,
|
||||||
|
postExplosionGasRadiusOverride: null,
|
||||||
|
postExplosionGasAmount: 0,
|
||||||
|
applyDamageToExplosionCellsNeighbors: false,
|
||||||
|
preExplosionSpawnThingDef: null,
|
||||||
|
preExplosionSpawnChance: 0f,
|
||||||
|
preExplosionSpawnThingCount: 1,
|
||||||
|
chanceToStartFire: 0f,
|
||||||
|
damageFalloff: false,
|
||||||
|
direction: null,
|
||||||
|
ignoredThings: null,
|
||||||
|
affectedAngle: affectedAngle2,
|
||||||
|
doVisualEffects: true,
|
||||||
|
propagationSpeed: 0.6f,
|
||||||
|
excludeRadius: 0f,
|
||||||
|
doSoundEffects: false,
|
||||||
|
postExplosionSpawnThingDefWater: null,
|
||||||
|
screenShakeFactor: 1f,
|
||||||
|
flammabilityChanceCurve: null,
|
||||||
|
overrideCells: null,
|
||||||
|
postExplosionSpawnSingleThingDef: null,
|
||||||
|
preExplosionSpawnSingleThingDef: null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (int j = 1; j < this.pawnConduct.Count<Pawn>(); j++)
|
||||||
|
{
|
||||||
|
bool flag10 = this.Props.EMPDamageAmount > 0f;
|
||||||
|
bool flag22 = flag10;
|
||||||
|
if (flag22)
|
||||||
|
{
|
||||||
|
this.TargetTakeDamage(casterPawn, this.pawnConduct[j], DamageDefOf.EMP, this.Props.EMPDamageAmount, -1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.pawnConduct.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public override void DrawHighlight(LocalTargetInfo target)
|
||||||
|
{
|
||||||
|
base.DrawHighlight(target);
|
||||||
|
bool isValid = target.IsValid;
|
||||||
|
bool flag = isValid;
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
IntVec3 position = this.caster.Position;
|
||||||
|
float num = Mathf.Atan2(-(float)(target.Cell.z - position.z), (float)(target.Cell.x - position.x)) * 57.29578f;
|
||||||
|
Verb_ShootArc.RenderPredictedAreaOfEffect(this.caster.Position, this.Props.range, this.verbProps.explosionRadiusRingColor, new FloatRange(num - this.Props.affectedAngle, num + this.Props.affectedAngle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RenderPredictedAreaOfEffect(IntVec3 loc, float radius, Color color, FloatRange affectedAngle)
|
||||||
|
{
|
||||||
|
bool flag = affectedAngle.min < -180f || affectedAngle.max > 180f;
|
||||||
|
bool flag2 = flag;
|
||||||
|
List<IntVec3> cellsSum;
|
||||||
|
if (flag2)
|
||||||
|
{
|
||||||
|
DamageWorker worker = DamageDefOf.Bomb.Worker;
|
||||||
|
Map currentMap = Find.CurrentMap;
|
||||||
|
FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(affectedAngle.min), 180f));
|
||||||
|
List<IntVec3> cells = worker.ExplosionCellsToHit(loc, currentMap, radius, null, null, affectedAngle2).ToList<IntVec3>();
|
||||||
|
DamageWorker worker2 = DamageDefOf.Bomb.Worker;
|
||||||
|
Map currentMap2 = Find.CurrentMap;
|
||||||
|
affectedAngle2 = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(affectedAngle.max)));
|
||||||
|
List<IntVec3> cells2 = worker2.ExplosionCellsToHit(loc, currentMap2, radius, null, null, affectedAngle2).ToList<IntVec3>();
|
||||||
|
cellsSum = cells.Concat(cells2).ToList<IntVec3>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DamageWorker worker3 = DamageDefOf.Bomb.Worker;
|
||||||
|
Map currentMap3 = Find.CurrentMap;
|
||||||
|
FloatRange? affectedAngle3 = new FloatRange?(affectedAngle);
|
||||||
|
cellsSum = worker3.ExplosionCellsToHit(loc, currentMap3, radius, null, null, affectedAngle3).ToList<IntVec3>();
|
||||||
|
}
|
||||||
|
GenDraw.DrawFieldEdges(cellsSum, color, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float AngleWrapped(float angle)
|
||||||
|
{
|
||||||
|
while (angle > 180f)
|
||||||
|
{
|
||||||
|
angle -= 360f;
|
||||||
|
}
|
||||||
|
while (angle < -180f)
|
||||||
|
{
|
||||||
|
angle += 360f;
|
||||||
|
}
|
||||||
|
return (angle == 180f) ? -180f : angle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<IntVec3> circularSectorCellsStartedCaster(IntVec3 center, Map map, IntVec3 target, float radius, float angle, bool useCenter = false)
|
||||||
|
{
|
||||||
|
float num = Mathf.Atan2(-(float)(target.z - center.z), (float)(target.x - center.x)) * 57.29578f;
|
||||||
|
FloatRange affectedAngle = new FloatRange(num - angle, num + angle);
|
||||||
|
bool flag = affectedAngle.min < -180f || affectedAngle.max > 180f;
|
||||||
|
bool flag2 = flag;
|
||||||
|
List<IntVec3> cellsSum;
|
||||||
|
if (flag2)
|
||||||
|
{
|
||||||
|
DamageWorker worker = DamageDefOf.Bomb.Worker;
|
||||||
|
FloatRange? affectedAngle2 = new FloatRange?(new FloatRange(Verb_ShootArc.AngleWrapped(affectedAngle.min), 180f));
|
||||||
|
List<IntVec3> cells = worker.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle2).ToList<IntVec3>();
|
||||||
|
DamageWorker worker2 = DamageDefOf.Bomb.Worker;
|
||||||
|
affectedAngle2 = new FloatRange?(new FloatRange(-180f, Verb_ShootArc.AngleWrapped(affectedAngle.max)));
|
||||||
|
List<IntVec3> cells2 = worker2.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle2).ToList<IntVec3>();
|
||||||
|
cellsSum = cells.Concat(cells2).ToList<IntVec3>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DamageWorker worker3 = DamageDefOf.Bomb.Worker;
|
||||||
|
FloatRange? affectedAngle3 = new FloatRange?(affectedAngle);
|
||||||
|
cellsSum = worker3.ExplosionCellsToHit(center, map, radius, null, null, affectedAngle3).ToList<IntVec3>();
|
||||||
|
}
|
||||||
|
return cellsSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual HashSet<IntVec3> HashSetConverter(IEnumerable<IntVec3> points)
|
||||||
|
{
|
||||||
|
HashSet<IntVec3> hashSet = new HashSet<IntVec3>();
|
||||||
|
bool flag = points.Any<IntVec3>();
|
||||||
|
bool flag2 = flag;
|
||||||
|
if (flag2)
|
||||||
|
{
|
||||||
|
foreach (IntVec3 point in points)
|
||||||
|
{
|
||||||
|
hashSet.Add(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hashSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TargetTakeDamage(Pawn caster, Pawn target, DamageDef damageDef, float damageAmount, float armorPenetration = -1f)
|
||||||
|
{
|
||||||
|
bool flag = caster == null || target == null;
|
||||||
|
bool flag2 = flag;
|
||||||
|
if (flag2)
|
||||||
|
{
|
||||||
|
Log.Error("TargetTakeDamage has null caster or target");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float angleFlat = (this.currentTarget.Cell - caster.Position).AngleFlat;
|
||||||
|
BattleLogEntry_RangedImpact log = new BattleLogEntry_RangedImpact(caster, target, this.currentTarget.Thing, base.EquipmentSource.def, null, null);
|
||||||
|
DamageInfo dinfo = new DamageInfo(damageDef, damageAmount, armorPenetration, angleFlat, caster, null, base.EquipmentSource.def, DamageInfo.SourceCategory.ThingOrUnknown, this.currentTarget.Thing, true, true, QualityCategory.Normal, true);
|
||||||
|
target.TakeDamage(dinfo).AssociateWithLog(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetDamageAmount(float weaponDamageMultiplier, StringBuilder explanation = null)
|
||||||
|
{
|
||||||
|
int num = this.damageAmount;
|
||||||
|
bool flag = explanation != null;
|
||||||
|
bool flag3 = flag;
|
||||||
|
if (flag3)
|
||||||
|
{
|
||||||
|
explanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + num.ToString());
|
||||||
|
explanation.Append("StatsReport_QualityMultiplier".Translate() + ": " + weaponDamageMultiplier.ToStringPercent());
|
||||||
|
}
|
||||||
|
num = Mathf.RoundToInt((float)num * weaponDamageMultiplier);
|
||||||
|
bool flag2 = explanation != null;
|
||||||
|
bool flag4 = flag2;
|
||||||
|
if (flag4)
|
||||||
|
{
|
||||||
|
explanation.AppendLine();
|
||||||
|
explanation.AppendLine();
|
||||||
|
explanation.Append("StatsReport_FinalValue".Translate() + ": " + num.ToString());
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetArmorPenetration(float weaponDamageMultiplier, StringBuilder explanation = null)
|
||||||
|
{
|
||||||
|
float num = this.armorPenetration;
|
||||||
|
bool flag = num < 0f;
|
||||||
|
bool flag4 = flag;
|
||||||
|
if (flag4)
|
||||||
|
{
|
||||||
|
num = (float)this.damageAmount * 0.015f;
|
||||||
|
}
|
||||||
|
bool flag2 = explanation != null;
|
||||||
|
bool flag5 = flag2;
|
||||||
|
if (flag5)
|
||||||
|
{
|
||||||
|
explanation.AppendLine("StatsReport_BaseValue".Translate() + ": " + num.ToStringPercent());
|
||||||
|
explanation.AppendLine();
|
||||||
|
explanation.Append("StatsReport_QualityMultiplier".Translate() + ": " + weaponDamageMultiplier.ToStringPercent());
|
||||||
|
}
|
||||||
|
num *= weaponDamageMultiplier;
|
||||||
|
bool flag3 = explanation != null;
|
||||||
|
bool flag6 = flag3;
|
||||||
|
if (flag6)
|
||||||
|
{
|
||||||
|
explanation.AppendLine();
|
||||||
|
explanation.AppendLine();
|
||||||
|
explanation.Append("StatsReport_FinalValue".Translate() + ": " + num.ToStringPercent());
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Pawn> pawnConduct = new List<Pawn>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user