This commit is contained in:
2026-02-15 16:32:55 +08:00
parent c7a520b2f3
commit 2eabf020fd
26 changed files with 1743 additions and 281 deletions

Binary file not shown.

View File

@@ -762,7 +762,7 @@
<defName>ARA_Flyer_TrackingCharge</defName> <defName>ARA_Flyer_TrackingCharge</defName>
<thingClass>ArachnaeSwarm.PawnFlyer_TrackingCharge</thingClass> <thingClass>ArachnaeSwarm.PawnFlyer_TrackingCharge</thingClass>
<pawnFlyer> <pawnFlyer>
<flightSpeed>0.5</flightSpeed> <flightSpeed>1.5</flightSpeed>
<heightFactor>0</heightFactor> <heightFactor>0</heightFactor>
</pawnFlyer> </pawnFlyer>
</ThingDef> </ThingDef>
@@ -1579,7 +1579,7 @@
<!-- 禁卫 --> <!-- 禁卫 -->
<AbilityDef> <AbilityDef>
<defName>ARA_Praetorian_jump</defName> <defName>ARA_Praetorian_Jump</defName>
<label>禁卫种跳跃</label> <label>禁卫种跳跃</label>
<description>以强力的肌腱向目标地点跳跃。</description> <description>以强力的肌腱向目标地点跳跃。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Fighter_Invisibility_jump</iconPath> <iconPath>ArachnaeSwarm/UI/Abilities/ARA_Fighter_Invisibility_jump</iconPath>
@@ -1703,6 +1703,118 @@
</li> </li>
</comps> </comps>
</AbilityDef> </AbilityDef>
<AbilityDef>
<defName>ARA_Praetorian_TailSweep</defName>
<label>扫尾</label>
<description>阿拉克涅督虫甩动尾巴猛抽面前的敌人,对扇形范围内所有的敌对目标造成伤害,如果对方在攻击中幸存,就会被击飞并眩晕一段时间。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Praetorian_TailSweep</iconPath>
<aiCanUse>true</aiCanUse>
<hostile>true</hostile>
<casterMustBeCapableOfViolence>true</casterMustBeCapableOfViolence>
<cooldownTicksRange>1800</cooldownTicksRange>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<range>6</range>
<warmupTime>0.6</warmupTime>
<soundCast>Pawn_Melee_BigBash_HitPawn</soundCast>
<targetParams>
<canTargetLocations>true</canTargetLocations>
</targetParams>
</verbProperties>
<comps>
<li Class="CompProperties_AbilityEffecterOnCaster" MayRequire="Ludeon.Rimworld.Odyssey">
<effecterDef>WarTrumpet</effecterDef>
<maintainTicks>20</maintainTicks> <!-- Long enough for the "2nd wave" to spawn -->
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
<customLabel>饮食</customLabel>
<showProgressBar>true</showProgressBar>
<needDef>Food</needDef>
<needCost>0.3</needCost>
<failMessage>营养值不足,需要进食</failMessage>
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityFanShapedStunKnockback">
<!-- 扇形参数 -->
<range>6</range>
<coneSizeDegrees>100</coneSizeDegrees>
<lineWidthEnd>12</lineWidthEnd>
<!-- 伤害参数 -->
<damageDef>Blunt</damageDef>
<damageAmount>25</damageAmount>
<armorPenetration>1</armorPenetration>
<!-- 眩晕参数 -->
<stunTicks>120</stunTicks>
<!-- 击退参数 -->
<maxKnockbackDistance>3</maxKnockbackDistance>
<canKnockbackIntoWalls>false</canKnockbackIntoWalls>
<requireLineOfSight>false</requireLineOfSight>
<affectNonPawnThings>true</affectNonPawnThings>
<canDamageNonPawnThings>true</canDamageNonPawnThings>
<nonPawnDamageMultiplier>5</nonPawnDamageMultiplier>
<applySpecialEffectsToNonPawn>false</applySpecialEffectsToNonPawn>
<!-- 视觉效果 -->
<impactEffecter>ARA_Melee_Attack_Hit</impactEffecter>
<impactSound>Pawn_Melee_BigBash_HitPawn</impactSound>
<!-- 飞行效果 -->
<knockbackFlyerDef>PawnFlyer</knockbackFlyerDef>
<!-- <flightEffecterDef>FlightEffect_Knockback</flightEffecterDef> -->
<landingSound>PawnFlyer_Land</landingSound>
<!-- 过滤设置 -->
<affectCaster>false</affectCaster>
<canHitFilledCells>true</canHitFilledCells>
<onlyAffectEnemies>false</onlyAffectEnemies>
<requireLineOfSightToTarget>true</requireLineOfSightToTarget>
<!-- 近战伤害系数加成 -->
<multiplyDamageByMeleeFactor>false</multiplyDamageByMeleeFactor>
<multiplyStunTimeByMeleeFactor>false</multiplyStunTimeByMeleeFactor>
</li>
</comps>
</AbilityDef>
<AbilityDef>
<defName>ARA_Praetorian_Long_Jump</defName>
<label>禁卫种跳跃</label>
<description>以强力的肌腱向目标地点跳跃。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Fighter_Invisibility_jump</iconPath>
<cooldownTicksRange>1000</cooldownTicksRange>
<charges>3</charges>
<cooldownPerCharge>true</cooldownPerCharge>
<aiCanUse>false</aiCanUse>
<hostile>false</hostile>
<casterMustBeCapableOfViolence>false</casterMustBeCapableOfViolence>
<verbProperties>
<verbClass>Verb_CastAbilityJump</verbClass>
<violent>false</violent>
<forceNormalTimeSpeed>false</forceNormalTimeSpeed>
<!-- <warmupTime>0.5</warmupTime> -->
<range>26</range>
<requireLineOfSight>false</requireLineOfSight>
<soundCast>Longjump_Jump</soundCast>
<soundLanding>Longjump_Land</soundLanding>
<targetParams>
<canTargetLocations>true</canTargetLocations>
<canTargetPawns>false</canTargetPawns>
<canTargetBuildings>false</canTargetBuildings>
</targetParams>
</verbProperties>
<jobDef>CastJump</jobDef>
<comps>
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
<customLabel>饮食</customLabel>
<showProgressBar>true</showProgressBar>
<needDef>Food</needDef>
<needCost>0.1</needCost>
<failMessage>营养值不足,需要进食</failMessage>
</li>
</comps>
</AbilityDef>
<!-- 蜕荚 --> <!-- 蜕荚 -->
<AbilityDef> <AbilityDef>

View File

@@ -1334,12 +1334,14 @@
<li Class="HediffCompProperties_GiveAbility"> <li Class="HediffCompProperties_GiveAbility">
<abilityDefs> <abilityDefs>
<li>ARA_Skyraider_jump</li> <li>ARA_Skyraider_jump</li>
<li>ARA_Skyraider_Hivelord</li> <li>ARA_Skyraider_Ferry</li>
<li>ARA_Skyraider_Empthrower</li> <li>ARA_Skyraider_Empthrower</li>
<li>ARA_Skyraider_Hivelord</li>
</abilityDefs> </abilityDefs>
</li> </li>
<li Class="HediffCompProperties_RemoveIfOtherHediff"> <li Class="HediffCompProperties_RemoveIfOtherHediff">
<hediffs> <hediffs>
<li>ARA_Skyraider_Ferry</li>
<li>ARA_Skyraider_Hivelord</li> <li>ARA_Skyraider_Hivelord</li>
<li>ARA_Skyraider_Empthrower</li> <li>ARA_Skyraider_Empthrower</li>
</hediffs> </hediffs>
@@ -1347,10 +1349,10 @@
</comps> </comps>
</HediffDef> </HediffDef>
<AbilityDef> <AbilityDef>
<defName>ARA_Skyraider_Hivelord</defName> <defName>ARA_Skyraider_Ferry</defName>
<label>空天种转换——巢虫之主</label> <label>空天种转换——搬运工蜂</label>
<description>使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得孵化大量天巢种辅虫的能力——这种辅虫体型很小,会以让人烦扰的近战紧紧黏住敌人。\n\n该进化方向提供8只阿拉克涅天巢种辅虫。</description> <description>使空天种发生内驱性进化,以失去高空机动能力为代价,使其获得更高的移动速度,且在远行队时大幅增加远行队移动速度。\n\n该进化方向提供阿拉克涅辅虫。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Skyraider_Hivelord</iconPath> <iconPath>ArachnaeSwarm/UI/Abilities/ARA_Skyraider_Ferry</iconPath>
<cooldownTicksRange>1800</cooldownTicksRange> <cooldownTicksRange>1800</cooldownTicksRange>
<hostile>false</hostile> <hostile>false</hostile>
<groupAbility>true</groupAbility> <groupAbility>true</groupAbility>
@@ -1374,20 +1376,20 @@
<comps> <comps>
<li Class="CompProperties_AbilityGiveHediff"> <li Class="CompProperties_AbilityGiveHediff">
<compClass>CompAbilityEffect_GiveHediff</compClass> <compClass>CompAbilityEffect_GiveHediff</compClass>
<hediffDef>ARA_Skyraider_Hivelord</hediffDef> <hediffDef>ARA_Skyraider_Ferry</hediffDef>
<onlyApplyToSelf>True</onlyApplyToSelf> <onlyApplyToSelf>True</onlyApplyToSelf>
<replaceExisting>true</replaceExisting> <replaceExisting>true</replaceExisting>
<severity>1</severity> <severity>1</severity>
</li> </li>
<li Class="ArachnaeSwarm.CompProperties_AbilityResearchPrereq"> <li Class="ArachnaeSwarm.CompProperties_AbilityResearchPrereq">
<requiredResearch>ARA_Technology_6LOD</requiredResearch> <requiredResearch>ARA_Technology_1FRY</requiredResearch>
</li> </li>
</comps> </comps>
</AbilityDef> </AbilityDef>
<HediffDef> <HediffDef>
<defName>ARA_Skyraider_Hivelord</defName> <defName>ARA_Skyraider_Ferry</defName>
<label>亚种-领主</label> <label>亚种-穿梭</label>
<description>这只阿拉克涅空天种已经获得拔耀,可以投掷天巢种辅虫,这些灵敏的辅虫会后散开四处狩猎目标</description> <description>这只阿拉克涅空天种已经获得拔耀,虽然无法再孵化辅虫,但是速度极快,且可以以常态化飞行以增加远行队速度</description>
<hediffClass>HediffWithComps</hediffClass> <hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor> <defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad> <isBad>false</isBad>
@@ -1397,7 +1399,7 @@
<li> <li>
<nodeClass>PawnRenderNode_AttachmentHead</nodeClass> <nodeClass>PawnRenderNode_AttachmentHead</nodeClass>
<workerClass>PawnRenderNodeWorker_FlipWhenCrawling</workerClass> <workerClass>PawnRenderNodeWorker_FlipWhenCrawling</workerClass>
<texPath>ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Addons_Hivelord_Tail</texPath> <texPath>ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Addons_Ferry_Tail</texPath>
<parentTagDef>Body</parentTagDef> <parentTagDef>Body</parentTagDef>
<useSkinShader>false</useSkinShader> <useSkinShader>false</useSkinShader>
<useRottenColor>false</useRottenColor> <useRottenColor>false</useRottenColor>
@@ -1425,49 +1427,15 @@
<stages> <stages>
<li> <li>
<minSeverity>0.01</minSeverity> <minSeverity>0.01</minSeverity>
<statOffsets>
<MoveSpeed>5</MoveSpeed>
</statOffsets>
<statFactors> <statFactors>
<CaravanBonusSpeedFactor>2</CaravanBonusSpeedFactor> <CaravanBonusSpeedFactor>10</CaravanBonusSpeedFactor>
</statFactors> </statFactors>
</li> </li>
</stages> </stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_ProductionQueue">
<productionQueue>
<li>
<pawnKind>ArachnaeBase_Race_Skyhive</pawnKind>
<count>4</count>
<cooldownTicks>200</cooldownTicks>
</li>
</productionQueue>
</li>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Skyraider_Hivelord_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
<li Class="ArachnaeSwarm.HediffCompProperties_DrawMote">
<mote>ARA_Mote_Hivelord_Turret_Range</mote>
<hideMoteWhenNotDrafted>true</hideMoteWhenNotDrafted>
</li>
</comps>
</HediffDef> </HediffDef>
<ThingDef ParentName="MoteBase">
<defName>ARA_Mote_Hivelord_Turret_Range</defName>
<thingClass>MoteAttached</thingClass>
<altitudeLayer>LightingOverlay</altitudeLayer>
<drawOffscreen>true</drawOffscreen>
<mote>
<solidTime>9999999</solidTime>
<needsMaintenance>true</needsMaintenance>
</mote>
<graphicData>
<graphicClass>Graphic_Mote</graphicClass>
<texPath>Things/Mote/CombatCommandMask</texPath>
<shaderType>MoteGlow</shaderType>
<color>(32, 17, 0, 255)</color>
<drawSize>66</drawSize>
</graphicData>
</ThingDef>
<AbilityDef> <AbilityDef>
<defName>ARA_Skyraider_Empthrower</defName> <defName>ARA_Skyraider_Empthrower</defName>
<label>空天种转换——电磁风暴</label> <label>空天种转换——电磁风暴</label>
@@ -1581,6 +1549,128 @@
<drawSize>51</drawSize> <drawSize>51</drawSize>
</graphicData> </graphicData>
</ThingDef> </ThingDef>
<AbilityDef>
<defName>ARA_Skyraider_Hivelord</defName>
<label>空天种转换——巢虫之主</label>
<description>使空天种发生内驱性进化,以降低机动力和失去高空机动能力为代价,使其获得孵化大量天巢种辅虫的能力——这种辅虫体型很小,会以让人烦扰的近战紧紧黏住敌人。\n\n该进化方向提供8只阿拉克涅天巢种辅虫。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Skyraider_Hivelord</iconPath>
<cooldownTicksRange>1800</cooldownTicksRange>
<hostile>false</hostile>
<groupAbility>true</groupAbility>
<displayGizmoWhileUndrafted>true</displayGizmoWhileUndrafted>
<disableGizmoWhileUndrafted>false</disableGizmoWhileUndrafted>
<aiCanUse>false</aiCanUse>
<ai_IsOffensive>true</ai_IsOffensive>
<targetRequired>false</targetRequired>
<jobDef>CastAbilityOnThing</jobDef>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<range>1</range>
<warmupTime>12</warmupTime>
<soundCast>AcidSpray_Resolve</soundCast>
<violent>false</violent>
<targetable>false</targetable>
<targetParams>
<canTargetSelf>True</canTargetSelf>
</targetParams>
</verbProperties>
<comps>
<li Class="CompProperties_AbilityGiveHediff">
<compClass>CompAbilityEffect_GiveHediff</compClass>
<hediffDef>ARA_Skyraider_Hivelord</hediffDef>
<onlyApplyToSelf>True</onlyApplyToSelf>
<replaceExisting>true</replaceExisting>
<severity>1</severity>
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityResearchPrereq">
<requiredResearch>ARA_Technology_6LOD_T</requiredResearch>
</li>
</comps>
</AbilityDef>
<HediffDef>
<defName>ARA_Skyraider_Hivelord</defName>
<label>亚种-领主种</label>
<description>这只阿拉克涅空天种已经获得拔耀,可以投掷天巢种辅虫,这些灵敏的辅虫会后散开四处狩猎目标。</description>
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad>
<scenarioCanAdd>false</scenarioCanAdd>
<maxSeverity>1.0</maxSeverity>
<renderNodeProperties>
<li>
<nodeClass>PawnRenderNode_AttachmentHead</nodeClass>
<workerClass>PawnRenderNodeWorker_FlipWhenCrawling</workerClass>
<texPath>ArachnaeSwarm/Things/ARA_HiveNode/Addons/ArachnaeNode_Race_Addons_Hivelord_Tail</texPath>
<parentTagDef>Body</parentTagDef>
<useSkinShader>false</useSkinShader>
<useRottenColor>false</useRottenColor>
<rotDrawMode>Fresh, Rotting</rotDrawMode>
<drawData>
<dataNorth>
<offset>(0, 0, -0.05)</offset>
<layer>120</layer>
</dataNorth>
<dataEast>
<offset>(0, 0, -0.05)</offset>
</dataEast>
<dataSouth>
<offset>(0, 0, -0.05)</offset>
</dataSouth>
<dataWest>
<offset>(0, 0, -0.05)</offset>
</dataWest>
<defaultData>
<layer>-40</layer>
</defaultData>
</drawData>
</li>
</renderNodeProperties>
<stages>
<li>
<minSeverity>0.01</minSeverity>
<statFactors>
<CaravanBonusSpeedFactor>2</CaravanBonusSpeedFactor>
</statFactors>
</li>
</stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_ProductionQueue">
<productionQueue>
<li>
<pawnKind>ArachnaeBase_Race_Skyhive</pawnKind>
<count>4</count>
<cooldownTicks>200</cooldownTicks>
</li>
</productionQueue>
</li>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Skyraider_Hivelord_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
<li Class="ArachnaeSwarm.HediffCompProperties_DrawMote">
<mote>ARA_Mote_Hivelord_Turret_Range</mote>
<hideMoteWhenNotDrafted>true</hideMoteWhenNotDrafted>
</li>
</comps>
</HediffDef>
<ThingDef ParentName="MoteBase">
<defName>ARA_Mote_Hivelord_Turret_Range</defName>
<thingClass>MoteAttached</thingClass>
<altitudeLayer>LightingOverlay</altitudeLayer>
<drawOffscreen>true</drawOffscreen>
<mote>
<solidTime>9999999</solidTime>
<needsMaintenance>true</needsMaintenance>
</mote>
<graphicData>
<graphicClass>Graphic_Mote</graphicClass>
<texPath>Things/Mote/CombatCommandMask</texPath>
<shaderType>MoteGlow</shaderType>
<color>(32, 17, 0, 255)</color>
<drawSize>66</drawSize>
</graphicData>
</ThingDef>
<!-- 禁卫种 --> <!-- 禁卫种 -->
<HediffDef> <HediffDef>
@@ -1615,15 +1705,17 @@
</li> </li>
<li Class="HediffCompProperties_GiveAbility"> <li Class="HediffCompProperties_GiveAbility">
<abilityDefs> <abilityDefs>
<li>ARA_Praetorian_jump</li> <li>ARA_Praetorian_Jump</li>
<li>ARA_Praetorian_Commander_Ability_On</li> <li>ARA_Praetorian_Commander_Ability_On</li>
<li>ARA_Praetorian_Commander_Ability_Off</li> <li>ARA_Praetorian_Commander_Ability_Off</li>
<li>ARA_Praetorian_Navigator</li> <li>ARA_Praetorian_Navigator</li>
<li>ARA_Praetorian_Legion</li>
</abilityDefs> </abilityDefs>
</li> </li>
<li Class="HediffCompProperties_RemoveIfOtherHediff"> <li Class="HediffCompProperties_RemoveIfOtherHediff">
<hediffs> <hediffs>
<li>ARA_Praetorian_Navigator</li> <li>ARA_Praetorian_Navigator</li>
<li>ARA_Praetorian_Legion</li>
</hediffs> </hediffs>
</li> </li>
</comps> </comps>
@@ -1692,6 +1784,87 @@
</li> </li>
</comps> </comps>
</HediffDef> </HediffDef>
<AbilityDef>
<defName>ARA_Praetorian_Legion</defName>
<label>禁卫种转换——军团之威</label>
<description>使禁卫种发生内驱性进化,以牺牲指挥能力为代价,使其换取更强大的近战、远程、防御和通过甩尾、冲撞、跳跃等体术对抗敌人的能力。\n\n该进化方向不提供阿拉克涅辅虫。</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Praetorian_Legion</iconPath>
<cooldownTicksRange>1800</cooldownTicksRange>
<hostile>false</hostile>
<groupAbility>true</groupAbility>
<displayGizmoWhileUndrafted>true</displayGizmoWhileUndrafted>
<disableGizmoWhileUndrafted>false</disableGizmoWhileUndrafted>
<aiCanUse>false</aiCanUse>
<ai_IsOffensive>true</ai_IsOffensive>
<targetRequired>false</targetRequired>
<jobDef>CastAbilityOnThing</jobDef>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<range>1</range>
<warmupTime>12</warmupTime>
<soundCast>AcidSpray_Resolve</soundCast>
<violent>false</violent>
<targetable>false</targetable>
<targetParams>
<canTargetSelf>True</canTargetSelf>
</targetParams>
</verbProperties>
<comps>
<li Class="CompProperties_AbilityGiveHediff">
<compClass>CompAbilityEffect_GiveHediff</compClass>
<hediffDef>ARA_Praetorian_Legion</hediffDef>
<onlyApplyToSelf>True</onlyApplyToSelf>
<replaceExisting>true</replaceExisting>
<severity>1</severity>
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityAddExtraExp">
<skillChanges>
<li>
<skill>Melee</skill>
<passionGained>Major</passionGained>
<xpGainAmount>600000</xpGainAmount>
</li>
<li>
<skill>Shooting</skill>
<passionGained>Major</passionGained>
<xpGainAmount>600000</xpGainAmount>
</li>
</skillChanges>
</li>
<li Class="ArachnaeSwarm.CompProperties_AbilityResearchPrereq">
<requiredResearch>ARA_Technology_3LGN_T</requiredResearch>
</li>
</comps>
</AbilityDef>
<HediffDef>
<defName>ARA_Praetorian_Legion</defName>
<label>亚种-军团种</label>
<description>这只阿拉克涅禁卫种已经获得拔耀,战斗能力在虫群节点个体中已经登峰造极。</description>
<hediffClass>HediffWithComps</hediffClass>
<defaultLabelColor>(0.6, 0.4, 0.8)</defaultLabelColor>
<isBad>false</isBad>
<scenarioCanAdd>false</scenarioCanAdd>
<maxSeverity>1.0</maxSeverity>
<stages>
<li>
<minSeverity>0</minSeverity>
<statOffsets>
<ArmorRating_Blunt>0.75</ArmorRating_Blunt>
<ArmorRating_Sharp>0.75</ArmorRating_Sharp>
<ArmorRating_Heat>1</ArmorRating_Heat>
</statOffsets>
</li>
</stages>
<comps>
<li Class="HediffCompProperties_GiveAbility">
<abilityDefs>
<li>ARA_Praetorian_Long_Jump</li>
<li>ARA_Praetorian_TailSweep</li>
<li>ARA_Ability_TrackingCharge</li>
</abilityDefs>
</li>
</comps>
</HediffDef>
<!-- 暴徒种 --> <!-- 暴徒种 -->
<HediffDef> <HediffDef>

View File

@@ -14,7 +14,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -49,7 +49,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -84,7 +84,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -119,7 +119,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -150,7 +150,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -191,7 +191,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Melee</li> <li>ARA_Armed_Organ_Melee</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -226,7 +226,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Huge</li> <li>ARA_Armed_Organ_Huge</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>
@@ -257,7 +257,7 @@
<weaponTags> <weaponTags>
<li>ARA_Armed_Organ_Base</li> <li>ARA_Armed_Organ_Base</li>
</weaponTags> </weaponTags>
<apparelTags> <apparelTags Inherit="False">
<li>ARA_Inner</li> <li>ARA_Inner</li>
<li>ARA_Clothes</li> <li>ARA_Clothes</li>
</apparelTags> </apparelTags>

View File

@@ -211,6 +211,10 @@
</xenotypeChances> </xenotypeChances>
</xenotypeSet> </xenotypeSet>
<useFactionXenotypes>false</useFactionXenotypes> <useFactionXenotypes>false</useFactionXenotypes>
<apparelTags>
<li>ARA_Init_Clothes</li>
</apparelTags>
<apparelMoney>1000~2000</apparelMoney>
<requiredWorkTags> <requiredWorkTags>
<li>Violent</li> <li>Violent</li>
</requiredWorkTags> </requiredWorkTags>
@@ -238,9 +242,6 @@
<abilities> <abilities>
<li>ARA_AcidSprayBurst</li> <li>ARA_AcidSprayBurst</li>
</abilities> </abilities>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_ShieldHead" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_ShieldHead" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_ShieldHead</defName> <defName>ArachnaeNode_Race_ShieldHead</defName>
@@ -256,9 +257,6 @@
</categories> </categories>
</li> </li>
</backstoryFiltersOverride> </backstoryFiltersOverride>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_WeaponSmith" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_WeaponSmith" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_WeaponSmith</defName> <defName>ArachnaeNode_Race_WeaponSmith</defName>
@@ -274,9 +272,6 @@
</categories> </categories>
</li> </li>
</backstoryFiltersOverride> </backstoryFiltersOverride>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_Facehugger" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_Facehugger" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_Facehugger</defName> <defName>ArachnaeNode_Race_Facehugger</defName>
@@ -295,9 +290,6 @@
<abilities> <abilities>
<li>ARA_Ability_Possess</li> <li>ARA_Ability_Possess</li>
</abilities> </abilities>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_Fighter" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_Fighter" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_Fighter</defName> <defName>ArachnaeNode_Race_Fighter</defName>
@@ -319,9 +311,6 @@
<def>ARA_RaceBaseSwarmProduceSwitchHediff</def> <def>ARA_RaceBaseSwarmProduceSwitchHediff</def>
</li> </li>
</startingHediffs> </startingHediffs>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_Smokepop" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_Smokepop" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_Smokepop</defName> <defName>ArachnaeNode_Race_Smokepop</defName>
@@ -406,9 +395,6 @@
<li>ARA_GuardianPsyField_Off</li> <li>ARA_GuardianPsyField_Off</li>
<li>ARA_Ability_Morph</li> <li>ARA_Ability_Morph</li>
</abilities> </abilities>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>
<PawnKindDef Name="ArachnaeNode_Race_Praetorian" ParentName="ArachnaeNodeABasePawnKind"> <PawnKindDef Name="ArachnaeNode_Race_Praetorian" ParentName="ArachnaeNodeABasePawnKind">
<defName>ArachnaeNode_Race_Praetorian</defName> <defName>ArachnaeNode_Race_Praetorian</defName>
@@ -453,9 +439,6 @@
</backstoryFiltersOverride> </backstoryFiltersOverride>
<abilities> <abilities>
</abilities> </abilities>
<apparelTags>
</apparelTags>
<apparelMoney>0</apparelMoney>
</PawnKindDef> </PawnKindDef>

View File

@@ -102,88 +102,6 @@
<ARA_Gene_Essence>30</ARA_Gene_Essence> <ARA_Gene_Essence>30</ARA_Gene_Essence>
</costList> </costList>
</ThingDef> </ThingDef>
<RecipeDef ParentName="ARA_SurgeryInstallImplantBase">
<defName>ARA_Surgery_Install_Shell_Thorn</defName>
<label>甲壳棘刺植入</label>
<description>为阿拉克涅虫族的甲壳植入两排棘刺腔管,它们是拥有半自主意识的器官,会对附近的敌军自动发射棘刺。此外,该变异也会加厚甲壳以获得更强的防御力。</description>
<descriptionHyperlinks>
<HediffDef>ARA_Shell_Thorn_Hediff</HediffDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<jobString>正在实施定向变异</jobString>
<ingredients>
<li>
<filter>
<thingDefs>
<li>ARA_Activated_Bacterium</li>
</thingDefs>
</filter>
<count>15</count>
</li>
<li>
<filter>
<thingDefs>
<li>ARA_Gene_Essence</li>
</thingDefs>
</filter>
<count>20</count>
</li>
</ingredients>
<appliedOnFixedBodyParts>
<li>ARA_Chitin_Shell</li>
</appliedOnFixedBodyParts>
<fixedIngredientFilter>
<thingDefs>
<li>ARA_Activated_Bacterium</li>
</thingDefs>
</fixedIngredientFilter>
<addsHediff>ARA_Shell_Thorn_Hediff</addsHediff>
<researchPrerequisite>ARA_Technology_7EVO</researchPrerequisite>
</RecipeDef>
<HediffDef ParentName="AddedBodyPartBase">
<defName>ARA_Shell_Thorn_Hediff</defName>
<label>甲壳棘刺</label>
<hediffClass>Hediff_Implant</hediffClass>
<description>阿拉克涅虫族在甲壳上植入了两排棘刺腔管,只要不处于近战状态下,它们就会对靠近的敌人自动发射棘刺攻击对方。</description>
<descriptionHyperlinks>
<RecipeDef>ARA_Surgery_Install_Shell_Thorn</RecipeDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<addedPartProps>
<betterThanNatural>true</betterThanNatural>
</addedPartProps>
<stages>
<li>
<statOffsets>
<ArmorRating_Sharp>0.2</ArmorRating_Sharp>
<ArmorRating_Blunt>0.2</ArmorRating_Blunt>
</statOffsets>
</li>
</stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Shell_Thorn_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
</comps>
</HediffDef>
<ThingDef ParentName="ARA_BodyPartProstheticBase">
<defName>ARA_Shell_Thorn</defName>
<label>甲壳棘刺</label>
<description>在阿拉克涅虫族甲壳上植入两排棘刺腔管,只要不处于近战状态下,它们就会对靠近的敌人自动发射棘刺攻击对方。该手术不需要制作部件,可以直接在阿拉克涅督虫身上实施。</description>
<descriptionHyperlinks>
<RecipeDef>ARA_Surgery_Install_Shell_Thorn</RecipeDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<recipeMaker>
<researchPrerequisite>ARA_Technology_7EVO</researchPrerequisite>
</recipeMaker>
<costList>
<ARA_Activated_Bacterium>15</ARA_Activated_Bacterium>
<ARA_Gene_Essence>20</ARA_Gene_Essence>
</costList>
</ThingDef>
<RecipeDef ParentName="ARA_SurgeryInstallImplantBase"> <RecipeDef ParentName="ARA_SurgeryInstallImplantBase">
<defName>ARA_Surgery_Install_Reactive_Shell</defName> <defName>ARA_Surgery_Install_Reactive_Shell</defName>
<label>反应甲壳植入</label> <label>反应甲壳植入</label>

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<RecipeDef ParentName="ARA_SurgeryInstallImplantBase">
<defName>ARA_Surgery_Install_Shell_Thorn</defName>
<label>甲壳棘刺植入</label>
<description>为阿拉克涅虫族的甲壳植入两排棘刺腔管,它们是拥有半自主意识的器官,会对附近的敌军自动发射棘刺。此外,该变异也会加厚甲壳以获得更强的防御力。</description>
<descriptionHyperlinks>
<HediffDef>ARA_Shell_Thorn_Hediff</HediffDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<jobString>正在实施定向变异</jobString>
<ingredients>
<li>
<filter>
<thingDefs>
<li>ARA_Activated_Bacterium</li>
</thingDefs>
</filter>
<count>15</count>
</li>
<li>
<filter>
<thingDefs>
<li>ARA_Gene_Essence</li>
</thingDefs>
</filter>
<count>20</count>
</li>
</ingredients>
<appliedOnFixedBodyParts>
<li>ARA_Chitin_Shell</li>
</appliedOnFixedBodyParts>
<fixedIngredientFilter>
<thingDefs>
<li>ARA_Activated_Bacterium</li>
</thingDefs>
</fixedIngredientFilter>
<addsHediff>ARA_Shell_Thorn_Hediff</addsHediff>
<researchPrerequisite>ARA_Technology_7EVO_T</researchPrerequisite>
</RecipeDef>
<HediffDef ParentName="AddedBodyPartBase">
<defName>ARA_Shell_Thorn_Hediff</defName>
<label>甲壳棘刺</label>
<hediffClass>Hediff_Implant</hediffClass>
<description>阿拉克涅虫族在甲壳上植入了两排棘刺腔管,只要不处于近战状态下,它们就会对靠近的敌人自动发射棘刺攻击对方。</description>
<descriptionHyperlinks>
<RecipeDef>ARA_Surgery_Install_Shell_Thorn</RecipeDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<addedPartProps>
<betterThanNatural>true</betterThanNatural>
</addedPartProps>
<stages>
<li>
<statOffsets>
<ArmorRating_Sharp>0.2</ArmorRating_Sharp>
<ArmorRating_Blunt>0.2</ArmorRating_Blunt>
</statOffsets>
</li>
</stages>
<comps>
<li Class="ArachnaeSwarm.HediffCompProperties_TopTurret">
<turretDef>ARA_Shell_Thorn_Turret</turretDef>
<angleOffset>0</angleOffset>
<autoAttack>true</autoAttack>
</li>
</comps>
</HediffDef>
<ThingDef ParentName="ARA_BodyPartProstheticBase">
<defName>ARA_Shell_Thorn</defName>
<label>甲壳棘刺</label>
<description>在阿拉克涅虫族甲壳上植入两排棘刺腔管,只要不处于近战状态下,它们就会对靠近的敌人自动发射棘刺攻击对方。该手术不需要制作部件,可以直接在阿拉克涅督虫身上实施。</description>
<descriptionHyperlinks>
<RecipeDef>ARA_Surgery_Install_Shell_Thorn</RecipeDef>
<thingDef>ARA_Shell_Thorn_Turret</thingDef>
</descriptionHyperlinks>
<recipeMaker>
<researchPrerequisite>ARA_Technology_7EVO</researchPrerequisite>
</recipeMaker>
<costList>
<ARA_Activated_Bacterium>15</ARA_Activated_Bacterium>
<ARA_Gene_Essence>20</ARA_Gene_Essence>
</costList>
</ThingDef>
</Defs>

View File

@@ -80,7 +80,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_7VXI</defName> <defName>ARA_Technology_7VXI</defName>
<label>节点VXI-7"外置酸袋"</label> <label>节点VXI-7"外置酸袋"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>300</baseCost> <baseCost>300</baseCost>
<researchViewX>2.00</researchViewX> <researchViewX>2.00</researchViewX>
<researchViewY>0.90</researchViewY> <researchViewY>0.90</researchViewY>
@@ -94,7 +94,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_8VXI</defName> <defName>ARA_Technology_8VXI</defName>
<label>节点VXI-8"巨型酸腺"</label> <label>节点VXI-8"巨型酸腺"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>1250</baseCost> <baseCost>1250</baseCost>
<researchViewX>5.50</researchViewX> <researchViewX>5.50</researchViewX>
<researchViewY>0.90</researchViewY> <researchViewY>0.90</researchViewY>
@@ -108,7 +108,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_9VXI</defName> <defName>ARA_Technology_9VXI</defName>
<label>节点VXI-9"酸雨"</label> <label>节点VXI-9"酸雨"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>2000</baseCost> <baseCost>2000</baseCost>
<researchViewX>10.00</researchViewX> <researchViewX>10.00</researchViewX>
<researchViewY>1.50</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>1.50</researchViewY> <!-- ARA_MorphableResearchBench-->
@@ -122,7 +122,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_10VXI</defName> <defName>ARA_Technology_10VXI</defName>
<label>节点VXI-10"微型天灾"</label> <label>节点VXI-10"微型天灾"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>3000</baseCost> <baseCost>3000</baseCost>
<researchViewX>11.00</researchViewX> <researchViewX>11.00</researchViewX>
<researchViewY>1.50</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>1.50</researchViewY> <!-- ARA_MorphableResearchBench-->
@@ -146,7 +146,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_1THD</defName> <defName>ARA_Technology_1THD</defName>
<label>节点THD-1"灵能闪电"</label> <label>节点THD-1"灵能闪电"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的灵能闪电系武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的灵能闪电系武器。</description>
<baseCost>2500</baseCost> <baseCost>2500</baseCost>
<researchViewX>7.50</researchViewX> <researchViewX>7.50</researchViewX>
<researchViewY>2.70</researchViewY> <researchViewY>2.70</researchViewY>
@@ -299,7 +299,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_5PAV</defName> <defName>ARA_Technology_5PAV</defName>
<label>节点PAV-5"毒刺"</label> <label>节点PAV-5"毒刺"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器,并允许部分带毒针的虫族进行毒针喷射。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器,并允许部分带毒针的虫族进行毒针喷射。</description>
<baseCost>200</baseCost> <baseCost>200</baseCost>
<researchViewX>1.00</researchViewX> <researchViewX>1.00</researchViewX>
<researchViewY>0.30</researchViewY> <researchViewY>0.30</researchViewY>
@@ -313,7 +313,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_6PAV</defName> <defName>ARA_Technology_6PAV</defName>
<label>节点PAV-6"暴雨"</label> <label>节点PAV-6"暴雨"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>1000</baseCost> <baseCost>1000</baseCost>
<researchViewX>5.50</researchViewX> <researchViewX>5.50</researchViewX>
<researchViewY>0.30</researchViewY> <researchViewY>0.30</researchViewY>
@@ -327,7 +327,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_7PAV</defName> <defName>ARA_Technology_7PAV</defName>
<label>节点PAV-7"血棘"</label> <label>节点PAV-7"血棘"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>1800</baseCost> <baseCost>1800</baseCost>
<researchViewX>10.00</researchViewX> <researchViewX>10.00</researchViewX>
<researchViewY>0.30</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>0.30</researchViewY> <!-- ARA_MorphableResearchBench-->
@@ -338,17 +338,6 @@
<li>ARA_Technology_2WMT</li> <li>ARA_Technology_2WMT</li>
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_7XPAV</defName>
<label>节点PAV-7X"梭镖"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description>
<baseCost>2000</baseCost>
<researchViewX>11.00</researchViewX>
<researchViewY>0.30</researchViewY> <!-- ARA_MorphableResearchBench-->
<prerequisites>
<li>ARA_Technology_7PAV</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_8PAV</defName> <defName>ARA_Technology_8PAV</defName>
<label>节点PAV-8"千兆炮"</label> <label>节点PAV-8"千兆炮"</label>
@@ -358,14 +347,14 @@
<researchViewY>0.30</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>0.30</researchViewY> <!-- ARA_MorphableResearchBench-->
<prerequisites> <prerequisites>
<li>ARA_Technology_1NPT</li> <li>ARA_Technology_1NPT</li>
<li>ARA_Technology_7XPAV</li> <li>ARA_Technology_7PAV</li>
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<!-- 近战发展 --> <!-- 近战发展 -->
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_2MEL</defName> <defName>ARA_Technology_2MEL</defName>
<label>节点MEL-2"骨鞭"</label> <label>节点MEL-2"骨鞭"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>600</baseCost> <baseCost>600</baseCost>
<researchViewX>5.50</researchViewX> <researchViewX>5.50</researchViewX>
<researchViewY>2.70</researchViewY> <researchViewY>2.70</researchViewY>
@@ -376,7 +365,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_3MEL</defName> <defName>ARA_Technology_3MEL</defName>
<label>节点MEL-3"镰爪"</label> <label>节点MEL-3"镰爪"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>1200</baseCost> <baseCost>1200</baseCost>
<researchViewX>10.00</researchViewX> <researchViewX>10.00</researchViewX>
<researchViewY>0.90</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>0.90</researchViewY> <!-- ARA_MorphableResearchBench-->
@@ -532,7 +521,7 @@
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_6SPV</defName> <defName>ARA_Technology_6SPV</defName>
<label>节点SPV-6"辅虫巢"</label> <label>节点SPV-6"辅虫巢"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许工艺种孵化新的武器。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>800</baseCost> <baseCost>800</baseCost>
<researchViewX>5.50</researchViewX> <researchViewX>5.50</researchViewX>
<researchViewY>1.50</researchViewY> <researchViewY>1.50</researchViewY>
@@ -646,17 +635,14 @@
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint"> <ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_6LOD</defName> <defName>ARA_Technology_1FRY</defName>
<label>节点LOD-6"巢之主"</label> <label>节点FRY-1"搬运者"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许空天种进行定向进化以牺牲高速和高空机动的能力换取向敌人投射大量天巢种的能力,这种飞行辅虫速度很快,并且在近战中很难缠。\n\n阿拉克涅虫群所有需要蓝图的科技都需要使用其触须分支特有的研究方式完成研究。</description> <description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许空天种进行定向进化以牺牲高空机动和辅虫孵化的能力换取在远行队中的大量移动速度增幅。\n\n阿拉克涅虫群所有需要蓝图的科技都需要使用其触须分支特有的研究方式完成研究。</description>
<baseCost>3500</baseCost> <baseCost>1000</baseCost>
<researchViewX>10.00</researchViewX> <researchViewX>6.50</researchViewX>
<researchViewY>5.30</researchViewY> <!-- ARA_MorphableResearchBench--> <researchViewY>3.80</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_2KYC</li>
</hiddenPrerequisites>
<prerequisites> <prerequisites>
<li>ARA_Technology_2WMT</li> <li>ARA_Technology_2KYC</li>
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint"> <ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
@@ -774,20 +760,6 @@
<li>ARA_Technology_4CLO</li> <li>ARA_Technology_4CLO</li>
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_7EVO</defName>
<label>节点EVO-7"甲壳棘刺"</label>
<description>&lt;color=#887E78>&lt;i>阿拉克涅虫群-主巢触须\n主巢触须的进化路径是包含于每一支虫群中的通用进化路径它们奠定了虫群在生物学上的优越性。&lt;/i>&lt;/color>\n\n允许实行新的阿拉克涅进化手术允许阿拉克涅虫族植入会自动攻击附近敌人的棘刺腔管。</description>
<baseCost>1500</baseCost>
<researchViewX>7.50</researchViewX>
<researchViewY>4.80</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_5ESS</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Technology_1VTE</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase"> <ResearchProjectDef ParentName="ARA_techBase">
<defName>ARA_Technology_8EVO</defName> <defName>ARA_Technology_8EVO</defName>
<label>节点EVO-8"玻璃钢壳"</label> <label>节点EVO-8"玻璃钢壳"</label>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<Defs> <Defs>
<!-- 女皇工艺进化 -->
<ResearchProjectDef ParentName="ARA_techBaseCantResearch"> <ResearchProjectDef ParentName="ARA_techBaseCantResearch">
<defName>ARA_Titan_Base_Technology</defName> <defName>ARA_Titan_Base_Technology</defName>
<label>泰坦触须特异化</label> <label>泰坦触须特异化</label>
@@ -12,7 +11,7 @@
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint"> <ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_8SLA</defName> <defName>ARA_Technology_8SLA</defName>
<label>节点SLA-8"暴戮之兽"</label> <label>节点SLA-8"暴戮之兽"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许女皇种孵化新的兽虫——暴屠种。\n\n阿拉克涅虫群 泰坦触须所有需要蓝图的科技,其研究只能通过基因试验卵进行。</description> <description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许女皇种孵化新的兽虫——暴屠种。\n\n阿拉克涅虫群泰坦触须所有需要蓝图的科技其研究只能通过基因试验卵进行。</description>
<baseCost>3000</baseCost> <baseCost>3000</baseCost>
<researchViewX>17.00</researchViewX> <researchViewX>17.00</researchViewX>
<researchViewY>5.80</researchViewY> <researchViewY>5.80</researchViewY>
@@ -27,10 +26,10 @@
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint"> <ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_7ACD_T</defName> <defName>ARA_Technology_7ACD_T</defName>
<label>节点ACD-7"溶脂强酸"</label> <label>节点ACD-7"溶脂强酸"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许蜜罐种进行定向进化抛弃孵化辅虫的能力换取溶解囚犯和俘虏以快速换取虫蜜的溶脂强酸。\n\n阿拉克涅虫群 泰坦触须所有需要蓝图的科技,其研究只能通过基因试验卵进行。</description> <description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许蜜罐种进行定向进化抛弃孵化辅虫的能力换取溶解囚犯和俘虏以快速换取虫蜜的溶脂强酸。\n\n阿拉克涅虫群泰坦触须所有需要蓝图的科技其研究只能通过基因试验卵进行。</description>
<baseCost>500</baseCost> <baseCost>500</baseCost>
<researchViewX>17.00</researchViewX> <researchViewX>17.00</researchViewX>
<researchViewY>0.30</researchViewY> <researchViewY>1.50</researchViewY>
<hiddenPrerequisites> <hiddenPrerequisites>
<li>ARA_Technology_7VXI</li> <li>ARA_Technology_7VXI</li>
</hiddenPrerequisites> </hiddenPrerequisites>
@@ -38,4 +37,75 @@
<li>ARA_Titan_Base_Technology</li> <li>ARA_Titan_Base_Technology</li>
</prerequisites> </prerequisites>
</ResearchProjectDef> </ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_3LGN_T</defName>
<label>节点LGN-3"军团之威"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许禁卫种进行定向进化抛弃孵化辅虫的能力换取更强大的近战、远程、防御能力和各种体术。\n\n阿拉克涅虫群泰坦触须所有需要蓝图的科技其研究只能通过基因试验卵进行。</description>
<baseCost>3000</baseCost>
<researchViewX>17.00</researchViewX>
<researchViewY>3.90</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_7KYC</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Titan_Base_Technology</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_6LOD_T</defName>
<label>节点LOD-6"巢之主"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许空天种进行定向进化以牺牲高速和高空机动的能力换取向敌人投射大量天巢种的能力这种飞行辅虫速度很快并且在近战中很难缠。\n\n阿拉克涅虫群泰坦触须所有需要蓝图的科技其研究只能通过基因试验卵进行。</description>
<baseCost>3500</baseCost>
<researchViewX>17.00</researchViewX>
<researchViewY>4.90</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_2KYC</li>
<li>ARA_Technology_2WMT</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Titan_Base_Technology</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_7EVO_T</defName>
<label>节点EVO-7"甲壳棘刺"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许实行新的阿拉克涅进化手术允许阿拉克涅虫族植入会自动攻击附近敌人的棘刺腔管。\n\n阿拉克涅虫群泰坦触须所有需要蓝图的科技其研究只能通过基因试验卵进行。</description>
<baseCost>1500</baseCost>
<researchViewX>17.00</researchViewX>
<researchViewY>4.40</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_5KYC</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Titan_Base_Technology</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_1STG_T</defName>
<label>节点STG-1"绽放腔"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>500</baseCost>
<researchViewX>17.00</researchViewX>
<researchViewY>0.90</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_6PAV</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Titan_Base_Technology</li>
</prerequisites>
</ResearchProjectDef>
<ResearchProjectDef ParentName="ARA_techBase_Needtechprint">
<defName>ARA_Technology_3XPV_T</defName>
<label>节点XPV-3"梭镖"</label>
<description>&lt;color=#915A30>&lt;i>阿拉克涅虫群-泰坦触须\n泰坦触须是阿拉克涅虫群的主力军团包含阿拉克涅虫群中最坚韧、最具有适应力的族群承担在战场上维持战线的任务。这个分支下的虫群拥有均衡的攻防能力擅长以硬碰硬的模式消灭对手。&lt;/i>&lt;/color>\n\n允许阿拉克涅茧孵化新的武器。</description>
<baseCost>2000</baseCost>
<researchViewX>17.00</researchViewX>
<researchViewY>0.30</researchViewY>
<hiddenPrerequisites>
<li>ARA_Technology_7PAV</li>
</hiddenPrerequisites>
<prerequisites>
<li>ARA_Titan_Base_Technology</li>
</prerequisites>
</ResearchProjectDef>
</Defs> </Defs>

View File

@@ -227,8 +227,8 @@
</graphicData> </graphicData>
<apparel> <apparel>
<tags> <tags>
<li>Wula_Apparel</li> <li>ARA_Apparel</li>
<li>Wula_Clothes</li> <li>ARA_Clothes</li>
</tags> </tags>
<renderSkipFlags> <renderSkipFlags>
<li>None</li> <li>None</li>
@@ -277,6 +277,9 @@
<texPath>ArachnaeSwarm/Apparel/ARA_Maid_Uniform</texPath> <texPath>ArachnaeSwarm/Apparel/ARA_Maid_Uniform</texPath>
</graphicData> </graphicData>
<apparel> <apparel>
<tags>
<li>ARA_Init_Clothes</li>
</tags>
<bodyPartGroups> <bodyPartGroups>
<li>Torso</li> <li>Torso</li>
<li>Shoulders</li> <li>Shoulders</li>
@@ -324,6 +327,9 @@
<texPath>ArachnaeSwarm/Apparel/ARA_Maid_Dress</texPath> <texPath>ArachnaeSwarm/Apparel/ARA_Maid_Dress</texPath>
</graphicData> </graphicData>
<apparel> <apparel>
<tags>
<li>ARA_Init_Clothes</li>
</tags>
<bodyPartGroups> <bodyPartGroups>
<li>Torso</li> <li>Torso</li>
<li>Shoulders</li> <li>Shoulders</li>
@@ -371,6 +377,9 @@
<texPath>ArachnaeSwarm/Apparel/ARA_Daily_Wear</texPath> <texPath>ArachnaeSwarm/Apparel/ARA_Daily_Wear</texPath>
</graphicData> </graphicData>
<apparel> <apparel>
<tags>
<li>ARA_Init_Clothes</li>
</tags>
<bodyPartGroups> <bodyPartGroups>
<li>Torso</li> <li>Torso</li>
<li>Shoulders</li> <li>Shoulders</li>

View File

@@ -467,7 +467,7 @@
<soundInteract>SpitterSpawn</soundInteract> <soundInteract>SpitterSpawn</soundInteract>
<recipeMaker> <recipeMaker>
<recipeUsers Inherit="False" /> <recipeUsers Inherit="False" />
<researchPrerequisite>ARA_Technology_6PAV</researchPrerequisite> <researchPrerequisite>ARA_Technology_1STG_T</researchPrerequisite>
<unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef> <unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef>
</recipeMaker> </recipeMaker>
<statBases> <statBases>
@@ -705,7 +705,7 @@
<soundInteract>SpitterSpawn</soundInteract> <soundInteract>SpitterSpawn</soundInteract>
<recipeMaker> <recipeMaker>
<recipeUsers Inherit="False" /> <recipeUsers Inherit="False" />
<researchPrerequisite>ARA_Technology_7XPAV</researchPrerequisite> <researchPrerequisite>ARA_Technology_3XPV_T</researchPrerequisite>
<unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef> <unfinishedThingDef>UnfinishedWeapon</unfinishedThingDef>
</recipeMaker> </recipeMaker>
<statBases> <statBases>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -2,6 +2,18 @@
"Version": 1, "Version": 1,
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [ "Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_fanshapedstunknockback\\compproperties_abilityfanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_fanshapedstunknockback\\compproperties_abilityfanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_fanshapedstunknockback\\compabilityeffect_fanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_fanshapedstunknockback\\compabilityeffect_fanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_ejectorgans\\compabilityeffect_ejectorgans.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_ejectorgans\\compabilityeffect_ejectorgans.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{ {
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_comphediffgiver\\compproperties_hediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_comphediffgiver\\compproperties_hediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_comphediffgiver\\compproperties_hediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_comphediffgiver\\compproperties_hediffgiver.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
@@ -18,15 +30,54 @@
"DocumentGroups": [ "DocumentGroups": [
{ {
"DockedWidth": 200, "DockedWidth": 200,
"SelectedChildIndex": 2, "SelectedChildIndex": 1,
"Children": [ "Children": [
{ {
"$type": "Bookmark", "$type": "Bookmark",
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
}, },
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "CompProperties_AbilityFanShapedStunKnockback.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
"RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAA9AAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-15T06:29:46.581Z",
"EditorCaption": ""
},
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 1, "DocumentIndex": 1,
"Title": "CompAbilityEffect_FanShapedStunKnockback.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
"RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\CompAbilityEffect_FanShapedStunKnockback.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-15T06:29:34.172Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "CompAbilityEffect_EjectOrgans.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
"RelativeToolTip": "Abilities\\ARA_EjectOrgans\\CompAbilityEffect_EjectOrgans.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAQAAAAXAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-15T06:29:29.494Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"Title": "CompHediffGiver.cs", "Title": "CompHediffGiver.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompHediffGiver.cs",
@@ -38,7 +89,7 @@
}, },
{ {
"$type": "Document", "$type": "Document",
"DocumentIndex": 0, "DocumentIndex": 3,
"Title": "CompProperties_HediffGiver.cs", "Title": "CompProperties_HediffGiver.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs", "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs", "RelativeDocumentMoniker": "Pawn_Comps\\ARA_CompHediffGiver\\CompProperties_HediffGiver.cs",

View File

@@ -0,0 +1,722 @@
using RimWorld;
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.Sound;
namespace ArachnaeSwarm
{
public class CompAbilityEffect_FanShapedStunKnockback : CompAbilityEffect
{
private readonly List<IntVec3> tmpCells = new List<IntVec3>();
private Effecter effecter;
public new CompProperties_AbilityFanShapedStunKnockback Props => (CompProperties_AbilityFanShapedStunKnockback)props;
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
Pawn caster = parent.pawn;
if (caster == null || caster.Map == null || !target.IsValid)
return;
// 1. 获取扇形区域内的所有单元格
List<IntVec3> affectedCells = GetFanShapedCells(caster, target.Cell);
// 2. 收集区域内的所有目标
var affectedTargets = CollectAffectedTargets(caster, affectedCells);
// 3. 对每个目标应用效果
foreach (Thing targetThing in affectedTargets)
{
if (targetThing != null && !targetThing.Destroyed && targetThing.Spawned)
{
if (targetThing is Pawn pawn)
{
ApplyEffectToPawn(caster, pawn, target);
}
else if (Props.affectNonPawnThings)
{
ApplyEffectToNonPawnThing(caster, targetThing, target);
}
}
}
// 4. 播放整体攻击效果参考Verb_MeleeAttack_Cleave
PlayMainAttackEffect(caster, target);
}
/// <summary>
/// 播放主要攻击效果
/// </summary>
private void PlayMainAttackEffect(Pawn caster, LocalTargetInfo target)
{
if (caster == null || caster.Map == null || !target.IsValid)
return;
// 播放主要攻击效果
if (Props.impactEffecter != null)
{
effecter = Props.impactEffecter.Spawn();
// 关键修复:第一个参数是施法者位置,第二个参数是目标位置
effecter.Trigger(new TargetInfo(caster.Position, caster.Map), target.ToTargetInfo(caster.Map));
effecter.Cleanup();
effecter = null;
}
// 播放攻击音效
if (Props.impactSound != null)
{
Props.impactSound.PlayOneShot(new TargetInfo(target.Cell, caster.Map));
}
}
/// <summary>
/// 收集扇形区域内的所有目标包括Pawn和非Pawn物体
/// </summary>
private List<Thing> CollectAffectedTargets(Pawn caster, List<IntVec3> cells)
{
List<Thing> targets = new List<Thing>();
HashSet<Thing> addedThings = new HashSet<Thing>();
if (caster == null || caster.Map == null || cells == null)
return targets;
foreach (IntVec3 cell in cells)
{
if (!cell.InBounds(caster.Map))
continue;
List<Thing> things = cell.GetThingList(caster.Map);
foreach (Thing thing in things)
{
if (thing == null || addedThings.Contains(thing))
continue;
// 检查是否为施法者
if (!Props.affectCaster && thing == caster)
continue;
// 检查是否需要视线
if (Props.requireLineOfSightToTarget && !GenSight.LineOfSight(caster.Position, cell, caster.Map))
continue;
// Pawn的处理
if (thing is Pawn pawn)
{
// 检查是否为敌人
if (Props.onlyAffectEnemies && !pawn.HostileTo(caster))
continue;
targets.Add(pawn);
addedThings.Add(pawn);
}
// 非Pawn物体的处理
else if (Props.affectNonPawnThings && thing is ThingWithComps thingWithComps)
{
// 检查是否为敌人(如果物体有派系)
if (Props.onlyAffectEnemies)
{
bool isEnemy = IsThingEnemy(caster, thingWithComps);
if (!isEnemy)
continue;
}
// 检查是否可以被伤害
if (Props.canDamageNonPawnThings && !CanBeDamaged(thingWithComps))
continue;
targets.Add(thingWithComps);
addedThings.Add(thingWithComps);
}
}
}
return targets;
}
/// <summary>
/// 检查物体是否为敌人
/// </summary>
private bool IsThingEnemy(Pawn caster, Thing thing)
{
// 如果物体有派系,检查是否敌对
if (thing.Faction != null)
{
return caster.HostileTo(thing);
}
// 如果物体是建筑且没有派系,根据设置决定
// 默认情况下视为中立只有当onlyAffectEnemies为false时才影响
return false;
}
/// <summary>
/// 检查物体是否可以被伤害
/// </summary>
private bool CanBeDamaged(Thing thing)
{
// 检查是否有生命值组件
if (thing.def.useHitPoints)
{
// 检查是否被摧毁或已死亡
if (thing.Destroyed || thing.HitPoints <= 0)
return false;
// 检查是否可以承受伤害
if (thing.def.destroyable)
return true;
}
return false;
}
/// <summary>
/// 对非Pawn物体应用效果
/// </summary>
private void ApplyEffectToNonPawnThing(Pawn caster, Thing targetThing, LocalTargetInfo targetInfo)
{
if (targetThing == null || caster == null)
return;
// 1. 造成伤害
ApplyDamageToNonPawn(caster, targetThing);
// 注意非Pawn物体不进行击退也不眩晕
}
/// <summary>
/// 对非Pawn物体造成伤害
/// </summary>
private void ApplyDamageToNonPawn(Pawn caster, Thing targetThing)
{
if (!Props.canDamageNonPawnThings)
return;
// 获取调整后的伤害值
float adjustedDamage = GetAdjustedDamage(caster);
// 应用非Pawn物体的伤害倍率
float finalDamage = adjustedDamage * Props.nonPawnDamageMultiplier;
// 检查目标是否可以被伤害
if (targetThing.def.useHitPoints && targetThing.HitPoints > 0)
{
// 创建伤害信息
DamageInfo damageInfo = new DamageInfo(
Props.damageDef,
finalDamage,
Props.armorPenetration,
-1f,
caster,
null
);
// 应用伤害
targetThing.TakeDamage(damageInfo);
// 播放个体命中效果
if (Props.applySpecialEffectsToNonPawn && Props.impactEffecter != null && caster.Map != null)
{
Effecter effect = Props.impactEffecter.Spawn();
// 关键修复:第一个参数是施法者,第二个参数是目标
effect.Trigger(new TargetInfo(caster.Position, caster.Map), new TargetInfo(targetThing.Position, caster.Map));
effect.Cleanup();
}
// 播放个体命中音效
if (Props.applySpecialEffectsToNonPawn && Props.impactSound != null && caster.Map != null)
{
Props.impactSound.PlayOneShot(new TargetInfo(targetThing.Position, caster.Map));
}
}
}
/// <summary>
/// 获取伤害系数
/// </summary>
private float GetDamageMultiplier(Pawn caster)
{
if (caster == null) return 1f;
if (Props.multiplyDamageByMeleeFactor)
{
if (Props.damageMultiplierStat != null)
{
return caster.GetStatValue(Props.damageMultiplierStat);
}
return caster.GetStatValue(StatDefOf.MeleeDamageFactor);
}
return 1f;
}
/// <summary>
/// 获取眩晕时间系数
/// </summary>
private float GetStunMultiplier(Pawn caster)
{
if (caster == null) return 1f;
if (Props.multiplyStunTimeByMeleeFactor)
{
if (Props.stunMultiplierStat != null)
{
return caster.GetStatValue(Props.stunMultiplierStat);
}
return caster.GetStatValue(StatDefOf.MeleeDamageFactor);
}
return 1f;
}
/// <summary>
/// 获取调整后的伤害值
/// </summary>
private float GetAdjustedDamage(Pawn caster)
{
float baseDamage = Props.damageAmount;
float multiplier = GetDamageMultiplier(caster);
return baseDamage * multiplier;
}
/// <summary>
/// 获取调整后的眩晕时间
/// </summary>
private int GetAdjustedStunTicks(Pawn caster)
{
int baseStunTicks = Props.stunTicks;
float multiplier = GetStunMultiplier(caster);
return Mathf.RoundToInt(baseStunTicks * multiplier);
}
/// <summary>
/// 显示伤害和眩晕加成信息(用于预览)
/// </summary>
public string GetAdjustedDamageAndStunInfo(Pawn caster)
{
if (caster == null) return string.Empty;
float damageMultiplier = GetDamageMultiplier(caster);
float stunMultiplier = GetStunMultiplier(caster);
// 如果都不需要乘以系数,则不显示信息
if (damageMultiplier == 1f && stunMultiplier == 1f)
{
return string.Empty;
}
var sb = new System.Text.StringBuilder();
sb.AppendLine("LBD_AdjustedEffects".Translate());
if (damageMultiplier != 1f)
{
float adjustedDamage = Props.damageAmount * damageMultiplier;
sb.AppendLine("LBD_AdjustedDamage".Translate(Props.damageAmount, adjustedDamage));
}
if (stunMultiplier != 1f)
{
int adjustedStunTicks = Mathf.RoundToInt(Props.stunTicks * stunMultiplier);
float baseStunSeconds = Props.stunTicks / 60f;
float adjustedStunSeconds = adjustedStunTicks / 60f;
sb.AppendLine("LBD_AdjustedStun".Translate(baseStunSeconds, adjustedStunSeconds));
}
return sb.ToString();
}
/// <summary>
/// 获取扇形区域内的所有单元格
/// </summary>
private List<IntVec3> GetFanShapedCells(Pawn caster, IntVec3 targetCell)
{
tmpCells.Clear();
if (caster == null || caster.Map == null)
return tmpCells;
IntVec3 casterPos = caster.Position;
IntVec3 clampedTarget = targetCell.ClampInsideMap(caster.Map);
// 如果施法者和目标在同一位置,则没有扇形
if (casterPos == clampedTarget)
return tmpCells;
Vector3 casterVector = casterPos.ToVector3Shifted().Yto0();
// 计算方向向量和角度
float horizontalLength = (clampedTarget - casterPos).LengthHorizontal;
float dirX = (clampedTarget.x - casterPos.x) / horizontalLength;
float dirZ = (clampedTarget.z - casterPos.z) / horizontalLength;
// 调整目标点到扇形半径
clampedTarget.x = Mathf.RoundToInt(casterPos.x + dirX * Props.range);
clampedTarget.z = Mathf.RoundToInt(casterPos.z + dirZ * Props.range);
// 计算扇形的中心角
float targetAngle = Vector3.SignedAngle(
clampedTarget.ToVector3Shifted().Yto0() - casterVector,
Vector3.right,
Vector3.up);
// 计算扇形的半角(从中心线到边缘)
float halfWidth = Props.lineWidthEnd / 2f;
float coneEdgeDistance = Mathf.Sqrt(
Mathf.Pow((clampedTarget - casterPos).LengthHorizontal, 2f) +
Mathf.Pow(halfWidth, 2f));
float halfAngle = Mathf.Rad2Deg * Mathf.Asin(halfWidth / coneEdgeDistance);
// 限制最大角度不超过设定值
halfAngle = Mathf.Min(halfAngle, Props.coneSizeDegrees / 2f);
// 遍历半径内的所有单元格,检查是否在扇形内
int radialCellCount = GenRadial.NumCellsInRadius(Props.range);
for (int i = 0; i < radialCellCount; i++)
{
IntVec3 cell = casterPos + GenRadial.RadialPattern[i];
// 检查单元格是否有效
if (!CanUseCell(caster, cell))
continue;
// 计算单元格相对于施法者的角度
float cellAngle = Vector3.SignedAngle(
cell.ToVector3Shifted().Yto0() - casterVector,
Vector3.right,
Vector3.up);
// 检查角度差是否在扇形范围内
if (Mathf.Abs(Mathf.DeltaAngle(cellAngle, targetAngle)) <= halfAngle)
{
tmpCells.Add(cell);
}
}
// 添加从施法者到目标点的直线上的单元格
List<IntVec3> lineCells = GenSight.BresenhamCellsBetween(casterPos, clampedTarget);
for (int i = 0; i < lineCells.Count; i++)
{
IntVec3 cell = lineCells[i];
if (!tmpCells.Contains(cell) && CanUseCell(caster, cell))
{
tmpCells.Add(cell);
}
}
return tmpCells;
}
/// <summary>
/// 对单个Pawn应用效果
/// </summary>
private void ApplyEffectToPawn(Pawn caster, Pawn target, LocalTargetInfo targetInfo)
{
// 1. 造成伤害
bool targetDied = ApplyDamageAndStun(caster, target);
// 2. 如果目标存活,执行击退
if (!targetDied && target != null && !target.Dead && !target.Downed)
{
PerformKnockback(caster, target);
}
}
/// <summary>
/// 应用伤害和眩晕效果,返回目标是否死亡
/// </summary>
private bool ApplyDamageAndStun(Pawn caster, Pawn target)
{
// 获取调整后的伤害和眩晕时间
float adjustedDamage = GetAdjustedDamage(caster);
int adjustedStunTicks = GetAdjustedStunTicks(caster);
// 创建伤害信息
DamageInfo damageInfo = new DamageInfo(
Props.damageDef,
adjustedDamage,
Props.armorPenetration,
-1f,
caster,
null
);
// 应用伤害
target.TakeDamage(damageInfo);
// 检查目标是否死亡
bool targetDied = target.Dead || target.Destroyed;
if (targetDied)
{
return true;
}
// 播放个体命中效果(可选,因为已经有主要攻击效果)
if (Props.applySpecialEffectsToNonPawn && Props.impactEffecter != null && caster.Map != null)
{
Effecter effect = Props.impactEffecter.Spawn();
// 关键修复:第一个参数是施法者,第二个参数是目标
effect.Trigger(new TargetInfo(caster.Position, caster.Map), new TargetInfo(target.Position, caster.Map));
effect.Cleanup();
}
// 应用眩晕 - 只在目标存活时应用
if (adjustedStunTicks > 0 && !target.Dead)
{
target.stances?.stunner?.StunFor(adjustedStunTicks, caster);
}
return false;
}
/// <summary>
/// 执行击退
/// </summary>
private void PerformKnockback(Pawn caster, Pawn target)
{
if (target == null || target.Destroyed || target.Dead || caster.Map == null)
return;
// 计算击退方向(从施法者指向目标)
IntVec3 knockbackDirection = CalculateKnockbackDirection(caster, target.Position);
// 寻找最远的可站立击退位置
IntVec3 knockbackDestination = FindFarthestStandablePosition(caster, target, knockbackDirection);
// 如果找到了有效位置,执行击退飞行
if (knockbackDestination.IsValid && knockbackDestination != target.Position)
{
CreateKnockbackFlyer(caster, target, knockbackDestination);
}
}
/// <summary>
/// 计算击退方向
/// </summary>
private IntVec3 CalculateKnockbackDirection(Pawn caster, IntVec3 targetPosition)
{
IntVec3 direction = targetPosition - caster.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 FindFarthestStandablePosition(Pawn caster, Pawn target, IntVec3 direction)
{
Map map = caster.Map;
IntVec3 currentPos = target.Position;
IntVec3 farthestValidPos = currentPos;
// 从最大距离开始向回找,找到第一个可站立的格子
for (int distance = Props.maxKnockbackDistance; distance >= 1; distance--)
{
IntVec3 testPos = currentPos + (direction * distance);
if (!testPos.InBounds(map))
continue;
if (IsCellStandableAndEmpty(caster, target, testPos, map))
{
farthestValidPos = testPos;
break;
}
}
return farthestValidPos;
}
/// <summary>
/// 检查格子是否可站立且没有其他Pawn
/// </summary>
private bool IsCellStandableAndEmpty(Pawn caster, Pawn target, IntVec3 cell, Map map)
{
if (!cell.InBounds(map))
return false;
// 检查是否可站立
if (!cell.Standable(map))
return false;
// 检查是否有建筑阻挡
if (!Props.canKnockbackIntoWalls)
{
Building edifice = cell.GetEdifice(map);
if (edifice != null && !(edifice is Building_Door))
return false;
}
// 检查视线
if (Props.requireLineOfSight && !GenSight.LineOfSight(target.Position, cell, map))
return false;
// 检查是否有其他pawn
List<Thing> thingList = cell.GetThingList(map);
foreach (Thing thing in thingList)
{
if (thing is Pawn otherPawn && otherPawn != target)
return false;
}
return true;
}
/// <summary>
/// 创建击退飞行器
/// </summary>
private void CreateKnockbackFlyer(Pawn caster, Pawn target, IntVec3 destination)
{
Map map = caster.Map;
// 使用自定义飞行器或默认飞行器
ThingDef flyerDef = Props.knockbackFlyerDef ?? ThingDefOf.PawnFlyer;
// 创建飞行器
PawnFlyer flyer = PawnFlyer.MakeFlyer(
flyerDef,
target,
destination,
Props.flightEffecterDef,
Props.landingSound,
false, // 不携带物品
null, // 不覆盖起始位置
parent, // 传递Ability对象
new LocalTargetInfo(destination)
);
if (flyer != null)
{
GenSpawn.Spawn(flyer, destination, map);
}
}
/// <summary>
/// 检查单元格是否可用于效果
/// </summary>
private bool CanUseCell(Pawn caster, IntVec3 cell)
{
if (caster == null || caster.Map == null)
return false;
if (!cell.InBounds(caster.Map))
return false;
if (!Props.affectCaster && cell == caster.Position)
return false;
if (!Props.canHitFilledCells && cell.Filled(caster.Map))
return false;
if (!cell.InHorDistOf(caster.Position, Props.range))
return false;
return true;
}
/// <summary>
/// 绘制效果预览
/// </summary>
public override void DrawEffectPreview(LocalTargetInfo target)
{
base.DrawEffectPreview(target);
Pawn caster = parent.pawn;
if (caster == null || caster.Map == null || !target.IsValid)
return;
// 绘制扇形区域
List<IntVec3> cells = GetFanShapedCells(caster, target.Cell);
GenDraw.DrawFieldEdges(cells, Color.red);
// 绘制扇形边线
DrawConeBoundaries(caster, target.Cell);
}
/// <summary>
/// 绘制扇形边界线
/// </summary>
private void DrawConeBoundaries(Pawn caster, IntVec3 targetCell)
{
if (caster == null || caster.Map == null)
return;
IntVec3 casterPos = caster.Position;
Vector3 casterVector = casterPos.ToVector3Shifted().Yto0();
// 计算中心线
float horizontalLength = (targetCell - casterPos).LengthHorizontal;
float dirX = (targetCell.x - casterPos.x) / horizontalLength;
float dirZ = (targetCell.z - casterPos.z) / horizontalLength;
IntVec3 clampedTarget = targetCell;
clampedTarget.x = Mathf.RoundToInt(casterPos.x + dirX * Props.range);
clampedTarget.z = Mathf.RoundToInt(casterPos.z + dirZ * Props.range);
float targetAngle = Vector3.SignedAngle(
clampedTarget.ToVector3Shifted().Yto0() - casterVector,
Vector3.right,
Vector3.up);
float halfWidth = Props.lineWidthEnd / 2f;
float coneEdgeDistance = Mathf.Sqrt(
Mathf.Pow((clampedTarget - casterPos).LengthHorizontal, 2f) +
Mathf.Pow(halfWidth, 2f));
float halfAngle = Mathf.Rad2Deg * Mathf.Asin(halfWidth / coneEdgeDistance);
halfAngle = Mathf.Min(halfAngle, Props.coneSizeDegrees / 2f);
// 绘制两条边界线
float leftAngle = targetAngle - halfAngle;
float rightAngle = targetAngle + halfAngle;
Vector3 leftDir = Quaternion.Euler(0, leftAngle, 0) * Vector3.right;
Vector3 rightDir = Quaternion.Euler(0, rightAngle, 0) * Vector3.right;
IntVec3 leftEnd = casterPos + new IntVec3(
Mathf.RoundToInt(leftDir.x * Props.range),
0,
Mathf.RoundToInt(leftDir.z * Props.range)
).ClampInsideMap(caster.Map);
IntVec3 rightEnd = casterPos + new IntVec3(
Mathf.RoundToInt(rightDir.x * Props.range),
0,
Mathf.RoundToInt(rightDir.z * Props.range)
).ClampInsideMap(caster.Map);
GenDraw.DrawLineBetween(casterPos.ToVector3Shifted(), leftEnd.ToVector3Shifted(), SimpleColor.White);
GenDraw.DrawLineBetween(casterPos.ToVector3Shifted(), rightEnd.ToVector3Shifted(), SimpleColor.White);
}
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
{
if (!base.Valid(target, throwMessages))
return false;
Pawn caster = parent.pawn;
if (caster == null || caster.Map == null)
return false;
// 检查目标是否在范围内
float distance = caster.Position.DistanceTo(target.Cell);
if (distance > Props.range)
{
if (throwMessages)
Messages.Message("AbilityTargetOutOfRange".Translate(), caster, MessageTypeDefOf.RejectInput);
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,58 @@
using RimWorld;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_AbilityFanShapedStunKnockback : CompProperties_AbilityEffect
{
// 扇形参数
public float range = 5f; // 扇形半径
public float coneSizeDegrees = 45f; // 扇形角度(总角度)
public float lineWidthEnd = 3f; // 扇形末端宽度
// 伤害参数
public DamageDef damageDef = DamageDefOf.Blunt;
public float damageAmount = 15f;
public float armorPenetration = 0f;
// 眩晕参数
public int stunTicks = 180; // 3秒眩晕 (60 ticks = 1秒)
// 击退参数
public int maxKnockbackDistance = 3; // 最大击退距离
public bool canKnockbackIntoWalls = false; // 是否可以击退到墙上
public bool requireLineOfSight = true; // 击退路径是否需要视线
// 新增对非Pawn物体的处理参数
public bool affectNonPawnThings = true; // 是否影响非Pawn物体
public bool canDamageNonPawnThings = true; // 是否可以对非Pawn物体造成伤害
public float nonPawnDamageMultiplier = 1.0f; // 非Pawn物体的伤害倍率
public bool applySpecialEffectsToNonPawn = false; // 是否对非Pawn物体应用特殊效果
// 视觉和音效效果
public EffecterDef impactEffecter; // 命中效果
public SoundDef impactSound; // 命中音效
// 飞行效果设置
public ThingDef knockbackFlyerDef; // 击退飞行器定义
public EffecterDef flightEffecterDef; // 飞行效果
public SoundDef landingSound; // 落地音效
// 过滤设置
public bool affectCaster = false; // 是否影响施法者
public bool canHitFilledCells = true; // 是否可以击中已填充的单元格
public bool onlyAffectEnemies = true; // 只影响敌人
public bool requireLineOfSightToTarget = true; // 是否需要视线到目标
// 近战伤害系数加成
public bool multiplyDamageByMeleeFactor = false; // 伤害是否乘以近战伤害系数
public bool multiplyStunTimeByMeleeFactor = false; // 眩晕时间是否乘以近战伤害系数
public StatDef damageMultiplierStat = null; // 自定义伤害系数Stat如果为空则使用MeleeDamageFactor
public StatDef stunMultiplierStat = null; // 自定义眩晕时间系数Stat如果为空则使用MeleeDamageFactor
public CompProperties_AbilityFanShapedStunKnockback()
{
compClass = typeof(CompAbilityEffect_FanShapedStunKnockback);
}
}
}

View File

@@ -34,6 +34,8 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Abilities\ARA_FanShapedStunKnockback\CompAbilityEffect_FanShapedStunKnockback.cs" />
<Compile Include="Abilities\ARA_FanShapedStunKnockback\CompProperties_AbilityFanShapedStunKnockback.cs" />
<Compile Include="Abilities\ARA_HediffBlacklist\CompAbilityEffect_HediffBlacklist.cs" /> <Compile Include="Abilities\ARA_HediffBlacklist\CompAbilityEffect_HediffBlacklist.cs" />
<Compile Include="Abilities\ARA_HediffBlacklist\CompProperties_AbilityHediffBlacklist.cs" /> <Compile Include="Abilities\ARA_HediffBlacklist\CompProperties_AbilityHediffBlacklist.cs" />
<Compile Include="Abilities\ARA_HediffGacha\CompAbilityEffect_HediffGacha.cs" /> <Compile Include="Abilities\ARA_HediffGacha\CompAbilityEffect_HediffGacha.cs" />

View File

@@ -1,4 +1,3 @@
// File: Managers/ResearchBlueprintReaderManager.cs
using RimWorld; using RimWorld;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -23,9 +22,18 @@ namespace ArachnaeSwarm
private int cleanupTimer; private int cleanupTimer;
private const int CleanupInterval = 2500; private const int CleanupInterval = 2500;
// === 新增:反向校验相关字段 ===
private int reverseCheckTimer;
private const int ReverseCheckInterval = 10000; // 每10秒检查一次6000ticks = 10秒
// === 新增:建筑健康状态记录 ===
private Dictionary<Building_ResearchBlueprintReader, BuildingHealthRecord> buildingHealthRecords;
// === 新增:用于序列化的临时字段 === // === 新增:用于序列化的临时字段 ===
private List<ResearchProjectDef> serializedProjects; private List<ResearchProjectDef> serializedProjects;
private List<List<Building_ResearchBlueprintReader>> serializedBuildings; private List<List<Building_ResearchBlueprintReader>> serializedBuildings;
private List<Building_ResearchBlueprintReader> serializedHealthRecordsKeys;
private List<BuildingHealthRecord> serializedHealthRecordsValues;
// === 新增:科技丢失检查计时器 === // === 新增:科技丢失检查计时器 ===
private int lostResearchCheckTimer; private int lostResearchCheckTimer;
@@ -36,7 +44,9 @@ namespace ArachnaeSwarm
instance = this; instance = this;
allReaders = new List<Building_ResearchBlueprintReader>(); allReaders = new List<Building_ResearchBlueprintReader>();
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>(); researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
buildingHealthRecords = new Dictionary<Building_ResearchBlueprintReader, BuildingHealthRecord>();
lostResearchCheckTimer = 0; lostResearchCheckTimer = 0;
reverseCheckTimer = 0;
} }
public static ResearchBlueprintReaderManager Instance => instance; public static ResearchBlueprintReaderManager Instance => instance;
@@ -69,19 +79,41 @@ namespace ArachnaeSwarm
Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def); Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def);
Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference); Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference);
// === 新增:序列化建筑健康记录 ===
serializedHealthRecordsKeys = new List<Building_ResearchBlueprintReader>();
serializedHealthRecordsValues = new List<BuildingHealthRecord>();
foreach (var kvp in buildingHealthRecords)
{
if (kvp.Key != null && !kvp.Key.Destroyed)
{
serializedHealthRecordsKeys.Add(kvp.Key);
serializedHealthRecordsValues.Add(kvp.Value);
}
}
Scribe_Collections.Look(ref serializedHealthRecordsKeys, "healthRecordsKeys", LookMode.Reference);
Scribe_Collections.Look(ref serializedHealthRecordsValues, "healthRecordsValues", LookMode.Deep);
} }
else if (Scribe.mode == LoadSaveMode.LoadingVars) else if (Scribe.mode == LoadSaveMode.LoadingVars)
{ {
// 加载时:清空现有数据 // 加载时:清空现有数据
allReaders = new List<Building_ResearchBlueprintReader>(); allReaders = new List<Building_ResearchBlueprintReader>();
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>(); researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
buildingHealthRecords = new Dictionary<Building_ResearchBlueprintReader, BuildingHealthRecord>();
serializedProjects = null; serializedProjects = null;
serializedBuildings = null; serializedBuildings = null;
serializedHealthRecordsKeys = null;
serializedHealthRecordsValues = null;
Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def); Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def);
Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference); Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference);
Scribe_Collections.Look(ref serializedHealthRecordsKeys, "healthRecordsKeys", LookMode.Reference);
Scribe_Collections.Look(ref serializedHealthRecordsValues, "healthRecordsValues", LookMode.Deep);
// 重建 researchBuildings 字典
if (serializedProjects != null && serializedBuildings != null && if (serializedProjects != null && serializedBuildings != null &&
serializedProjects.Count == serializedBuildings.Count) serializedProjects.Count == serializedBuildings.Count)
{ {
@@ -102,7 +134,7 @@ namespace ArachnaeSwarm
// 添加到所有建筑列表 // 添加到所有建筑列表
foreach (var building in buildings) foreach (var building in buildings)
{ {
if (!allReaders.Contains(building)) if (building != null && !allReaders.Contains(building))
{ {
allReaders.Add(building); allReaders.Add(building);
} }
@@ -112,22 +144,41 @@ namespace ArachnaeSwarm
} }
} }
ArachnaeLog.Debug($"[ResearchManager] Loaded {allReaders.Count} buildings, {researchBuildings.Count} research projects"); // 重建 buildingHealthRecords 字典
if (serializedHealthRecordsKeys != null && serializedHealthRecordsValues != null &&
serializedHealthRecordsKeys.Count == serializedHealthRecordsValues.Count)
{
for (int i = 0; i < serializedHealthRecordsKeys.Count; i++)
{
var building = serializedHealthRecordsKeys[i];
var record = serializedHealthRecordsValues[i];
if (building != null && record != null)
{
buildingHealthRecords[building] = record;
}
}
}
ArachnaeLog.Debug($"[ResearchManager] Loaded {allReaders.Count} buildings, {researchBuildings.Count} research projects, {buildingHealthRecords.Count} health records");
} }
else if (Scribe.mode == LoadSaveMode.PostLoadInit) else if (Scribe.mode == LoadSaveMode.PostLoadInit)
{ {
// 后加载初始化:清理所有无效数据 // 后加载初始化:清理所有无效数据
CleanupInvalidData(); CleanupInvalidData();
ValidateAllBuildings();
} }
// 保存和加载计时器 // 保存和加载计时器
Scribe_Values.Look(ref lostResearchCheckTimer, "lostResearchCheckTimer", 0); Scribe_Values.Look(ref lostResearchCheckTimer, "lostResearchCheckTimer", 0);
Scribe_Values.Look(ref reverseCheckTimer, "reverseCheckTimer", 0);
} }
public override void GameComponentTick() public override void GameComponentTick()
{ {
base.GameComponentTick(); base.GameComponentTick();
// 正向清理计时器
cleanupTimer++; cleanupTimer++;
if (cleanupTimer >= CleanupInterval) if (cleanupTimer >= CleanupInterval)
{ {
@@ -135,7 +186,15 @@ namespace ArachnaeSwarm
cleanupTimer = 0; cleanupTimer = 0;
} }
// === 新增:定期检查是否有科技因建筑损失而丢失 === // 反向校验计时器
reverseCheckTimer++;
if (reverseCheckTimer >= ReverseCheckInterval)
{
PerformReverseValidation();
reverseCheckTimer = 0;
}
// 科技丢失检查计时器
lostResearchCheckTimer++; lostResearchCheckTimer++;
if (lostResearchCheckTimer >= LostResearchCheckInterval) if (lostResearchCheckTimer >= LostResearchCheckInterval)
{ {
@@ -145,50 +204,238 @@ namespace ArachnaeSwarm
} }
/// <summary> /// <summary>
/// === 新增:检查建筑损失而丢失的科技 === /// === 新增:反向校验 - 管理器主动检查建筑状态 ===
/// </summary> /// </summary>
private void CheckForLostResearch() private void PerformReverseValidation()
{ {
if (researchBuildings == null || researchBuildings.Count == 0) if (allReaders == null || allReaders.Count == 0)
return; return;
ArachnaeLog.Debug($"[ResearchManager] Checking for lost research projects..."); ArachnaeLog.Debug($"[ResearchManager] Performing reverse validation on {allReaders.Count} buildings");
// 获取需要检查的项目列表(复制以避免修改时遍历) int invalidCount = 0;
var projectsToCheck = new List<ResearchProjectDef>(researchBuildings.Keys); int missingCount = 0;
foreach (var project in projectsToCheck) // 检查所有已注册的建筑
foreach (var building in allReaders.ToList()) // 使用副本避免修改时错误
{ {
if (project == null) if (building == null)
continue;
if (!researchBuildings.ContainsKey(project))
continue;
var buildings = researchBuildings[project];
if (buildings == null)
{ {
researchBuildings.Remove(project); invalidCount++;
RemoveDeadBuilding(building);
continue; continue;
} }
// 清理无效建筑 // 检查建筑是否仍然存在
buildings.RemoveAll(b => bool isValid = ValidateBuildingExistence(building);
b == null || b.Destroyed || !b.Spawned || b.Map == null);
// 如果已经没有建筑了 if (!isValid)
if (buildings.Count == 0) {
missingCount++;
// 更新建筑健康记录
UpdateBuildingHealthRecord(building, false);
// 如果建筑连续多次检查失败,则移除
if (ShouldRemoveBuilding(building))
{
RemoveDeadBuilding(building);
}
}
else
{
// 建筑有效,更新健康记录
UpdateBuildingHealthRecord(building, true);
}
}
if (invalidCount > 0 || missingCount > 0)
{
ArachnaeLog.Debug($"[ResearchManager] Reverse validation found {invalidCount} invalid and {missingCount} missing buildings");
}
}
/// <summary>
/// === 新增:验证建筑是否存在 ===
/// </summary>
private bool ValidateBuildingExistence(Building_ResearchBlueprintReader building)
{
if (building == null)
return false;
try
{
// 方法1检查建筑是否被标记为已摧毁
if (building.Destroyed)
{
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} is marked as destroyed");
return false;
}
// 方法2检查建筑是否在地图上
if (!building.Spawned)
{
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} is not spawned");
return false;
}
// 方法3检查建筑是否有效
if (building.Map == null)
{
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} has no map reference");
return false;
}
// 方法4检查建筑是否在地图建筑列表中
if (building.Map != null && !building.Map.listerBuildings.allBuildingsColonist.Contains(building))
{
// 建筑可能被取消、拆除或移动
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} not found in map building list");
return false;
}
return true;
}
catch (Exception ex)
{
ArachnaeLog.Debug($"[ResearchManager] Error validating building {building.ThingID}: {ex.Message}");
return false;
}
}
/// <summary>
/// === 新增:更新建筑健康记录 ===
/// </summary>
private void UpdateBuildingHealthRecord(Building_ResearchBlueprintReader building, bool isHealthy)
{
if (building == null)
return;
if (!buildingHealthRecords.ContainsKey(building))
{
buildingHealthRecords[building] = new BuildingHealthRecord();
}
var record = buildingHealthRecords[building];
record.LastCheckTick = Find.TickManager.TicksGame;
record.IsHealthy = isHealthy;
if (isHealthy)
{
record.ConsecutiveFailures = 0;
record.LastHealthyTick = Find.TickManager.TicksGame;
}
else
{
record.ConsecutiveFailures++;
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} health check failed {record.ConsecutiveFailures} times");
}
}
/// <summary>
/// === 新增:判断是否应该移除建筑 ===
/// </summary>
private bool ShouldRemoveBuilding(Building_ResearchBlueprintReader building)
{
if (building == null || !buildingHealthRecords.ContainsKey(building))
return true;
var record = buildingHealthRecords[building];
// 如果连续失败超过3次或者超过30秒没有健康状态
if (record.ConsecutiveFailures >= 3)
{
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} has {record.ConsecutiveFailures} consecutive failures, removing");
return true;
}
if (record.LastHealthyTick > 0 &&
Find.TickManager.TicksGame - record.LastHealthyTick > 1800) // 30秒
{
ArachnaeLog.Debug($"[ResearchManager] Building {building.ThingID} has been unhealthy for 30+ seconds, removing");
return true;
}
return false;
}
/// <summary>
/// === 新增:移除死亡建筑 ===
/// </summary>
private void RemoveDeadBuilding(Building_ResearchBlueprintReader building)
{
if (building == null)
return;
ArachnaeLog.Debug($"[ResearchManager] Removing dead building: {building.ThingID}");
// 从所有列表中移除
allReaders.Remove(building);
buildingHealthRecords.Remove(building);
// 从研究项目中移除
var project = building.StoredResearch;
if (project != null && researchBuildings.ContainsKey(project))
{
researchBuildings[project].Remove(building);
// 如果项目没有建筑了,检查是否丢失
if (researchBuildings[project].Count == 0)
{ {
researchBuildings.Remove(project); researchBuildings.Remove(project);
// 调用Patch创建的移除方法来丢失科技
OnResearchLostDueToBuildingLoss(project); OnResearchLostDueToBuildingLoss(project);
} }
} }
} }
/// <summary> /// <summary>
/// === 新增:科技因建筑损失而丢失的处理 === /// === 新增:加载后验证所有建筑 ===
/// </summary>
private void ValidateAllBuildings()
{
ArachnaeLog.Debug("[ResearchManager] Validating all buildings after load");
// 验证所有已注册的建筑
foreach (var building in allReaders.ToList())
{
if (!ValidateBuildingExistence(building))
{
ArachnaeLog.Debug($"[ResearchManager] Invalid building detected after load: {building.ThingID}");
RemoveDeadBuilding(building);
}
else
{
UpdateBuildingHealthRecord(building, true);
}
}
// 清理无效的建筑健康记录
var invalidRecords = buildingHealthRecords.Keys.Where(b => b == null || b.Destroyed).ToList();
foreach (var building in invalidRecords)
{
buildingHealthRecords.Remove(building);
}
ArachnaeLog.Debug($"[ResearchManager] Validation complete: {allReaders.Count} valid buildings, {buildingHealthRecords.Count} health records");
}
/// <summary>
/// 检查因建筑损失而丢失的科技
/// </summary>
private void CheckForLostResearch()
{
if (researchBuildings == null || researchBuildings.Count == 0)
return;
// 只记录调试信息,不重复执行
if (Find.TickManager.TicksGame % 60000 == 0) // 每分钟记录一次
{
ArachnaeLog.Debug($"[ResearchManager] Research status: {researchBuildings.Count} active projects");
}
}
/// <summary>
/// 科技因建筑损失而丢失的处理
/// </summary> /// </summary>
private void OnResearchLostDueToBuildingLoss(ResearchProjectDef project) private void OnResearchLostDueToBuildingLoss(ResearchProjectDef project)
{ {
@@ -233,7 +480,7 @@ namespace ArachnaeSwarm
if (allReaders != null) if (allReaders != null)
{ {
removedCount += allReaders.RemoveAll(b => removedCount += allReaders.RemoveAll(b =>
b == null || b.Destroyed || !b.Spawned || b.Map == null); b == null || b.Destroyed);
if (removedCount > 0) if (removedCount > 0)
{ {
@@ -260,7 +507,7 @@ namespace ArachnaeSwarm
// 清理无效建筑 // 清理无效建筑
kvp.Value.RemoveAll(b => kvp.Value.RemoveAll(b =>
b == null || b.Destroyed || !b.Spawned || b.Map == null); b == null || b.Destroyed);
if (kvp.Value.Count == 0) if (kvp.Value.Count == 0)
{ {
@@ -289,6 +536,20 @@ namespace ArachnaeSwarm
{ {
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>(); researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
} }
// 清理建筑健康记录
if (buildingHealthRecords != null)
{
var keysToRemove = buildingHealthRecords.Keys.Where(k => k == null || k.Destroyed).ToList();
foreach (var key in keysToRemove)
{
buildingHealthRecords.Remove(key);
}
}
else
{
buildingHealthRecords = new Dictionary<Building_ResearchBlueprintReader, BuildingHealthRecord>();
}
} }
/// <summary> /// <summary>
@@ -296,7 +557,7 @@ namespace ArachnaeSwarm
/// </summary> /// </summary>
public void RegisterReader(Building_ResearchBlueprintReader reader) public void RegisterReader(Building_ResearchBlueprintReader reader)
{ {
if (reader == null || reader.Destroyed || !reader.Spawned) if (reader == null || reader.Destroyed)
return; return;
// 防止重复注册 // 防止重复注册
@@ -308,6 +569,19 @@ namespace ArachnaeSwarm
if (!allReaders.Contains(reader)) if (!allReaders.Contains(reader))
{ {
allReaders.Add(reader); allReaders.Add(reader);
// 初始化健康记录
if (!buildingHealthRecords.ContainsKey(reader))
{
buildingHealthRecords[reader] = new BuildingHealthRecord
{
LastHealthyTick = Find.TickManager.TicksGame,
LastCheckTick = Find.TickManager.TicksGame,
IsHealthy = true,
ConsecutiveFailures = 0
};
}
ArachnaeLog.Debug($"[ResearchManager] Registered reader: {reader.ThingID} at position {reader.Position}"); ArachnaeLog.Debug($"[ResearchManager] Registered reader: {reader.ThingID} at position {reader.Position}");
} }
} }
@@ -370,10 +644,34 @@ namespace ArachnaeSwarm
{ {
allReaders.Remove(building); allReaders.Remove(building);
} }
// 从健康记录中移除
if (buildingHealthRecords != null)
{
buildingHealthRecords.Remove(building);
}
} }
/// <summary> /// <summary>
/// === 新增:获取指定科技的建筑数量 === /// === 新增:建筑健康心跳 - 建筑主动报告 ===
/// </summary>
public void ReportBuildingHealth(Building_ResearchBlueprintReader building)
{
if (building == null)
return;
if (buildingHealthRecords.ContainsKey(building))
{
var record = buildingHealthRecords[building];
record.LastHealthyTick = Find.TickManager.TicksGame;
record.LastCheckTick = Find.TickManager.TicksGame;
record.IsHealthy = true;
record.ConsecutiveFailures = 0;
}
}
/// <summary>
/// 获取指定科技的建筑数量
/// </summary> /// </summary>
public int GetBuildingCountForResearch(ResearchProjectDef project) public int GetBuildingCountForResearch(ResearchProjectDef project)
{ {
@@ -384,37 +682,12 @@ namespace ArachnaeSwarm
} }
/// <summary> /// <summary>
/// === 新增:手动触发科技丢失检查(用于调试) === /// === 新增:手动触发反向校验(用于调试) ===
/// </summary> /// </summary>
public void DebugTriggerLostResearchCheck() public void DebugTriggerReverseValidation()
{ {
ArachnaeLog.Debug("[ResearchManager] Manual trigger of lost research check"); ArachnaeLog.Debug("[ResearchManager] Manual trigger of reverse validation");
CheckForLostResearch(); PerformReverseValidation();
}
/// <summary>
/// === 新增:强制移除某个科技(用于调试) ===
/// </summary>
public void DebugForceRemoveResearch(ResearchProjectDef project)
{
if (project == null)
return;
ArachnaeLog.Debug($"[ResearchManager] Debug force remove research: {project.defName}");
// 从字典中移除
if (researchBuildings.ContainsKey(project))
{
researchBuildings.Remove(project);
}
// 使用ResearchRemover移除科技
ResearchRemover.RemoveResearchProject(project, removeDependencies: false);
Messages.Message(
$"Debug: Research '{project.LabelCap}' has been forcibly removed.",
MessageTypeDefOf.NeutralEvent
);
} }
/// <summary> /// <summary>
@@ -431,6 +704,7 @@ namespace ArachnaeSwarm
ArachnaeLog.Debug("=== Research Manager Status ==="); ArachnaeLog.Debug("=== Research Manager Status ===");
ArachnaeLog.Debug($"Total buildings: {Instance.allReaders?.Count ?? 0}"); ArachnaeLog.Debug($"Total buildings: {Instance.allReaders?.Count ?? 0}");
ArachnaeLog.Debug($"Active research projects: {Instance.researchBuildings?.Count ?? 0}"); ArachnaeLog.Debug($"Active research projects: {Instance.researchBuildings?.Count ?? 0}");
ArachnaeLog.Debug($"Building health records: {Instance.buildingHealthRecords?.Count ?? 0}");
if (Instance.researchBuildings != null) if (Instance.researchBuildings != null)
{ {
@@ -442,6 +716,39 @@ namespace ArachnaeSwarm
ArachnaeLog.Debug($" - {kvp.Key.defName}: {activeBuildings} active buildings"); ArachnaeLog.Debug($" - {kvp.Key.defName}: {activeBuildings} active buildings");
} }
} }
// 显示建筑健康状态
if (Instance.buildingHealthRecords != null && Instance.buildingHealthRecords.Count > 0)
{
ArachnaeLog.Debug("=== Building Health Status ===");
foreach (var kvp in Instance.buildingHealthRecords)
{
if (kvp.Key == null) continue;
string status = kvp.Value.IsHealthy ? "Healthy" : "Unhealthy";
string timeSinceHealthy = (Find.TickManager.TicksGame - kvp.Value.LastHealthyTick).ToStringTicksToPeriod();
ArachnaeLog.Debug($" - {kvp.Key.ThingID}: {status}, Failures: {kvp.Value.ConsecutiveFailures}, Last healthy: {timeSinceHealthy} ago");
}
}
}
}
/// <summary>
/// === 新增:建筑健康记录类 ===
/// </summary>
public class BuildingHealthRecord : IExposable
{
public int LastCheckTick = 0;
public int LastHealthyTick = 0;
public bool IsHealthy = false;
public int ConsecutiveFailures = 0;
public void ExposeData()
{
Scribe_Values.Look(ref LastCheckTick, "LastCheckTick", 0);
Scribe_Values.Look(ref LastHealthyTick, "LastHealthyTick", 0);
Scribe_Values.Look(ref IsHealthy, "IsHealthy", false);
Scribe_Values.Look(ref ConsecutiveFailures, "ConsecutiveFailures", 0);
} }
} }
} }