This commit is contained in:
2026-02-07 11:57:23 +08:00
parent 0ce702b9cc
commit b26761a848
13 changed files with 70 additions and 1090 deletions

Binary file not shown.

View File

@@ -1621,27 +1621,33 @@
</comps>
</AbilityDef>
<AbilityDef>
<defName>ARA_Locust_Needle_Fire</defName>
<label>毒针射击</label>
<description>阿拉克涅蝗虫种使用可以喷射剧毒尾针的毒针腺对敌方进行一轮射击</description>
<writeCombatLog>True</writeCombatLog>
<showPsycastEffects>False</showPsycastEffects>
<cooldownTicksRange>90</cooldownTicksRange>
<defName>ARA_Locust_AcidSprayBurst</defName>
<label>酸液喷洒</label>
<description>阿拉克涅蝗虫种向目标地点喷射腐蚀性酸液</description>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_AcidSprayBurst</iconPath>
<cooldownTicksRange>180</cooldownTicksRange>
<aiCanUse>true</aiCanUse>
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Toxic_Needle_Fire</iconPath>
<displayOrder>300</displayOrder>
<warmupStartSound>AcidSpray_Warmup</warmupStartSound>
<verbProperties>
<verbClass>Verb_CastAbility</verbClass>
<range>24</range>
<warmupTime>0</warmupTime>
<soundCast>SpitterSpit</soundCast>
<soundCastTail>Heatspikes_Tail</soundCastTail>
<range>16</range>
<warmupTime>0.01</warmupTime>
<soundCast>AcidSpray_Resolve</soundCast>
<targetParams>
<canTargetPawns>True</canTargetPawns>
<canTargetLocations>true</canTargetLocations>
</targetParams>
</verbProperties>
<comps>
<li Class="CompProperties_AbilityLaunchProjectile">
<projectileDef>Bullet_ARA_RW_Basic_Fist_Needle_Gun</projectileDef>
<li Class="ArachnaeSwarm.CompProperties_AbilitySprayLiquidMulti">
<!-- CompProperties_AbilitySprayLiquid 的属性 -->
<projectileDef>ARA_Proj_StrongSludgeSpray</projectileDef>
<numCellsToHit>4</numCellsToHit>
<sprayEffecter>AcidSpray_Directional</sprayEffecter>
<!-- CompProperties_AbilitySprayLiquidMulti 新增的属性 -->
<shotCount>1</shotCount> <!-- 总共发射5次 -->
<ticksBetweenShots>3</ticksBetweenShots> <!-- 每次发射间隔12 Ticks (0.2秒) -->
</li>
</comps>
</AbilityDef>

View File

@@ -683,7 +683,7 @@
</li>
</lifeStages>
<abilities>
<li>ARA_Locust_Needle_Fire</li>
<li>ARA_Locust_AcidSprayBurst</li>
</abilities>
</PawnKindDef>

View File

@@ -126,99 +126,4 @@
<traverseSound>TraversePitGate</traverseSound>
</portal>
</ThingDef>
<ThingDef>
<defName>ARA_WormholePortal_Spawner</defName>
<label>掘进中的虫洞</label>
<description>一只阿拉克涅坑道种的尾部正在地下活动——毫无疑问,它很快就要破土而出了!</description>
<thingClass>ArachnaeSwarm.BuildingGroundSpawner_WormholePortal</thingClass>
<destroyable>false</destroyable>
<holdsRoof>true</holdsRoof>
<selectable>true</selectable>
<tickerType>Normal</tickerType>
<useHitPoints>false</useHitPoints>
<drawerType>RealtimeOnly</drawerType>
<size>(2, 2)</size>
<uiIconPath>UI/Icons/UndergroundEmergence</uiIconPath>
<building>
<groundSpawnerSustainedEffecter>EmergencePointSustained2X2</groundSpawnerSustainedEffecter>
<groundSpawnerCompleteEffecter>EmergencePointComplete2X2</groundSpawnerCompleteEffecter>
<groundSpawnerThingToSpawn>ARA_WormholePortal_B</groundSpawnerThingToSpawn>
<groundSpawnerSpawnDelay>600</groundSpawnerSpawnDelay>
<groundSpawnerDestroyAdjacent>true</groundSpawnerDestroyAdjacent>
<groundSpawnerSustainerSound>PitBurrowOpening</groundSpawnerSustainerSound>
</building>
<modExtensions>
<li Class="ArachnaeSwarm.WormholePortalSpawnerExtension">
<minEmergeDelayTicks>600</minEmergeDelayTicks>
<maxEmergeDelayTicks>600</maxEmergeDelayTicks>
<requiresOpenSky>false</requiresOpenSky>
<minSpaceRadius>3</minSpaceRadius>
<destroyTerrain>true</destroyTerrain>
<destroyBuildings>false</destroyBuildings>
</li>
</modExtensions>
</ThingDef>
<ThingDef ParentName="BuildingBase">
<defName>ARA_WormholePortal_Enermy</defName>
<label>阿拉克涅坑道种尾部出口</label>
<description>阿拉克涅坑道种的尾巴,是其狭长身躯形成的地下通路的出口。</description>
<rotatable>false</rotatable>
<graphicData>
<texPath>ArachnaeSwarm/Building/ARA_Wormhole_B</texPath>
<graphicClass>Graphic_Single</graphicClass>
<shaderType>CutoutComplex</shaderType>
<drawSize>(4,4)</drawSize>
<shadowData>
<volume>(2.6, 2.5, 1.6)</volume>
<offset>(0,0,-0.1)</offset>
</shadowData>
</graphicData>
<altitudeLayer>Building</altitudeLayer>
<passability>Impassable</passability>
<statBases>
<MaxHitPoints>500</MaxHitPoints>
<Flammability>0.5</Flammability>
</statBases>
<size>(2,2)</size>
<comps>
<li Class="ArachnaeSwarm.CompProperties_WormholePortal">
<initialDelayTicks>60</initialDelayTicks>
<jumpIntervalTicks>30</jumpIntervalTicks>
<stunDurationTicks>60</stunDurationTicks>
<deactivationDelayTicks>120</deactivationDelayTicks>
<!-- <activationSound>PsycastPsychicPulse</activationSound>
<deactivationSound>PsycastPsychicPulse</deactivationSound>
<jumpSound>PsycastPsychicPulse</jumpSound> -->
<!-- <activationEffecter>PsycastPsychicPulse</activationEffecter>
<deactivationEffecter>PsycastPsychicPulse</deactivationEffecter> -->
<!-- <perJumpEffecter>PsycastSkipEffect</perJumpEffecter>
<jumpEffecter>PawnFlyerLanding</jumpEffecter> -->
<useColorCycling>false</useColorCycling>
<!-- <colorCycleSpeed>0.5</colorCycleSpeed> -->
</li>
</comps>
<tradeability>None</tradeability>
</ThingDef>
<!-- 到达模式定义 -->
<PawnsArrivalModeDef>
<defName>ARA_WormholePortal</defName>
<label>虫洞传送门</label>
<description>通过虫洞传送门到达</description>
<workerClass>ArachnaeSwarm.PawnsArrivalModeWorker_WormholePortal</workerClass>
<selectionWeightCurve>
<points>
<li>(0, 0)</li>
<li>(500, 0.3)</li>
<li>(1000, 0.5)</li>
<li>(2000, 0.7)</li>
</points>
</selectionWeightCurve>
<forQuickMilitaryAid>false</forQuickMilitaryAid>
<techLevel>Industrial</techLevel>
</PawnsArrivalModeDef>
</Defs>

View File

@@ -3097,7 +3097,7 @@
<targetAcquireRadius>65</targetAcquireRadius>
<targetKeepRadius>72</targetKeepRadius>
<skipIfCantTargetNow>false</skipIfCantTargetNow>
<ability>ARA_Locust_Needle_Fire</ability>
<ability>ARA_Locust_AcidSprayBurst</ability>
<allowTurrets>true</allowTurrets>
<needLOSToAcquireNonPawnTargets>true</needLOSToAcquireNonPawnTargets>
</li>
@@ -3117,10 +3117,6 @@
<subNodes>
<li Class="ArachnaeSwarm.ThinkNode_ConditionalShouldFollowProducer">
<subNodes>
<!-- <li Class="ArachnaeSwarm.JobGiver_AIDefendProducer">
<attackMeleeThreatEvenIfNotHostile>true</attackMeleeThreatEvenIfNotHostile>
<defendRadius>100</defendRadius>
</li> -->
<!-- Keep distance -->
<li Class="JobGiver_FleeForDistance">
<enemyDistToFleeRange>2.9~7.9</enemyDistToFleeRange>
@@ -3135,10 +3131,14 @@
<targetAcquireRadius>65</targetAcquireRadius>
<targetKeepRadius>72</targetKeepRadius>
<skipIfCantTargetNow>false</skipIfCantTargetNow>
<ability>ARA_Locust_Needle_Fire</ability>
<ability>ARA_Locust_AcidSprayBurst</ability>
<allowTurrets>true</allowTurrets>
<needLOSToAcquireNonPawnTargets>true</needLOSToAcquireNonPawnTargets>
</li>
<li Class="ArachnaeSwarm.JobGiver_AIDefendProducer">
<attackMeleeThreatEvenIfNotHostile>true</attackMeleeThreatEvenIfNotHostile>
<defendRadius>100</defendRadius>
</li>
<li Class="ArachnaeSwarm.JobGiver_AIFollowProducer"/>
<li Class="ArachnaeSwarm.JobGiver_WanderNearProducer"/>
</subNodes>

View File

@@ -3,19 +3,15 @@
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawnsarrivalmode\\pawnsarrivalmodeworker_wormholeportal.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawnsarrivalmode\\pawnsarrivalmodeworker_wormholeportal.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\\buildings\\wormhole\\travelingwormhole.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\wormhole\\travelingwormhole.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\\building_comps\\ara_wormholeportal\\comp_wormholeportal.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_wormholeportal\\comp_wormholeportal.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\\buildings\\wormhole\\complaunchablewormhole.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:buildings\\wormhole\\complaunchablewormhole.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\\building_comps\\ara_wormholeportal\\compproperties_wormholeportal.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\ara_wormholeportal\\compproperties_wormholeportal.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_uniquepawn\\uniquepawnmanager.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_uniquepawn\\uniquepawnmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_uniquepawn\\uniquepawnmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
},
{
@@ -123,45 +119,32 @@
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "PawnsArrivalModeWorker_WormholePortal.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PawnsArrivalMode\\PawnsArrivalModeWorker_WormholePortal.cs",
"RelativeDocumentMoniker": "PawnsArrivalMode\\PawnsArrivalModeWorker_WormholePortal.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PawnsArrivalMode\\PawnsArrivalModeWorker_WormholePortal.cs",
"RelativeToolTip": "PawnsArrivalMode\\PawnsArrivalModeWorker_WormholePortal.cs",
"ViewState": "AgIAADEBAAAAAAAAAAAkwEABAABSAAAAAAAAAA==",
"Title": "TravelingWormhole.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\TravelingWormhole.cs",
"RelativeDocumentMoniker": "Buildings\\Wormhole\\TravelingWormhole.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\TravelingWormhole.cs",
"RelativeToolTip": "Buildings\\Wormhole\\TravelingWormhole.cs",
"ViewState": "AgIAADsAAAAAAAAAAAAuwEAAAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T09:04:02.296Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 2,
"Title": "CompProperties_WormholePortal.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_WormholePortal\\CompProperties_WormholePortal.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_WormholePortal\\CompProperties_WormholePortal.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_WormholePortal\\CompProperties_WormholePortal.cs",
"RelativeToolTip": "Building_Comps\\ARA_WormholePortal\\CompProperties_WormholePortal.cs",
"ViewState": "AgIAAAMAAAAAAAAAAAAuwBoAAAAIAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T09:03:50.674Z",
"WhenOpened": "2026-02-07T03:22:07.586Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "Comp_WormholePortal.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_WormholePortal\\Comp_WormholePortal.cs",
"RelativeDocumentMoniker": "Building_Comps\\ARA_WormholePortal\\Comp_WormholePortal.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\ARA_WormholePortal\\Comp_WormholePortal.cs",
"RelativeToolTip": "Building_Comps\\ARA_WormholePortal\\Comp_WormholePortal.cs",
"ViewState": "AgIAABQBAAAAAAAAAAAowCcBAAAJAAAAAAAAAA==",
"Title": "CompLaunchableWormhole.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\CompLaunchableWormhole.cs",
"RelativeDocumentMoniker": "Buildings\\Wormhole\\CompLaunchableWormhole.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Buildings\\Wormhole\\CompLaunchableWormhole.cs",
"RelativeToolTip": "Buildings\\Wormhole\\CompLaunchableWormhole.cs",
"ViewState": "AgIAACEAAAAAAAAAAAAAACEAAABrAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-06T09:01:19.98Z",
"WhenOpened": "2026-02-07T03:22:06.34Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 3,
"DocumentIndex": 2,
"Title": "UniquePawnManager.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs",
@@ -169,12 +152,11 @@
"RelativeToolTip": "Pawn_Comps\\ARA_UniquePawn\\UniquePawnManager.cs",
"ViewState": "AgIAAHQAAAAAAAAAAAAiwJEAAAAJAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2026-02-05T03:36:35.207Z",
"EditorCaption": ""
"WhenOpened": "2026-02-05T03:36:35.207Z"
},
{
"$type": "Document",
"DocumentIndex": 4,
"DocumentIndex": 3,
"Title": "CompUniquePawn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_UniquePawn\\CompUniquePawn.cs",
@@ -186,7 +168,7 @@
},
{
"$type": "Document",
"DocumentIndex": 6,
"DocumentIndex": 5,
"Title": "JobDriver_ExtractHoney.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
"RelativeDocumentMoniker": "Jobs\\JobDriver_ExtractHoney\\JobDriver_ExtractHoney.cs",
@@ -198,7 +180,7 @@
},
{
"$type": "Document",
"DocumentIndex": 5,
"DocumentIndex": 4,
"Title": "Need_HoneyProduction.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_HoneyProduction.cs",
"RelativeDocumentMoniker": "Needs\\Need_HoneyProduction.cs",
@@ -210,7 +192,7 @@
},
{
"$type": "Document",
"DocumentIndex": 7,
"DocumentIndex": 6,
"Title": "Need_ChitinArmor.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Needs\\Need_ChitinArmor.cs",
"RelativeDocumentMoniker": "Needs\\Need_ChitinArmor.cs",
@@ -222,7 +204,7 @@
},
{
"$type": "Document",
"DocumentIndex": 9,
"DocumentIndex": 8,
"Title": "CompProperties_AbilityPsychicLoadDump.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompProperties_AbilityPsychicLoadDump.cs",
@@ -234,7 +216,7 @@
},
{
"$type": "Document",
"DocumentIndex": 8,
"DocumentIndex": 7,
"Title": "CompAbilityEffect_PsychicLoadDump.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadDump\\CompAbilityEffect_PsychicLoadDump.cs",
@@ -246,7 +228,7 @@
},
{
"$type": "Document",
"DocumentIndex": 13,
"DocumentIndex": 12,
"Title": "CompAbilityEffect_PsychicResearchHarvest.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompAbilityEffect_PsychicResearchHarvest.cs",
@@ -258,7 +240,7 @@
},
{
"$type": "Document",
"DocumentIndex": 17,
"DocumentIndex": 16,
"Title": "CompProperties_AbilityPsychicLoadCost.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompProperties_AbilityPsychicLoadCost.cs",
@@ -270,7 +252,7 @@
},
{
"$type": "Document",
"DocumentIndex": 16,
"DocumentIndex": 15,
"Title": "SwarmSpellUtility.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\SwarmSpellUtility.cs",
@@ -282,7 +264,7 @@
},
{
"$type": "Document",
"DocumentIndex": 12,
"DocumentIndex": 11,
"Title": "CompAbilityEffect_PsychicLoadCost.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicLoadCost\\CompAbilityEffect_PsychicLoadCost.cs",
@@ -294,7 +276,7 @@
},
{
"$type": "Document",
"DocumentIndex": 10,
"DocumentIndex": 9,
"Title": "Comp_SwarmSpellHolder.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Comp_SwarmSpellHolder.cs",
@@ -306,7 +288,7 @@
},
{
"$type": "Document",
"DocumentIndex": 11,
"DocumentIndex": 10,
"Title": "Gizmo_SwarmSpellStatus.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_SwarmSpellHolder\\Gizmo_SwarmSpellStatus.cs",
@@ -318,7 +300,7 @@
},
{
"$type": "Document",
"DocumentIndex": 18,
"DocumentIndex": 17,
"Title": "CompAbilityEffect_HediffGacha.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\CompAbilityEffect_HediffGacha.cs",
@@ -330,7 +312,7 @@
},
{
"$type": "Document",
"DocumentIndex": 15,
"DocumentIndex": 14,
"Title": "CompFighterInvisible.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_Fighter_Invisible\\CompFighterInvisible.cs",
@@ -342,7 +324,7 @@
},
{
"$type": "Document",
"DocumentIndex": 14,
"DocumentIndex": 13,
"Title": "CompProperties_AbilityPsychicResearchHarvest.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_PsychicResearchHarvest\\CompProperties_AbilityPsychicResearchHarvest.cs",
@@ -354,7 +336,7 @@
},
{
"$type": "Document",
"DocumentIndex": 19,
"DocumentIndex": 18,
"Title": "CompAbilityEffect_HediffRestriction.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffRestriction\\CompAbilityEffect_HediffRestriction.cs",
@@ -366,7 +348,7 @@
},
{
"$type": "Document",
"DocumentIndex": 20,
"DocumentIndex": 19,
"Title": "Window_HediffSelection.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_HediffGacha\\Window_HediffSelection.cs",
@@ -378,7 +360,7 @@
},
{
"$type": "Document",
"DocumentIndex": 21,
"DocumentIndex": 20,
"Title": "ARA_PowerArmor.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PowerArmor\\ARA_PowerArmor.cs",
"RelativeDocumentMoniker": "PowerArmor\\ARA_PowerArmor.cs",
@@ -390,7 +372,7 @@
},
{
"$type": "Document",
"DocumentIndex": 22,
"DocumentIndex": 21,
"Title": "PawnCapacityWorker_PsychicStange.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs",
"RelativeDocumentMoniker": "PawnCapacityWorker\\PawnCapacityWorker_PsychicStange.cs",
@@ -402,7 +384,7 @@
},
{
"$type": "Document",
"DocumentIndex": 24,
"DocumentIndex": 23,
"Title": "CompAbilityEffect_PsychicBrainburn.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs",
"RelativeDocumentMoniker": "Abilities\\PsychicBrainburn\\CompAbilityEffect_PsychicBrainburn.cs",
@@ -414,7 +396,7 @@
},
{
"$type": "Document",
"DocumentIndex": 23,
"DocumentIndex": 22,
"Title": "ARA_DefOf.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
"RelativeDocumentMoniker": "ARA_DefOf.cs",
@@ -426,7 +408,7 @@
},
{
"$type": "Document",
"DocumentIndex": 25,
"DocumentIndex": 24,
"Title": "CompAutoMechCarrier.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",

View File

@@ -42,13 +42,9 @@
<Compile Include="Abilities\ARA_PsychicLoadDump\CompProperties_AbilityPsychicLoadDump.cs" />
<Compile Include="Abilities\ARA_PsychicResearchHarvest\CompAbilityEffect_PsychicResearchHarvest.cs" />
<Compile Include="Abilities\ARA_PsychicResearchHarvest\CompProperties_AbilityPsychicResearchHarvest.cs" />
<Compile Include="Buildings\BuildingGroundSpawner_WormholePortal.cs" />
<Compile Include="Buildings\Building_CorpseVat\Building_CorpseVat.cs" />
<Compile Include="Buildings\Building_CorpseVat\CorpseVatExtension.cs" />
<Compile Include="Buildings\Building_CorpseVat\JobDriver_HaulCorpseToVat.cs" />
<Compile Include="Building_Comps\ARA_WormholePortal\CompProperties_WormholePortal.cs" />
<Compile Include="Building_Comps\ARA_WormholePortal\Comp_WormholePortal.cs" />
<Compile Include="Building_Comps\ARA_WormholePortal\WormholePortalSpawnerExtension.cs" />
<Compile Include="Damage\DamageDefExtension_TerrainCover.cs" />
<Compile Include="Damage\DamageWorker_ExplosionWithTerrain.cs" />
<Compile Include="Hediffs\ARA_GestaltNode\CompGestalt.cs" />
@@ -343,7 +339,6 @@
<Compile Include="Needs\Need_ChitinArmor.cs" />
<Compile Include="Needs\Need_HoneyProduction.cs" />
<Compile Include="PawnCapacityWorker\PawnCapacityWorker_PsychicStange.cs" />
<Compile Include="PawnsArrivalMode\PawnsArrivalModeWorker_WormholePortal.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompAutoMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProducedByMechCarrier.cs" />
<Compile Include="Pawn_Comps\ARA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />

View File

@@ -1,91 +0,0 @@
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 虫洞传送门组件属性
/// </summary>
public class CompProperties_WormholePortal : CompProperties
{
#region
/// <summary>
/// 初始延迟ticks
/// </summary>
public int initialDelayTicks = 60; // 1秒
/// <summary>
/// 单位跳出间隔ticks
/// </summary>
public int jumpIntervalTicks = 30; // 0.5秒
/// <summary>
/// 单位跳出时的眩晕时间ticks
/// </summary>
public int stunDurationTicks = 60; // 1秒
#endregion
#region
/// <summary>
/// 激活音效
/// </summary>
public SoundDef activationSound = null;
/// <summary>
/// 停用音效
/// </summary>
public SoundDef deactivationSound = null;
/// <summary>
/// 跳出音效
/// </summary>
public SoundDef jumpSound = null;
/// <summary>
/// 激活效果器
/// </summary>
public EffecterDef activationEffecter = null;
/// <summary>
/// 停用效果器
/// </summary>
public EffecterDef deactivationEffecter = null;
/// <summary>
/// 每次跳出效果器
/// </summary>
public EffecterDef perJumpEffecter = null;
/// <summary>
/// 单位跳出效果器
/// </summary>
public EffecterDef jumpEffecter = null;
#endregion
#region
/// <summary>
/// 活跃时的材质
/// </summary>
public GraphicData activeGraphicData = null;
/// <summary>
/// 颜色循环
/// </summary>
public bool useColorCycling = true;
/// <summary>
/// 颜色循环速度
/// </summary>
public float colorCycleSpeed = 0.5f;
#endregion
#region
public CompProperties_WormholePortal()
{
compClass = typeof(Comp_WormholePortal);
}
#endregion
}
}

View File

@@ -1,336 +0,0 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.Sound;
namespace ArachnaeSwarm
{
/// <summary>
/// 虫洞传送门组件
/// 处理从虫洞中跳出单位
/// </summary>
public class Comp_WormholePortal : ThingComp
{
#region
private List<Pawn> emergingPawns = new List<Pawn>();
private int currentPawnIndex = 0;
private int ticksUntilNextJump = 0;
private bool isActive = false;
private int activateTick = -1;
#endregion
#region
public CompProperties_WormholePortal Props => (CompProperties_WormholePortal)props;
/// <summary>
/// 还有多少单位等待跳出
/// </summary>
public int RemainingPawns => emergingPawns.Count - currentPawnIndex;
/// <summary>
/// 虫洞是否活跃
/// </summary>
public bool IsActive => isActive;
/// <summary>
/// 激活后经过的时间
/// </summary>
public int TicksSinceActivation
{
get
{
if (!isActive || activateTick < 0)
return 0;
return Find.TickManager.TicksGame - activateTick;
}
}
#endregion
#region
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
if (respawningAfterLoad)
return;
// 非加载生成时,准备激活
PrepareForActivation();
}
public override void CompTick()
{
base.CompTick();
if (!isActive || emergingPawns.NullOrEmpty() || currentPawnIndex >= emergingPawns.Count)
return;
// 计时下一个单位跳出
if (ticksUntilNextJump > 0)
{
ticksUntilNextJump--;
return;
}
// 跳出当前单位
JumpNextPawn();
// 设置下一个单位的跳出间隔
if (currentPawnIndex < emergingPawns.Count)
{
ticksUntilNextJump = Props.jumpIntervalTicks;
}
}
public void PostDeSpawn(Map map)
{
// 虫洞消失时,销毁剩余未跳出的单位
DestroyRemainingPawns();
}
public override void PostDestroy(DestroyMode mode, Map previousMap)
{
base.PostDestroy(mode, previousMap);
// 虫洞被摧毁时,销毁剩余未跳出的单位
DestroyRemainingPawns();
}
#endregion
#region
/// <summary>
/// 设置要跳出的单位
/// </summary>
public void SetEmergingPawns(List<Pawn> pawns)
{
emergingPawns = pawns ?? new List<Pawn>();
currentPawnIndex = 0;
}
/// <summary>
/// 激活虫洞
/// </summary>
public void Activate()
{
if (isActive)
return;
isActive = true;
activateTick = Find.TickManager.TicksGame;
// 设置第一个单位的跳出计时
if (emergingPawns.Count > 0)
{
ticksUntilNextJump = Props.initialDelayTicks;
}
// 播放激活效果
PlayActivationEffects();
}
/// <summary>
/// 获取虫洞状态描述
/// </summary>
public string GetStatusDescription()
{
if (!isActive)
return "休眠中";
if (RemainingPawns <= 0)
return "已完成";
return $"跳出中: {RemainingPawns} 个单位剩余";
}
#endregion
#region
/// <summary>
/// 准备激活
/// </summary>
private void PrepareForActivation()
{
// 可以在这里添加预热效果
// 例如:粒子效果、声音等
}
/// <summary>
/// 跳出下一个单位
/// </summary>
private void JumpNextPawn()
{
if (currentPawnIndex >= emergingPawns.Count)
return;
Pawn pawn = emergingPawns[currentPawnIndex];
currentPawnIndex++;
// 确保单位存在且有效
if (pawn == null || pawn.Destroyed)
{
Log.Warning("[虫洞传送门] 尝试跳出无效单位");
return;
}
// 生成单位
TrySpawnPawn(pawn);
// 播放跳出效果
PlayJumpEffects();
// 如果所有单位都已跳出,关闭虫洞
if (currentPawnIndex >= emergingPawns.Count)
{
StartDeactivation();
}
}
/// <summary>
/// 尝试生成单位
/// </summary>
private void TrySpawnPawn(Pawn pawn)
{
try
{
Map map = parent.Map;
if (map == null)
return;
// 找到虫洞周围的可行走位置
if (CellFinder.TryFindRandomCellNear(parent.Position, map, 2,
c => c.Walkable(map) && c.InBounds(map) && !c.Fogged(map), out IntVec3 spawnCell))
{
// 生成单位
GenSpawn.Spawn(pawn, spawnCell, map);
// 应用跳出效果
ApplyJumpEffectsToPawn(pawn, spawnCell);
}
else
{
// 如果找不到位置,在虫洞位置生成
GenSpawn.Spawn(pawn, parent.Position, map);
Log.Warning($"[虫洞传送门] 无法找到合适位置,在虫洞位置生成 {pawn.Label}");
}
}
catch (System.Exception ex)
{
Log.Error($"[虫洞传送门] 跳出单位失败: {ex.Message}");
}
}
/// <summary>
/// 应用跳出效果给单位
/// </summary>
private void ApplyJumpEffectsToPawn(Pawn pawn, IntVec3 spawnCell)
{
// 短暂眩晕效果
if (Props.stunDurationTicks > 0)
{
pawn.stances.stunner.StunFor(Props.stunDurationTicks, parent);
}
// 播放音效
if (Props.jumpSound != null)
{
Props.jumpSound.PlayOneShot(new TargetInfo(spawnCell, parent.Map));
}
// 显示效果
if (Props.jumpEffecter != null)
{
Effecter effecter = Props.jumpEffecter.Spawn();
effecter.Trigger(new TargetInfo(spawnCell, parent.Map), new TargetInfo(spawnCell, parent.Map));
effecter.Cleanup();
}
}
/// <summary>
/// 播放激活效果
/// </summary>
private void PlayActivationEffects()
{
if (Props.activationSound != null)
{
Props.activationSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
if (Props.activationEffecter != null)
{
Effecter effecter = Props.activationEffecter.Spawn();
effecter.Trigger(new TargetInfo(parent.Position, parent.Map), new TargetInfo(parent.Position, parent.Map));
effecter.Cleanup();
}
}
/// <summary>
/// 播放跳出效果
/// </summary>
private void PlayJumpEffects()
{
if (Props.perJumpEffecter != null)
{
Effecter effecter = Props.perJumpEffecter.Spawn();
effecter.Trigger(new TargetInfo(parent.Position, parent.Map), new TargetInfo(parent.Position, parent.Map));
effecter.Cleanup();
}
}
/// <summary>
/// 开始停用虫洞
/// </summary>
private void StartDeactivation()
{
// 播放停用效果
if (Props.deactivationSound != null)
{
Props.deactivationSound.PlayOneShot(new TargetInfo(parent.Position, parent.Map));
}
if (Props.deactivationEffecter != null)
{
Effecter effecter = Props.deactivationEffecter.Spawn();
effecter.Trigger(new TargetInfo(parent.Position, parent.Map), new TargetInfo(parent.Position, parent.Map));
effecter.Cleanup();
}
}
/// <summary>
/// 销毁剩余未跳出的单位
/// </summary>
private void DestroyRemainingPawns()
{
if (emergingPawns.NullOrEmpty())
return;
for (int i = currentPawnIndex; i < emergingPawns.Count; i++)
{
Pawn pawn = emergingPawns[i];
if (pawn != null && !pawn.Destroyed)
{
pawn.Destroy();
}
}
}
#endregion
#region
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Collections.Look(ref emergingPawns, "emergingPawns", LookMode.Reference);
Scribe_Values.Look(ref currentPawnIndex, "currentPawnIndex", 0);
Scribe_Values.Look(ref ticksUntilNextJump, "ticksUntilNextJump", 0);
Scribe_Values.Look(ref isActive, "isActive", false);
Scribe_Values.Look(ref activateTick, "activateTick", -1);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
// 清理空引用
emergingPawns?.RemoveAll(p => p == null);
}
}
#endregion
}
}

View File

@@ -1,40 +0,0 @@
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 虫洞传送门生成器扩展
/// </summary>
public class WormholePortalSpawnerExtension : DefModExtension
{
/// <summary>
/// 最小跳出延迟ticks
/// </summary>
public int minEmergeDelayTicks = 180; // 3秒
/// <summary>
/// 最大跳出延迟ticks
/// </summary>
public int maxEmergeDelayTicks = 300; // 5秒
/// <summary>
/// 是否需要露天
/// </summary>
public bool requiresOpenSky = true;
/// <summary>
/// 最小空间半径
/// </summary>
public int minSpaceRadius = 3;
/// <summary>
/// 是否破坏地形
/// </summary>
public bool destroyTerrain = true;
/// <summary>
/// 是否破坏建筑
/// </summary>
public bool destroyBuildings = false;
}
}

View File

@@ -1,54 +0,0 @@
using RimWorld;
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 自定义虫洞传送门生成器
/// </summary>
public class BuildingGroundSpawner_WormholePortal : BuildingGroundSpawner
{
// 存储要传递的Pawn列表
public List<Pawn> emergingPawns = new List<Pawn>();
// 延迟参数
public IntRange? customEmergeDelay = null;
protected override void PostMakeInt()
{
base.PostMakeInt();
// 创建虫洞传送门
ThingDef portalDef = DefDatabase<ThingDef>.GetNamed("ARA_WormholePortal");
if (portalDef != null)
{
thingToSpawn = ThingMaker.MakeThing(portalDef);
// 设置Pawn列表
Comp_WormholePortal comp = thingToSpawn.TryGetComp<Comp_WormholePortal>();
if (comp != null && emergingPawns != null)
{
comp.SetEmergingPawns(emergingPawns);
}
}
}
protected override IntRange ResultSpawnDelay
{
get
{
if (customEmergeDelay.HasValue)
return customEmergeDelay.Value;
return base.ResultSpawnDelay;
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Collections.Look(ref emergingPawns, "emergingPawns", LookMode.Reference);
Scribe_Values.Look(ref customEmergeDelay, "customEmergeDelay");
}
}
}

View File

@@ -1,387 +0,0 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
namespace ArachnaeSwarm
{
/// <summary>
/// 虫洞传送门到达模式
/// 在地图边缘生成虫洞传送门生成器,预热后生成虫洞传送门,单位从虫洞中跳出
/// </summary>
public class PawnsArrivalModeWorker_WormholePortal : PawnsArrivalModeWorker
{
#region
private const float MIN_EDGE_DISTANCE = 5f; // 最小边缘距离
private const float MAX_EDGE_DISTANCE = 20f; // 最大边缘距离
private const int MIN_SPACE_RADIUS = 3; // 需要的最小空间半径
private const int MAX_SPAWNERS_PER_GROUP = 3; // 每组最大生成器数量
private const int DEFAULT_EMERGE_DELAY_TICKS = 60; // 默认跳出延迟1秒
#endregion
#region
/// <summary>
/// 单位到达
/// </summary>
public override void Arrive(List<Pawn> pawns, IncidentParms parms)
{
Map map = parms.target as Map;
if (map == null || pawns.NullOrEmpty())
return;
if (!TryResolveRaidSpawnCenter(parms))
return;
// 将Pawn分组每组由一个传送门生成器处理
List<List<Pawn>> pawnGroups = SplitPawnsIntoGroups(pawns, parms);
// 为每组生成一个虫洞传送门生成器
int spawnedCount = 0;
foreach (var group in pawnGroups)
{
if (TrySpawnWormholePortalGroup(group, parms))
{
spawnedCount++;
}
// 限制每组数量
if (spawnedCount >= MAX_SPAWNERS_PER_GROUP)
break;
}
}
/// <summary>
/// 旅行运输器到达
/// </summary>
public override void TravellingTransportersArrived(List<ActiveTransporterInfo> transporters, Map map)
{
// 虫洞传送门不支持运输器到达
Log.Warning("[虫洞传送门] 不支持运输器到达模式");
base.TravellingTransportersArrived(transporters, map);
}
/// <summary>
/// 尝试解析袭击生成中心
/// </summary>
public override bool TryResolveRaidSpawnCenter(IncidentParms parms)
{
Map map = parms.target as Map;
if (map == null)
return false;
// 如果没有指定生成中心,找到地图边缘的位置
if (!parms.spawnCenter.IsValid)
{
if (!TryFindEdgeSpawnCenter(map, out IntVec3 spawnCenter))
{
// 如果找不到边缘位置,使用默认的掉落中心
spawnCenter = DropCellFinder.FindRaidDropCenterDistant(map);
}
parms.spawnCenter = spawnCenter;
}
parms.spawnRotation = Rot4.Random;
return true;
}
/// <summary>
/// 判断是否可以在指定地图使用
/// </summary>
public override bool CanUseOnMap(Map map)
{
// 检查地图是否允许此到达模式
if (map == null)
return false;
// 检查是否有足够的空间生成虫洞
return HasEnoughSpaceForWormhole(map);
}
#endregion
#region
/// <summary>
/// 将Pawn分成组
/// </summary>
private List<List<Pawn>> SplitPawnsIntoGroups(List<Pawn> pawns, IncidentParms parms)
{
List<List<Pawn>> groups = new List<List<Pawn>>();
if (pawns.NullOrEmpty())
return groups;
// 根据点数计算每组大小
int groupSize = CalculateGroupSize(parms);
// 如果组大小为1或更小每个Pawn单独一组
if (groupSize <= 1)
{
foreach (var pawn in pawns)
{
groups.Add(new List<Pawn> { pawn });
}
return groups;
}
// 分组
List<Pawn> currentGroup = new List<Pawn>();
foreach (var pawn in pawns)
{
currentGroup.Add(pawn);
if (currentGroup.Count >= groupSize)
{
groups.Add(currentGroup);
currentGroup = new List<Pawn>();
}
}
// 添加剩余的Pawn
if (currentGroup.Count > 0)
{
groups.Add(currentGroup);
}
return groups;
}
/// <summary>
/// 计算每组大小
/// </summary>
private int CalculateGroupSize(IncidentParms parms)
{
// 根据点数动态调整组大小
float points = parms.points;
if (points <= 500f)
return 1;
else if (points <= 1000f)
return 2;
else if (points <= 2000f)
return 3;
else
return 4;
}
/// <summary>
/// 尝试生成虫洞传送门组
/// </summary>
private bool TrySpawnWormholePortalGroup(List<Pawn> pawns, IncidentParms parms)
{
Map map = parms.target as Map;
if (map == null || pawns.NullOrEmpty())
return false;
// 找到合适的生成位置(靠近边缘,有足够空间)
if (!TryFindWormholeSpawnPosition(map, out IntVec3 spawnPosition))
return false;
// 创建虫洞传送门生成器
return SpawnWormholePortalSpawner(map, spawnPosition, pawns, parms);
}
/// <summary>
/// 尝试找到虫洞生成位置
/// </summary>
private bool TryFindWormholeSpawnPosition(Map map, out IntVec3 spawnPosition)
{
spawnPosition = IntVec3.Invalid;
// 尝试在地图边缘区域查找
// 使用CellRect.WholeMap而不是CellsInMapRandomOrder
CellRect mapRect = CellRect.WholeMap(map);
// 定义边缘区域(地图边界向内一定距离)
int edgeWidth = 5;
CellRect edgeRect = new CellRect(
edgeWidth,
edgeWidth,
map.Size.x - edgeWidth * 2,
map.Size.z - edgeWidth * 2);
// 在地图边界但不是边缘区域内部查找
for (int attempts = 0; attempts < 30; attempts++)
{
IntVec3 candidate;
// 随机选择边界
if (Rand.Value < 0.25f) // 北边界
{
candidate = new IntVec3(Rand.Range(0, map.Size.x), 0, map.Size.z - 1);
}
else if (Rand.Value < 0.5f) // 南边界
{
candidate = new IntVec3(Rand.Range(0, map.Size.x), 0, 0);
}
else if (Rand.Value < 0.75f) // 东边界
{
candidate = new IntVec3(map.Size.x - 1, 0, Rand.Range(0, map.Size.z));
}
else // 西边界
{
candidate = new IntVec3(0, 0, Rand.Range(0, map.Size.z));
}
// 检查位置是否有效
if (IsValidWormholePosition(candidate, map))
{
spawnPosition = candidate;
return true;
}
}
// 如果找不到边界位置,尝试在地图任意位置查找
for (int attempts = 0; attempts < 20; attempts++)
{
IntVec3 candidate = CellFinder.RandomCell(map);
if (IsValidWormholePosition(candidate, map))
{
spawnPosition = candidate;
return true;
}
}
return false;
}
/// <summary>
/// 检查是否为有效的虫洞位置
/// </summary>
private bool IsValidWormholePosition(IntVec3 position, Map map)
{
if (!position.InBounds(map))
return false;
if (!position.Standable(map))
return false;
if (position.Fogged(map))
return false;
// 检查是否有足够的空间3x3区域
CellRect requiredRect = new CellRect(position.x - 1, position.z - 1, 3, 3);
// 修复:检查矩形是否完全包含在地图内
if (!requiredRect.InBounds(map))
return false;
// 检查区域内所有单元格是否都可行走
foreach (IntVec3 cell in requiredRect)
{
if (!cell.InBounds(map) || !cell.Walkable(map))
return false;
// 检查是否有其他建筑阻挡
if (cell.GetEdifice(map) != null)
return false;
// 检查是否有屋顶(虫洞需要露天)
if (cell.Roofed(map))
return false;
}
return true;
}
/// <summary>
/// 生成虫洞传送门生成器
/// </summary>
private bool SpawnWormholePortalSpawner(Map map, IntVec3 position, List<Pawn> pawns, IncidentParms parms)
{
try
{
ThingDef spawnerDef = DefDatabase<ThingDef>.GetNamedSilentFail("ARA_WormholePortal_Spawner");
if (spawnerDef == null)
{
Log.Error("[虫洞传送门] 未找到ARA_WormholePortal_Spawner定义");
return false;
}
// 创建自定义生成器
BuildingGroundSpawner_WormholePortal spawner = (BuildingGroundSpawner_WormholePortal)ThingMaker.MakeThing(spawnerDef);
// 设置参数
spawner.emergingPawns = pawns;
// 设置延迟
WormholePortalSpawnerExtension spawnerExt = spawnerDef.GetModExtension<WormholePortalSpawnerExtension>();
if (spawnerExt != null)
{
spawner.customEmergeDelay = new IntRange(
spawnerExt.minEmergeDelayTicks,
spawnerExt.maxEmergeDelayTicks);
}
// 生成到地图
GenSpawn.Spawn(spawner, position, map);
return true;
}
catch (System.Exception ex)
{
Log.Error($"[虫洞传送门] 生成虫洞传送门生成器失败: {ex.Message}\n{ex.StackTrace}");
return false;
}
}
/// <summary>
/// 尝试找到边缘生成中心
/// </summary>
private bool TryFindEdgeSpawnCenter(Map map, out IntVec3 spawnCenter)
{
spawnCenter = IntVec3.Invalid;
// 尝试在地图四个边缘区域查找
List<IntVec3> edgeCells = new List<IntVec3>();
// 北边缘
for (int x = 0; x < map.Size.x; x += 5)
{
IntVec3 cell = new IntVec3(x, 0, map.Size.z - 1);
if (cell.InBounds(map) && cell.Walkable(map) && !cell.Fogged(map))
edgeCells.Add(cell);
}
// 南边缘
for (int x = 0; x < map.Size.x; x += 5)
{
IntVec3 cell = new IntVec3(x, 0, 0);
if (cell.InBounds(map) && cell.Walkable(map) && !cell.Fogged(map))
edgeCells.Add(cell);
}
// 东边缘
for (int z = 0; z < map.Size.z; z += 5)
{
IntVec3 cell = new IntVec3(map.Size.x - 1, 0, z);
if (cell.InBounds(map) && cell.Walkable(map) && !cell.Fogged(map))
edgeCells.Add(cell);
}
// 西边缘
for (int z = 0; z < map.Size.z; z += 5)
{
IntVec3 cell = new IntVec3(0, 0, z);
if (cell.InBounds(map) && cell.Walkable(map) && !cell.Fogged(map))
edgeCells.Add(cell);
}
if (edgeCells.Count > 0)
{
spawnCenter = edgeCells.RandomElement();
return true;
}
return false;
}
/// <summary>
/// 检查地图是否有足够的空间生成虫洞
/// </summary>
private bool HasEnoughSpaceForWormhole(Map map)
{
// 简单检查:地图是否至少有一定大小
return map.Size.x >= 50 && map.Size.z >= 50;
}
#endregion
}
}