1
This commit is contained in:
Binary file not shown.
@@ -202,6 +202,32 @@
|
|||||||
</li>
|
</li>
|
||||||
</stages>
|
</stages>
|
||||||
</HediffDef>
|
</HediffDef>
|
||||||
|
<HediffDef>
|
||||||
|
<defName>WULA_MechShutdown</defName>
|
||||||
|
<hediffClass>HediffWithComps</hediffClass>
|
||||||
|
<label></label>
|
||||||
|
<description>This mech has stopped due to insufficient fuel, need to assign a colonist to refuel it to restore its operational capability.</description>
|
||||||
|
<descriptionShort>This mech has stopped due to insufficient fuel.</descriptionShort>
|
||||||
|
<!-- <initialSeverity>0.5</initialSeverity> -->
|
||||||
|
<minSeverity>0.01</minSeverity>
|
||||||
|
<maxSeverity>1</maxSeverity>
|
||||||
|
<alwaysShowSeverity>true</alwaysShowSeverity>
|
||||||
|
<isBad>true</isBad>
|
||||||
|
<duplicationAllowed>true</duplicationAllowed>
|
||||||
|
<keepOnBodyPartRestoration>true</keepOnBodyPartRestoration> <!-- true -->
|
||||||
|
<!-- <defaultInstallPart>Brain</defaultInstallPart> -->
|
||||||
|
<stages>
|
||||||
|
<li>
|
||||||
|
<capMods>
|
||||||
|
<li>
|
||||||
|
<capacity>Moving</capacity>
|
||||||
|
<setMax>0.1</setMax>
|
||||||
|
</li>
|
||||||
|
</capMods>
|
||||||
|
</li>
|
||||||
|
</stages>
|
||||||
|
</HediffDef>
|
||||||
|
|
||||||
|
|
||||||
<HediffDef>
|
<HediffDef>
|
||||||
<defName>WULA_MechCarrierSwitchHediff</defName>
|
<defName>WULA_MechCarrierSwitchHediff</defName>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
<makeTargetPrisoner>false</makeTargetPrisoner> -->
|
<makeTargetPrisoner>false</makeTargetPrisoner> -->
|
||||||
</JobDef>
|
</JobDef>
|
||||||
<WorkGiverDef>
|
<WorkGiverDef>
|
||||||
<defName>WULA_Refuel</defName>
|
<defName>WULA_RefuelMech</defName>
|
||||||
<label>refuel Mechs</label>
|
<label>refuel Mechs</label>
|
||||||
<giverClass>WulaFallenEmpire.WorkGiver_RefuelMech</giverClass>
|
<giverClass>WulaFallenEmpire.WorkGiver_RefuelMech</giverClass>
|
||||||
<workType>Hauling</workType>
|
<workType>Hauling</workType>
|
||||||
|
|||||||
@@ -179,6 +179,7 @@
|
|||||||
<defaultFactionType>PlayerColony</defaultFactionType>
|
<defaultFactionType>PlayerColony</defaultFactionType>
|
||||||
<canMeleeAttack>false</canMeleeAttack>
|
<canMeleeAttack>false</canMeleeAttack>
|
||||||
<isGoodBreacher>true</isGoodBreacher>
|
<isGoodBreacher>true</isGoodBreacher>
|
||||||
|
<collidesWithPawns>false</collidesWithPawns>
|
||||||
|
|
||||||
<flyingAnimationFramePathPrefix>Wula/Things/Wula_Mech_Mobile_Factory/Flying/Wula_Mech_Mobile_Factory_Flying_</flyingAnimationFramePathPrefix>
|
<flyingAnimationFramePathPrefix>Wula/Things/Wula_Mech_Mobile_Factory/Flying/Wula_Mech_Mobile_Factory_Flying_</flyingAnimationFramePathPrefix>
|
||||||
<flyingAnimationDrawSize>1</flyingAnimationDrawSize>
|
<flyingAnimationDrawSize>1</flyingAnimationDrawSize>
|
||||||
|
|||||||
@@ -133,4 +133,17 @@
|
|||||||
<showOnDrones>true</showOnDrones>
|
<showOnDrones>true</showOnDrones>
|
||||||
<workerClass>WulaFallenEmpire.StatWorker_Maintenance</workerClass>
|
<workerClass>WulaFallenEmpire.StatWorker_Maintenance</workerClass>
|
||||||
</StatDef>
|
</StatDef>
|
||||||
|
|
||||||
|
<!-- 机甲装甲值 -->
|
||||||
|
<StatDef>
|
||||||
|
<defName>WULA_MechArmor</defName>
|
||||||
|
<label>复合装甲层</label>
|
||||||
|
<description>乌拉帝国在大型战争机械和少部分护甲上使用的特殊防御装甲,当 护甲穿透乘数 * 攻击 的最终值小于此值时,该攻击将被完全抵消而不造成任何伤害。</description>
|
||||||
|
<category>Apparel</category>
|
||||||
|
<toStringStyle>FloatTwo</toStringStyle>
|
||||||
|
<defaultBaseValue>0</defaultBaseValue>
|
||||||
|
<hideAtValue>0</hideAtValue>
|
||||||
|
<minValue>0</minValue>
|
||||||
|
<displayPriorityInCategory>5000</displayPriorityInCategory>
|
||||||
|
</StatDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
@@ -477,9 +477,17 @@
|
|||||||
<Steel>200</Steel>
|
<Steel>200</Steel>
|
||||||
<ComponentIndustrial>12</ComponentIndustrial>
|
<ComponentIndustrial>12</ComponentIndustrial>
|
||||||
</costList>
|
</costList>
|
||||||
<weaponTags>
|
<weaponTags Inherit="False">
|
||||||
<li>Wula_AI_Heavy_Panzer_Weapon</li>
|
<li>Wula_AI_Heavy_Panzer_Weapon</li>
|
||||||
</weaponTags>
|
</weaponTags>
|
||||||
|
<thingCategories Inherit="False"/>
|
||||||
|
<comps>
|
||||||
|
<li Class="WulaFallenEmpire.CompProperties_MechOnlyWeapon">
|
||||||
|
<allowedMechRaces>
|
||||||
|
<li>Wula_AI_Heavy_Panzer</li>
|
||||||
|
</allowedMechRaces>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
<ThingDef ParentName="BaseBullet">
|
<ThingDef ParentName="BaseBullet">
|
||||||
<defName>Bullet_Wula_AI_Heavy_Panzer_Main_Weapon</defName>
|
<defName>Bullet_Wula_AI_Heavy_Panzer_Main_Weapon</defName>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<Defs>
|
<Defs>
|
||||||
<!-- human的克隆,防止其他mod修改human导致的不兼容 -->
|
|
||||||
<ThingDef Abstract="True" Name="Wula_Human_Protect_Superclass" ParentName="BasePawn">
|
<ThingDef Abstract="True" Name="Wula_Human_Protect_Superclass" ParentName="BasePawn">
|
||||||
<defName>Wula_Human</defName>
|
<defName>Wula_Human</defName>
|
||||||
<label>human</label>
|
<label>human</label>
|
||||||
@@ -225,7 +224,6 @@
|
|||||||
</li>
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
<!-- 基础类,希望对human的更改在此处应用 -->
|
|
||||||
<ThingDef Abstract="True" Name="Wula_Human_Base" ParentName="Wula_Human_Protect_Superclass">
|
<ThingDef Abstract="True" Name="Wula_Human_Base" ParentName="Wula_Human_Protect_Superclass">
|
||||||
<statBases>
|
<statBases>
|
||||||
<MarketValue>0</MarketValue>
|
<MarketValue>0</MarketValue>
|
||||||
@@ -785,7 +783,6 @@
|
|||||||
</comps>
|
</comps>
|
||||||
</AlienRace.ThingDef_AlienRace>
|
</AlienRace.ThingDef_AlienRace>
|
||||||
|
|
||||||
<!-- 乌拉基础机械族类 -->
|
|
||||||
<ThingDef ParentName="BasePawn" Name="WULA_BaseMechanoid" Abstract="True">
|
<ThingDef ParentName="BasePawn" Name="WULA_BaseMechanoid" Abstract="True">
|
||||||
<soundImpactDefault>BulletImpact_Metal</soundImpactDefault>
|
<soundImpactDefault>BulletImpact_Metal</soundImpactDefault>
|
||||||
<statBases>
|
<statBases>
|
||||||
@@ -877,7 +874,6 @@
|
|||||||
</comps>
|
</comps>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
|
||||||
<!-- 猫猫族系 -->
|
|
||||||
<ThingDef Abstract="True" Name="Mech_WULA_Cat_Base" ParentName="WULA_BaseMechanoid">
|
<ThingDef Abstract="True" Name="Mech_WULA_Cat_Base" ParentName="WULA_BaseMechanoid">
|
||||||
<statBases>
|
<statBases>
|
||||||
<MoveSpeed>5</MoveSpeed>
|
<MoveSpeed>5</MoveSpeed>
|
||||||
@@ -1099,695 +1095,6 @@
|
|||||||
</comps>
|
</comps>
|
||||||
</AlienRace.ThingDef_AlienRace>
|
</AlienRace.ThingDef_AlienRace>
|
||||||
|
|
||||||
<AlienRace.ThingDef_AlienRace ParentName="WULA_BaseMechanoid">
|
|
||||||
<defName>Wula_AI_Heavy_Panzer</defName> <!-- 修改了defName以避免冲突 -->
|
|
||||||
<label>HAp-6"战车"</label>
|
|
||||||
<description>乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。</description>
|
|
||||||
<uiIconPath>Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Heavy_Panzer_Icon</uiIconPath>
|
|
||||||
<alienRace>
|
|
||||||
<raceRestriction>
|
|
||||||
<weaponList>
|
|
||||||
<li>Wula_AI_Heavy_Panzer_Main_Weapon</li>
|
|
||||||
</weaponList>
|
|
||||||
<onlyUseRaceRestrictedApparel>true</onlyUseRaceRestrictedApparel>
|
|
||||||
<onlyUseRaceRestrictedWeapons>true</onlyUseRaceRestrictedWeapons>
|
|
||||||
</raceRestriction>
|
|
||||||
<compatibility>
|
|
||||||
<isFlesh>false</isFlesh>
|
|
||||||
</compatibility>
|
|
||||||
</alienRace>
|
|
||||||
<statBases>
|
|
||||||
<BandwidthCost>1</BandwidthCost>
|
|
||||||
<MoveSpeed>2</MoveSpeed>
|
|
||||||
<EnergyShieldEnergyMax>2</EnergyShieldEnergyMax>
|
|
||||||
<StaggerDurationFactor>0</StaggerDurationFactor>
|
|
||||||
|
|
||||||
<MaxFlightTime>9999</MaxFlightTime>
|
|
||||||
<FlightCooldown>0</FlightCooldown>
|
|
||||||
|
|
||||||
<ArmorRating_Sharp>1</ArmorRating_Sharp>
|
|
||||||
<ArmorRating_Blunt>1</ArmorRating_Blunt>
|
|
||||||
<ArmorRating_Heat>2</ArmorRating_Heat>
|
|
||||||
</statBases>
|
|
||||||
<costList Inherit="False">
|
|
||||||
<WULA_Alloy>300</WULA_Alloy>
|
|
||||||
<WULA_Charge_Cube>18</WULA_Charge_Cube>
|
|
||||||
<ComponentSpacer>2</ComponentSpacer>
|
|
||||||
</costList>
|
|
||||||
<race>
|
|
||||||
<body>WULA_AI_Heavy_Panzer_Body</body>
|
|
||||||
<baseBodySize>20</baseBodySize>
|
|
||||||
<lifeStageAges>
|
|
||||||
<li>
|
|
||||||
<def>MechanoidFullyFormed</def>
|
|
||||||
<minAge>0</minAge>
|
|
||||||
<soundCall>Pawn_Wula_AI_Heavy_Panzer_Call</soundCall>
|
|
||||||
</li>
|
|
||||||
</lifeStageAges>
|
|
||||||
<baseHealthScale>10</baseHealthScale>
|
|
||||||
|
|
||||||
<flightStartChanceOnJobStart>1</flightStartChanceOnJobStart>
|
|
||||||
<mechWeightClass>Heavy</mechWeightClass>
|
|
||||||
<!-- <thinkTreeConstant>WarUrchinConstant</thinkTreeConstant> -->
|
|
||||||
</race>
|
|
||||||
<tools Inherit="False">
|
|
||||||
<li>
|
|
||||||
<label>碾压</label>
|
|
||||||
<capacities>
|
|
||||||
<li>Blunt</li>
|
|
||||||
</capacities>
|
|
||||||
<power>360</power>
|
|
||||||
<cooldownTime>8</cooldownTime>
|
|
||||||
<linkedBodyPartsGroup>Torso</linkedBodyPartsGroup>
|
|
||||||
<ensureLinkedBodyPartsGroupAlwaysUsable>true</ensureLinkedBodyPartsGroupAlwaysUsable>
|
|
||||||
</li>
|
|
||||||
</tools>
|
|
||||||
<comps>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>0</ID>
|
|
||||||
<turretDef>Wula_AI_Heavy_Panzer_Turret_Weapon</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(7, 7)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="CompProperties_Shield">
|
|
||||||
<startingTicksToReset>36000</startingTicksToReset><!-- 10 mins -->
|
|
||||||
<minDrawSize>5.2</minDrawSize>
|
|
||||||
<maxDrawSize>5.4</maxDrawSize>
|
|
||||||
<energyLossPerDamage>0.02</energyLossPerDamage>
|
|
||||||
<energyOnReset>4.0</energyOnReset>
|
|
||||||
<blocksRangedWeapons>false</blocksRangedWeapons>
|
|
||||||
</li>
|
|
||||||
<!-- 飞行组件 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_PawnFlight">
|
|
||||||
|
|
||||||
<!-- 飞行触发条件:仅在征召时飞行 -->
|
|
||||||
<flightCondition>Drafted</flightCondition>
|
|
||||||
|
|
||||||
<!-- 链接到我们刚刚创建的 AnimationDef -->
|
|
||||||
<flyingAnimationNorth>WULA_Hover_FlyNorth</flyingAnimationNorth>
|
|
||||||
<flyingAnimationEast>WULA_Hover_FlyEast</flyingAnimationEast>
|
|
||||||
<flyingAnimationSouth>WULA_Hover_FlySouth</flyingAnimationSouth>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaDamage">
|
|
||||||
<radius>1.5</radius>
|
|
||||||
<damageIntervalTicks>30</damageIntervalTicks>
|
|
||||||
<damageDef>Crush</damageDef>
|
|
||||||
<damageAmount>3</damageAmount>
|
|
||||||
<scaleWithPsychicSensitivity>false</scaleWithPsychicSensitivity>
|
|
||||||
<affectFriendly>false</affectFriendly>
|
|
||||||
<affectNeutral>false</affectNeutral>
|
|
||||||
<affectHostile>true</affectHostile>
|
|
||||||
<affectBuildings>false</affectBuildings>
|
|
||||||
<ignoreFactionRelations>false</ignoreFactionRelations>
|
|
||||||
<startEnabled>false</startEnabled>
|
|
||||||
<toggleLabel>碾压伤害</toggleLabel>
|
|
||||||
<toggleDescription>HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。</toggleDescription>
|
|
||||||
<toggleIconPath>Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage</toggleIconPath>
|
|
||||||
</li>
|
|
||||||
</comps>
|
|
||||||
</AlienRace.ThingDef_AlienRace>
|
|
||||||
<AlienRace.ThingDef_AlienRace ParentName="WULA_BaseMechanoid">
|
|
||||||
<defName>Wula_AI_Rocket_Panzer</defName> <!-- 修改了defName以避免冲突 -->
|
|
||||||
<label>HRp-3"喷火战车"</label>
|
|
||||||
<description>乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢,但是未像其姊妹型号那样装备护盾。</description>
|
|
||||||
<uiIconPath>Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Rocket_Panzer_Icon</uiIconPath>
|
|
||||||
<alienRace>
|
|
||||||
<raceRestriction>
|
|
||||||
<weaponList>
|
|
||||||
<li>Wula_AI_Heavy_Panzer_Main_Weapon</li>
|
|
||||||
</weaponList>
|
|
||||||
<onlyUseRaceRestrictedApparel>true</onlyUseRaceRestrictedApparel>
|
|
||||||
<onlyUseRaceRestrictedWeapons>true</onlyUseRaceRestrictedWeapons>
|
|
||||||
</raceRestriction>
|
|
||||||
<compatibility>
|
|
||||||
<isFlesh>false</isFlesh>
|
|
||||||
</compatibility>
|
|
||||||
</alienRace>
|
|
||||||
<statBases>
|
|
||||||
<BandwidthCost>1</BandwidthCost>
|
|
||||||
<MoveSpeed>2</MoveSpeed>
|
|
||||||
<EnergyShieldEnergyMax>2</EnergyShieldEnergyMax>
|
|
||||||
<StaggerDurationFactor>0</StaggerDurationFactor>
|
|
||||||
|
|
||||||
<MaxFlightTime>9999</MaxFlightTime>
|
|
||||||
<FlightCooldown>0</FlightCooldown>
|
|
||||||
|
|
||||||
<ArmorRating_Sharp>1</ArmorRating_Sharp>
|
|
||||||
<ArmorRating_Blunt>1</ArmorRating_Blunt>
|
|
||||||
<ArmorRating_Heat>2</ArmorRating_Heat>
|
|
||||||
</statBases>
|
|
||||||
<costList Inherit="False">
|
|
||||||
<WULA_Alloy>300</WULA_Alloy>
|
|
||||||
<WULA_Charge_Cube>18</WULA_Charge_Cube>
|
|
||||||
<ComponentSpacer>2</ComponentSpacer>
|
|
||||||
</costList>
|
|
||||||
<race>
|
|
||||||
<body>WULA_AI_Heavy_Panzer_Body</body>
|
|
||||||
<baseBodySize>20</baseBodySize>
|
|
||||||
<lifeStageAges>
|
|
||||||
<li>
|
|
||||||
<def>MechanoidFullyFormed</def>
|
|
||||||
<minAge>0</minAge>
|
|
||||||
<soundCall>Pawn_Wula_AI_Heavy_Panzer_Call</soundCall>
|
|
||||||
</li>
|
|
||||||
</lifeStageAges>
|
|
||||||
<baseHealthScale>10</baseHealthScale>
|
|
||||||
|
|
||||||
<flightStartChanceOnJobStart>1</flightStartChanceOnJobStart>
|
|
||||||
<mechWeightClass>Heavy</mechWeightClass>
|
|
||||||
<!-- <thinkTreeConstant>WarUrchinConstant</thinkTreeConstant> -->
|
|
||||||
</race>
|
|
||||||
<tools Inherit="False">
|
|
||||||
<li>
|
|
||||||
<label>碾压</label>
|
|
||||||
<capacities>
|
|
||||||
<li>Blunt</li>
|
|
||||||
</capacities>
|
|
||||||
<power>360</power>
|
|
||||||
<cooldownTime>8</cooldownTime>
|
|
||||||
<linkedBodyPartsGroup>Torso</linkedBodyPartsGroup>
|
|
||||||
<ensureLinkedBodyPartsGroupAlwaysUsable>true</ensureLinkedBodyPartsGroupAlwaysUsable>
|
|
||||||
</li>
|
|
||||||
</tools>
|
|
||||||
<comps>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>0</ID>
|
|
||||||
<turretDef>Wula_AI_Rocket_Panzer_Turret_Weapon</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(7, 7)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<!-- 飞行组件 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_PawnFlight">
|
|
||||||
|
|
||||||
<!-- 飞行触发条件:仅在征召时飞行 -->
|
|
||||||
<flightCondition>Drafted</flightCondition>
|
|
||||||
|
|
||||||
<!-- 链接到我们刚刚创建的 AnimationDef -->
|
|
||||||
<flyingAnimationNorth>WULA_Hover_FlyNorth</flyingAnimationNorth>
|
|
||||||
<flyingAnimationEast>WULA_Hover_FlyEast</flyingAnimationEast>
|
|
||||||
<flyingAnimationSouth>WULA_Hover_FlySouth</flyingAnimationSouth>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaDamage">
|
|
||||||
<radius>1.5</radius>
|
|
||||||
<damageIntervalTicks>30</damageIntervalTicks>
|
|
||||||
<damageDef>Crush</damageDef>
|
|
||||||
<damageAmount>3</damageAmount>
|
|
||||||
<scaleWithPsychicSensitivity>false</scaleWithPsychicSensitivity>
|
|
||||||
<affectFriendly>false</affectFriendly>
|
|
||||||
<affectNeutral>false</affectNeutral>
|
|
||||||
<affectHostile>true</affectHostile>
|
|
||||||
<affectBuildings>false</affectBuildings>
|
|
||||||
<ignoreFactionRelations>false</ignoreFactionRelations>
|
|
||||||
<startEnabled>false</startEnabled>
|
|
||||||
<toggleLabel>碾压伤害</toggleLabel>
|
|
||||||
<toggleDescription>HRp-3"喷火战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。</toggleDescription>
|
|
||||||
<toggleIconPath>Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage</toggleIconPath>
|
|
||||||
</li>
|
|
||||||
</comps>
|
|
||||||
</AlienRace.ThingDef_AlienRace>
|
|
||||||
<AlienRace.ThingDef_AlienRace ParentName="WULA_BaseMechanoid">
|
|
||||||
<defName>Wula_Mech_Mobile_Shield</defName> <!-- 修改了defName以避免冲突 -->
|
|
||||||
<label>MSm-8"放射盾"</label>
|
|
||||||
<description>乌拉帝国的中型战争机械,常被用于镇压异族聚居地的暴动。它形状非常奇怪,根本分不出头在哪,但是不要因此小瞧这个机械体——其强大的立场盾能护佑一片区域并反射大量炮火,机体放射出来的辐射则会点燃进入反射盾范围内的敌人。在相关许可开放后,它甚至可以支持机械乌拉使用其内置的相位场进行区域传送,使其获得无与伦比的机动性。</description>
|
|
||||||
<alienRace>
|
|
||||||
<raceRestriction>
|
|
||||||
<onlyUseRaceRestrictedApparel>true</onlyUseRaceRestrictedApparel>
|
|
||||||
<onlyUseRaceRestrictedWeapons>true</onlyUseRaceRestrictedWeapons>
|
|
||||||
</raceRestriction>
|
|
||||||
<compatibility>
|
|
||||||
<isFlesh>false</isFlesh>
|
|
||||||
</compatibility>
|
|
||||||
</alienRace>
|
|
||||||
<statBases>
|
|
||||||
<BandwidthCost>1</BandwidthCost>
|
|
||||||
<MoveSpeed>3</MoveSpeed>
|
|
||||||
|
|
||||||
<ArmorRating_Sharp>0.5</ArmorRating_Sharp>
|
|
||||||
<ArmorRating_Blunt>0.5</ArmorRating_Blunt>
|
|
||||||
<ArmorRating_Heat>2</ArmorRating_Heat>
|
|
||||||
</statBases>
|
|
||||||
<race>
|
|
||||||
<body>WULA_Mech_Mobile_Shield_Body</body>
|
|
||||||
<baseBodySize>50</baseBodySize>
|
|
||||||
<lifeStageAges>
|
|
||||||
<li>
|
|
||||||
<def>MechanoidFullyFormed</def>
|
|
||||||
<minAge>0</minAge>
|
|
||||||
<soundCall>Pawn_Wula_Mech_Mobile_Factory_Call</soundCall>
|
|
||||||
</li>
|
|
||||||
</lifeStageAges>
|
|
||||||
<baseHealthScale>5</baseHealthScale>
|
|
||||||
<mechWeightClass>Heavy</mechWeightClass>
|
|
||||||
</race>
|
|
||||||
<tools Inherit="False">
|
|
||||||
<li>
|
|
||||||
<label>碾压</label>
|
|
||||||
<capacities>
|
|
||||||
<li>Blunt</li>
|
|
||||||
</capacities>
|
|
||||||
<power>360</power>
|
|
||||||
<cooldownTime>8</cooldownTime>
|
|
||||||
<linkedBodyPartsGroup>Torso</linkedBodyPartsGroup>
|
|
||||||
<ensureLinkedBodyPartsGroupAlwaysUsable>true</ensureLinkedBodyPartsGroupAlwaysUsable>
|
|
||||||
</li>
|
|
||||||
</tools>
|
|
||||||
<comps>
|
|
||||||
<!-- 护盾无法在此绘制 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaShield">
|
|
||||||
<radius>15</radius>
|
|
||||||
<baseHitPoints>300</baseHitPoints>
|
|
||||||
<rechargeDelay>2400</rechargeDelay>
|
|
||||||
<rechargeHitPointsIntervalTicks>30</rechargeHitPointsIntervalTicks>
|
|
||||||
|
|
||||||
<!-- 效果器配置 -->
|
|
||||||
<absorbEffecter>Interceptor_BlockedProjectile</absorbEffecter>
|
|
||||||
<interceptEffecter>Interceptor_BlockedProjectile</interceptEffecter>
|
|
||||||
<breakEffecter>Shield_Break</breakEffecter>
|
|
||||||
<reactivateEffecter>BulletShieldGenerator_Reactivate</reactivateEffecter>
|
|
||||||
|
|
||||||
<color>(0.9, 0.2, 0.2, 0.5)</color> <!-- 护盾气泡的颜色 (RGBA) -->
|
|
||||||
|
|
||||||
<!-- 拦截设置 -->
|
|
||||||
<interceptGroundProjectiles>true</interceptGroundProjectiles>
|
|
||||||
<interceptNonHostileProjectiles>false</interceptNonHostileProjectiles>
|
|
||||||
<interceptAirProjectiles>true</interceptAirProjectiles>
|
|
||||||
|
|
||||||
<!-- 反射设置 -->
|
|
||||||
<canReflect>true</canReflect>
|
|
||||||
<reflectChance>0.85</reflectChance>
|
|
||||||
<reflectAngleRange>30</reflectAngleRange>
|
|
||||||
<reflectCost>0</reflectCost>
|
|
||||||
<reflectEffecter>Interceptor_BlockedProjectile</reflectEffecter>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaDamage">
|
|
||||||
<radius>15</radius>
|
|
||||||
<damageIntervalTicks>30</damageIntervalTicks>
|
|
||||||
<damageDef>Flame</damageDef>
|
|
||||||
<damageAmount>8</damageAmount>
|
|
||||||
<scaleWithPsychicSensitivity>false</scaleWithPsychicSensitivity>
|
|
||||||
<affectFriendly>false</affectFriendly>
|
|
||||||
<affectNeutral>false</affectNeutral>
|
|
||||||
<affectHostile>true</affectHostile>
|
|
||||||
<affectBuildings>false</affectBuildings>
|
|
||||||
<ignoreFactionRelations>false</ignoreFactionRelations>
|
|
||||||
<startEnabled>false</startEnabled>
|
|
||||||
<toggleLabel>热辐射</toggleLabel>
|
|
||||||
<toggleDescription>MSm-8"放射盾"可以打开外壳,蒸发胆敢进入反射立场内的敌军——这同时会使得它伤害附近所有的散落物品。</toggleDescription>
|
|
||||||
<toggleIconPath>Wula/UI/Commands/Wula_Psi_Titan_AreaDamage</toggleIconPath>
|
|
||||||
</li>
|
|
||||||
<!-- 区域传送组件 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaTeleporter">
|
|
||||||
<teleportRadius>15</teleportRadius>
|
|
||||||
<stunTicks>60</stunTicks>
|
|
||||||
|
|
||||||
<allowedRaces>
|
|
||||||
<li>WulaSpecies</li>
|
|
||||||
</allowedRaces>
|
|
||||||
<onlyPawnsInSameFaction>true</onlyPawnsInSameFaction>
|
|
||||||
|
|
||||||
<entryEffecter>Skip_Entry</entryEffecter>
|
|
||||||
<exitEffecter>Skip_Exit</exitEffecter>
|
|
||||||
<teleportSound>Psycast_Skip_Entry</teleportSound>
|
|
||||||
|
|
||||||
<requireResearchToUse>true</requireResearchToUse>
|
|
||||||
<requiredResearch>WULA_Mech_Mobile_Shield_Teleporter_Technology</requiredResearch>
|
|
||||||
</li>
|
|
||||||
</comps>
|
|
||||||
</AlienRace.ThingDef_AlienRace>
|
|
||||||
<AlienRace.ThingDef_AlienRace ParentName="WULA_BaseMechanoid">
|
|
||||||
<defName>Wula_Mech_Mobile_Factory</defName> <!-- 修改了defName以避免冲突 -->
|
|
||||||
<label>MFm-2"陆行舰"</label>
|
|
||||||
<description>乌拉帝国的大型战争机械,简直就是一座移动堡垒——它不仅装甲厚实、火炮林立,还能在战场上生产大量的辅助战争机械以形成坚实的弹性阵线,生来就是为了粉碎坚固的要塞和顽强的抵抗。</description>
|
|
||||||
<alienRace>
|
|
||||||
<raceRestriction>
|
|
||||||
<weaponList>
|
|
||||||
<li>WULA_RW_Unlimit_Penetrating_Beam_Cannon</li>
|
|
||||||
</weaponList>
|
|
||||||
<onlyUseRaceRestrictedApparel>true</onlyUseRaceRestrictedApparel>
|
|
||||||
<onlyUseRaceRestrictedWeapons>true</onlyUseRaceRestrictedWeapons>
|
|
||||||
</raceRestriction>
|
|
||||||
<compatibility>
|
|
||||||
<isFlesh>false</isFlesh>
|
|
||||||
</compatibility>
|
|
||||||
</alienRace>
|
|
||||||
<statBases>
|
|
||||||
<BandwidthCost>1</BandwidthCost>
|
|
||||||
<MoveSpeed>1</MoveSpeed>
|
|
||||||
<EnergyShieldEnergyMax>5</EnergyShieldEnergyMax>
|
|
||||||
|
|
||||||
<MaxFlightTime>9999</MaxFlightTime>
|
|
||||||
<FlightCooldown>0</FlightCooldown>
|
|
||||||
|
|
||||||
<ArmorRating_Sharp>1.75</ArmorRating_Sharp>
|
|
||||||
<ArmorRating_Blunt>1.75</ArmorRating_Blunt>
|
|
||||||
<ArmorRating_Heat>2</ArmorRating_Heat>
|
|
||||||
</statBases>
|
|
||||||
<race>
|
|
||||||
<body>WULA_Mech_Mobile_Factory_Body</body>
|
|
||||||
<baseBodySize>50</baseBodySize>
|
|
||||||
<lifeStageAges>
|
|
||||||
<li>
|
|
||||||
<def>MechanoidFullyFormed</def>
|
|
||||||
<minAge>0</minAge>
|
|
||||||
<soundCall>Pawn_Wula_Mech_Mobile_Factory_Call</soundCall>
|
|
||||||
</li>
|
|
||||||
</lifeStageAges>
|
|
||||||
<baseHealthScale>25</baseHealthScale>
|
|
||||||
|
|
||||||
<flightStartChanceOnJobStart>1</flightStartChanceOnJobStart>
|
|
||||||
<mechWeightClass>Heavy</mechWeightClass>
|
|
||||||
<!-- <thinkTreeConstant>WarUrchinConstant</thinkTreeConstant> -->
|
|
||||||
</race>
|
|
||||||
<tools Inherit="False">
|
|
||||||
<li>
|
|
||||||
<label>碾压</label>
|
|
||||||
<capacities>
|
|
||||||
<li>Blunt</li>
|
|
||||||
</capacities>
|
|
||||||
<power>360</power>
|
|
||||||
<cooldownTime>8</cooldownTime>
|
|
||||||
<linkedBodyPartsGroup>Torso</linkedBodyPartsGroup>
|
|
||||||
<ensureLinkedBodyPartsGroupAlwaysUsable>true</ensureLinkedBodyPartsGroupAlwaysUsable>
|
|
||||||
</li>
|
|
||||||
</tools>
|
|
||||||
<comps>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>0</ID>
|
|
||||||
<turretDef>Wula_CR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-1, 0, -1.45)</offset>
|
|
||||||
<flip>true</flip>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
<offset>(3.25, 0, -1)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(1.5, 0, -1.45)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<offset>(-3.25, 0, -1)</offset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>1</ID>
|
|
||||||
<turretDef>Wula_CR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(1, 0, -1.45)</offset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(3.25, 0, -1)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-1.6, 0, -1.45)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<offset>(-3.25, 0, -1)</offset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>2</ID>
|
|
||||||
<turretDef>Wula_MR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-1.3, 0, -0.45)</offset>
|
|
||||||
<flip>true</flip>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
<offset>(2.4, 0, -0.35)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(2.3, 0, -0.45)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<offset>(-2.4, 0, -0.35)</offset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>3</ID>
|
|
||||||
<turretDef>Wula_MR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(1.3, 0, -0.45)</offset>
|
|
||||||
<flip>true</flip>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(2.4, 0, -0.35)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-2.3, 0, -0.45)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
<offset>(-2.4, 0, -0.35)</offset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>4</ID>
|
|
||||||
<turretDef>Wula_LR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(1.25, 0, 0.45)</offset>
|
|
||||||
<flip>true</flip>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
<offset>(1.6, 0, 0.25)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-2.15, 0, 0.65)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<offset>(-1.6, 0, 0.25)</offset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_MultiTurretGun">
|
|
||||||
<ID>5</ID>
|
|
||||||
<turretDef>Wula_LR_Mobile_Factory_Turret</turretDef>
|
|
||||||
<!-- <angleOffset>-90</angleOffset> -->
|
|
||||||
<renderNodeProperties>
|
|
||||||
<li>
|
|
||||||
<nodeClass>PawnRenderNode_TurretGun</nodeClass>
|
|
||||||
<workerClass>PawnRenderNodeWorker_TurretGun</workerClass>
|
|
||||||
<parentTagDef>Body</parentTagDef>
|
|
||||||
<overrideMeshSize>(2, 2)</overrideMeshSize>
|
|
||||||
<baseLayer>20</baseLayer>
|
|
||||||
<pawnType>Any</pawnType>
|
|
||||||
<drawData>
|
|
||||||
<dataNorth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(-1.25, 0, 0.45)</offset>
|
|
||||||
<flip>true</flip>
|
|
||||||
<layer>-5</layer>
|
|
||||||
</dataNorth>
|
|
||||||
<dataEast>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(1.6, 0, 0.25)</offset>
|
|
||||||
</dataEast>
|
|
||||||
<dataSouth>
|
|
||||||
<rotationOffset>-90</rotationOffset>
|
|
||||||
<offset>(2.05, 0, 0.65)</offset>
|
|
||||||
</dataSouth>
|
|
||||||
<dataWest>
|
|
||||||
<rotationOffset>90</rotationOffset>
|
|
||||||
<layer>-5</layer>
|
|
||||||
<offset>(-1.6, 0, 0.25)</offset>
|
|
||||||
</dataWest>
|
|
||||||
</drawData>
|
|
||||||
</li>
|
|
||||||
</renderNodeProperties>
|
|
||||||
</li>
|
|
||||||
<!-- 护盾无法在此绘制 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaShield">
|
|
||||||
<radius>9</radius>
|
|
||||||
<baseHitPoints>300</baseHitPoints>
|
|
||||||
<rechargeDelay>2400</rechargeDelay>
|
|
||||||
<rechargeHitPointsIntervalTicks>30</rechargeHitPointsIntervalTicks>
|
|
||||||
|
|
||||||
<!-- 效果器配置 -->
|
|
||||||
<absorbEffecter>Interceptor_BlockedProjectile</absorbEffecter>
|
|
||||||
<interceptEffecter>Interceptor_BlockedProjectile</interceptEffecter>
|
|
||||||
<breakEffecter>Shield_Break</breakEffecter>
|
|
||||||
<reactivateEffecter>BulletShieldGenerator_Reactivate</reactivateEffecter>
|
|
||||||
|
|
||||||
<color>(0.9, 0.2, 0.2, 0.5)</color> <!-- 护盾气泡的颜色 (RGBA) -->
|
|
||||||
|
|
||||||
<!-- 拦截设置 -->
|
|
||||||
<interceptGroundProjectiles>true</interceptGroundProjectiles>
|
|
||||||
<interceptNonHostileProjectiles>false</interceptNonHostileProjectiles>
|
|
||||||
<interceptAirProjectiles>true</interceptAirProjectiles>
|
|
||||||
|
|
||||||
<!-- 反射设置 -->
|
|
||||||
<canReflect>true</canReflect>
|
|
||||||
<reflectChance>0.6</reflectChance>
|
|
||||||
<reflectAngleRange>30</reflectAngleRange>
|
|
||||||
<reflectCost>0</reflectCost>
|
|
||||||
<reflectEffecter>Interceptor_BlockedProjectile</reflectEffecter>
|
|
||||||
</li>
|
|
||||||
<!-- 飞行组件 -->
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_PawnFlight">
|
|
||||||
|
|
||||||
<!-- 飞行触发条件:仅在征召时飞行 -->
|
|
||||||
<flightCondition>Drafted</flightCondition>
|
|
||||||
|
|
||||||
<!-- 链接到我们刚刚创建的 AnimationDef -->
|
|
||||||
<flyingAnimationNorth>WULA_Hover_FlyNorth</flyingAnimationNorth>
|
|
||||||
<flyingAnimationEast>WULA_Hover_FlyEast</flyingAnimationEast>
|
|
||||||
<flyingAnimationSouth>WULA_Hover_FlySouth</flyingAnimationSouth>
|
|
||||||
</li>
|
|
||||||
<li Class="WulaFallenEmpire.CompProperties_AreaDamage">
|
|
||||||
<radius>3.5</radius>
|
|
||||||
<damageIntervalTicks>30</damageIntervalTicks>
|
|
||||||
<damageDef>Crush</damageDef>
|
|
||||||
<damageAmount>4</damageAmount>
|
|
||||||
<scaleWithPsychicSensitivity>false</scaleWithPsychicSensitivity>
|
|
||||||
<affectFriendly>false</affectFriendly>
|
|
||||||
<affectNeutral>false</affectNeutral>
|
|
||||||
<affectHostile>true</affectHostile>
|
|
||||||
<affectBuildings>false</affectBuildings>
|
|
||||||
<ignoreFactionRelations>false</ignoreFactionRelations>
|
|
||||||
<startEnabled>false</startEnabled>
|
|
||||||
<toggleLabel>碾压伤害</toggleLabel>
|
|
||||||
<toggleDescription>MFm-2"陆行舰"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。</toggleDescription>
|
|
||||||
<toggleIconPath>Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage</toggleIconPath>
|
|
||||||
</li>
|
|
||||||
</comps>
|
|
||||||
</AlienRace.ThingDef_AlienRace>
|
|
||||||
<ThingDef ParentName="BaseMechanoidWalker">
|
<ThingDef ParentName="BaseMechanoidWalker">
|
||||||
<defName>WULA_Mech_Flyer</defName>
|
<defName>WULA_Mech_Flyer</defName>
|
||||||
<label>CRm-51"兵蚁"</label>
|
<label>CRm-51"兵蚁"</label>
|
||||||
@@ -2004,7 +1311,6 @@
|
|||||||
</comps>
|
</comps>
|
||||||
</AlienRace.ThingDef_AlienRace>
|
</AlienRace.ThingDef_AlienRace>
|
||||||
|
|
||||||
<!-- 特殊单位 -->
|
|
||||||
<ThingDef ParentName="BaseMechanoidWalker">
|
<ThingDef ParentName="BaseMechanoidWalker">
|
||||||
<defName>WULA_Fxxk_Goose</defName>
|
<defName>WULA_Fxxk_Goose</defName>
|
||||||
<label>神人大鹅</label>
|
<label>神人大鹅</label>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -560,4 +560,99 @@
|
|||||||
</subNodes>
|
</subNodes>
|
||||||
</thinkRoot>
|
</thinkRoot>
|
||||||
</ThinkTreeDef>
|
</ThinkTreeDef>
|
||||||
|
|
||||||
|
<ThinkTreeDef>
|
||||||
|
<defName>Wula_Battle_Mech_With_1_Pilot</defName>
|
||||||
|
<thinkRoot Class="ThinkNode_Priority">
|
||||||
|
<subNodes>
|
||||||
|
<!-- Despawned -->
|
||||||
|
<li Class="ThinkNode_Subtree">
|
||||||
|
<treeDef>Despawned</treeDef>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Deactivated -->
|
||||||
|
<li Class="ThinkNode_ConditionalDeactivated" MayRequire="Ludeon.RimWorld.Odyssey">
|
||||||
|
<subNodes>
|
||||||
|
<li Class="JobGiver_Deactivated" />
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Downed -->
|
||||||
|
<li Class="ThinkNode_Subtree">
|
||||||
|
<treeDef>Downed</treeDef>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- 重点!你需要在思考树中插入此项,以规定当没有足够的驾驶员时,机甲将执行什么行动 -->
|
||||||
|
<li Class="WulaFallenEmpire.ThinkNode_ConditionalMechHasPilot">
|
||||||
|
<minPilotCount>1</minPilotCount>
|
||||||
|
<subNodes>
|
||||||
|
<li Class="WulaFallenEmpire.JobGiver_NoPilot"/>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Mental state -->
|
||||||
|
<li Class="ThinkNode_ConditionalMentalState">
|
||||||
|
<state>BerserkMechanoid</state>
|
||||||
|
<subNodes>
|
||||||
|
<li Class="ThinkNode_Priority">
|
||||||
|
<subNodes>
|
||||||
|
<li Class="JobGiver_Berserk" />
|
||||||
|
<li Class="JobGiver_WanderAnywhere">
|
||||||
|
<maxDanger>Deadly</maxDanger>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Do a queued job -->
|
||||||
|
<li Class="ThinkNode_QueuedJob" />
|
||||||
|
|
||||||
|
<!-- Wait if drafted -->
|
||||||
|
<li Class="ThinkNode_ConditionalOfPlayerFaction">
|
||||||
|
<subNodes>
|
||||||
|
<li Class="ThinkNode_Tagger">
|
||||||
|
<tagToGive>DraftedOrder</tagToGive>
|
||||||
|
<subNodes>
|
||||||
|
<li Class="JobGiver_MoveToStandable" />
|
||||||
|
<li Class="JobGiver_Orders" />
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Lord -->
|
||||||
|
<li Class="ThinkNode_Subtree">
|
||||||
|
<treeDef>LordDuty</treeDef>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Idle player mech -->
|
||||||
|
<li Class="ThinkNode_ConditionalOfPlayerFaction">
|
||||||
|
<subNodes>
|
||||||
|
<li Class="ThinkNode_Tagger">
|
||||||
|
<tagToGive>Idle</tagToGive>
|
||||||
|
<subNodes>
|
||||||
|
<li Class="JobGiver_WanderColony">
|
||||||
|
<maxDanger>None</maxDanger>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Idle -->
|
||||||
|
<li Class="ThinkNode_Tagger">
|
||||||
|
<tagToGive>Idle</tagToGive>
|
||||||
|
<subNodes>
|
||||||
|
<li Class="JobGiver_WanderAnywhere">
|
||||||
|
<maxDanger>Deadly</maxDanger>
|
||||||
|
</li>
|
||||||
|
</subNodes>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<!-- Idle error -->
|
||||||
|
<li Class="JobGiver_IdleError"/>
|
||||||
|
</subNodes>
|
||||||
|
</thinkRoot>
|
||||||
|
</ThinkTreeDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Verse;
|
|||||||
namespace ArachnaeSwarm
|
namespace ArachnaeSwarm
|
||||||
{
|
{
|
||||||
[HarmonyPatch(typeof(Hediff_Mechlink), "PostAdd")]
|
[HarmonyPatch(typeof(Hediff_Mechlink), "PostAdd")]
|
||||||
public static class Hediff_Mechlink_PostAdd_Patch
|
public static class Hediff_Mechlink_PostAWULA_Patch
|
||||||
{
|
{
|
||||||
public static bool Prefix(Hediff_Mechlink __instance, DamageInfo? dinfo)
|
public static bool Prefix(Hediff_Mechlink __instance, DamageInfo? dinfo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] Error in fixed ColonistBar patch: {ex}");
|
Log.Error($"[WULA] Error in fixed ColonistBar patch: {ex}");
|
||||||
// 出错时不改变原列表
|
// 出错时不改变原列表
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace WulaFallenEmpire
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 此机甲不在允许列表中
|
// 此机甲不在允许列表中
|
||||||
cantReason = "DD_Equipment_For_Other_Mech".Translate();
|
cantReason = "WULA_Equipment_For_Other_Mech".Translate();
|
||||||
__result = false;
|
__result = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ namespace WulaFallenEmpire
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 非机甲尝试装备专用武器,禁止
|
// 非机甲尝试装备专用武器,禁止
|
||||||
cantReason = "DD_Human_Cannot_Equip_Mech_Weapon".Translate();
|
cantReason = "WULA_Human_Cannot_Equip_Mech_Weapon".Translate();
|
||||||
__result = false;
|
__result = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ namespace WulaFallenEmpire
|
|||||||
if (pawn is Wulamechunit)
|
if (pawn is Wulamechunit)
|
||||||
{
|
{
|
||||||
// 机甲不能装备普通武器
|
// 机甲不能装备普通武器
|
||||||
cantReason = "DD_Equipment_Not_Allow_For_Mech".Translate();
|
cantReason = "WULA_Equipment_Not_Allow_For_Mech".Translate();
|
||||||
__result = false;
|
__result = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] CanEquip patch error: {ex}");
|
Log.Error($"[WULA] CanEquip patch error: {ex}");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,14 +80,14 @@ namespace WulaFallenEmpire
|
|||||||
// 如果任一pawn是机甲单位,返回拒绝
|
// 如果任一pawn是机甲单位,返回拒绝
|
||||||
if (initiator is Wulamechunit || target is Wulamechunit)
|
if (initiator is Wulamechunit || target is Wulamechunit)
|
||||||
{
|
{
|
||||||
__result = new AcceptanceReport("DD_MechCannotRomance".Translate());
|
__result = new AcceptanceReport("WULA_MechCannotRomance".Translate());
|
||||||
return false; // 跳过原始方法
|
return false; // 跳过原始方法
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果任一pawn没有story组件,返回拒绝
|
// 如果任一pawn没有story组件,返回拒绝
|
||||||
if (initiator?.story == null || target?.story == null)
|
if (initiator?.story == null || target?.story == null)
|
||||||
{
|
{
|
||||||
__result = new AcceptanceReport("DD_NoStoryComponent".Translate());
|
__result = new AcceptanceReport("WULA_NoStoryComponent".Translate());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace WulaFallenEmpire.HarmonyPatches
|
|||||||
public static class Thing_TakeDamage_Patch
|
public static class Thing_TakeDamage_Patch
|
||||||
{
|
{
|
||||||
// 缓存装甲值StatDef
|
// 缓存装甲值StatDef
|
||||||
private static readonly StatDef ArmorStatDef = StatDef.Named("DD_MechArmor");
|
private static readonly StatDef ArmorStatDef = StatDef.Named("WULA_MechArmor");
|
||||||
|
|
||||||
// 阻挡效果的MoteDef
|
// 阻挡效果的MoteDef
|
||||||
private static readonly ThingDef BlockMoteDef = DefDatabase<ThingDef>.GetNamedSilentFail("Mote_Spark");
|
private static readonly ThingDef BlockMoteDef = DefDatabase<ThingDef>.GetNamedSilentFail("Mote_Spark");
|
||||||
@@ -102,7 +102,7 @@ namespace WulaFallenEmpire.HarmonyPatches
|
|||||||
|
|
||||||
// 显示文字效果
|
// 显示文字效果
|
||||||
Vector3 textPos = target.DrawPos + new Vector3(0, 0, 1f);
|
Vector3 textPos = target.DrawPos + new Vector3(0, 0, 1f);
|
||||||
MoteMaker.ThrowText(textPos, target.Map, "DD_BlockByMechArmor".Translate(), Color.yellow, 2.5f);
|
MoteMaker.ThrowText(textPos, target.Map, "WULA_BlockByMechArmor".Translate(), Color.yellow, 2.5f);
|
||||||
|
|
||||||
// 显示粒子效果
|
// 显示粒子效果
|
||||||
if (BlockMoteDef != null)
|
if (BlockMoteDef != null)
|
||||||
|
|||||||
@@ -277,7 +277,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] Harmony patch error in TryMeleeAttack: {ex}");
|
Log.Error($"[WULA] Harmony patch error in TryMeleeAttack: {ex}");
|
||||||
return true; // 出错时继续执行原始方法
|
return true; // 出错时继续执行原始方法
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else if (Prefs.DevMode)
|
else if (Prefs.DevMode)
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] OnPilotEnteredMech: 参数不是Wulamechunit类型: {mech?.GetType().Name}");
|
Log.Warning($"[WULA] OnPilotEnteredMech: 参数不是Wulamechunit类型: {mech?.GetType().Name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 在机甲{mech.LabelShort}上添加Hediff时出错: {ex}");
|
Log.Error($"[WULA] 在机甲{mech.LabelShort}上添加Hediff时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 从机甲{mech.LabelShort}移除Hediff时出错: {ex}");
|
Log.Error($"[WULA] 从机甲{mech.LabelShort}移除Hediff时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +242,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 触发同步效果时出错: {ex}");
|
Log.Error($"[WULA] 触发同步效果时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace WulaFallenEmpire
|
|||||||
public ITab_MechSkills()
|
public ITab_MechSkills()
|
||||||
{
|
{
|
||||||
this.size = new Vector2(520f, 600f);
|
this.size = new Vector2(520f, 600f);
|
||||||
this.labelKey = "DD_MechSkills".Translate();
|
this.labelKey = "WULA_MechSkills".Translate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FillTab()
|
protected override void FillTab()
|
||||||
@@ -36,7 +36,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (pawn.TryGetComp<CompMechSkillInheritance>() == null)
|
if (pawn.TryGetComp<CompMechSkillInheritance>() == null)
|
||||||
{
|
{
|
||||||
DrawError("DD_NoMechSkillComps".Translate());
|
DrawError("WULA_NoMechSkillComps".Translate());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ namespace WulaFallenEmpire
|
|||||||
);
|
);
|
||||||
|
|
||||||
string status = GetStatus(pawn);
|
string status = GetStatus(pawn);
|
||||||
string type = "DD_Mech".Translate();
|
string type = "WULA_Mech".Translate();
|
||||||
Widgets.Label(statusRect, $"{type} | {status}");
|
Widgets.Label(statusRect, $"{type} | {status}");
|
||||||
|
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
@@ -248,7 +248,7 @@ namespace WulaFallenEmpire
|
|||||||
);
|
);
|
||||||
|
|
||||||
Text.Font = GameFont.Medium;
|
Text.Font = GameFont.Medium;
|
||||||
Widgets.Label(titleRect, "DD_PilotTitle".Translate());
|
Widgets.Label(titleRect, "WULA_PilotTitle".Translate());
|
||||||
Text.Font = GameFont.Small;
|
Text.Font = GameFont.Small;
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
@@ -268,12 +268,12 @@ namespace WulaFallenEmpire
|
|||||||
if (pilot != null) pilotNames.Add(pilot.LabelShort);
|
if (pilot != null) pilotNames.Add(pilot.LabelShort);
|
||||||
}
|
}
|
||||||
var pilotNamelist = string.Join(", ", pilotNames);
|
var pilotNamelist = string.Join(", ", pilotNames);
|
||||||
Widgets.Label(contentRect, $"DD_PilotInfo".Translate(pilotNamelist));
|
Widgets.Label(contentRect, $"WULA_PilotInfo".Translate(pilotNamelist));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUI.color = Color.gray;
|
GUI.color = Color.gray;
|
||||||
Widgets.Label(contentRect, "DD_NoPilotShort".Translate());
|
Widgets.Label(contentRect, "WULA_NoPilotShort".Translate());
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,7 +307,7 @@ namespace WulaFallenEmpire
|
|||||||
if (pawn.skills == null || pawn.skills.skills.Count == 0)
|
if (pawn.skills == null || pawn.skills.skills.Count == 0)
|
||||||
{
|
{
|
||||||
GUI.color = Color.gray;
|
GUI.color = Color.gray;
|
||||||
Widgets.Label(skillsArea.ContractedBy(padding * 2), "DD_MechNoSkill".Translate());
|
Widgets.Label(skillsArea.ContractedBy(padding * 2), "WULA_MechNoSkill".Translate());
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -412,9 +412,9 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
var pilotComp = pawn.TryGetComp<CompMechPilotHolder>();
|
var pilotComp = pawn.TryGetComp<CompMechPilotHolder>();
|
||||||
if (pilotComp == null || !pilotComp.HasPilots)
|
if (pilotComp == null || !pilotComp.HasPilots)
|
||||||
return "DD_NoPilot".Translate();
|
return "WULA_NoPilot".Translate();
|
||||||
|
|
||||||
return "DD_Operational".Translate();
|
return "WULA_Operational".Translate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawError(string message)
|
private void DrawError(string message)
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class MentalState_MechNoPilot : MentalState
|
||||||
|
{
|
||||||
|
public override void PostStart(string reason)
|
||||||
|
{
|
||||||
|
base.PostStart(reason);
|
||||||
|
|
||||||
|
// 停止所有工作和移动
|
||||||
|
pawn.jobs?.StopAll();
|
||||||
|
pawn.pather?.StopDead();
|
||||||
|
|
||||||
|
// 取消征召
|
||||||
|
if (pawn.drafter != null && pawn.Drafted)
|
||||||
|
{
|
||||||
|
pawn.drafter.Drafted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除当前敌人目标
|
||||||
|
pawn.mindState.enemyTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostEnd()
|
||||||
|
{
|
||||||
|
base.PostEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void MentalStateTick(int delta)
|
||||||
|
{
|
||||||
|
// 使用父类的tick逻辑,但不允许自动恢复
|
||||||
|
if (pawn.IsHashIntervalTick(30, delta))
|
||||||
|
{
|
||||||
|
age += 30;
|
||||||
|
|
||||||
|
// 只有在有驾驶员时才允许恢复
|
||||||
|
// 检查会由 CompMechPilotHolder 处理
|
||||||
|
// 这里不实现自动恢复逻辑
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重写以禁用敌对行为
|
||||||
|
public override bool ForceHostileTo(Thing t)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ForceHostileTo(Faction f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重写以禁用社交活动
|
||||||
|
public override RandomSocialMode SocialModeMax()
|
||||||
|
{
|
||||||
|
return RandomSocialMode.Off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -63,7 +63,7 @@ namespace WulaFallenEmpire
|
|||||||
var pilotComp = this.TryGetComp<CompMechPilotHolder>();
|
var pilotComp = this.TryGetComp<CompMechPilotHolder>();
|
||||||
if (pilotComp != null && !pilotComp.HasPilots)
|
if (pilotComp != null && !pilotComp.HasPilots)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_CannotDraftWithoutPilot".Translate(this.LabelShort),
|
Messages.Message("WULA_CannotDraftWithoutPilot".Translate(this.LabelShort),
|
||||||
this, MessageTypeDefOf.RejectInput);
|
this, MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ namespace WulaFallenEmpire
|
|||||||
var pilotComp = this.TryGetComp<CompMechPilotHolder>();
|
var pilotComp = this.TryGetComp<CompMechPilotHolder>();
|
||||||
if (pilotComp != null && !pilotComp.HasPilots)
|
if (pilotComp != null && !pilotComp.HasPilots)
|
||||||
{
|
{
|
||||||
command_Toggle.Disable("DD_NoPilot".Translate());
|
command_Toggle.Disable("WULA_NoPilot".Translate());
|
||||||
}
|
}
|
||||||
|
|
||||||
command_Toggle.tutorTag = ((!base.Drafted) ? "Draft" : "Undraft");
|
command_Toggle.tutorTag = ((!base.Drafted) ? "Draft" : "Undraft");
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace WulaFallenEmpire
|
|||||||
var pilotKind = Props.SelectRandomPilotKind();
|
var pilotKind = Props.SelectRandomPilotKind();
|
||||||
if (pilotKind == null)
|
if (pilotKind == null)
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] No valid pilot kind found");
|
Log.Warning($"[WULA] No valid pilot kind found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] Cannot add pilot {pilot.LabelShortCap} to mech");
|
Log.Warning($"[WULA] Cannot add pilot {pilot.LabelShortCap} to mech");
|
||||||
// 清理生成的pawn
|
// 清理生成的pawn
|
||||||
pilot.Destroy();
|
pilot.Destroy();
|
||||||
return false;
|
return false;
|
||||||
@@ -159,7 +159,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] Error generating default pilot: {ex}");
|
Log.Error($"[WULA] Error generating default pilot: {ex}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,855 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using RimWorld;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
using Verse.Sound;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 高速移动撞击组件
|
||||||
|
/// </summary>
|
||||||
|
public class CompHighSpeedCollision : ThingComp
|
||||||
|
{
|
||||||
|
// === 运行时状态 ===
|
||||||
|
private enum SpeedStage
|
||||||
|
{
|
||||||
|
Stage0, // 0阶段:不移动
|
||||||
|
Stage1, // 1阶段:低速碰撞
|
||||||
|
Stage2 // 2阶段:高速击飞
|
||||||
|
}
|
||||||
|
|
||||||
|
private SpeedStage currentStage = SpeedStage.Stage0;
|
||||||
|
private int stageTransitionCooldown = 0;
|
||||||
|
|
||||||
|
// 用于计算速度的帧历史
|
||||||
|
private Queue<float> speedHistory = new Queue<float>();
|
||||||
|
private IntVec3 lastPosition = IntVec3.Invalid;
|
||||||
|
private int lastPositionTick = -1;
|
||||||
|
|
||||||
|
// 已处理的敌人记录(避免同一帧重复处理)
|
||||||
|
private HashSet<Pawn> processedPawnsThisTick = new HashSet<Pawn>();
|
||||||
|
|
||||||
|
// === 缓存 ===
|
||||||
|
private CellRect collisionAreaCache = default;
|
||||||
|
private int lastAreaRecalculationTick = -1;
|
||||||
|
|
||||||
|
public CompProperties_HighSpeedCollision Props => (CompProperties_HighSpeedCollision)props;
|
||||||
|
|
||||||
|
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||||
|
{
|
||||||
|
base.PostSpawnSetup(respawningAfterLoad);
|
||||||
|
|
||||||
|
// 初始化速度历史
|
||||||
|
speedHistory.Clear();
|
||||||
|
for (int i = 0; i < Props.speedHistoryFrameCount; i++)
|
||||||
|
{
|
||||||
|
speedHistory.Enqueue(0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPosition = parent.Position;
|
||||||
|
lastPositionTick = Find.TickManager.TicksGame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CompTick()
|
||||||
|
{
|
||||||
|
base.CompTick();
|
||||||
|
|
||||||
|
if (!parent.Spawned || parent.Destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Pawn pawn = parent as Pawn;
|
||||||
|
if (pawn == null || pawn.Dead || pawn.Downed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 检查是否死亡或不能移动
|
||||||
|
if (!CanMove(pawn))
|
||||||
|
{
|
||||||
|
ResetToStage0();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每帧更新
|
||||||
|
ProcessFrame(pawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 处理每帧逻辑
|
||||||
|
/// </summary>
|
||||||
|
private void ProcessFrame(Pawn pawn)
|
||||||
|
{
|
||||||
|
int currentTick = Find.TickManager.TicksGame;
|
||||||
|
|
||||||
|
// 1. 计算当前速度
|
||||||
|
float currentSpeed = CalculateCurrentSpeed(pawn, currentTick);
|
||||||
|
|
||||||
|
// 2. 更新速度历史
|
||||||
|
UpdateSpeedHistory(currentSpeed);
|
||||||
|
|
||||||
|
// 3. 计算平均速度
|
||||||
|
float averageSpeed = GetAverageSpeed();
|
||||||
|
|
||||||
|
// 4. 确定阶段
|
||||||
|
DetermineSpeedStage(averageSpeed);
|
||||||
|
|
||||||
|
// 5. 根据阶段应用效果
|
||||||
|
ApplyStageEffects(pawn);
|
||||||
|
|
||||||
|
// 6. 清理每帧记录
|
||||||
|
processedPawnsThisTick.Clear();
|
||||||
|
|
||||||
|
// 7. 更新冷却
|
||||||
|
if (stageTransitionCooldown > 0)
|
||||||
|
stageTransitionCooldown--;
|
||||||
|
|
||||||
|
// 8. 调试绘制
|
||||||
|
if (Props.enableDebugVisuals && DebugSettings.godMode)
|
||||||
|
DrawDebugVisuals(pawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算当前速度(每秒格数)
|
||||||
|
/// </summary>
|
||||||
|
private float CalculateCurrentSpeed(Pawn pawn, int currentTick)
|
||||||
|
{
|
||||||
|
// 如果没有上次位置记录,无法计算速度
|
||||||
|
if (lastPositionTick < 0 || lastPosition == IntVec3.Invalid)
|
||||||
|
{
|
||||||
|
lastPosition = pawn.Position;
|
||||||
|
lastPositionTick = currentTick;
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算时间差(秒)
|
||||||
|
float timeDelta = (currentTick - lastPositionTick) / 60f;
|
||||||
|
if (timeDelta <= 0f)
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
// 计算距离(格数)
|
||||||
|
float distance = pawn.Position.DistanceTo(lastPosition);
|
||||||
|
|
||||||
|
// 计算速度(格/秒)
|
||||||
|
float speed = distance / timeDelta;
|
||||||
|
|
||||||
|
// 更新记录
|
||||||
|
lastPosition = pawn.Position;
|
||||||
|
lastPositionTick = currentTick;
|
||||||
|
|
||||||
|
return speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 更新速度历史
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateSpeedHistory(float currentSpeed)
|
||||||
|
{
|
||||||
|
speedHistory.Enqueue(currentSpeed);
|
||||||
|
while (speedHistory.Count > Props.speedHistoryFrameCount)
|
||||||
|
{
|
||||||
|
speedHistory.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取平均速度
|
||||||
|
/// </summary>
|
||||||
|
private float GetAverageSpeed()
|
||||||
|
{
|
||||||
|
if (speedHistory.Count == 0)
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
float sum = 0f;
|
||||||
|
foreach (float speed in speedHistory)
|
||||||
|
{
|
||||||
|
sum += speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / speedHistory.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确定速度阶段
|
||||||
|
/// </summary>
|
||||||
|
private void DetermineSpeedStage(float averageSpeed)
|
||||||
|
{
|
||||||
|
// 如果有冷却,保持当前阶段
|
||||||
|
if (stageTransitionCooldown > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpeedStage newStage;
|
||||||
|
|
||||||
|
if (averageSpeed <= Props.minSpeedForStage1)
|
||||||
|
{
|
||||||
|
newStage = SpeedStage.Stage0;
|
||||||
|
}
|
||||||
|
else if (averageSpeed >= Props.minSpeedForStage2)
|
||||||
|
{
|
||||||
|
newStage = SpeedStage.Stage2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newStage = SpeedStage.Stage1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 阶段变化时设置冷却
|
||||||
|
if (newStage != currentStage)
|
||||||
|
{
|
||||||
|
currentStage = newStage;
|
||||||
|
stageTransitionCooldown = Props.stageTransitionCooldownTicks;
|
||||||
|
|
||||||
|
if (Props.enableDebugLogging)
|
||||||
|
{
|
||||||
|
Log.Message($"[HighSpeedCollision] {parent.Label} transitioned to Stage {(int)currentStage} " +
|
||||||
|
$"at speed {averageSpeed:F2} cells/sec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用阶段效果
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyStageEffects(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (currentStage == SpeedStage.Stage0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 获取碰撞区域内的所有敌人
|
||||||
|
List<Pawn> enemiesInArea = GetEnemiesInCollisionArea(pawn);
|
||||||
|
|
||||||
|
foreach (Pawn enemy in enemiesInArea)
|
||||||
|
{
|
||||||
|
if (enemy == null || enemy.Destroyed || enemy.Dead || processedPawnsThisTick.Contains(enemy))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (currentStage)
|
||||||
|
{
|
||||||
|
case SpeedStage.Stage1:
|
||||||
|
ApplyStage1Effects(pawn, enemy);
|
||||||
|
break;
|
||||||
|
case SpeedStage.Stage2:
|
||||||
|
ApplyStage2Effects(pawn, enemy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
processedPawnsThisTick.Add(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用阶段1效果(伤害+hediff)
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyStage1Effects(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
// 检查目标是否已有hediff
|
||||||
|
bool alreadyHasHediff = target.health.hediffSet.HasHediff(Props.stage1Hediff);
|
||||||
|
|
||||||
|
// 如果已有hediff,不造成伤害
|
||||||
|
if (alreadyHasHediff && Props.stage1HediffPreventsDamage)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 造成伤害
|
||||||
|
if (Props.stage1DamageAmount > 0f)
|
||||||
|
{
|
||||||
|
ApplyDamage(attacker, target, Props.stage1DamageAmount, Props.stage1DamageDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 应用hediff
|
||||||
|
if (Props.stage1Hediff != null)
|
||||||
|
{
|
||||||
|
Hediff hediff = HediffMaker.MakeHediff(Props.stage1Hediff, target);
|
||||||
|
if (Props.stage1HediffDurationTicks > 0)
|
||||||
|
{
|
||||||
|
hediff.Severity = 1f;
|
||||||
|
hediff.TryGetComp<HediffComp_Disappears>()?.CompPostMake();
|
||||||
|
}
|
||||||
|
target.health.AddHediff(hediff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 播放效果
|
||||||
|
PlayStage1Effects(attacker, target);
|
||||||
|
|
||||||
|
if (Props.enableDebugLogging)
|
||||||
|
{
|
||||||
|
Log.Message($"[HighSpeedCollision] Stage1: {attacker.Label} -> {target.Label}, " +
|
||||||
|
$"Damage: {Props.stage1DamageAmount}, Hediff: {Props.stage1Hediff?.defName}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用阶段2效果(伤害+击飞)
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyStage2Effects(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
// 造成伤害
|
||||||
|
if (Props.stage2DamageAmount > 0f)
|
||||||
|
{
|
||||||
|
ApplyDamage(attacker, target, Props.stage2DamageAmount, Props.stage2DamageDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行击飞
|
||||||
|
PerformKnockback(attacker, target);
|
||||||
|
|
||||||
|
// 播放效果
|
||||||
|
PlayStage2Effects(attacker, target);
|
||||||
|
|
||||||
|
if (Props.enableDebugLogging)
|
||||||
|
{
|
||||||
|
Log.Message($"[HighSpeedCollision] Stage2: {attacker.Label} -> {target.Label}, " +
|
||||||
|
$"Damage: {Props.stage2DamageAmount}, Knockback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行击飞(参考CompAbilityEffect_FanShapedStunKnockback)
|
||||||
|
/// </summary>
|
||||||
|
private void PerformKnockback(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
if (target == null || target.Destroyed || target.Dead || attacker.Map == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 计算击飞方向(从攻击者指向目标)
|
||||||
|
IntVec3 knockbackDirection = CalculateKnockbackDirection(attacker, target.Position);
|
||||||
|
|
||||||
|
// 寻找击飞位置
|
||||||
|
IntVec3 knockbackDestination = FindKnockbackDestination(attacker, target, knockbackDirection);
|
||||||
|
|
||||||
|
// 如果找到有效位置,执行击飞
|
||||||
|
if (knockbackDestination.IsValid && knockbackDestination != target.Position)
|
||||||
|
{
|
||||||
|
CreateKnockbackFlyer(attacker, target, knockbackDestination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算击飞方向
|
||||||
|
/// </summary>
|
||||||
|
private IntVec3 CalculateKnockbackDirection(Pawn attacker, IntVec3 targetPosition)
|
||||||
|
{
|
||||||
|
IntVec3 direction = targetPosition - attacker.Position;
|
||||||
|
|
||||||
|
// 标准化方向
|
||||||
|
if (direction.x != 0 || direction.z != 0)
|
||||||
|
{
|
||||||
|
if (Mathf.Abs(direction.x) > Mathf.Abs(direction.z))
|
||||||
|
{
|
||||||
|
return new IntVec3(Mathf.Sign(direction.x) > 0 ? 1 : -1, 0, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new IntVec3(0, 0, Mathf.Sign(direction.z) > 0 ? 1 : -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果攻击者和目标在同一位置,使用随机方向
|
||||||
|
return new IntVec3(Rand.Value > 0.5f ? 1 : -1, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 寻找击飞位置
|
||||||
|
/// </summary>
|
||||||
|
private IntVec3 FindKnockbackDestination(Pawn attacker, Pawn target, IntVec3 direction)
|
||||||
|
{
|
||||||
|
Map map = attacker.Map;
|
||||||
|
IntVec3 currentPos = target.Position;
|
||||||
|
|
||||||
|
// 从最大距离开始向回找
|
||||||
|
for (int distance = Props.stage2KnockbackDistance; distance >= 1; distance--)
|
||||||
|
{
|
||||||
|
IntVec3 testPos = currentPos + (direction * distance);
|
||||||
|
|
||||||
|
if (!IsValidKnockbackDestination(testPos, map, target, attacker))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return testPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查击飞位置是否有效
|
||||||
|
/// </summary>
|
||||||
|
private bool IsValidKnockbackDestination(IntVec3 destination, Map map, Pawn victim, Pawn attacker)
|
||||||
|
{
|
||||||
|
if (!destination.IsValid || !destination.InBounds(map))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!destination.Standable(map))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否有其他pawn
|
||||||
|
Pawn existingPawn = destination.GetFirstPawn(map);
|
||||||
|
if (existingPawn != null && existingPawn != victim)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查视线
|
||||||
|
if (Props.requireLineOfSightForKnockback && !GenSight.LineOfSight(victim.Position, destination, map))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建击飞飞行器
|
||||||
|
/// </summary>
|
||||||
|
private void CreateKnockbackFlyer(Pawn attacker, Pawn target, IntVec3 destination)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Map map = attacker.Map;
|
||||||
|
|
||||||
|
// 使用自定义飞行器或默认飞行器
|
||||||
|
ThingDef flyerDef = Props.knockbackFlyerDef ?? ThingDefOf.PawnFlyer;
|
||||||
|
|
||||||
|
// 创建飞行器
|
||||||
|
PawnFlyer flyer = PawnFlyer.MakeFlyer(
|
||||||
|
flyerDef,
|
||||||
|
target,
|
||||||
|
destination,
|
||||||
|
Props.flightEffecterDef,
|
||||||
|
Props.landingSound,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new LocalTargetInfo(destination)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (flyer != null)
|
||||||
|
{
|
||||||
|
GenSpawn.Spawn(flyer, destination, map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[HighSpeedCollision] Exception creating PawnFlyer: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 应用伤害
|
||||||
|
/// </summary>
|
||||||
|
private void ApplyDamage(Pawn attacker, Pawn target, float amount, DamageDef damageDef)
|
||||||
|
{
|
||||||
|
if (amount <= 0f || damageDef == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DamageInfo damageInfo = new DamageInfo(
|
||||||
|
damageDef,
|
||||||
|
amount,
|
||||||
|
Props.armorPenetration,
|
||||||
|
-1f,
|
||||||
|
attacker,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
target.TakeDamage(damageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 播放阶段1效果
|
||||||
|
/// </summary>
|
||||||
|
private void PlayStage1Effects(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
if (Props.stage1Effecter != null && attacker.Map != null)
|
||||||
|
{
|
||||||
|
Effecter effect = Props.stage1Effecter.Spawn();
|
||||||
|
effect.Trigger(new TargetInfo(attacker.Position, attacker.Map),
|
||||||
|
new TargetInfo(target.Position, attacker.Map));
|
||||||
|
effect.Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Props.stage1Sound != null && attacker.Map != null)
|
||||||
|
{
|
||||||
|
Props.stage1Sound.PlayOneShot(new TargetInfo(target.Position, attacker.Map));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 播放阶段2效果
|
||||||
|
/// </summary>
|
||||||
|
private void PlayStage2Effects(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
if (Props.stage2Effecter != null && attacker.Map != null)
|
||||||
|
{
|
||||||
|
Effecter effect = Props.stage2Effecter.Spawn();
|
||||||
|
effect.Trigger(new TargetInfo(attacker.Position, attacker.Map),
|
||||||
|
new TargetInfo(target.Position, attacker.Map));
|
||||||
|
effect.Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Props.stage2Sound != null && attacker.Map != null)
|
||||||
|
{
|
||||||
|
Props.stage2Sound.PlayOneShot(new TargetInfo(target.Position, attacker.Map));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取碰撞区域内的所有敌人
|
||||||
|
/// </summary>
|
||||||
|
private List<Pawn> GetEnemiesInCollisionArea(Pawn pawn)
|
||||||
|
{
|
||||||
|
List<Pawn> enemies = new List<Pawn>();
|
||||||
|
|
||||||
|
// 获取碰撞区域
|
||||||
|
CellRect collisionArea = GetCollisionArea(pawn);
|
||||||
|
|
||||||
|
// 检查区域内的每个单元格
|
||||||
|
foreach (IntVec3 cell in collisionArea)
|
||||||
|
{
|
||||||
|
if (!cell.InBounds(pawn.Map))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 获取单元格内的所有pawn
|
||||||
|
List<Thing> things = cell.GetThingList(pawn.Map);
|
||||||
|
foreach (Thing thing in things)
|
||||||
|
{
|
||||||
|
if (thing is Pawn otherPawn && otherPawn != pawn)
|
||||||
|
{
|
||||||
|
// 检查是否为敌人
|
||||||
|
if (IsValidTarget(pawn, otherPawn))
|
||||||
|
{
|
||||||
|
enemies.Add(otherPawn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return enemies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取碰撞区域
|
||||||
|
/// </summary>
|
||||||
|
private CellRect GetCollisionArea(Pawn pawn)
|
||||||
|
{
|
||||||
|
int currentTick = Find.TickManager.TicksGame;
|
||||||
|
|
||||||
|
// 每10帧重新计算一次区域,或当位置变化时
|
||||||
|
if (currentTick - lastAreaRecalculationTick > 10 ||
|
||||||
|
pawn.Position != collisionAreaCache.CenterCell)
|
||||||
|
{
|
||||||
|
int radius = Props.collisionAreaRadius;
|
||||||
|
IntVec3 center = pawn.Position;
|
||||||
|
|
||||||
|
collisionAreaCache = new CellRect(
|
||||||
|
center.x - radius,
|
||||||
|
center.z - radius,
|
||||||
|
radius * 2 + 1,
|
||||||
|
radius * 2 + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
collisionAreaCache.ClipInsideMap(pawn.Map);
|
||||||
|
lastAreaRecalculationTick = currentTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
return collisionAreaCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查是否是有效目标
|
||||||
|
/// </summary>
|
||||||
|
private bool IsValidTarget(Pawn attacker, Pawn target)
|
||||||
|
{
|
||||||
|
if (target == null || target.Destroyed || target.Dead)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否为敌人
|
||||||
|
if (Props.onlyAffectEnemies && !target.HostileTo(attacker))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否排除友方
|
||||||
|
if (Props.excludeAlliedPawns && target.Faction == attacker.Faction)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否排除中立
|
||||||
|
if (Props.excludeNeutralPawns && !target.HostileTo(attacker))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查Pawn是否可以移动
|
||||||
|
/// </summary>
|
||||||
|
private bool CanMove(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.Downed || pawn.Dead || pawn.InMentalState)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pawn.stances?.stunner?.Stunned ?? false)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置到阶段0
|
||||||
|
/// </summary>
|
||||||
|
private void ResetToStage0()
|
||||||
|
{
|
||||||
|
currentStage = SpeedStage.Stage0;
|
||||||
|
|
||||||
|
// 清空速度历史
|
||||||
|
speedHistory.Clear();
|
||||||
|
for (int i = 0; i < Props.speedHistoryFrameCount; i++)
|
||||||
|
{
|
||||||
|
speedHistory.Enqueue(0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制调试视觉效果
|
||||||
|
/// </summary>
|
||||||
|
private void DrawDebugVisuals(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (!pawn.Spawned)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 绘制碰撞区域
|
||||||
|
CellRect area = GetCollisionArea(pawn);
|
||||||
|
GenDraw.DrawFieldEdges(area.Cells.ToList(), GetStageColor(currentStage));
|
||||||
|
|
||||||
|
// 绘制速度指示器
|
||||||
|
float averageSpeed = GetAverageSpeed();
|
||||||
|
string speedText = $"Speed: {averageSpeed:F1} cells/sec\nStage: {(int)currentStage}";
|
||||||
|
|
||||||
|
Vector3 drawPos = pawn.DrawPos + new Vector3(0, 0, 1f);
|
||||||
|
GenMapUI.DrawText(drawPos, speedText, GetStageColor(currentStage));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取阶段颜色
|
||||||
|
/// </summary>
|
||||||
|
private Color GetStageColor(SpeedStage stage)
|
||||||
|
{
|
||||||
|
switch (stage)
|
||||||
|
{
|
||||||
|
case SpeedStage.Stage0: return Color.gray;
|
||||||
|
case SpeedStage.Stage1: return Color.yellow;
|
||||||
|
case SpeedStage.Stage2: return Color.red;
|
||||||
|
default: return Color.white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取调试信息
|
||||||
|
/// </summary>
|
||||||
|
public string GetDebugInfo()
|
||||||
|
{
|
||||||
|
float averageSpeed = GetAverageSpeed();
|
||||||
|
|
||||||
|
return $"HighSpeedCollision Debug Info:\n" +
|
||||||
|
$"Current Stage: {(int)currentStage}\n" +
|
||||||
|
$"Average Speed: {averageSpeed:F2} cells/sec\n" +
|
||||||
|
$"Stage 1 Threshold: {Props.minSpeedForStage1:F2}\n" +
|
||||||
|
$"Stage 2 Threshold: {Props.minSpeedForStage2:F2}\n" +
|
||||||
|
$"Speed History: {speedHistory.Count} frames\n" +
|
||||||
|
$"Stage Cooldown: {stageTransitionCooldown} ticks";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostExposeData()
|
||||||
|
{
|
||||||
|
base.PostExposeData();
|
||||||
|
|
||||||
|
Scribe_Values.Look(ref currentStage, "currentStage", SpeedStage.Stage0);
|
||||||
|
Scribe_Values.Look(ref stageTransitionCooldown, "stageTransitionCooldown", 0);
|
||||||
|
Scribe_Values.Look(ref lastPosition, "lastPosition", IntVec3.Invalid);
|
||||||
|
Scribe_Values.Look(ref lastPositionTick, "lastPositionTick", -1);
|
||||||
|
|
||||||
|
// 保存速度历史
|
||||||
|
if (Scribe.mode == LoadSaveMode.Saving)
|
||||||
|
{
|
||||||
|
List<float> speedList = speedHistory.ToList();
|
||||||
|
Scribe_Collections.Look(ref speedList, "speedHistory", LookMode.Value);
|
||||||
|
}
|
||||||
|
else if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||||
|
{
|
||||||
|
List<float> speedList = null;
|
||||||
|
Scribe_Collections.Look(ref speedList, "speedHistory", LookMode.Value);
|
||||||
|
|
||||||
|
speedHistory.Clear();
|
||||||
|
if (speedList != null)
|
||||||
|
{
|
||||||
|
foreach (float speed in speedList)
|
||||||
|
{
|
||||||
|
speedHistory.Enqueue(speed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保有足够的历史数据
|
||||||
|
while (speedHistory.Count < Props.speedHistoryFrameCount)
|
||||||
|
{
|
||||||
|
speedHistory.Enqueue(0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 高速移动撞击组件属性
|
||||||
|
/// </summary>
|
||||||
|
public class CompProperties_HighSpeedCollision : CompProperties
|
||||||
|
{
|
||||||
|
// === 速度阈值配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 进入阶段1所需的最小速度(格/秒)
|
||||||
|
/// </summary>
|
||||||
|
public float minSpeedForStage1 = 3f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 进入阶段2所需的最小速度(格/秒)
|
||||||
|
/// </summary>
|
||||||
|
public float minSpeedForStage2 = 6f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 速度历史帧数(用于计算平均速度)
|
||||||
|
/// </summary>
|
||||||
|
public int speedHistoryFrameCount = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段转换冷却时间(tick)
|
||||||
|
/// </summary>
|
||||||
|
public int stageTransitionCooldownTicks = 5;
|
||||||
|
|
||||||
|
// === 碰撞区域配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 碰撞区域半径(以pawn为中心的正方形)
|
||||||
|
/// </summary>
|
||||||
|
public int collisionAreaRadius = 1;
|
||||||
|
|
||||||
|
// === 目标过滤 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 只影响敌人
|
||||||
|
/// </summary>
|
||||||
|
public bool onlyAffectEnemies = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排除友方单位
|
||||||
|
/// </summary>
|
||||||
|
public bool excludeAlliedPawns = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 排除中立单位
|
||||||
|
/// </summary>
|
||||||
|
public bool excludeNeutralPawns = false;
|
||||||
|
|
||||||
|
// === 阶段1效果配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1伤害类型
|
||||||
|
/// </summary>
|
||||||
|
public DamageDef stage1DamageDef = DamageDefOf.Blunt;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1伤害量
|
||||||
|
/// </summary>
|
||||||
|
public float stage1DamageAmount = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1护甲穿透
|
||||||
|
/// </summary>
|
||||||
|
public float armorPenetration = 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1应用的hediff
|
||||||
|
/// </summary>
|
||||||
|
public HediffDef stage1Hediff;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1hediff持续时间(tick)
|
||||||
|
/// </summary>
|
||||||
|
public int stage1HediffDurationTicks = 60;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拥有hediff的目标是否免疫伤害
|
||||||
|
/// </summary>
|
||||||
|
public bool stage1HediffPreventsDamage = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1效果器
|
||||||
|
/// </summary>
|
||||||
|
public EffecterDef stage1Effecter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段1音效
|
||||||
|
/// </summary>
|
||||||
|
public SoundDef stage1Sound;
|
||||||
|
|
||||||
|
// === 阶段2效果配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段2伤害类型
|
||||||
|
/// </summary>
|
||||||
|
public DamageDef stage2DamageDef = DamageDefOf.Blunt;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段2伤害量
|
||||||
|
/// </summary>
|
||||||
|
public float stage2DamageAmount = 10f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段2击退距离
|
||||||
|
/// </summary>
|
||||||
|
public int stage2KnockbackDistance = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 击退是否需要视线
|
||||||
|
/// </summary>
|
||||||
|
public bool requireLineOfSightForKnockback = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段2效果器
|
||||||
|
/// </summary>
|
||||||
|
public EffecterDef stage2Effecter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阶段2音效
|
||||||
|
/// </summary>
|
||||||
|
public SoundDef stage2Sound;
|
||||||
|
|
||||||
|
// === 击飞配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 击退飞行器定义
|
||||||
|
/// </summary>
|
||||||
|
public ThingDef knockbackFlyerDef;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 飞行效果器
|
||||||
|
/// </summary>
|
||||||
|
public EffecterDef flightEffecterDef;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 落地音效
|
||||||
|
/// </summary>
|
||||||
|
public SoundDef landingSound;
|
||||||
|
|
||||||
|
// === 调试配置 ===
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用调试日志
|
||||||
|
/// </summary>
|
||||||
|
public bool enableDebugLogging = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用调试视觉效果
|
||||||
|
/// </summary>
|
||||||
|
public bool enableDebugVisuals = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制速度历史图
|
||||||
|
/// </summary>
|
||||||
|
public bool debugDrawSpeedHistory = false;
|
||||||
|
|
||||||
|
public CompProperties_HighSpeedCollision()
|
||||||
|
{
|
||||||
|
compClass = typeof(CompHighSpeedCollision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
// File: CompMechArmor.cs
|
|
||||||
using RimWorld;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
using Verse.Sound;
|
|
||||||
using static RimWorld.MechClusterSketch;
|
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 机甲装甲组件:提供基于装甲值的伤害减免系统
|
|
||||||
/// </summary>
|
|
||||||
public class CompMechArmor : ThingComp
|
|
||||||
{
|
|
||||||
public CompProperties_MechArmor Props =>
|
|
||||||
(CompProperties_MechArmor)props;
|
|
||||||
|
|
||||||
private static StatDef DD_MechArmorDef = null;
|
|
||||||
|
|
||||||
// 当前装甲值(从Stat获取)
|
|
||||||
public float CurrentArmor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (DD_MechArmorDef == null)
|
|
||||||
{
|
|
||||||
DD_MechArmorDef = StatDef.Named("DD_MechArmor");
|
|
||||||
if (DD_MechArmorDef == null)
|
|
||||||
{
|
|
||||||
Log.Warning("[DD] DD_MechArmor stat definition not found!");
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parent.GetStatValue(DD_MechArmorDef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调试信息
|
|
||||||
private int blockedHits = 0;
|
|
||||||
private int totalHits = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查伤害是否被装甲抵消
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dinfo">伤害信息</param>
|
|
||||||
/// <returns>true=伤害被抵消,false=伤害有效</returns>
|
|
||||||
public bool TryBlockDamage(ref DamageInfo dinfo)
|
|
||||||
{
|
|
||||||
totalHits++;
|
|
||||||
|
|
||||||
// 获取穿甲率(如果没有则为0)
|
|
||||||
float armorPenetration = dinfo.ArmorPenetrationInt;
|
|
||||||
|
|
||||||
// 计算穿甲伤害
|
|
||||||
float armorPiercingDamage = dinfo.Amount * armorPenetration;
|
|
||||||
|
|
||||||
// 获取当前装甲值
|
|
||||||
float currentArmor = CurrentArmor;
|
|
||||||
|
|
||||||
// 检查是否应该被装甲抵消
|
|
||||||
bool shouldBlock = armorPiercingDamage < currentArmor;
|
|
||||||
|
|
||||||
if (shouldBlock)
|
|
||||||
{
|
|
||||||
blockedHits++;
|
|
||||||
|
|
||||||
// 可选:触发视觉效果
|
|
||||||
if (Props.showBlockEffect && parent.Spawned)
|
|
||||||
{
|
|
||||||
ShowBlockEffect(dinfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 可选:播放音效
|
|
||||||
if (Props.soundOnBlock != null && parent.Spawned)
|
|
||||||
{
|
|
||||||
Props.soundOnBlock.PlayOneShot(parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 调试日志
|
|
||||||
if (Props.debugLogging && parent.Spawned)
|
|
||||||
{
|
|
||||||
Log.Message($"[DD Armor] {parent.LabelShort}: " +
|
|
||||||
$"Damage={dinfo.Amount}, " +
|
|
||||||
$"Penetration={armorPenetration:P0}, " +
|
|
||||||
$"PierceDamage={armorPiercingDamage:F1}, " +
|
|
||||||
$"Armor={currentArmor:F1}, " +
|
|
||||||
$"Blocked={shouldBlock}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return shouldBlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示阻挡效果
|
|
||||||
/// </summary>
|
|
||||||
private void ShowBlockEffect(DamageInfo dinfo)
|
|
||||||
{
|
|
||||||
MoteMaker.ThrowText(parent.DrawPos, parent.Map, "DD_BlockByMechArmor".Translate(), Color.white, 3.5f);
|
|
||||||
// 创建火花或特效
|
|
||||||
if (Props.blockEffectMote != null)
|
|
||||||
{
|
|
||||||
MoteMaker.MakeStaticMote(
|
|
||||||
parent.DrawPos + new Vector3(0, 0, 0.5f),
|
|
||||||
parent.Map,
|
|
||||||
Props.blockEffectMote,
|
|
||||||
1.0f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取装甲信息(用于调试)
|
|
||||||
/// </summary>
|
|
||||||
public string GetArmorInfo()
|
|
||||||
{
|
|
||||||
return $"<b>{parent.LabelShort}的装甲系统</b>\n" +
|
|
||||||
$"当前装甲值: {CurrentArmor:F1}\n" +
|
|
||||||
$"阻挡规则: 穿甲伤害 < 装甲值\n" +
|
|
||||||
$"统计: 已阻挡 {blockedHits}/{totalHits} 次攻击\n" +
|
|
||||||
$"阻挡率: {(totalHits > 0 ? (float)blockedHits / totalHits * 100 : 0):F1}%";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取调试按钮
|
|
||||||
/// </summary>
|
|
||||||
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
|
||||||
{
|
|
||||||
foreach (var gizmo in base.CompGetGizmosExtra())
|
|
||||||
{
|
|
||||||
yield return gizmo;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在开发模式下显示装甲信息
|
|
||||||
if (DebugSettings.ShowDevGizmos)
|
|
||||||
{
|
|
||||||
yield return new Command_Action
|
|
||||||
{
|
|
||||||
defaultLabel = "DEBUG: 装甲信息",
|
|
||||||
defaultDesc = GetArmorInfo(),
|
|
||||||
//icon = TexCommand.Shield,
|
|
||||||
action = () =>
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add(new Dialog_MessageBox(
|
|
||||||
GetArmorInfo(),
|
|
||||||
"关闭",
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
"机甲装甲信息"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
yield return new Command_Action
|
|
||||||
{
|
|
||||||
defaultLabel = "DEBUG: 重置统计",
|
|
||||||
defaultDesc = "重置阻挡统计计数器",
|
|
||||||
//icon = TexCommand.Clear,
|
|
||||||
action = () =>
|
|
||||||
{
|
|
||||||
blockedHits = 0;
|
|
||||||
totalHits = 0;
|
|
||||||
Messages.Message("装甲统计已重置", MessageTypeDefOf.TaskCompletion);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PostExposeData()
|
|
||||||
{
|
|
||||||
base.PostExposeData();
|
|
||||||
Scribe_Values.Look(ref blockedHits, "blockedHits", 0);
|
|
||||||
Scribe_Values.Look(ref totalHits, "totalHits", 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 机甲装甲组件属性
|
|
||||||
/// </summary>
|
|
||||||
public class CompProperties_MechArmor : CompProperties
|
|
||||||
{
|
|
||||||
// 视觉效果
|
|
||||||
public bool showBlockEffect = true;
|
|
||||||
public ThingDef blockEffectMote; // 阻挡时显示的特效
|
|
||||||
|
|
||||||
// 音效
|
|
||||||
public SoundDef soundOnBlock;
|
|
||||||
|
|
||||||
// 调试
|
|
||||||
public bool debugLogging = false;
|
|
||||||
|
|
||||||
public CompProperties_MechArmor()
|
|
||||||
{
|
|
||||||
compClass = typeof(CompMechArmor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -26,7 +26,7 @@ namespace WulaFallenEmpire
|
|||||||
public ThingDef FuelType => Props.fuelType;
|
public ThingDef FuelType => Props.fuelType;
|
||||||
|
|
||||||
// 停机状态 Hediff
|
// 停机状态 Hediff
|
||||||
private HediffDef ShutdownHediffDef => HediffDef.Named("DD_MechShutdown");
|
private HediffDef ShutdownHediffDef => HediffDef.Named("WULA_MechShutdown");
|
||||||
|
|
||||||
public override void PostSpawnSetup(bool respawningAfterLoad)
|
public override void PostSpawnSetup(bool respawningAfterLoad)
|
||||||
{
|
{
|
||||||
@@ -162,7 +162,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 播放关机效果
|
// 播放关机效果
|
||||||
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Shutdown".Translate(), Color.gray, 3.5f);
|
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "WULA_Shutdown".Translate(), Color.gray, 3.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Startup".Translate(), Color.green, 3.5f);
|
MoteMaker.ThrowText(mech.DrawPos, mech.Map, "WULA_Startup".Translate(), Color.green, 3.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +236,7 @@ namespace WulaFallenEmpire
|
|||||||
// 发送调试消息
|
// 发送调试消息
|
||||||
if (DebugSettings.godMode)
|
if (DebugSettings.godMode)
|
||||||
{
|
{
|
||||||
Messages.Message($"DD_Debug_FuelSet".Translate(
|
Messages.Message($"WULA_Debug_FuelSet".Translate(
|
||||||
parent.LabelShort,
|
parent.LabelShort,
|
||||||
fuel.ToString("F1"),
|
fuel.ToString("F1"),
|
||||||
Props.fuelCapacity.ToString("F1"),
|
Props.fuelCapacity.ToString("F1"),
|
||||||
@@ -267,7 +267,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (bestColonist == null)
|
if (bestColonist == null)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
|
Messages.Message("WULA_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +275,7 @@ namespace WulaFallenEmpire
|
|||||||
Thing fuel = FindFuelForRefuel(bestColonist);
|
Thing fuel = FindFuelForRefuel(bestColonist);
|
||||||
if (fuel == null)
|
if (fuel == null)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_NoFuelAvailable".Translate(FuelType), parent, MessageTypeDefOf.RejectInput);
|
Messages.Message("WULA_NoFuelAvailable".Translate(FuelType), parent, MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ namespace WulaFallenEmpire
|
|||||||
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
|
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
|
||||||
|
|
||||||
// 显示消息
|
// 显示消息
|
||||||
Messages.Message("DD_OrderedRefuel".Translate(bestColonist.LabelShort, parent.LabelShort),
|
Messages.Message("WULA_OrderedRefuel".Translate(bestColonist.LabelShort, parent.LabelShort),
|
||||||
parent, MessageTypeDefOf.PositiveEvent);
|
parent, MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,16 +370,16 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
Command_Action refuelNow = new Command_Action
|
Command_Action refuelNow = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_RefuelNow".Translate(),
|
defaultLabel = "WULA_RefuelNow".Translate(),
|
||||||
defaultDesc = "DD_RefuelNowDesc".Translate(),
|
defaultDesc = "WULA_RefuelNowDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("WulaFallenEmpire/UI/Commands/DD_Refuel_Mech"),
|
icon = ContentFinder<Texture2D>.Get("WulaFallenEmpire/UI/Commands/WULA_Refuel_Mech"),
|
||||||
action = () => RefuelNow()
|
action = () => RefuelNow()
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查是否可以立刻加注
|
// 检查是否可以立刻加注
|
||||||
if (!CanRefuelNow())
|
if (!CanRefuelNow())
|
||||||
{
|
{
|
||||||
refuelNow.Disable("DD_CannotRefuelNow".Translate());
|
refuelNow.Disable("WULA_CannotRefuelNow".Translate());
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return refuelNow;
|
yield return refuelNow;
|
||||||
@@ -391,8 +391,8 @@ namespace WulaFallenEmpire
|
|||||||
// 设置燃料为空
|
// 设置燃料为空
|
||||||
Command_Action setEmpty = new Command_Action
|
Command_Action setEmpty = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_SetEmpty".Translate(),
|
defaultLabel = "WULA_Debug_SetEmpty".Translate(),
|
||||||
defaultDesc = "DD_Debug_SetEmptyDesc".Translate(),
|
defaultDesc = "WULA_Debug_SetEmptyDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetEmpty", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetEmpty", false) ?? BaseContent.BadTex,
|
||||||
action = () => SetFuel(0f)
|
action = () => SetFuel(0f)
|
||||||
};
|
};
|
||||||
@@ -401,8 +401,8 @@ namespace WulaFallenEmpire
|
|||||||
// 设置燃料为50%
|
// 设置燃料为50%
|
||||||
Command_Action setHalf = new Command_Action
|
Command_Action setHalf = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_SetHalf".Translate(),
|
defaultLabel = "WULA_Debug_SetHalf".Translate(),
|
||||||
defaultDesc = "DD_Debug_SetHalfDesc".Translate(),
|
defaultDesc = "WULA_Debug_SetHalfDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetHalf", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetHalf", false) ?? BaseContent.BadTex,
|
||||||
action = () => SetFuel(Props.fuelCapacity * 0.5f)
|
action = () => SetFuel(Props.fuelCapacity * 0.5f)
|
||||||
};
|
};
|
||||||
@@ -411,8 +411,8 @@ namespace WulaFallenEmpire
|
|||||||
// 设置燃料为满
|
// 设置燃料为满
|
||||||
Command_Action setFull = new Command_Action
|
Command_Action setFull = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_SetFull".Translate(),
|
defaultLabel = "WULA_Debug_SetFull".Translate(),
|
||||||
defaultDesc = "DD_Debug_SetFullDesc".Translate(),
|
defaultDesc = "WULA_Debug_SetFullDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetFull", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/SetFull", false) ?? BaseContent.BadTex,
|
||||||
action = () => SetFuel(Props.fuelCapacity)
|
action = () => SetFuel(Props.fuelCapacity)
|
||||||
};
|
};
|
||||||
@@ -433,7 +433,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
string baseString = base.CompInspectStringExtra();
|
string baseString = base.CompInspectStringExtra();
|
||||||
|
|
||||||
string fuelString = "DD_Fuel".Translate(FuelType) + ": " +
|
string fuelString = "WULA_Fuel".Translate(FuelType) + ": " +
|
||||||
fuel.ToString("F1") + " / " + Props.fuelCapacity.ToString("F1") +
|
fuel.ToString("F1") + " / " + Props.fuelCapacity.ToString("F1") +
|
||||||
" (" + (FuelPercent * 100f).ToString("F0") + "%)";
|
" (" + (FuelPercent * 100f).ToString("F0") + "%)";
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
// 在 God Mode 下显示"调试模式"标题
|
// 在 God Mode 下显示"调试模式"标题
|
||||||
string title = DebugSettings.godMode ?
|
string title = DebugSettings.godMode ?
|
||||||
"DD_MechFuel".Translate().Resolve() + " [DEBUG]" :
|
"WULA_MechFuel".Translate().Resolve() + " [DEBUG]" :
|
||||||
"DD_MechFuel".Translate().Resolve();
|
"WULA_MechFuel".Translate().Resolve();
|
||||||
|
|
||||||
Widgets.Label(titleRect, title);
|
Widgets.Label(titleRect, title);
|
||||||
|
|
||||||
@@ -88,13 +88,13 @@ namespace WulaFallenEmpire
|
|||||||
Text.Font = GameFont.Tiny;
|
Text.Font = GameFont.Tiny;
|
||||||
Text.Anchor = TextAnchor.UpperCenter;
|
Text.Anchor = TextAnchor.UpperCenter;
|
||||||
GUI.color = Color.red;
|
GUI.color = Color.red;
|
||||||
Widgets.Label(statusRect, "DD_Shutdown".Translate());
|
Widgets.Label(statusRect, "WULA_Shutdown".Translate());
|
||||||
GUI.color = Color.white;
|
GUI.color = Color.white;
|
||||||
Text.Anchor = TextAnchor.UpperLeft;
|
Text.Anchor = TextAnchor.UpperLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 工具提示
|
// 工具提示
|
||||||
string tip = "DD_MechFuelTip".Translate(
|
string tip = "WULA_MechFuelTip".Translate(
|
||||||
fuelComp.FuelPercent.ToStringPercent(),
|
fuelComp.FuelPercent.ToStringPercent(),
|
||||||
fuelComp.Props.dailyFuelConsumption,
|
fuelComp.Props.dailyFuelConsumption,
|
||||||
fuelComp.Props.fuelType.label
|
fuelComp.Props.fuelType.label
|
||||||
@@ -102,20 +102,20 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (fuelComp.IsShutdown)
|
if (fuelComp.IsShutdown)
|
||||||
{
|
{
|
||||||
tip += "\n\n" + "DD_ShutdownTip".Translate();
|
tip += "\n\n" + "WULA_ShutdownTip".Translate();
|
||||||
}
|
}
|
||||||
else if (fuelComp.NeedsRefueling)
|
else if (fuelComp.NeedsRefueling)
|
||||||
{
|
{
|
||||||
tip += "\n\n" + "DD_NeedsRefueling".Translate();
|
tip += "\n\n" + "WULA_NeedsRefueling".Translate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在 God Mode 下添加调试信息到工具提示
|
// 在 God Mode 下添加调试信息到工具提示
|
||||||
if (DebugSettings.godMode)
|
if (DebugSettings.godMode)
|
||||||
{
|
{
|
||||||
tip += "\n\n" + "DD_Debug_Tip".Translate().Colorize(Color.gray) +
|
tip += "\n\n" + "WULA_Debug_Tip".Translate().Colorize(Color.gray) +
|
||||||
"\n" + "DD_Debug_Status".Translate(
|
"\n" + "WULA_Debug_Status".Translate(
|
||||||
fuelComp.IsShutdown ? "DD_Shutdown".Translate() : "DD_Running".Translate(),
|
fuelComp.IsShutdown ? "WULA_Shutdown".Translate() : "WULA_Running".Translate(),
|
||||||
fuelComp.HasPilot() ? "DD_HasPilot".Translate() : "DD_NoPilot".Translate()
|
fuelComp.HasPilot() ? "WULA_HasPilot".Translate() : "WULA_NoPilot".Translate()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] Failed to create sustainer for {Props.movementSound.defName}");
|
Log.Warning($"[WULA] Failed to create sustainer for {Props.movementSound.defName}");
|
||||||
isPlaying = false;
|
isPlaying = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace WulaFallenEmpire
|
|||||||
// 如果需要驾驶员,检查是否配置了驾驶员容器
|
// 如果需要驾驶员,检查是否配置了驾驶员容器
|
||||||
if (requirePilot && parentDef.GetCompProperties<CompProperties_MechPilotHolder>() == null)
|
if (requirePilot && parentDef.GetCompProperties<CompProperties_MechPilotHolder>() == null)
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] requirePilot is true but no CompProperties_MechPilotHolder found for {parentDef.defName}");
|
Log.Warning($"[WULA] requirePilot is true but no CompProperties_MechPilotHolder found for {parentDef.defName}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ namespace WulaFallenEmpire
|
|||||||
public string pilotWorkTag = "MechPilot";
|
public string pilotWorkTag = "MechPilot";
|
||||||
|
|
||||||
// 新增:驾驶员图标配置
|
// 新增:驾驶员图标配置
|
||||||
public string summonPilotIcon = "WulaFallenEmpire/UI/Commands/DD_Enter_Mech";
|
public string summonPilotIcon = "WulaFallenEmpire/UI/Commands/WULA_Enter_Mech";
|
||||||
public string ejectPilotIcon = "WulaFallenEmpire/UI/Commands/DD_Exit_Mech";
|
public string ejectPilotIcon = "WulaFallenEmpire/UI/Commands/WULA_Exit_Mech";
|
||||||
|
|
||||||
public float ejectPilotHealthPercentThreshold = 0.1f; // 默认30%血量
|
public float ejectPilotHealthPercentThreshold = 0.1f; // 默认30%血量
|
||||||
public bool allowEntryBelowThreshold = false; // 血量低于阈值时是否允许进入
|
public bool allowEntryBelowThreshold = false; // 血量低于阈值时是否允许进入
|
||||||
@@ -204,7 +204,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 同步Hediff时出错: {ex}");
|
Log.Error($"[WULA] 同步Hediff时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 取消同步Hediff时出错: {ex}");
|
Log.Error($"[WULA] 取消同步Hediff时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 自动添加Hediff时出错: {ex}");
|
Log.Error($"[WULA] 自动添加Hediff时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] CompTick error: {ex}");
|
Log.Error($"[WULA] CompTick error: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,7 +384,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 检查Hediff同步状态时出错: {ex}");
|
Log.Error($"[WULA] 检查Hediff同步状态时出错: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,7 +395,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (!(parent is Wulamechunit))
|
if (!(parent is Wulamechunit))
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] CompMechPilotHolder attached to non-mech: {parent}");
|
Log.Warning($"[WULA] CompMechPilotHolder attached to non-mech: {parent}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保加载后恢复状态
|
// 确保加载后恢复状态
|
||||||
@@ -567,7 +567,7 @@ namespace WulaFallenEmpire
|
|||||||
// 发送消息
|
// 发送消息
|
||||||
if (parent.Faction == Faction.OfPlayer)
|
if (parent.Faction == Faction.OfPlayer)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_PilotsEjectedDueToLowHealth".Translate(parent.LabelShort,
|
Messages.Message("WULA_PilotsEjectedDueToLowHealth".Translate(parent.LabelShort,
|
||||||
(Props.ejectPilotHealthPercentThreshold * 100).ToString("F0")),
|
(Props.ejectPilotHealthPercentThreshold * 100).ToString("F0")),
|
||||||
parent, MessageTypeDefOf.NegativeEvent);
|
parent, MessageTypeDefOf.NegativeEvent);
|
||||||
}
|
}
|
||||||
@@ -605,8 +605,8 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
Command_Action summonCommand = new Command_Action
|
Command_Action summonCommand = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_SummonPilot".Translate(),
|
defaultLabel = "WULA_SummonPilot".Translate(),
|
||||||
defaultDesc = "DD_SummonPilotDesc".Translate(),
|
defaultDesc = "WULA_SummonPilotDesc".Translate(),
|
||||||
icon = Props.GetSummonPilotIcon(),
|
icon = Props.GetSummonPilotIcon(),
|
||||||
action = () =>
|
action = () =>
|
||||||
{
|
{
|
||||||
@@ -618,7 +618,7 @@ namespace WulaFallenEmpire
|
|||||||
// 如果血量低于阈值且不允许进入,禁用按钮
|
// 如果血量低于阈值且不允许进入,禁用按钮
|
||||||
if (!Props.allowEntryBelowThreshold && IsBelowHealthThreshold)
|
if (!Props.allowEntryBelowThreshold && IsBelowHealthThreshold)
|
||||||
{
|
{
|
||||||
summonCommand.Disable("DD_MechTooDamagedForEntry".Translate());
|
summonCommand.Disable("WULA_MechTooDamagedForEntry".Translate());
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return summonCommand;
|
yield return summonCommand;
|
||||||
@@ -629,8 +629,8 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
yield return new Command_Action
|
yield return new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_EjectAllPilots".Translate(),
|
defaultLabel = "WULA_EjectAllPilots".Translate(),
|
||||||
defaultDesc = "DD_EjectAllPilotsDesc".Translate(),
|
defaultDesc = "WULA_EjectAllPilotsDesc".Translate(),
|
||||||
icon = Props.GetEjectPilotIcon(),
|
icon = Props.GetEjectPilotIcon(),
|
||||||
action = () =>
|
action = () =>
|
||||||
{
|
{
|
||||||
@@ -723,14 +723,14 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 无法弹出驾驶员: {pawn.LabelShort}");
|
Log.Error($"[WULA] 无法弹出驾驶员: {pawn.LabelShort}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 弹出驾驶员时发生错误: {ex}");
|
Log.Error($"[WULA] 弹出驾驶员时发生错误: {ex}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -778,7 +778,7 @@ namespace WulaFallenEmpire
|
|||||||
Map map = parent.Map;
|
Map map = parent.Map;
|
||||||
if (map == null)
|
if (map == null)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 尝试在没有地图的情况下生成驾驶员: {pawn.LabelShort}");
|
Log.Error($"[WULA] 尝试在没有地图的情况下生成驾驶员: {pawn.LabelShort}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,7 +810,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] 生成驾驶员时发生错误: {ex}");
|
Log.Error($"[WULA] 生成驾驶员时发生错误: {ex}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -841,7 +841,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
if (pilot.Faction == Faction.OfPlayer)
|
if (pilot.Faction == Faction.OfPlayer)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_PilotEnteredMech".Translate(pilot.LabelShort, parent.LabelShort),
|
Messages.Message("WULA_PilotEnteredMech".Translate(pilot.LabelShort, parent.LabelShort),
|
||||||
parent, MessageTypeDefOf.PositiveEvent);
|
parent, MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -850,7 +850,7 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
if (pilot.Faction == Faction.OfPlayer)
|
if (pilot.Faction == Faction.OfPlayer)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_PilotExitedMech".Translate(pilot.LabelShort, parent.LabelShort),
|
Messages.Message("WULA_PilotExitedMech".Translate(pilot.LabelShort, parent.LabelShort),
|
||||||
parent, MessageTypeDefOf.NeutralEvent);
|
parent, MessageTypeDefOf.NeutralEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -899,7 +899,7 @@ namespace WulaFallenEmpire
|
|||||||
// 为能够行动的殖民者创建选项
|
// 为能够行动的殖民者创建选项
|
||||||
if (ableColonists.Count == 0 && disabledColonists.Count == 0)
|
if (ableColonists.Count == 0 && disabledColonists.Count == 0)
|
||||||
{
|
{
|
||||||
options.Add(new FloatMenuOption("DD_NoAvailablePilots".Translate(), null));
|
options.Add(new FloatMenuOption("WULA_NoAvailablePilots".Translate(), null));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -930,7 +930,7 @@ namespace WulaFallenEmpire
|
|||||||
// 无法行动的殖民者:需要搬运
|
// 无法行动的殖民者:需要搬运
|
||||||
foreach (var colonist in disabledColonists)
|
foreach (var colonist in disabledColonists)
|
||||||
{
|
{
|
||||||
string colonistLabel = colonist.LabelShortCap + " " + "DD_DisabledColonistRequiresCarry".Translate();
|
string colonistLabel = colonist.LabelShortCap + " " + "WULA_DisabledColonistRequiresCarry".Translate();
|
||||||
Action action = () => OrderCarryDisabledColonistToMech(colonist);
|
Action action = () => OrderCarryDisabledColonistToMech(colonist);
|
||||||
|
|
||||||
FloatMenuOption option = new FloatMenuOption(
|
FloatMenuOption option = new FloatMenuOption(
|
||||||
@@ -977,7 +977,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (carrier == null)
|
if (carrier == null)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_NoAvailableCarrier".Translate(disabledColonist.LabelShortCap),
|
Messages.Message("WULA_NoAvailableCarrier".Translate(disabledColonist.LabelShortCap),
|
||||||
parent, MessageTypeDefOf.RejectInput);
|
parent, MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -986,7 +986,7 @@ namespace WulaFallenEmpire
|
|||||||
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_CarryToMech, disabledColonist, mech);
|
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_CarryToMech, disabledColonist, mech);
|
||||||
carrier.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
carrier.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||||
|
|
||||||
Messages.Message("DD_CarrierAssigned".Translate(carrier.LabelShortCap, disabledColonist.LabelShortCap),
|
Messages.Message("WULA_CarrierAssigned".Translate(carrier.LabelShortCap, disabledColonist.LabelShortCap),
|
||||||
parent, MessageTypeDefOf.PositiveEvent);
|
parent, MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,16 +84,16 @@ namespace WulaFallenEmpire
|
|||||||
{
|
{
|
||||||
Command_Action repairCommand = new Command_Action
|
Command_Action repairCommand = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_ForceRepair".Translate(),
|
defaultLabel = "WULA_ForceRepair".Translate(),
|
||||||
defaultDesc = "DD_ForceRepairDesc".Translate(),
|
defaultDesc = "WULA_ForceRepairDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("WulaFallenEmpire/UI/Commands/DD_Repair_Mech"),
|
icon = ContentFinder<Texture2D>.Get("WulaFallenEmpire/UI/Commands/WULA_Repair_Mech"),
|
||||||
action = () => ForceRepairNow()
|
action = () => ForceRepairNow()
|
||||||
};
|
};
|
||||||
|
|
||||||
// 检查是否可以立即维修
|
// 检查是否可以立即维修
|
||||||
if (!CanRepairNow())
|
if (!CanRepairNow())
|
||||||
{
|
{
|
||||||
repairCommand.Disable("DD_CannotRepairNow".Translate());
|
repairCommand.Disable("WULA_CannotRepairNow".Translate());
|
||||||
}
|
}
|
||||||
|
|
||||||
yield return repairCommand;
|
yield return repairCommand;
|
||||||
@@ -105,8 +105,8 @@ namespace WulaFallenEmpire
|
|||||||
// 模拟受伤按钮
|
// 模拟受伤按钮
|
||||||
Command_Action damageCommand = new Command_Action
|
Command_Action damageCommand = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_Damage".Translate(),
|
defaultLabel = "WULA_Debug_Damage".Translate(),
|
||||||
defaultDesc = "DD_Debug_DamageDesc".Translate(),
|
defaultDesc = "WULA_Debug_DamageDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Damage", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/Damage", false) ?? BaseContent.BadTex,
|
||||||
action = () => DebugDamage()
|
action = () => DebugDamage()
|
||||||
};
|
};
|
||||||
@@ -115,8 +115,8 @@ namespace WulaFallenEmpire
|
|||||||
// 完全修复按钮
|
// 完全修复按钮
|
||||||
Command_Action fullRepairCommand = new Command_Action
|
Command_Action fullRepairCommand = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_FullRepair".Translate(),
|
defaultLabel = "WULA_Debug_FullRepair".Translate(),
|
||||||
defaultDesc = "DD_Debug_FullRepairDesc".Translate(),
|
defaultDesc = "WULA_Debug_FullRepairDesc".Translate(),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Repair", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/Repair", false) ?? BaseContent.BadTex,
|
||||||
action = () => DebugFullRepair()
|
action = () => DebugFullRepair()
|
||||||
};
|
};
|
||||||
@@ -125,8 +125,8 @@ namespace WulaFallenEmpire
|
|||||||
// 显示维修统计
|
// 显示维修统计
|
||||||
Command_Action statsCommand = new Command_Action
|
Command_Action statsCommand = new Command_Action
|
||||||
{
|
{
|
||||||
defaultLabel = "DD_Debug_RepairStats".Translate(),
|
defaultLabel = "WULA_Debug_RepairStats".Translate(),
|
||||||
defaultDesc = "DD_Debug_RepairStatsDesc".Translate(totalRepairedHP.ToString("F1")),
|
defaultDesc = "WULA_Debug_RepairStatsDesc".Translate(totalRepairedHP.ToString("F1")),
|
||||||
icon = ContentFinder<Texture2D>.Get("UI/Commands/Stats", false) ?? BaseContent.BadTex,
|
icon = ContentFinder<Texture2D>.Get("UI/Commands/Stats", false) ?? BaseContent.BadTex,
|
||||||
action = () => DebugShowStats()
|
action = () => DebugShowStats()
|
||||||
};
|
};
|
||||||
@@ -145,7 +145,7 @@ namespace WulaFallenEmpire
|
|||||||
|
|
||||||
if (bestColonist == null)
|
if (bestColonist == null)
|
||||||
{
|
{
|
||||||
Messages.Message("DD_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
|
Messages.Message("WULA_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ namespace WulaFallenEmpire
|
|||||||
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
|
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
|
||||||
|
|
||||||
// 显示消息
|
// 显示消息
|
||||||
Messages.Message("DD_OrderedRepair".Translate(bestColonist.LabelShort, parent.LabelShort),
|
Messages.Message("WULA_OrderedRepair".Translate(bestColonist.LabelShort, parent.LabelShort),
|
||||||
parent, MessageTypeDefOf.PositiveEvent);
|
parent, MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ namespace WulaFallenEmpire
|
|||||||
DamageInfo dinfo = new DamageInfo(DamageDefOf.Cut, damage, 1f, -1f, null, part);
|
DamageInfo dinfo = new DamageInfo(DamageDefOf.Cut, damage, 1f, -1f, null, part);
|
||||||
mech.TakeDamage(dinfo);
|
mech.TakeDamage(dinfo);
|
||||||
|
|
||||||
Messages.Message($"DD_Debug_Damaged".Translate(parent.LabelShort, damage.ToString("F1")),
|
Messages.Message($"WULA_Debug_Damaged".Translate(parent.LabelShort, damage.ToString("F1")),
|
||||||
parent, MessageTypeDefOf.NeutralEvent);
|
parent, MessageTypeDefOf.NeutralEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,14 +246,14 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Messages.Message($"DD_Debug_FullyRepaired".Translate(parent.LabelShort),
|
Messages.Message($"WULA_Debug_FullyRepaired".Translate(parent.LabelShort),
|
||||||
parent, MessageTypeDefOf.PositiveEvent);
|
parent, MessageTypeDefOf.PositiveEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调试功能:显示维修统计
|
// 调试功能:显示维修统计
|
||||||
private void DebugShowStats()
|
private void DebugShowStats()
|
||||||
{
|
{
|
||||||
Messages.Message($"DD_Debug_RepairStatsInfo".Translate(
|
Messages.Message($"WULA_Debug_RepairStatsInfo".Translate(
|
||||||
parent.LabelShort,
|
parent.LabelShort,
|
||||||
totalRepairedHP.ToString("F1"),
|
totalRepairedHP.ToString("F1"),
|
||||||
Props.repairAmountPerCycle.ToString("F1"),
|
Props.repairAmountPerCycle.ToString("F1"),
|
||||||
@@ -277,7 +277,7 @@ namespace WulaFallenEmpire
|
|||||||
string repairString = "";
|
string repairString = "";
|
||||||
if (NeedsRepair)
|
if (NeedsRepair)
|
||||||
{
|
{
|
||||||
repairString = "DD_NeedsRepair".Translate().Colorize(Color.yellow);
|
repairString = "WULA_NeedsRepair".Translate().Colorize(Color.yellow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!baseString.NullOrEmpty())
|
if (!baseString.NullOrEmpty())
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace WulaFallenEmpire
|
|||||||
// 如果需要驾驶员但组件不存在,发出警告
|
// 如果需要驾驶员但组件不存在,发出警告
|
||||||
if (Props.requirePilot && pilotHolder == null)
|
if (Props.requirePilot && pilotHolder == null)
|
||||||
{
|
{
|
||||||
Log.Warning($"[DD] CompMoteEmitterNorthward on {parent} requires pilot but no CompMechPilotHolder found");
|
Log.Warning($"[WULA] CompMoteEmitterNorthward on {parent} requires pilot but no CompMechPilotHolder found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化位置
|
// 初始化位置
|
||||||
@@ -154,7 +154,7 @@ namespace WulaFallenEmpire
|
|||||||
catch (NullReferenceException ex)
|
catch (NullReferenceException ex)
|
||||||
{
|
{
|
||||||
// 发生异常时重置状态
|
// 发生异常时重置状态
|
||||||
Log.Warning($"[DD] Error updating movement state for {parent}: {ex.Message}");
|
Log.Warning($"[WULA] Error updating movement state for {parent}: {ex.Message}");
|
||||||
isMoving = false;
|
isMoving = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ namespace WulaFallenEmpire
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error($"[DD] Error emitting mote: {ex}");
|
Log.Error($"[WULA] Error emitting mote: {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
using Verse;
|
using Verse;
|
||||||
using RimWorld;
|
using RimWorld;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace WulaFallenEmpire
|
namespace WulaFallenEmpire
|
||||||
{
|
{
|
||||||
public enum FlightCondition
|
public enum FlightCondition
|
||||||
{
|
{
|
||||||
Drafted,
|
Drafted,
|
||||||
MechAlwaysExceptSpecialJobs // 新增:机械族在非特殊工作状态下始终飞行
|
DraftedAndMove,
|
||||||
|
Always
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CompProperties_PawnFlight : CompProperties
|
public class CompProperties_PawnFlight : CompProperties
|
||||||
@@ -15,13 +15,6 @@ namespace WulaFallenEmpire
|
|||||||
// --- Custom Flight Logic ---
|
// --- Custom Flight Logic ---
|
||||||
public FlightCondition flightCondition = FlightCondition.Drafted;
|
public FlightCondition flightCondition = FlightCondition.Drafted;
|
||||||
|
|
||||||
// --- 新增:机械族特殊工作检查 ---
|
|
||||||
public List<JobDef> mechForbiddenJobs = new List<JobDef>
|
|
||||||
{
|
|
||||||
JobDefOf.MechCharge, // 充电工作
|
|
||||||
JobDefOf.SelfShutdown // 关机工作
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- Vanilla PawnKindDef Flight Parameters ---
|
// --- Vanilla PawnKindDef Flight Parameters ---
|
||||||
[NoTranslate]
|
[NoTranslate]
|
||||||
public string flyingAnimationFramePathPrefix;
|
public string flyingAnimationFramePathPrefix;
|
||||||
@@ -40,6 +33,8 @@ namespace WulaFallenEmpire
|
|||||||
public bool flyingAnimationInheritColors;
|
public bool flyingAnimationInheritColors;
|
||||||
|
|
||||||
// --- Vanilla PawnKindLifeStage Flight Parameters ---
|
// --- Vanilla PawnKindLifeStage Flight Parameters ---
|
||||||
|
// Note: These are normally defined per lifestage, we define them once here for simplicity.
|
||||||
|
// The harmony patch will need to inject these into the correct lifestage at runtime.
|
||||||
public AnimationDef flyingAnimationEast;
|
public AnimationDef flyingAnimationEast;
|
||||||
public AnimationDef flyingAnimationNorth;
|
public AnimationDef flyingAnimationNorth;
|
||||||
public AnimationDef flyingAnimationSouth;
|
public AnimationDef flyingAnimationSouth;
|
||||||
@@ -47,9 +42,10 @@ namespace WulaFallenEmpire
|
|||||||
public AnimationDef flyingAnimationNorthFemale;
|
public AnimationDef flyingAnimationNorthFemale;
|
||||||
public AnimationDef flyingAnimationSouthFemale;
|
public AnimationDef flyingAnimationSouthFemale;
|
||||||
|
|
||||||
|
|
||||||
public CompProperties_PawnFlight()
|
public CompProperties_PawnFlight()
|
||||||
{
|
{
|
||||||
compClass = typeof(CompPawnFlight);
|
compClass = typeof(CompPawnFlight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,20 @@ namespace WulaFallenEmpire
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool shouldBeFlying = false;
|
||||||
var compProps = flightComp.Props;
|
var compProps = flightComp.Props;
|
||||||
bool shouldBeFlying = (compProps.flightCondition == FlightCondition.Drafted && ___pawn.Drafted);
|
if (compProps.flightCondition == FlightCondition.Always)
|
||||||
|
{
|
||||||
|
shouldBeFlying = true;
|
||||||
|
}
|
||||||
|
else if (compProps.flightCondition == FlightCondition.DraftedAndMove && ___pawn.Drafted || ___pawn.pather.MovingNow)
|
||||||
|
{
|
||||||
|
shouldBeFlying = true;
|
||||||
|
}
|
||||||
|
else if (compProps.flightCondition == FlightCondition.Drafted && ___pawn.Drafted)
|
||||||
|
{
|
||||||
|
shouldBeFlying = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldBeFlying)
|
if (shouldBeFlying)
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,7 @@ namespace WulaFallenEmpire.Utils
|
|||||||
string outRoot = Path.Combine(
|
string outRoot = Path.Combine(
|
||||||
GenFilePaths.SaveDataFolderPath,
|
GenFilePaths.SaveDataFolderPath,
|
||||||
"WulaFallenEmpire_DefInjectedExport",
|
"WulaFallenEmpire_DefInjectedExport",
|
||||||
DateTime.Now.ToString("yyyyMMdd_HHmmss"));
|
DateTime.Now.ToString("yyyyMMWULA_HHmmss"));
|
||||||
|
|
||||||
string outDefInjected = Path.Combine(outRoot, "English", "DefInjected");
|
string outDefInjected = Path.Combine(outRoot, "English", "DefInjected");
|
||||||
Directory.CreateDirectory(outDefInjected);
|
Directory.CreateDirectory(outDefInjected);
|
||||||
|
|||||||
@@ -0,0 +1,213 @@
|
|||||||
|
// File: FloatMenuOptionProvider_EnterMech.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class FloatMenuOptionProvider_EnterMech : FloatMenuOptionProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
// 检查Thing是否为机甲
|
||||||
|
private bool IsMech(Thing thing)
|
||||||
|
{
|
||||||
|
return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool Drafted => true; // 征召状态下不能进入机甲
|
||||||
|
protected override bool Undrafted => true; // 非征召状态下可以进入
|
||||||
|
protected override bool Multiselect => true; // 不支持多选
|
||||||
|
|
||||||
|
// 检查是否适用于当前上下文
|
||||||
|
protected override bool AppliesInt(FloatMenuContext context)
|
||||||
|
{
|
||||||
|
// 必须有选中的殖民者
|
||||||
|
if (context.FirstSelectedPawn == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查点击的单元格中是否有机甲
|
||||||
|
var clickedThings = context.ClickedThings;
|
||||||
|
if (clickedThings == null || clickedThings.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 查找第一个机甲
|
||||||
|
Thing mech = null;
|
||||||
|
foreach (var thing in clickedThings)
|
||||||
|
{
|
||||||
|
if (IsMech(thing))
|
||||||
|
{
|
||||||
|
mech = thing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mech == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲是否有驾驶员组件
|
||||||
|
var comp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (comp == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查殖民者是否已经在机甲内
|
||||||
|
// 由于CompMechPilotHolder没有ContainsPilot方法,我们需要通过其他方式检查
|
||||||
|
if (IsPawnInMech(context.FirstSelectedPawn, mech))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者是否已经在机甲内(替代ContainsPilot)
|
||||||
|
private bool IsPawnInMech(Pawn pawn, Thing mech)
|
||||||
|
{
|
||||||
|
var comp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (comp == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 尝试通过内部容器检查
|
||||||
|
var holder = comp as IThingHolder;
|
||||||
|
if (holder != null)
|
||||||
|
{
|
||||||
|
var things = holder.GetDirectlyHeldThings();
|
||||||
|
if (things != null && things.Contains(pawn))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 或者尝试通过其他属性检查
|
||||||
|
// 这里假设CompMechPilotHolder有HasPilots属性
|
||||||
|
if (comp.HasPilots)
|
||||||
|
{
|
||||||
|
// 如果有必要,可以通过反射或其他方式检查具体驾驶员
|
||||||
|
// 暂时返回false,假设不在机甲内
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单个选项
|
||||||
|
protected override FloatMenuOption GetSingleOptionFor(Thing clickedThing, FloatMenuContext context)
|
||||||
|
{
|
||||||
|
if (clickedThing == null || context.FirstSelectedPawn == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 如果不是机甲,返回null
|
||||||
|
if (!IsMech(clickedThing))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 获取机甲和组件
|
||||||
|
var mech = clickedThing as Wulamechunit;
|
||||||
|
var comp = mech?.TryGetComp<CompMechPilotHolder>();
|
||||||
|
|
||||||
|
if (mech == null || comp == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 检查殖民者是否已经在机甲内
|
||||||
|
if (IsPawnInMech(context.FirstSelectedPawn, mech))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 检查各种条件,生成相应的菜单选项
|
||||||
|
return CreateEnterMechOption(mech, context.FirstSelectedPawn, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建进入机甲的菜单选项
|
||||||
|
private FloatMenuOption CreateEnterMechOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp)
|
||||||
|
{
|
||||||
|
string label = "WULA_EnterMech".Translate(mech.LabelShort);
|
||||||
|
string disabledReason = "";
|
||||||
|
|
||||||
|
// 检查条件是否允许进入
|
||||||
|
bool canEnter = CanEnterMech(mech, pawn, comp, ref disabledReason);
|
||||||
|
|
||||||
|
// 如果条件允许,创建可点击的选项
|
||||||
|
if (canEnter)
|
||||||
|
{
|
||||||
|
return new FloatMenuOption(label, () =>
|
||||||
|
{
|
||||||
|
// 创建进入机甲的工作
|
||||||
|
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, mech);
|
||||||
|
pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||||
|
|
||||||
|
// 播放音效(如果有的话)
|
||||||
|
FleckMaker.Static(mech.DrawPos, mech.MapHeld, FleckDefOf.FeedbackEquip);
|
||||||
|
}, MenuOptionPriority.High);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 创建禁用的选项,显示原因
|
||||||
|
return new FloatMenuOption(
|
||||||
|
"WULA_EnterMech".Translate(mech.LabelShort) + ": " + disabledReason,
|
||||||
|
null,
|
||||||
|
MenuOptionPriority.DisabledOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者是否可以进入机甲
|
||||||
|
private bool CanEnterMech(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason)
|
||||||
|
{
|
||||||
|
// 检查机甲是否已满
|
||||||
|
if (comp.IsFull)
|
||||||
|
{
|
||||||
|
disabledReason = "WULA_MechFull".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者是否可以成为驾驶员
|
||||||
|
if (!comp.CanAddPilot(pawn))
|
||||||
|
{
|
||||||
|
disabledReason = "WULA_CannotBecomePilot".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查距离
|
||||||
|
if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly))
|
||||||
|
{
|
||||||
|
disabledReason = "NoPath".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者状态
|
||||||
|
if (pawn.Downed)
|
||||||
|
{
|
||||||
|
disabledReason = "Downed".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pawn.Dead)
|
||||||
|
{
|
||||||
|
disabledReason = "Dead".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为囚犯
|
||||||
|
if (pawn.IsPrisoner)
|
||||||
|
{
|
||||||
|
disabledReason = "Prisoner".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为奴隶
|
||||||
|
if (pawn.IsSlave)
|
||||||
|
{
|
||||||
|
disabledReason = "Slave".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查机甲状态
|
||||||
|
if (mech.Downed)
|
||||||
|
{
|
||||||
|
disabledReason = "Downed".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mech.Dead)
|
||||||
|
{
|
||||||
|
disabledReason = "Dead".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
// File: JobDriver_EnterMech.cs (不再保留机甲)
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobDriver_EnterMech : JobDriver
|
||||||
|
{
|
||||||
|
private const TargetIndex MechIndex = TargetIndex.A;
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
Pawn pawn = this.pawn;
|
||||||
|
LocalTargetInfo target = this.job.GetTarget(MechIndex);
|
||||||
|
|
||||||
|
// 不再保留机甲,这样多个殖民者可以同时被命令进入同一个机甲
|
||||||
|
// 只需要检查殖民者是否可以到达机甲
|
||||||
|
if (!pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
// 0. 初始检查
|
||||||
|
AddFailCondition(() =>
|
||||||
|
{
|
||||||
|
var mech = TargetThingA as Wulamechunit;
|
||||||
|
if (mech == null || mech.Destroyed)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var comp = mech.GetComp<CompMechPilotHolder>();
|
||||||
|
if (comp == null || comp.IsFull || !comp.CanAddPilot(pawn))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pawn.Downed || pawn.Dead)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 1. 走到机甲旁边
|
||||||
|
yield return Toils_Goto.GotoThing(MechIndex, PathEndMode.Touch);
|
||||||
|
|
||||||
|
// 2. 检查是否仍然可以进入
|
||||||
|
yield return Toils_General.Wait(10).WithProgressBarToilDelay(MechIndex);
|
||||||
|
|
||||||
|
// 3. 进入机甲
|
||||||
|
Toil enterToil = new Toil();
|
||||||
|
enterToil.initAction = () =>
|
||||||
|
{
|
||||||
|
var mech = TargetThingA as Wulamechunit;
|
||||||
|
if (mech == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var comp = mech.GetComp<CompMechPilotHolder>();
|
||||||
|
if (comp != null && comp.CanAddPilot(pawn))
|
||||||
|
{
|
||||||
|
comp.AddPilot(pawn);
|
||||||
|
Messages.Message("WULA_PilotEnteredMech".Translate(pawn.LabelShort, mech.LabelShort),
|
||||||
|
MessageTypeDefOf.PositiveEvent, false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
enterToil.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||||
|
yield return enterToil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
188
Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
Normal file
188
Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
// File: WorkGiver_EnterMech.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class WorkGiver_EnterMech : WorkGiver_Scanner
|
||||||
|
{
|
||||||
|
// 缓存机甲定义列表
|
||||||
|
private static List<ThingDef> cachedMechDefs = null;
|
||||||
|
|
||||||
|
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||||
|
|
||||||
|
// 获取所有机甲定义的列表
|
||||||
|
private List<ThingDef> GetAllMechDefs()
|
||||||
|
{
|
||||||
|
if (cachedMechDefs == null)
|
||||||
|
{
|
||||||
|
cachedMechDefs = new List<ThingDef>();
|
||||||
|
|
||||||
|
// 搜索所有ThingDef,找出继承自Wulamechunit的类
|
||||||
|
foreach (var def in DefDatabase<ThingDef>.AllDefs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (def.thingClass == typeof(Wulamechunit) ||
|
||||||
|
def.thingClass?.IsSubclassOf(typeof(Wulamechunit)) == true)
|
||||||
|
{
|
||||||
|
cachedMechDefs.Add(def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// 忽略错误,继续搜索
|
||||||
|
Log.Warning($"[WULA] Error checking ThingDef {def.defName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedMechDefs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查Thing是否为机甲
|
||||||
|
private bool IsMech(Thing thing)
|
||||||
|
{
|
||||||
|
return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检查基本条件
|
||||||
|
if (t == null || pawn == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 必须是Wulamechunit或其子类
|
||||||
|
if (!IsMech(t))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查距离
|
||||||
|
if (!pawn.CanReach(t, PathEndMode, Danger.Deadly))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲是否有驾驶员槽位组件
|
||||||
|
var comp = t.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (comp == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否已满
|
||||||
|
if (comp.IsFull)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查殖民者是否可以成为驾驶员
|
||||||
|
if (!comp.CanAddPilot(pawn))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查殖民者状态
|
||||||
|
if (pawn.Downed || pawn.Dead)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查殖民者是否正在执行任务
|
||||||
|
if (pawn.CurJob != null && pawn.CurJob.def != JobDefOf.Wait)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否被征召
|
||||||
|
if (pawn.Drafted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否为囚犯
|
||||||
|
if (pawn.IsPrisoner)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否为奴隶
|
||||||
|
if (pawn.IsSlave)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] Error in HasJobOnThing: {ex}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (IsMech(t))
|
||||||
|
{
|
||||||
|
// 创建进入机甲的工作
|
||||||
|
return JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] Error creating job: {ex}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 只搜索玩家拥有的机甲
|
||||||
|
List<Thing> potentialMechs = new List<Thing>();
|
||||||
|
|
||||||
|
// 获取地图中的所有机甲
|
||||||
|
if (pawn.Map != null)
|
||||||
|
{
|
||||||
|
// 使用缓存的机甲定义列表
|
||||||
|
var mechDefs = GetAllMechDefs();
|
||||||
|
|
||||||
|
foreach (var def in mechDefs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var allMechs = pawn.Map.listerThings.ThingsOfDef(def);
|
||||||
|
foreach (var mech in allMechs)
|
||||||
|
{
|
||||||
|
if (mech.Faction == Faction.OfPlayer &&
|
||||||
|
mech.TryGetComp<CompMechPilotHolder>() != null)
|
||||||
|
{
|
||||||
|
potentialMechs.Add(mech);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Warning($"[WULA] Error getting mechs for def {def.defName}: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return potentialMechs;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] Error in PotentialWorkThingsGlobal: {ex}");
|
||||||
|
return Enumerable.Empty<Thing>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldSkip(Pawn pawn, bool forced = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 简化版本:只检查殖民者状态
|
||||||
|
if (pawn.Downed || pawn.Dead || pawn.Drafted || pawn.IsPrisoner || pawn.IsSlave)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] Error in ShouldSkip: {ex}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
// File: FloatMenuOptionProvider_ForceEjectPilot.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class FloatMenuOptionProvider_ForceEjectPilot : FloatMenuOptionProvider
|
||||||
|
{
|
||||||
|
// 征召状态下不能执行此工作
|
||||||
|
protected override bool Drafted => true;
|
||||||
|
|
||||||
|
// 非征召状态下可以执行
|
||||||
|
protected override bool Undrafted => true;
|
||||||
|
|
||||||
|
// 不支持多选
|
||||||
|
protected override bool Multiselect => false;
|
||||||
|
|
||||||
|
// 需要操纵能力
|
||||||
|
protected override bool RequiresManipulation => true;
|
||||||
|
|
||||||
|
// 检查Thing是否为机甲
|
||||||
|
private bool IsMech(Pawn thing)
|
||||||
|
{
|
||||||
|
return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否适用于当前上下文
|
||||||
|
protected override bool AppliesInt(FloatMenuContext context)
|
||||||
|
{
|
||||||
|
// 必须有选中的殖民者
|
||||||
|
if (context.FirstSelectedPawn == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查点击的单元格中是否有机甲
|
||||||
|
var ClickedPawns = context.ClickedPawns;
|
||||||
|
if (ClickedPawns == null || ClickedPawns.Count == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 查找第一个机甲
|
||||||
|
Pawn mech = null;
|
||||||
|
foreach (var thing in ClickedPawns)
|
||||||
|
{
|
||||||
|
if (IsMech(thing))
|
||||||
|
{
|
||||||
|
mech = thing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mech == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲是否有驾驶员组件
|
||||||
|
var comp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (comp == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲是否属于非玩家派系,且Downed但未死亡,并且有驾驶员
|
||||||
|
if (mech.Faction == Faction.OfPlayer || !mech.Downed || mech.Dead || !comp.HasPilots)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取单个选项
|
||||||
|
protected override FloatMenuOption GetSingleOptionFor(Pawn clickedPawn, FloatMenuContext context)
|
||||||
|
{
|
||||||
|
if (clickedPawn == null || context.FirstSelectedPawn == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 如果不是机甲,返回null
|
||||||
|
if (!IsMech(clickedPawn))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 获取机甲和组件
|
||||||
|
var mech = clickedPawn as Wulamechunit;
|
||||||
|
var comp = mech?.TryGetComp<CompMechPilotHolder>();
|
||||||
|
|
||||||
|
if (mech == null || comp == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 检查机甲是否属于非玩家派系,且Downed但未死亡,并且有驾驶员
|
||||||
|
if (mech.Faction == Faction.OfPlayer || !mech.Downed || mech.Dead || !comp.HasPilots)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 检查殖民者是否能够执行此工作
|
||||||
|
return CreateForceEjectOption(mech, context.FirstSelectedPawn, comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建强制拉出驾驶员的菜单选项
|
||||||
|
private FloatMenuOption CreateForceEjectOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp)
|
||||||
|
{
|
||||||
|
string label = "WULA_ForceEjectPilot".Translate(mech.LabelShort);
|
||||||
|
string disabledReason = "";
|
||||||
|
|
||||||
|
// 检查条件是否允许执行强制拉出
|
||||||
|
bool canForceEject = CanForceEject(mech, pawn, comp, ref disabledReason);
|
||||||
|
|
||||||
|
if (canForceEject)
|
||||||
|
{
|
||||||
|
return new FloatMenuOption(label, () =>
|
||||||
|
{
|
||||||
|
// 创建强制拉出驾驶员的工作
|
||||||
|
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_ForceEjectPilot, mech);
|
||||||
|
pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||||
|
}, MenuOptionPriority.High);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 创建禁用的选项,显示原因
|
||||||
|
return new FloatMenuOption(
|
||||||
|
"WULA_ForceEjectPilot".Translate(mech.LabelShort) + ": " + disabledReason,
|
||||||
|
null,
|
||||||
|
MenuOptionPriority.DisabledOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者是否可以执行强制拉出
|
||||||
|
private bool CanForceEject(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason)
|
||||||
|
{
|
||||||
|
// 检查殖民者是否能够到达机甲
|
||||||
|
if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Some))
|
||||||
|
{
|
||||||
|
disabledReason = "NoPath".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查殖民者状态
|
||||||
|
if (pawn.Downed)
|
||||||
|
{
|
||||||
|
disabledReason = "Downed".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pawn.Dead)
|
||||||
|
{
|
||||||
|
disabledReason = "Dead".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为囚犯
|
||||||
|
if (pawn.IsPrisoner)
|
||||||
|
{
|
||||||
|
disabledReason = "Prisoner".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否为奴隶
|
||||||
|
if (pawn.IsSlave)
|
||||||
|
{
|
||||||
|
disabledReason = "Slave".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查机甲是否已经被玩家派系控制
|
||||||
|
if (mech.Faction == Faction.OfPlayer)
|
||||||
|
{
|
||||||
|
disabledReason = "WULA_AlreadyPlayerMech".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查机甲是否Downed且未死亡
|
||||||
|
if (!mech.Downed || mech.Dead)
|
||||||
|
{
|
||||||
|
disabledReason = "WULA_MechNotDowned".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否有驾驶员
|
||||||
|
if (!comp.HasPilots)
|
||||||
|
{
|
||||||
|
disabledReason = "WULA_NoPilot".Translate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
// Jobs/JobDriver_ForceEjectPilot.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobDriver_ForceEjectPilot : JobDriver
|
||||||
|
{
|
||||||
|
private const int WorkDurationTicks = 600; // 10秒(60帧/秒)
|
||||||
|
|
||||||
|
// 目标机甲
|
||||||
|
private Pawn TargetMech => job.targetA.Thing as Pawn;
|
||||||
|
|
||||||
|
// 工作进度属性
|
||||||
|
private float WorkProgress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (TargetMech == null) return 0f;
|
||||||
|
return (float)ticksLeftThisToil / WorkDurationTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
// 为殖民者预留机甲的位置
|
||||||
|
return pawn.Reserve(TargetMech, job, 1, -1, null, errorOnFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
// 目标验证
|
||||||
|
this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
|
||||||
|
this.FailOn(() => !CanForceEject(TargetMech));
|
||||||
|
|
||||||
|
// Toil 1:移动到机甲位置
|
||||||
|
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch)
|
||||||
|
.FailOnDespawnedOrNull(TargetIndex.A);
|
||||||
|
|
||||||
|
// Toil 2:执行强制拉出工作
|
||||||
|
var workToil = new Toil();
|
||||||
|
workToil.initAction = () =>
|
||||||
|
{
|
||||||
|
pawn.rotationTracker.FaceCell(TargetMech.Position);
|
||||||
|
pawn.jobs.posture = PawnPosture.Standing;
|
||||||
|
};
|
||||||
|
workToil.tickAction = () =>
|
||||||
|
{
|
||||||
|
// 每帧工作进度
|
||||||
|
pawn.skills?.Learn(SkillDefOf.Melee, 0.1f);
|
||||||
|
|
||||||
|
// 显示工作条
|
||||||
|
if (pawn.IsColonistPlayerControlled)
|
||||||
|
{
|
||||||
|
TargetMech.Map.overlayDrawer.DrawOverlay(TargetMech, OverlayTypes.QuestionMark);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
workToil.defaultCompleteMode = ToilCompleteMode.Delay;
|
||||||
|
workToil.WithEffect(EffecterDefOf.MechRepairing, TargetIndex.A);
|
||||||
|
workToil.defaultDuration = WorkDurationTicks;
|
||||||
|
workToil.WithProgressBar(TargetIndex.A, () => 1f - WorkProgress);
|
||||||
|
workToil.handlingFacing = true;
|
||||||
|
workToil.activeSkill = () => SkillDefOf.Construction;
|
||||||
|
yield return workToil;
|
||||||
|
|
||||||
|
// Toil 3:完成工作
|
||||||
|
yield return new Toil
|
||||||
|
{
|
||||||
|
initAction = () =>
|
||||||
|
{
|
||||||
|
CompleteForceEject();
|
||||||
|
},
|
||||||
|
defaultCompleteMode = ToilCompleteMode.Instant
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否可以强制拉出
|
||||||
|
private bool CanForceEject(Pawn mech)
|
||||||
|
{
|
||||||
|
if (mech == null || mech.Dead)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 必须是机甲
|
||||||
|
if (!(mech is Wulamechunit))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 必须是玩家派系的目标
|
||||||
|
if (mech.Faction == Faction.OfPlayer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 必须失去行动能力但未死亡
|
||||||
|
if (!mech.Downed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 必须有驾驶员
|
||||||
|
var pilotComp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (pilotComp == null || !pilotComp.HasPilots)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 殖民者必须能够接触机甲
|
||||||
|
if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Some))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 殖民者不能是囚犯或已失去行动能力
|
||||||
|
if (pawn.Downed || pawn.Dead || pawn.IsPrisoner)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成强制拉出
|
||||||
|
private void CompleteForceEject()
|
||||||
|
{
|
||||||
|
var mech = TargetMech;
|
||||||
|
if (mech == null) return;
|
||||||
|
|
||||||
|
var pilotComp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (pilotComp == null) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. 弹出所有驾驶员
|
||||||
|
var ejectedPilots = pilotComp.GetPilots().ToList();
|
||||||
|
pilotComp.RemoveAllPilots();
|
||||||
|
|
||||||
|
// 2. 转换派系为玩家
|
||||||
|
mech.SetFaction(Faction.OfPlayer);
|
||||||
|
|
||||||
|
// 4. 发送消息
|
||||||
|
SendCompletionMessages(mech, ejectedPilots);
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] Error in ForceEjectPilot: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送完成消息
|
||||||
|
private void SendCompletionMessages(Pawn mech, List<Pawn> ejectedPilots)
|
||||||
|
{
|
||||||
|
string message;
|
||||||
|
|
||||||
|
if (ejectedPilots.Count > 0)
|
||||||
|
{
|
||||||
|
message = "WULA_ForceEjectComplete_WithPilots".Translate(
|
||||||
|
pawn.LabelShortCap,
|
||||||
|
mech.LabelShortCap,
|
||||||
|
ejectedPilots.Count
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message = "WULA_ForceEjectComplete".Translate(
|
||||||
|
pawn.LabelShortCap,
|
||||||
|
mech.LabelShortCap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages.Message(message, MessageTypeDefOf.PositiveEvent);
|
||||||
|
|
||||||
|
// 如果弹出的是敌对派系驾驶员,添加额外消息
|
||||||
|
foreach (var pilot in ejectedPilots)
|
||||||
|
{
|
||||||
|
if (pilot.Faction != null && pilot.Faction.HostileTo(Faction.OfPlayer))
|
||||||
|
{
|
||||||
|
Messages.Message("WULA_HostilePilotEjected".Translate(
|
||||||
|
pilot.LabelShortCap,
|
||||||
|
pilot.Faction.Name
|
||||||
|
), MessageTypeDefOf.NeutralEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
Source/WulaFallenEmpire/Work/JobDriver_CarryToMech.cs
Normal file
82
Source/WulaFallenEmpire/Work/JobDriver_CarryToMech.cs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// File: JobDriver_CarryToMech.cs (修复count问题)
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobDriver_CarryToMech : JobDriver
|
||||||
|
{
|
||||||
|
private const TargetIndex TakeeIndex = TargetIndex.A;
|
||||||
|
private const TargetIndex MechIndex = TargetIndex.B;
|
||||||
|
|
||||||
|
protected Pawn Takee => (Pawn)job.GetTarget(TakeeIndex).Thing;
|
||||||
|
protected Wulamechunit Mech => (Wulamechunit)job.GetTarget(MechIndex).Thing;
|
||||||
|
protected CompMechPilotHolder MechComp => Mech?.TryGetComp<CompMechPilotHolder>();
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
// 确保job.count是有效的(至少为1)
|
||||||
|
if (job.count <= 0)
|
||||||
|
{
|
||||||
|
job.count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保留目标和机甲,明确指定数量为1
|
||||||
|
return pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)
|
||||||
|
&& pawn.Reserve(Mech, job, 1, -1, null, errorOnFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
// 确保job.count是有效的
|
||||||
|
if (job.count <= 0)
|
||||||
|
{
|
||||||
|
job.count = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标准失败条件
|
||||||
|
this.FailOnDestroyedOrNull(TakeeIndex);
|
||||||
|
this.FailOnDestroyedOrNull(MechIndex);
|
||||||
|
this.FailOn(() => MechComp == null);
|
||||||
|
this.FailOn(() => !Takee.Downed); // 确保被搬运者是Downed状态
|
||||||
|
|
||||||
|
// 1. 前往要被搬运的殖民者
|
||||||
|
yield return Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch)
|
||||||
|
.FailOnDespawnedNullOrForbidden(TakeeIndex)
|
||||||
|
.FailOnDespawnedNullOrForbidden(MechIndex)
|
||||||
|
.FailOnSomeonePhysicallyInteracting(TakeeIndex);
|
||||||
|
|
||||||
|
// 2. 开始搬运殖民者 - 使用原版的StartCarryThing方法
|
||||||
|
yield return Toils_Haul.StartCarryThing(TakeeIndex, false, true, false);
|
||||||
|
|
||||||
|
// 3. 携带殖民者前往机甲
|
||||||
|
yield return Toils_Goto.GotoThing(MechIndex, PathEndMode.Touch);
|
||||||
|
|
||||||
|
// 4. 将殖民者放入机甲
|
||||||
|
yield return new Toil
|
||||||
|
{
|
||||||
|
initAction = () =>
|
||||||
|
{
|
||||||
|
if (MechComp != null && Takee != null && MechComp.CanAddPilot(Takee))
|
||||||
|
{
|
||||||
|
// 放下殖民者
|
||||||
|
if (pawn.carryTracker.CarriedThing == Takee)
|
||||||
|
{
|
||||||
|
pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out Thing droppedThing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将殖民者添加到机甲
|
||||||
|
MechComp.AddPilot(Takee);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Warning($"[WULA] 无法将殖民者添加到机甲");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultCompleteMode = ToilCompleteMode.Instant
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Source/WulaFallenEmpire/Work/JobGiver_NoPilot.cs
Normal file
18
Source/WulaFallenEmpire/Work/JobGiver_NoPilot.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobGiver_NoPilot : ThinkNode_JobGiver
|
||||||
|
{
|
||||||
|
private const int WaitTime = 100;
|
||||||
|
|
||||||
|
protected override Job TryGiveJob(Pawn pawn)
|
||||||
|
{
|
||||||
|
Job job = JobMaker.MakeJob(JobDefOf.Wait);
|
||||||
|
job.expiryInterval = 100;
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
176
Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
Normal file
176
Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// JobDriver_RefuelMech.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobDriver_RefuelMech : JobDriver
|
||||||
|
{
|
||||||
|
private const TargetIndex MechInd = TargetIndex.A;
|
||||||
|
private const TargetIndex FuelInd = TargetIndex.B;
|
||||||
|
private const int RefuelingDuration = 240; // 基础加注时间
|
||||||
|
|
||||||
|
protected Pawn Mech => job.GetTarget(MechInd).Thing as Pawn;
|
||||||
|
protected CompMechFuel FuelComp => Mech?.TryGetComp<CompMechFuel>();
|
||||||
|
protected Thing Fuel => job.GetTarget(FuelInd).Thing;
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
Pawn pawn = this.pawn;
|
||||||
|
Job job = this.job;
|
||||||
|
LocalTargetInfo target = job.GetTarget(MechInd);
|
||||||
|
|
||||||
|
if (!pawn.Reserve(target, job, 1, -1, null, errorOnFailed))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pawn.Reserve(job.GetTarget(FuelInd), job, 1, -1, null, errorOnFailed))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
// 检查目标是否有效
|
||||||
|
this.FailOnDespawnedNullOrForbidden(MechInd);
|
||||||
|
this.FailOn(() => FuelComp == null);
|
||||||
|
|
||||||
|
// 添加结束条件:燃料已满
|
||||||
|
AddEndCondition(() => {
|
||||||
|
if (FuelComp.IsFull)
|
||||||
|
return JobCondition.Succeeded;
|
||||||
|
return JobCondition.Ongoing;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果不是玩家强制命令,检查是否应该自动加注
|
||||||
|
AddFailCondition(() => {
|
||||||
|
if (job.playerForced)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 获取驾驶员组件
|
||||||
|
var pilotComp = Mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
bool hasPilot = pilotComp != null && pilotComp.HasPilots;
|
||||||
|
|
||||||
|
// 如果有驾驶员且不是玩家强制命令,不自动加注
|
||||||
|
if (hasPilot && !job.playerForced)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 检查燃料组件是否允许自动加注
|
||||||
|
if (!FuelComp.Props.allowAutoRefuel && !job.playerForced)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 第一步:计算需要多少燃料
|
||||||
|
yield return Toils_General.DoAtomic(delegate
|
||||||
|
{
|
||||||
|
if (FuelComp != null)
|
||||||
|
{
|
||||||
|
job.count = FuelComp.GetFuelCountToFullyRefuel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 第二步:预留燃料
|
||||||
|
Toil reserveFuel = Toils_Reserve.Reserve(FuelInd);
|
||||||
|
yield return reserveFuel;
|
||||||
|
|
||||||
|
// 第三步:前往燃料位置
|
||||||
|
yield return Toils_Goto.GotoThing(FuelInd, PathEndMode.ClosestTouch)
|
||||||
|
.FailOnDespawnedNullOrForbidden(FuelInd)
|
||||||
|
.FailOnSomeonePhysicallyInteracting(FuelInd);
|
||||||
|
|
||||||
|
// 第四步:拿起燃料
|
||||||
|
yield return Toils_Haul.StartCarryThing(FuelInd, putRemainderInQueue: false, subtractNumTakenFromJobCount: true)
|
||||||
|
.FailOnDestroyedNullOrForbidden(FuelInd);
|
||||||
|
|
||||||
|
// 第五步:检查是否有机会拿更多燃料
|
||||||
|
yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserveFuel, FuelInd, TargetIndex.None, takeFromValidStorage: true);
|
||||||
|
|
||||||
|
// 第六步:前往机甲位置
|
||||||
|
yield return Toils_Goto.GotoThing(MechInd, PathEndMode.Touch);
|
||||||
|
|
||||||
|
// 第七步:等待加注(有进度条)
|
||||||
|
Toil refuelToil = Toils_General.Wait(RefuelingDuration)
|
||||||
|
.FailOnDestroyedNullOrForbidden(FuelInd)
|
||||||
|
.FailOnDestroyedNullOrForbidden(MechInd)
|
||||||
|
.FailOnCannotTouch(MechInd, PathEndMode.Touch)
|
||||||
|
.WithProgressBarToilDelay(MechInd);
|
||||||
|
|
||||||
|
// 调整加注时间基于燃料组件的速度因子
|
||||||
|
refuelToil.defaultDuration = Mathf.RoundToInt(RefuelingDuration / FuelComp.Props.refuelSpeedFactor);
|
||||||
|
|
||||||
|
yield return refuelToil;
|
||||||
|
|
||||||
|
// 第八步:完成加注 - 模仿 RimWorld 原版实现
|
||||||
|
yield return FinalizeRefueling(MechInd, FuelInd);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模仿 RimWorld.Toils_Refuel.FinalizeRefueling 的实现
|
||||||
|
private static Toil FinalizeRefueling(TargetIndex refuelableInd, TargetIndex fuelInd)
|
||||||
|
{
|
||||||
|
Toil toil = ToilMaker.MakeToil("FinalizeRefueling");
|
||||||
|
toil.initAction = delegate
|
||||||
|
{
|
||||||
|
Pawn actor = toil.actor;
|
||||||
|
Job curJob = actor.CurJob;
|
||||||
|
Thing refuelable = curJob.GetTarget(refuelableInd).Thing;
|
||||||
|
CompMechFuel fuelComp = refuelable.TryGetComp<CompMechFuel>();
|
||||||
|
|
||||||
|
if (fuelComp != null)
|
||||||
|
{
|
||||||
|
// 获取所有燃料物品
|
||||||
|
List<Thing> fuelThings;
|
||||||
|
if (actor.CurJob.placedThings.NullOrEmpty())
|
||||||
|
{
|
||||||
|
// 如果没有 placedThings,则使用燃料目标
|
||||||
|
Thing fuel = curJob.GetTarget(fuelInd).Thing;
|
||||||
|
if (fuel != null)
|
||||||
|
{
|
||||||
|
fuelThings = new List<Thing> { fuel };
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fuelThings = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 使用 placedThings 中的所有燃料物品
|
||||||
|
fuelThings = actor.CurJob.placedThings.Select((ThingCountClass p) => p.thing).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fuelThings != null)
|
||||||
|
{
|
||||||
|
// 计算总燃料量并销毁燃料物品
|
||||||
|
float totalFuel = 0f;
|
||||||
|
foreach (Thing fuelThing in fuelThings)
|
||||||
|
{
|
||||||
|
if (fuelThing != null && fuelThing.def == fuelComp.FuelType)
|
||||||
|
{
|
||||||
|
totalFuel += fuelThing.stackCount;
|
||||||
|
fuelThing.Destroy(DestroyMode.Vanish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加燃料到机甲
|
||||||
|
if (totalFuel > 0)
|
||||||
|
{
|
||||||
|
fuelComp.Refuel(totalFuel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
toil.defaultCompleteMode = ToilCompleteMode.Instant;
|
||||||
|
return toil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
123
Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
Normal file
123
Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
// WorkGiver_RefuelMech.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class WorkGiver_RefuelMech : WorkGiver_Scanner
|
||||||
|
{
|
||||||
|
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||||
|
|
||||||
|
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
|
||||||
|
{
|
||||||
|
// 返回所有需要燃料的机甲
|
||||||
|
// 修复:使用 LINQ 的 Where 方法而不是 FindAll
|
||||||
|
var mechs = pawn.Map.mapPawns.AllPawnsSpawned.Where(p =>
|
||||||
|
p.TryGetComp<CompMechFuel>() != null);
|
||||||
|
|
||||||
|
foreach (Pawn mech in mechs)
|
||||||
|
{
|
||||||
|
yield return mech;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldSkip(Pawn pawn, bool forced = false)
|
||||||
|
{
|
||||||
|
// 如果没有需要燃料的机甲,跳过
|
||||||
|
return !PotentialWorkThingsGlobal(pawn).Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
if (!(t is Pawn mech))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var fuelComp = mech.TryGetComp<CompMechFuel>();
|
||||||
|
if (fuelComp == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲是否已加满燃料
|
||||||
|
if (fuelComp.IsFull)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否有可用的燃料
|
||||||
|
if (FindFuel(pawn, fuelComp) == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否能接触到机甲
|
||||||
|
if (!pawn.CanReserveAndReach(t, PathEndMode.Touch, Danger.Some))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查机甲状态
|
||||||
|
var pilotComp = mech.TryGetComp<CompMechPilotHolder>();
|
||||||
|
bool hasPilot = pilotComp != null && pilotComp.HasPilots;
|
||||||
|
|
||||||
|
// 如果有驾驶员且不是强制命令,不自动加注
|
||||||
|
if (hasPilot && !forced)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查燃料组件是否允许自动加注
|
||||||
|
if (!fuelComp.Props.allowAutoRefuel && !forced)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查是否达到自动加注阈值
|
||||||
|
if (!forced && !fuelComp.NeedsRefueling)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
var fuelComp = t.TryGetComp<CompMechFuel>();
|
||||||
|
if (fuelComp == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 寻找燃料
|
||||||
|
Thing fuel = FindFuel(pawn, fuelComp);
|
||||||
|
if (fuel == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 创建加注工作
|
||||||
|
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_RefuelMech, t, fuel);
|
||||||
|
job.count = fuelComp.GetFuelCountToFullyRefuel();
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改方法:返回 Thing 而不是 bool
|
||||||
|
private Thing FindFuel(Pawn pawn, CompMechFuel fuelComp)
|
||||||
|
{
|
||||||
|
if (fuelComp.FuelType == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// 在库存中寻找燃料
|
||||||
|
Thing fuel = FindFuelInInventory(pawn, fuelComp.FuelType);
|
||||||
|
if (fuel != null)
|
||||||
|
return fuel;
|
||||||
|
|
||||||
|
// 在地图上寻找燃料
|
||||||
|
fuel = GenClosest.ClosestThingReachable(
|
||||||
|
pawn.Position,
|
||||||
|
pawn.Map,
|
||||||
|
ThingRequest.ForDef(fuelComp.FuelType),
|
||||||
|
PathEndMode.ClosestTouch,
|
||||||
|
TraverseParms.For(pawn),
|
||||||
|
9999f,
|
||||||
|
validator: thing => !thing.IsForbidden(pawn) && pawn.CanReserve(thing)
|
||||||
|
);
|
||||||
|
|
||||||
|
return fuel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Thing FindFuelInInventory(Pawn pawn, ThingDef fuelType)
|
||||||
|
{
|
||||||
|
if (pawn.inventory == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return pawn.inventory.innerContainer.FirstOrDefault(t => t.def == fuelType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
416
Source/WulaFallenEmpire/Work/RepairMech/JobDriver_RepairMech.cs
Normal file
416
Source/WulaFallenEmpire/Work/RepairMech/JobDriver_RepairMech.cs
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
// JobDriver_RepairMech.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class JobDriver_RepairMech : JobDriver
|
||||||
|
{
|
||||||
|
private const TargetIndex MechInd = TargetIndex.A;
|
||||||
|
|
||||||
|
protected int ticksToNextRepair;
|
||||||
|
|
||||||
|
protected Pawn Mech => (Pawn)job.GetTarget(TargetIndex.A).Thing;
|
||||||
|
|
||||||
|
protected virtual bool Remote => false;
|
||||||
|
|
||||||
|
protected CompMechRepairable RepairableComp => Mech?.TryGetComp<CompMechRepairable>();
|
||||||
|
|
||||||
|
// 使用配置的修复周期ticks数,并根据MechRepairSpeed调整
|
||||||
|
protected int TicksPerRepairCycle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RepairableComp == null)
|
||||||
|
return 120;
|
||||||
|
|
||||||
|
int baseTicks = RepairableComp.Props.ticksPerRepairCycle;
|
||||||
|
return Mathf.RoundToInt(baseTicks / pawn.GetStatValue(StatDefOf.MechRepairSpeed));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每次修复的HP量
|
||||||
|
protected float RepairAmountPerCycle
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (RepairableComp == null)
|
||||||
|
return 1f;
|
||||||
|
|
||||||
|
return RepairableComp.Props.repairAmountPerCycle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增:缺失部位修复配置
|
||||||
|
protected float MissingPartRepairCostMultiplier => 2f;
|
||||||
|
protected HediffDef MissingPartReplacementInjury => HediffDefOf.Misc;
|
||||||
|
|
||||||
|
public override bool TryMakePreToilReservations(bool errorOnFailed)
|
||||||
|
{
|
||||||
|
return pawn.Reserve(Mech, job, 1, -1, null, errorOnFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Toil> MakeNewToils()
|
||||||
|
{
|
||||||
|
this.FailOnDestroyedOrNull(TargetIndex.A);
|
||||||
|
this.FailOnForbidden(TargetIndex.A);
|
||||||
|
this.FailOn(() => !MechRepairable() || !MechNeedsRepair());
|
||||||
|
|
||||||
|
if (!Remote)
|
||||||
|
{
|
||||||
|
yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toil repairToil = (Remote ? Toils_General.Wait(int.MaxValue) : Toils_General.WaitWith(TargetIndex.A, int.MaxValue, useProgressBar: true, maintainPosture: true, maintainSleep: true));
|
||||||
|
|
||||||
|
// 添加维修特效
|
||||||
|
if (RepairableComp?.Props.repairEffect != null)
|
||||||
|
{
|
||||||
|
repairToil.WithEffect(RepairableComp.Props.repairEffect, TargetIndex.A);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
repairToil.WithEffect(EffecterDefOf.MechRepairing, TargetIndex.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加维修音效
|
||||||
|
if (RepairableComp?.Props.repairSound != null)
|
||||||
|
{
|
||||||
|
repairToil.PlaySustainerOrSound(RepairableComp.Props.repairSound);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
repairToil.PlaySustainerOrSound(Remote ? SoundDefOf.RepairMech_Remote : SoundDefOf.RepairMech_Touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
repairToil.AddPreInitAction(delegate
|
||||||
|
{
|
||||||
|
ticksToNextRepair = TicksPerRepairCycle;
|
||||||
|
});
|
||||||
|
|
||||||
|
repairToil.handlingFacing = true;
|
||||||
|
|
||||||
|
repairToil.tickIntervalAction = delegate(int delta)
|
||||||
|
{
|
||||||
|
ticksToNextRepair -= delta;
|
||||||
|
if (ticksToNextRepair <= 0)
|
||||||
|
{
|
||||||
|
RepairTick(delta);
|
||||||
|
ticksToNextRepair = TicksPerRepairCycle;
|
||||||
|
}
|
||||||
|
pawn.rotationTracker.FaceTarget(Mech);
|
||||||
|
if (pawn.skills != null)
|
||||||
|
{
|
||||||
|
pawn.skills.Learn(SkillDefOf.Crafting, 0.05f * (float)delta);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
repairToil.AddFinishAction(delegate
|
||||||
|
{
|
||||||
|
// 维修完成后,如果机甲被征召,恢复其工作
|
||||||
|
if (Mech.jobs?.curJob != null && job.playerForced)
|
||||||
|
{
|
||||||
|
Mech.jobs.EndCurrentJob(JobCondition.InterruptForced);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
repairToil.AddEndCondition(() => MechNeedsRepair() ? JobCondition.Ongoing : JobCondition.Succeeded);
|
||||||
|
|
||||||
|
if (!Remote)
|
||||||
|
{
|
||||||
|
repairToil.activeSkill = () => SkillDefOf.Crafting;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return repairToil;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MechRepairable()
|
||||||
|
{
|
||||||
|
return RepairableComp != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MechNeedsRepair()
|
||||||
|
{
|
||||||
|
return RepairableComp?.NeedsRepair ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RepairTick(int delta)
|
||||||
|
{
|
||||||
|
if (Mech == null || Mech.health == null || Mech.Dead)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 计算本次修复的总HP量
|
||||||
|
float totalRepairAmount = RepairAmountPerCycle;
|
||||||
|
float originalRepairAmount = totalRepairAmount;
|
||||||
|
|
||||||
|
// 第一阶段:先修复现有伤口(非缺失部位)
|
||||||
|
totalRepairAmount = RepairExistingInjuries(totalRepairAmount);
|
||||||
|
|
||||||
|
// 第二阶段:如果还有修复量,并且机甲血量足够安全,再处理缺失部位
|
||||||
|
if (totalRepairAmount > 0f && IsSafeToRepairMissingParts())
|
||||||
|
{
|
||||||
|
// 直接尝试转换缺失部位,不消耗修复量
|
||||||
|
TryConvertMissingParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录修复统计(只统计实际修复的伤口)
|
||||||
|
if (RepairableComp != null && totalRepairAmount < originalRepairAmount)
|
||||||
|
{
|
||||||
|
RepairableComp.RecordRepair(originalRepairAmount - totalRepairAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修复现有伤口(非缺失部位)
|
||||||
|
private float RepairExistingInjuries(float totalRepairAmount)
|
||||||
|
{
|
||||||
|
float remainingAmount = totalRepairAmount;
|
||||||
|
|
||||||
|
// 获取所有非缺失部位的伤口
|
||||||
|
var existingInjuries = Mech.health.hediffSet.hediffs
|
||||||
|
.Where(h =>
|
||||||
|
(h is Hediff_Injury && h.Severity > 0f) ||
|
||||||
|
(h.def.tendable && h.Severity > 0f && !(h is Hediff_MissingPart))
|
||||||
|
)
|
||||||
|
.OrderByDescending(h => h.Severity) // 优先修复最严重的伤口
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var injury in existingInjuries)
|
||||||
|
{
|
||||||
|
if (remainingAmount <= 0f)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (injury is Hediff_Injury injuryHediff)
|
||||||
|
{
|
||||||
|
// 修复伤害
|
||||||
|
float healAmount = Mathf.Min(remainingAmount, injuryHediff.Severity);
|
||||||
|
injuryHediff.Severity -= healAmount;
|
||||||
|
remainingAmount -= healAmount;
|
||||||
|
|
||||||
|
if (injuryHediff.Severity <= 0f)
|
||||||
|
{
|
||||||
|
Mech.health.RemoveHediff(injuryHediff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (injury.def.tendable)
|
||||||
|
{
|
||||||
|
// 其他可治疗的hediff
|
||||||
|
float healAmount = Mathf.Min(remainingAmount, injury.Severity);
|
||||||
|
injury.Severity -= healAmount;
|
||||||
|
remainingAmount -= healAmount;
|
||||||
|
|
||||||
|
if (injury.Severity <= 0f)
|
||||||
|
{
|
||||||
|
Mech.health.RemoveHediff(injury);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return remainingAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否安全可以修复缺失部位
|
||||||
|
private bool IsSafeToRepairMissingParts()
|
||||||
|
{
|
||||||
|
// 获取机甲当前血量百分比
|
||||||
|
float currentHealthPercent = Mech.health.summaryHealth.SummaryHealthPercent;
|
||||||
|
|
||||||
|
// 如果血量低于30%,不安全修复缺失部位
|
||||||
|
if (currentHealthPercent < 0.3f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 如果有严重伤口(严重性大于5),先修复它们
|
||||||
|
bool hasCriticalInjuries = Mech.health.hediffSet.hediffs
|
||||||
|
.Any(h => h is Hediff_Injury && h.Severity > 5f);
|
||||||
|
|
||||||
|
if (hasCriticalInjuries)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查缺失部位转换是否会致命
|
||||||
|
if (WouldMissingPartConversionBeFatal())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查缺失部位转换是否会致命
|
||||||
|
private bool WouldMissingPartConversionBeFatal()
|
||||||
|
{
|
||||||
|
// 获取所有缺失部位
|
||||||
|
var missingParts = Mech.health.hediffSet.GetMissingPartsCommonAncestors();
|
||||||
|
if (!missingParts.Any())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 计算转换后可能增加的总伤害量
|
||||||
|
float potentialAddedDamage = 0f;
|
||||||
|
|
||||||
|
foreach (var missingPart in missingParts)
|
||||||
|
{
|
||||||
|
float partMaxHealth = missingPart.Part.def.GetMaxHealth(Mech);
|
||||||
|
float injurySeverity = partMaxHealth - 1;
|
||||||
|
if (partMaxHealth <= 1)
|
||||||
|
injurySeverity = 0.5f;
|
||||||
|
|
||||||
|
potentialAddedDamage += injurySeverity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前总伤害量
|
||||||
|
float currentTotalInjurySeverity = Mech.health.hediffSet.hediffs
|
||||||
|
.Where(h => h is Hediff_Injury)
|
||||||
|
.Sum(h => h.Severity);
|
||||||
|
|
||||||
|
// 计算转换后的总伤害量
|
||||||
|
float projectedTotalInjurySeverity = currentTotalInjurySeverity + potentialAddedDamage;
|
||||||
|
|
||||||
|
// 获取致命伤害阈值
|
||||||
|
float lethalDamageThreshold = Mech.health.LethalDamageThreshold;
|
||||||
|
|
||||||
|
// 如果转换后的总伤害量超过或接近致命阈值,不安全
|
||||||
|
return projectedTotalInjurySeverity >= lethalDamageThreshold * 0.8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试转换缺失部位
|
||||||
|
private void TryConvertMissingParts()
|
||||||
|
{
|
||||||
|
// 获取所有缺失部位
|
||||||
|
var missingParts = Mech.health.hediffSet.GetMissingPartsCommonAncestors();
|
||||||
|
if (!missingParts.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 选择最小的缺失部件进行转换(成本较低)
|
||||||
|
Hediff_MissingPart partToRepair = null;
|
||||||
|
float minHealth = float.MaxValue;
|
||||||
|
|
||||||
|
foreach (var missingPart in missingParts)
|
||||||
|
{
|
||||||
|
float partHealth = missingPart.Part.def.GetMaxHealth(Mech);
|
||||||
|
if (partHealth < minHealth)
|
||||||
|
{
|
||||||
|
minHealth = partHealth;
|
||||||
|
partToRepair = missingPart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partToRepair != null)
|
||||||
|
{
|
||||||
|
// 直接转换缺失部位
|
||||||
|
if (ConvertMissingPartToInjury(partToRepair))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将缺失部件转换为伤害hediff
|
||||||
|
private bool ConvertMissingPartToInjury(Hediff_MissingPart missingPart)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
float partMaxHealth = missingPart.Part.def.GetMaxHealth(Mech);
|
||||||
|
|
||||||
|
// 关键修复:确保转换后的损伤不会导致部位再次缺失
|
||||||
|
// 设置损伤严重性为最大健康值-1,这样部位健康值至少为1
|
||||||
|
float injurySeverity = partMaxHealth - 1;
|
||||||
|
|
||||||
|
// 如果最大健康值为1,则设置为0.5,确保部位健康值大于0
|
||||||
|
if (partMaxHealth <= 1)
|
||||||
|
{
|
||||||
|
injurySeverity = 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除缺失部件hediff
|
||||||
|
Mech.health.RemoveHediff(missingPart);
|
||||||
|
|
||||||
|
// 添加指定的伤害hediff
|
||||||
|
HediffDef injuryDef = MissingPartReplacementInjury;
|
||||||
|
if (injuryDef == null)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] 找不到指定的hediff定义: {MissingPartReplacementInjury?.defName ?? "null"}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建损伤
|
||||||
|
Hediff injury = HediffMaker.MakeHediff(injuryDef, Mech, missingPart.Part);
|
||||||
|
injury.Severity = injurySeverity;
|
||||||
|
|
||||||
|
Mech.health.AddHediff(injury);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"[WULA] 转换缺失部件 {missingPart.Part.def.defName} 时出错: {ex}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有可修复的hediff
|
||||||
|
private List<Hediff> GetAllRepairableHediffs()
|
||||||
|
{
|
||||||
|
var repairableHediffs = new List<Hediff>();
|
||||||
|
|
||||||
|
if (Mech.health?.hediffSet == null)
|
||||||
|
return repairableHediffs;
|
||||||
|
|
||||||
|
// 获取所有hediff
|
||||||
|
foreach (var hediff in Mech.health.hediffSet.hediffs)
|
||||||
|
{
|
||||||
|
if (CanRepairHediff(hediff))
|
||||||
|
{
|
||||||
|
repairableHediffs.Add(hediff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return repairableHediffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查hediff是否可修复
|
||||||
|
private bool CanRepairHediff(Hediff hediff)
|
||||||
|
{
|
||||||
|
// 缺失部位可以修复
|
||||||
|
if (hediff is Hediff_MissingPart)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 伤害可以修复
|
||||||
|
if (hediff is Hediff_Injury)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 可治疗的hediff可以修复
|
||||||
|
if (hediff.def.tendable && hediff.Severity > 0f)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// 跳过疾病
|
||||||
|
if (IsDisease(hediff))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是疾病
|
||||||
|
private bool IsDisease(Hediff hediff)
|
||||||
|
{
|
||||||
|
// 常见的疾病类型
|
||||||
|
string[] diseaseKeywords = {
|
||||||
|
"Disease", "Flu", "Plague", "Infection", "Malaria",
|
||||||
|
"SleepingSickness", "FibrousMechanites", "SensoryMechanites",
|
||||||
|
"WoundInfection", "FoodPoisoning", "GutWorms", "MuscleParasites"
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (string keyword in diseaseKeywords)
|
||||||
|
{
|
||||||
|
if (hediff.def.defName.Contains(keyword))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ExposeData()
|
||||||
|
{
|
||||||
|
base.ExposeData();
|
||||||
|
Scribe_Values.Look(ref ticksToNextRepair, "ticksToNextRepair", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
// WorkGiver_RepairMech.cs
|
||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class WorkGiver_RepairMech : WorkGiver_Scanner
|
||||||
|
{
|
||||||
|
public override PathEndMode PathEndMode => PathEndMode.Touch;
|
||||||
|
|
||||||
|
public override Danger MaxPathDanger(Pawn pawn)
|
||||||
|
{
|
||||||
|
return Danger.Deadly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.Faction != Faction.OfPlayer || pawn.Map == null)
|
||||||
|
return Enumerable.Empty<Thing>();
|
||||||
|
|
||||||
|
// 获取所有需要维修的玩家机甲
|
||||||
|
return pawn.Map.mapPawns.AllPawnsSpawned
|
||||||
|
.Where(p =>
|
||||||
|
p.Faction == Faction.OfPlayer &&
|
||||||
|
p.health != null &&
|
||||||
|
!p.Dead &&
|
||||||
|
p.TryGetComp<CompMechRepairable>()?.CanAutoRepair == true
|
||||||
|
)
|
||||||
|
.Cast<Thing>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool ShouldSkip(Pawn pawn, bool forced = false)
|
||||||
|
{
|
||||||
|
if (pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Crafting))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
if (!(t is Pawn mech) || mech.Dead)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var repairableComp = t.TryGetComp<CompMechRepairable>();
|
||||||
|
if (repairableComp == null || !repairableComp.CanAutoRepair)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!repairableComp.NeedsRepair)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pawn.Faction != Faction.OfPlayer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!pawn.CanReserveAndReach(t, PathEndMode.Touch, Danger.Some, 1, -1, null, forced))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// 检查工作标签
|
||||||
|
if (pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Crafting))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
|
||||||
|
{
|
||||||
|
return JobMaker.MakeJob(Wula_JobDefOf.WULA_RepairMech, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// ThinkNode_ConditionalMechHasPilot.cs (修复版)
|
||||||
|
using RimWorld;
|
||||||
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
|
|
||||||
|
namespace WulaFallenEmpire
|
||||||
|
{
|
||||||
|
public class ThinkNode_ConditionalMechHasPilot : ThinkNode_Conditional
|
||||||
|
{
|
||||||
|
// 可选的:可以在XML中设置的参数
|
||||||
|
public int minPilotCount = 1; // 最少需要的驾驶员数量
|
||||||
|
|
||||||
|
protected override bool Satisfied(Pawn pawn)
|
||||||
|
{
|
||||||
|
if (pawn.Faction != Faction.OfPlayer)
|
||||||
|
return false; // 仅适用于玩家派系的机甲
|
||||||
|
var pilotComp = pawn.TryGetComp<CompMechPilotHolder>();
|
||||||
|
if (pilotComp == null)
|
||||||
|
return false; // 如果没有驾驶员组件,条件满足(允许执行)
|
||||||
|
|
||||||
|
int currentPilotCount = pilotComp.CurrentPilotCount;
|
||||||
|
|
||||||
|
// 检查是否满足最小驾驶员数量要求
|
||||||
|
bool hasEnoughPilots = currentPilotCount >= minPilotCount;
|
||||||
|
|
||||||
|
// 这意味着机甲可以正常工作
|
||||||
|
bool conditionSatisfied = hasEnoughPilots;
|
||||||
|
|
||||||
|
return !conditionSatisfied;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ThinkNode DeepCopy(bool resolve = true)
|
||||||
|
{
|
||||||
|
ThinkNode_ConditionalMechHasPilot thinkNode_ConditionalMechHasPilot = (ThinkNode_ConditionalMechHasPilot)base.DeepCopy(resolve);
|
||||||
|
thinkNode_ConditionalMechHasPilot.minPilotCount = minPilotCount;
|
||||||
|
return thinkNode_ConditionalMechHasPilot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,6 @@ namespace WulaFallenEmpire
|
|||||||
public static JobDef WULA_Launch_Proj;
|
public static JobDef WULA_Launch_Proj;
|
||||||
public static JobDef WULA_EnterMech;
|
public static JobDef WULA_EnterMech;
|
||||||
public static JobDef WULA_RefuelMech;
|
public static JobDef WULA_RefuelMech;
|
||||||
public static JobDef WULA_Refuel;
|
|
||||||
public static JobDef WULA_RepairMech;
|
public static JobDef WULA_RepairMech;
|
||||||
public static JobDef WULA_ForceEjectPilot;
|
public static JobDef WULA_ForceEjectPilot;
|
||||||
public static JobDef WULA_CarryToMech;
|
public static JobDef WULA_CarryToMech;
|
||||||
|
|||||||
@@ -95,7 +95,23 @@
|
|||||||
<Compile Include="HediffComp\WULA_SyncedWithMech\HediffCompProperties_SyncedWithMech.cs" />
|
<Compile Include="HediffComp\WULA_SyncedWithMech\HediffCompProperties_SyncedWithMech.cs" />
|
||||||
<Compile Include="HediffComp\WULA_TimedExplosion\HediffComp_TimedExplosion.cs" />
|
<Compile Include="HediffComp\WULA_TimedExplosion\HediffComp_TimedExplosion.cs" />
|
||||||
<Compile Include="ITab\ITab_MechSkills.cs" />
|
<Compile Include="ITab\ITab_MechSkills.cs" />
|
||||||
<Compile Include="Pawn\WULA_PawnRenderExtra\Comp_PawnRenderExtra.cs" />
|
<Compile Include="MentalState\MentalState_MechNoPilot.cs" />
|
||||||
|
<Compile Include="Pawn_Comps\PawnRenderExtra\Comp_PawnRenderExtra.cs" />
|
||||||
|
<Compile Include="Pawn_Comps\HighSpeedCollision\CompHighSpeedCollision.cs" />
|
||||||
|
<Compile Include="Work\EnterMech\FloatMenuOptionProvider_EnterMech.cs" />
|
||||||
|
<Compile Include="Work\EnterMech\JobDriver_EnterMech.cs" />
|
||||||
|
<Compile Include="Work\EnterMech\WorkGiver_EnterMech.cs" />
|
||||||
|
<Compile Include="Work\ForceEjectPilot\FloatMenuOptionProvider_ForceEjectPilot.cs" />
|
||||||
|
<Compile Include="Work\ForceEjectPilot\JobDriver_ForceEjectPilot.cs" />
|
||||||
|
<Compile Include="Work\InspectBuilding\JobDriver_InspectBuilding.cs" />
|
||||||
|
<Compile Include="Work\InspectBuilding\JobGiver_InspectBuilding.cs" />
|
||||||
|
<Compile Include="Work\JobDriver_CarryToMech.cs" />
|
||||||
|
<Compile Include="Work\JobGiver_NoPilot.cs" />
|
||||||
|
<Compile Include="Work\RefuelMech\JobDriver_RefuelMech.cs" />
|
||||||
|
<Compile Include="Work\RefuelMech\WorkGiver_RefuelMech.cs" />
|
||||||
|
<Compile Include="Work\RepairMech\JobDriver_RepairMech.cs" />
|
||||||
|
<Compile Include="Work\RepairMech\WorkGiver_RepairMech.cs" />
|
||||||
|
<Compile Include="Work\ThinkNode_ConditionalMechHasPilot.cs" />
|
||||||
<Compile Include="WulaFallenEmpireMod.cs" />
|
<Compile Include="WulaFallenEmpireMod.cs" />
|
||||||
<Compile Include="WulaFallenEmpireSettings.cs" />
|
<Compile Include="WulaFallenEmpireSettings.cs" />
|
||||||
<Compile Include="WulaLog.cs" />
|
<Compile Include="WulaLog.cs" />
|
||||||
@@ -333,29 +349,27 @@
|
|||||||
<Compile Include="HediffComp\WULA_HediffSpawner\HediffComp_Spawner.cs" />
|
<Compile Include="HediffComp\WULA_HediffSpawner\HediffComp_Spawner.cs" />
|
||||||
<Compile Include="HediffComp\WULA_HediffSpawner\Tools.cs" />
|
<Compile Include="HediffComp\WULA_HediffSpawner\Tools.cs" />
|
||||||
<!-- Job 相关 -->
|
<!-- Job 相关 -->
|
||||||
<Compile Include="Job\JobDriver_InspectBuilding.cs" />
|
|
||||||
<Compile Include="Job\JobGiver_InspectBuilding.cs" />
|
|
||||||
<!-- Pawn 相关 -->
|
<!-- Pawn 相关 -->
|
||||||
<Compile Include="Pawn\Mechunit.cs" />
|
<Compile Include="Pawn\Mechunit.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutoMechCarrier\CompAutoMechCarrier.cs" />
|
<Compile Include="Pawn_Comps\AutoMechCarrier\CompAutoMechCarrier.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
|
<Compile Include="Pawn_Comps\AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutoMechCarrier\PawnProductionEntry.cs" />
|
<Compile Include="Pawn_Comps\AutoMechCarrier\PawnProductionEntry.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\CompAutonomousMech.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\CompAutonomousMech.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\DroneGizmo.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\DroneGizmo.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\JobGiver_DroneSelfShutdown.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\JobGiver_DroneSelfShutdown.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\PawnColumnWorker_DroneEnergy.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\PawnColumnWorker_DroneEnergy.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\PawnColumnWorker_DroneWorkMode.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\PawnColumnWorker_DroneWorkMode.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\ThinkNode_ConditionalAutonomousWorkMode.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\ThinkNode_ConditionalAutonomousWorkMode.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\ThinkNode_ConditionalLowEnergy_Drone.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\ThinkNode_ConditionalLowEnergy_Drone.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\ThinkNode_ConditionalNeedRecharge.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\ThinkNode_ConditionalNeedRecharge.cs" />
|
||||||
<Compile Include="Pawn\WULA_AutonomousMech\ThinkNode_ConditionalWorkMode_Drone.cs" />
|
<Compile Include="Pawn_Comps\AutonomousMech\ThinkNode_ConditionalWorkMode_Drone.cs" />
|
||||||
<Compile Include="Pawn\WULA_BrokenPersonality\MentalBreakWorker_BrokenPersonality.cs" />
|
<Compile Include="MentalState\BrokenPersonality\MentalBreakWorker_BrokenPersonality.cs" />
|
||||||
<Compile Include="Pawn\WULA_BrokenPersonality\MentalStateDefExtension_BrokenPersonality.cs" />
|
<Compile Include="MentalState\BrokenPersonality\MentalStateDefExtension_BrokenPersonality.cs" />
|
||||||
<Compile Include="Pawn\WULA_BrokenPersonality\MentalState_BrokenPersonality.cs" />
|
<Compile Include="MentalState\BrokenPersonality\MentalState_BrokenPersonality.cs" />
|
||||||
<Compile Include="Pawn\WULA_Cat_Invisible\CompFighterInvisible.cs" />
|
<Compile Include="Pawn_Comps\Cat_Invisible\CompFighterInvisible.cs" />
|
||||||
<Compile Include="Pawn\WULA_Cat_Invisible\CompProperties_FighterInvisible.cs" />
|
<Compile Include="Pawn_Comps\Cat_Invisible\CompProperties_FighterInvisible.cs" />
|
||||||
<Compile Include="Pawn\WULA_CompHediffGiver\CompHediffGiver.cs" />
|
<Compile Include="Pawn_Comps\HediffGiver\CompHediffGiver.cs" />
|
||||||
<Compile Include="Pawn\WULA_CompHediffGiver\CompProperties_HediffGiver.cs" />
|
<Compile Include="Pawn_Comps\HediffGiver\CompProperties_HediffGiver.cs" />
|
||||||
<Compile Include="Pawn\WULA_Energy\CompChargingBed.cs" />
|
<Compile Include="Pawn\WULA_Energy\CompChargingBed.cs" />
|
||||||
<Compile Include="Pawn\WULA_Energy\HediffComp_WulaCharging.cs" />
|
<Compile Include="Pawn\WULA_Energy\HediffComp_WulaCharging.cs" />
|
||||||
<Compile Include="Pawn\WULA_Energy\JobDriver_FeedWulaPatient.cs" />
|
<Compile Include="Pawn\WULA_Energy\JobDriver_FeedWulaPatient.cs" />
|
||||||
@@ -371,10 +385,10 @@
|
|||||||
<Compile Include="Pawn\WULA_Energy\WorkGiver_Warden_DeliverEnergy.cs" />
|
<Compile Include="Pawn\WULA_Energy\WorkGiver_Warden_DeliverEnergy.cs" />
|
||||||
<Compile Include="Pawn\WULA_Energy\WorkGiver_Warden_FeedWula.cs" />
|
<Compile Include="Pawn\WULA_Energy\WorkGiver_Warden_FeedWula.cs" />
|
||||||
<Compile Include="Pawn\WULA_Energy\WulaCaravanEnergyDef.cs" />
|
<Compile Include="Pawn\WULA_Energy\WulaCaravanEnergyDef.cs" />
|
||||||
<Compile Include="Pawn\WULA_Flight\CompPawnFlight.cs" />
|
<Compile Include="Pawn_Comps\Pawn_Flight\CompPawnFlight.cs" />
|
||||||
<Compile Include="Pawn\WULA_Flight\CompProperties_PawnFlight.cs" />
|
<Compile Include="Pawn_Comps\Pawn_Flight\CompProperties_PawnFlight.cs" />
|
||||||
<Compile Include="Pawn\WULA_Flight\PawnRenderNodeWorker_AttachmentBody_NoFlight.cs" />
|
<Compile Include="Pawn_Comps\Pawn_Flight\PawnRenderNodeWorker_AttachmentBody_NoFlight.cs" />
|
||||||
<Compile Include="Pawn\WULA_Flight\Pawn_FlightTrackerPatches.cs" />
|
<Compile Include="Pawn_Comps\Pawn_Flight\Pawn_FlightTrackerPatches.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\Building_MaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\Building_MaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\CompMaintenancePod.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\CompMaintenancePod.cs" />
|
||||||
<Compile Include="Pawn\WULA_Maintenance\HediffCompProperties_MaintenanceDamage.cs" />
|
<Compile Include="Pawn\WULA_Maintenance\HediffCompProperties_MaintenanceDamage.cs" />
|
||||||
@@ -388,7 +402,6 @@
|
|||||||
<Compile Include="Pawn_Comps\DefaultPilotEntry\CompProperties_MechDefaultPilot.cs" />
|
<Compile Include="Pawn_Comps\DefaultPilotEntry\CompProperties_MechDefaultPilot.cs" />
|
||||||
<Compile Include="Pawn_Comps\HediffGiverByKind\CompHediffGiverByKind.cs" />
|
<Compile Include="Pawn_Comps\HediffGiverByKind\CompHediffGiverByKind.cs" />
|
||||||
<Compile Include="Pawn_Comps\HediffGiverByKind\CompProperties_HediffGiverByKind.cs" />
|
<Compile Include="Pawn_Comps\HediffGiverByKind\CompProperties_HediffGiverByKind.cs" />
|
||||||
<Compile Include="Pawn_Comps\MechArmor\CompMechArmor.cs" />
|
|
||||||
<Compile Include="Pawn_Comps\MechFuel\CompMechFuel.cs" />
|
<Compile Include="Pawn_Comps\MechFuel\CompMechFuel.cs" />
|
||||||
<Compile Include="Pawn_Comps\MechFuel\CompProperties_MechFuel.cs" />
|
<Compile Include="Pawn_Comps\MechFuel\CompProperties_MechFuel.cs" />
|
||||||
<Compile Include="Pawn_Comps\MechFuel\Gizmo_MechFuelStatus.cs" />
|
<Compile Include="Pawn_Comps\MechFuel\Gizmo_MechFuelStatus.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user