1
This commit is contained in:
Binary file not shown.
@@ -943,22 +943,30 @@
|
|||||||
<displayGizmoWhileUndrafted>false</displayGizmoWhileUndrafted>
|
<displayGizmoWhileUndrafted>false</displayGizmoWhileUndrafted>
|
||||||
<aiCanUse>false</aiCanUse>
|
<aiCanUse>false</aiCanUse>
|
||||||
<verbProperties>
|
<verbProperties>
|
||||||
<verbClass>Verb_AbilityShoot</verbClass>
|
<verbClass>Verb_CastAbility</verbClass>
|
||||||
<defaultProjectile>Bullet_ARA_MimicNematode_Needle</defaultProjectile>
|
|
||||||
<range>5</range>
|
<range>5</range>
|
||||||
|
<warmupTime>0.1</warmupTime>
|
||||||
<soundCast>Heatspikes_Shot</soundCast>
|
<soundCast>Heatspikes_Shot</soundCast>
|
||||||
<soundCastTail>Heatspikes_Tail</soundCastTail>
|
<soundCastTail>Heatspikes_Tail</soundCastTail>
|
||||||
<muzzleFlashScale>9</muzzleFlashScale>
|
<violent>false</violent>
|
||||||
<ticksBetweenBurstShots>2</ticksBetweenBurstShots>
|
<targetable>false</targetable>
|
||||||
<warmupTime>0</warmupTime>
|
<targetParams>
|
||||||
<burstShotCount>32</burstShotCount>
|
<canTargetSelf>true</canTargetSelf>
|
||||||
<accuracyTouch>1</accuracyTouch>
|
</targetParams>
|
||||||
<accuracyShort>1</accuracyShort>
|
|
||||||
<accuracyMedium>1</accuracyMedium>
|
|
||||||
<accuracyLong>1</accuracyLong>
|
|
||||||
<ai_IsWeapon>false</ai_IsWeapon>
|
|
||||||
</verbProperties>
|
</verbProperties>
|
||||||
<comps>
|
<comps>
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_AbilityLaunchMultiProjectile">
|
||||||
|
<!-- 默认状态参数 -->
|
||||||
|
<projectileDef>Bullet_ARA_MimicNematode_Needle</projectileDef>
|
||||||
|
<numProjectiles>32</numProjectiles>
|
||||||
|
|
||||||
|
<!-- 偏移配置 -->
|
||||||
|
<offsetRadius>1</offsetRadius>
|
||||||
|
<useRandomOffset>true</useRandomOffset>
|
||||||
|
<offsetInCircle>true</offsetInCircle>
|
||||||
|
<avoidOverlap>false</avoidOverlap>
|
||||||
|
<shotIntervalTicks>3</shotIntervalTicks>
|
||||||
|
</li>
|
||||||
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
|
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
|
||||||
<customLabel>饮食</customLabel>
|
<customLabel>饮食</customLabel>
|
||||||
<showProgressBar>true</showProgressBar>
|
<showProgressBar>true</showProgressBar>
|
||||||
@@ -975,6 +983,52 @@
|
|||||||
</li>
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
</AbilityDef>
|
</AbilityDef>
|
||||||
|
<AbilityDef>
|
||||||
|
<defName>ARA_SymbioticStabilizer</defName>
|
||||||
|
<label>拟线控制</label>
|
||||||
|
<description>向目标注射阿拉克涅拟线种的控制溶液,溶液将保证目标不会因为阿拉克涅拟线种在体内的扩散而死亡。</description>
|
||||||
|
<iconPath>ArachnaeSwarm/UI/Abilities/ARA_Dissolver_Touch</iconPath>
|
||||||
|
<cooldownTicksRange>6000</cooldownTicksRange>
|
||||||
|
<charges>5</charges>
|
||||||
|
<cooldownPerCharge>true</cooldownPerCharge>
|
||||||
|
<hostile>false</hostile>
|
||||||
|
<casterMustBeCapableOfViolence>false</casterMustBeCapableOfViolence>
|
||||||
|
<stunTargetWhileCasting>true</stunTargetWhileCasting>
|
||||||
|
<aiCanUse>true</aiCanUse>
|
||||||
|
<!-- <warmupStartSound>AcidSpray_Warmup</warmupStartSound> -->
|
||||||
|
<jobDef>CastAbilityOnThingMelee</jobDef>
|
||||||
|
<verbProperties>
|
||||||
|
<verbClass>Verb_CastAbilityTouch</verbClass>
|
||||||
|
<violent>false</violent>
|
||||||
|
<forceNormalTimeSpeed>false</forceNormalTimeSpeed>
|
||||||
|
<warmupTime>0.5</warmupTime>
|
||||||
|
<range>-1</range>
|
||||||
|
<requireLineOfSight>false</requireLineOfSight>
|
||||||
|
<soundCast>AcidSpray_Resolve</soundCast>
|
||||||
|
<targetParams>
|
||||||
|
<canTargetPawns>true</canTargetPawns>
|
||||||
|
<canTargetAnimals>true</canTargetAnimals>
|
||||||
|
<canTargetMechs>false</canTargetMechs>
|
||||||
|
<canTargetSubhumans>true</canTargetSubhumans>
|
||||||
|
<canTargetEntities>false</canTargetEntities>
|
||||||
|
<canTargetBuildings>false</canTargetBuildings>
|
||||||
|
</targetParams>
|
||||||
|
</verbProperties>
|
||||||
|
<comps>
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_AbilityNeedCost">
|
||||||
|
<customLabel>饮食</customLabel>
|
||||||
|
<showProgressBar>true</showProgressBar>
|
||||||
|
<needDef>Food</needDef>
|
||||||
|
<needCost>0.2</needCost>
|
||||||
|
<failMessage>营养值不足,需要进食</failMessage>
|
||||||
|
</li>
|
||||||
|
<li Class="CompProperties_AbilityGiveHediff">
|
||||||
|
<compClass>CompAbilityEffect_GiveHediff</compClass>
|
||||||
|
<hediffDef>ARA_SymbioticStabilizer</hediffDef>
|
||||||
|
<replaceExisting>true</replaceExisting>
|
||||||
|
</li>
|
||||||
|
</comps>
|
||||||
|
</AbilityDef>
|
||||||
<ThingDef ParentName="BaseBullet">
|
<ThingDef ParentName="BaseBullet">
|
||||||
<defName>Bullet_ARA_MimicNematode_Needle</defName>
|
<defName>Bullet_ARA_MimicNematode_Needle</defName>
|
||||||
<label>拟线种寄生针</label>
|
<label>拟线种寄生针</label>
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Defs>
|
|
||||||
<IncidentDef>
|
|
||||||
<defName>ARA_Loop_Raid_Incident</defName>
|
|
||||||
<label>虫群袭击</label>
|
|
||||||
<category>Misc</category>
|
|
||||||
<targetTags>
|
|
||||||
<li>Map_PlayerHome</li>
|
|
||||||
</targetTags>
|
|
||||||
|
|
||||||
<!-- This uses the vanilla quest giver worker -->
|
|
||||||
<workerClass>IncidentWorker_GiveQuest</workerClass>
|
|
||||||
|
|
||||||
<!-- This points to our custom QuestScriptDef -->
|
|
||||||
<questScriptDef>ARA_Loop_Raid_Quest</questScriptDef>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
<baseChance>1.0</baseChance>
|
|
||||||
<earliestDay>0.001</earliestDay>
|
|
||||||
<minRefireDays>99999</minRefireDays>
|
|
||||||
-->
|
|
||||||
</IncidentDef>
|
|
||||||
<QuestScriptDef>
|
|
||||||
<defName>ARA_Loop_Raid_Quest</defName>
|
|
||||||
<label>虫群袭击</label>
|
|
||||||
<description>虫群袭击description</description>
|
|
||||||
<root Class="QuestNode_Sequence">
|
|
||||||
<nodes>
|
|
||||||
<li Class="QuestNode_ResolveQuestName">
|
|
||||||
<rules>
|
|
||||||
<rulesStrings>
|
|
||||||
<li>questName->虫群袭击</li>
|
|
||||||
</rulesStrings>
|
|
||||||
</rules>
|
|
||||||
</li>
|
|
||||||
<li Class="QuestNode_ResolveQuestDescription">
|
|
||||||
<rules>
|
|
||||||
<rulesStrings>
|
|
||||||
<li>questDescription->虫群袭击questDescription</li>
|
|
||||||
</rulesStrings>
|
|
||||||
</rules>
|
|
||||||
</li>
|
|
||||||
<li Class="ArachnaeSwarm.QuestNode_Root_EventLetter">
|
|
||||||
<letterLabel>虫群袭击Label</letterLabel>
|
|
||||||
<letterTitle>虫群袭击Title</letterTitle>
|
|
||||||
<letterText>虫群袭击Text</letterText>
|
|
||||||
<options>
|
|
||||||
<li>
|
|
||||||
<label>袭击开始</label>
|
|
||||||
<optionEffects>
|
|
||||||
<li>
|
|
||||||
<effects>
|
|
||||||
<li Class="ArachnaeSwarm.Effect_OpenCustomUI">
|
|
||||||
<defName>ARA_Loop_Raid_Main_Event_1</defName>
|
|
||||||
</li>
|
|
||||||
</effects>
|
|
||||||
</li>
|
|
||||||
</optionEffects>
|
|
||||||
</li>
|
|
||||||
</options>
|
|
||||||
</li>
|
|
||||||
</nodes>
|
|
||||||
</root>
|
|
||||||
</QuestScriptDef>
|
|
||||||
<ArachnaeSwarm.EventDef>
|
|
||||||
<defName>ARA_Loop_Raid_Main_Event_1</defName>
|
|
||||||
<characterName>嘻嘻</characterName>
|
|
||||||
<hiddenWindow>true</hiddenWindow>
|
|
||||||
<immediateEffects>
|
|
||||||
<li>
|
|
||||||
<!-- 系统会从这个列表中根据权重随机选择一个执行 -->
|
|
||||||
<randomlistEffects>
|
|
||||||
<li Class="ArachnaeSwarm.Effect_TriggerRaid">
|
|
||||||
<points>10000</points>
|
|
||||||
<faction>ARA_Hostile_Hive</faction>
|
|
||||||
<raidStrategy>ImmediateAttack</raidStrategy>
|
|
||||||
<raidArrivalMode>EdgeWalkIn</raidArrivalMode>
|
|
||||||
<groupKind>Combat</groupKind>
|
|
||||||
<pawnGroupMakers>
|
|
||||||
<li>
|
|
||||||
<kindDef>Combat</kindDef>
|
|
||||||
<commonality>100</commonality>
|
|
||||||
<options>
|
|
||||||
<ArachnaeBase_Race_Acidcut_Enermy>7</ArachnaeBase_Race_Acidcut_Enermy>
|
|
||||||
<ArachnaeNode_Race_ShieldHead_Enermy>3</ArachnaeNode_Race_ShieldHead_Enermy>
|
|
||||||
</options>
|
|
||||||
</li>
|
|
||||||
</pawnGroupMakers>
|
|
||||||
</li>
|
|
||||||
</randomlistEffects>
|
|
||||||
<effects>
|
|
||||||
</effects>
|
|
||||||
</li>
|
|
||||||
</immediateEffects>
|
|
||||||
</ArachnaeSwarm.EventDef>
|
|
||||||
</Defs>
|
|
||||||
@@ -221,6 +221,7 @@
|
|||||||
<li Class="HediffCompProperties_GiveAbility">
|
<li Class="HediffCompProperties_GiveAbility">
|
||||||
<abilityDefs>
|
<abilityDefs>
|
||||||
<li>ARA_MimicNematode_Needle_Fire</li>
|
<li>ARA_MimicNematode_Needle_Fire</li>
|
||||||
|
<li>ARA_SymbioticStabilizer</li>
|
||||||
</abilityDefs>
|
</abilityDefs>
|
||||||
</li>
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<Defs>
|
|
||||||
|
|
||||||
<ArachnaeSwarm.EventUIConfigDef>
|
|
||||||
<defName>ARA_EventUIConfig</defName>
|
|
||||||
|
|
||||||
<!-- General Style -->
|
|
||||||
<labelFont>Small</labelFont>
|
|
||||||
<drawBorders>false</drawBorders>
|
|
||||||
<showDefName>false</showDefName>
|
|
||||||
<showLabel>true</showLabel>
|
|
||||||
<defaultBackgroundImagePath></defaultBackgroundImagePath>
|
|
||||||
|
|
||||||
<!-- Virtual Layout Dimensions -->
|
|
||||||
<lihuiSize>(500, 800)</lihuiSize>
|
|
||||||
<nameSize>(650, 130)</nameSize>
|
|
||||||
<textSize>(650, 350)</textSize>
|
|
||||||
<optionsWidth>750</optionsWidth>
|
|
||||||
|
|
||||||
<!-- Virtual Layout Offsets -->
|
|
||||||
<textNameOffset>0</textNameOffset>
|
|
||||||
<optionsTextOffset>0</optionsTextOffset>
|
|
||||||
|
|
||||||
<defaultWindowSize>(750, 600)</defaultWindowSize>
|
|
||||||
|
|
||||||
<!-- New Layout Dimensions -->
|
|
||||||
<newLayoutNameSize>(200, 50)</newLayoutNameSize>
|
|
||||||
<newLayoutLihuiSize>(600, 200)</newLayoutLihuiSize>
|
|
||||||
<newLayoutTextSize>(600, 200)</newLayoutTextSize>
|
|
||||||
<newLayoutOptionsWidth>600</newLayoutOptionsWidth>
|
|
||||||
<newLayoutPadding>20</newLayoutPadding>
|
|
||||||
<newLayoutTextNameOffset>20</newLayoutTextNameOffset>
|
|
||||||
<newLayoutOptionsTextOffset>20</newLayoutOptionsTextOffset>
|
|
||||||
|
|
||||||
</ArachnaeSwarm.EventUIConfigDef>
|
|
||||||
|
|
||||||
</Defs>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<Defs>
|
|
||||||
<LetterDef>
|
|
||||||
<defName>ARA_EventChoiceLetter</defName>
|
|
||||||
<letterClass>ArachnaeSwarm.Letter_EventChoice</letterClass>
|
|
||||||
<arriveSound>LetterArrive_Good</arriveSound>
|
|
||||||
<color>(120, 150, 255)</color>
|
|
||||||
</LetterDef>
|
|
||||||
</Defs>
|
|
||||||
@@ -774,6 +774,7 @@
|
|||||||
<body>ArachnaeMyrmecocystus_Body</body>
|
<body>ArachnaeMyrmecocystus_Body</body>
|
||||||
<!-- 血量上限 -->
|
<!-- 血量上限 -->
|
||||||
<baseHealthScale>2</baseHealthScale>
|
<baseHealthScale>2</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -927,6 +928,7 @@
|
|||||||
<baseBodySize>1.5</baseBodySize>
|
<baseBodySize>1.5</baseBodySize>
|
||||||
<!-- 血量上限 -->
|
<!-- 血量上限 -->
|
||||||
<baseHealthScale>3</baseHealthScale>
|
<baseHealthScale>3</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1041,6 +1043,7 @@
|
|||||||
<body>ArachnaeWeaponSmith_Body</body>
|
<body>ArachnaeWeaponSmith_Body</body>
|
||||||
<baseBodySize>0.8</baseBodySize>
|
<baseBodySize>0.8</baseBodySize>
|
||||||
<baseHealthScale>0.75</baseHealthScale>
|
<baseHealthScale>0.75</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1187,6 +1190,7 @@
|
|||||||
<body>ArachnaeFighter_Body</body>
|
<body>ArachnaeFighter_Body</body>
|
||||||
<baseBodySize>0.7</baseBodySize>
|
<baseBodySize>0.7</baseBodySize>
|
||||||
<baseHealthScale>3</baseHealthScale>
|
<baseHealthScale>3</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1313,6 +1317,7 @@
|
|||||||
<body>ArachnaeFacehugger_Body</body>
|
<body>ArachnaeFacehugger_Body</body>
|
||||||
<baseBodySize>0.5</baseBodySize>
|
<baseBodySize>0.5</baseBodySize>
|
||||||
<baseHealthScale>0.25</baseHealthScale>
|
<baseHealthScale>0.25</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
<comps>
|
<comps>
|
||||||
<li Class="ArachnaeSwarm.CompProperties_HediffGiver">
|
<li Class="ArachnaeSwarm.CompProperties_HediffGiver">
|
||||||
@@ -1394,6 +1399,7 @@
|
|||||||
<!-- 身体类型 -->
|
<!-- 身体类型 -->
|
||||||
<body>ArachnaeSmokepop_Body</body>
|
<body>ArachnaeSmokepop_Body</body>
|
||||||
<baseHealthScale>4</baseHealthScale>
|
<baseHealthScale>4</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1519,6 +1525,7 @@
|
|||||||
<flightStartChanceOnJobStart>1.0</flightStartChanceOnJobStart>
|
<flightStartChanceOnJobStart>1.0</flightStartChanceOnJobStart>
|
||||||
<!-- <baseBodySize>0.8</baseBodySize> -->
|
<!-- <baseBodySize>0.8</baseBodySize> -->
|
||||||
<baseHealthScale>2</baseHealthScale>
|
<baseHealthScale>2</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1735,6 +1742,7 @@
|
|||||||
<flightStartChanceOnJobStart>1.0</flightStartChanceOnJobStart>
|
<flightStartChanceOnJobStart>1.0</flightStartChanceOnJobStart>
|
||||||
<baseBodySize>0.8</baseBodySize>
|
<baseBodySize>0.8</baseBodySize>
|
||||||
<baseHealthScale>2</baseHealthScale>
|
<baseHealthScale>2</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
@@ -1942,6 +1950,7 @@
|
|||||||
<body>ArachnaePraetorian_Body</body>
|
<body>ArachnaePraetorian_Body</body>
|
||||||
<baseBodySize>2</baseBodySize>
|
<baseBodySize>2</baseBodySize>
|
||||||
<baseHealthScale>3</baseHealthScale>
|
<baseHealthScale>3</baseHealthScale>
|
||||||
|
<ageGenerationCurve Inherit="False" IsNull="True"/>
|
||||||
</race>
|
</race>
|
||||||
|
|
||||||
<comps>
|
<comps>
|
||||||
|
|||||||
@@ -84,15 +84,15 @@
|
|||||||
<defName>ARA_SymbioticStabilizer</defName>
|
<defName>ARA_SymbioticStabilizer</defName>
|
||||||
<label>信息素抑制</label>
|
<label>信息素抑制</label>
|
||||||
<labelNoun>一种信息素抑制效果</labelNoun>
|
<labelNoun>一种信息素抑制效果</labelNoun>
|
||||||
<description>阿拉克涅信息素溶剂的效果正在生效,它模拟了虫群的共生信号,抑制了体内寄生体的活性。在溶剂生效时,不会使得拟线种虫族寄生的进度超过80%。</description>
|
<description>阿拉克涅信息素溶剂的效果正在生效,它模拟了虫群的共生信号,抑制了体内寄生体的活性,不会使得拟线种虫族寄生的进度超过80%。</description>
|
||||||
<hediffClass>HediffWithComps</hediffClass>
|
<hediffClass>HediffWithComps</hediffClass>
|
||||||
<defaultLabelColor>(0.7, 1.0, 0.7)</defaultLabelColor>
|
<defaultLabelColor>(0.7, 1.0, 0.7)</defaultLabelColor>
|
||||||
<isBad>false</isBad>
|
<isBad>false</isBad>
|
||||||
<comps>
|
<comps>
|
||||||
<li Class="HediffCompProperties_SeverityPerDay">
|
<!-- <li Class="HediffCompProperties_SeverityPerDay">
|
||||||
<severityPerDay>-0.34</severityPerDay> <!-- 严重性每天降低0.34,大约3天从1.0掉到0 -->
|
<severityPerDay>-0.34</severityPerDay>
|
||||||
<showHoursToRecover>true</showHoursToRecover>
|
<showHoursToRecover>true</showHoursToRecover>
|
||||||
</li>
|
</li> -->
|
||||||
</comps>
|
</comps>
|
||||||
</HediffDef>
|
</HediffDef>
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -1,26 +1,42 @@
|
|||||||
{
|
{
|
||||||
"Version": 1,
|
"Version": 1,
|
||||||
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
|
"WorkspaceRootPath": "E:\\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\\safer_pawnflyer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_feedwithhoney\\thinknode_jobgiver_feedwithhoney.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_fanshapedstunknockback\\safer_pawnflyer.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_feedwithhoney\\thinknode_jobgiver_feedwithhoney.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\\compproperties_abilityfanshapedstunknockback.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_plant\\thinknode_conditionalanimalshoulddogrowingwork.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}"
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_plant\\thinknode_conditionalanimalshoulddogrowingwork.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\\hediffs\\ara_gestaltnode\\compgestalt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\jobs\\jobdriver_clean\\thinknode_conditionalanimalshoulddocleaningwork.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_gestaltnode\\compgestalt.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:jobs\\jobdriver_clean\\thinknode_conditionalanimalshoulddocleaningwork.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\\hediffs\\ara_hivemind\\hediff_hivemindmaster.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\hediffs\\ara_spawner\\hediffcomp_spawner.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_hivemind\\hediff_hivemindmaster.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:hediffs\\ara_spawner\\hediffcomp_spawner.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\\arachnaelog.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_trainingwork\\compadvancedtraining.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:arachnaelog.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_trainingwork\\compadvancedtraining.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\ara_showinteractivething\\compabilityeffect_showinteractivething.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_showinteractivething\\compabilityeffect_showinteractivething.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\ara_defof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:ara_defof.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_automechcarrier\\compautomechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_automechcarrier\\compautomechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\pawn_comps\\ara_automechcarrier\\compproducedbymechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:pawn_comps\\ara_automechcarrier\\compproducedbymechcarrier.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"DocumentGroupContainers": [
|
"DocumentGroupContainers": [
|
||||||
@@ -30,7 +46,7 @@
|
|||||||
"DocumentGroups": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": 2,
|
"SelectedChildIndex": 1,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
@@ -38,66 +54,120 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 1,
|
"DocumentIndex": 0,
|
||||||
"Title": "CompProperties_AbilityFanShapedStunKnockback.cs",
|
"Title": "ThinkNode_JobGiver_FeedWithHoney.cs",
|
||||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\ThinkNode_JobGiver_FeedWithHoney.cs",
|
||||||
"RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
|
"RelativeDocumentMoniker": "Jobs\\JobDriver_FeedWithHoney\\ThinkNode_JobGiver_FeedWithHoney.cs",
|
||||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_FeedWithHoney\\ThinkNode_JobGiver_FeedWithHoney.cs",
|
||||||
"RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\CompProperties_AbilityFanShapedStunKnockback.cs",
|
"RelativeToolTip": "Jobs\\JobDriver_FeedWithHoney\\ThinkNode_JobGiver_FeedWithHoney.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAAXAAAAAAAAAA==",
|
"ViewState": "AgIAAEsAAAAAAAAAAAAawGcAAAAZAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-03-27T07:30:03.977Z",
|
"WhenOpened": "2026-03-29T09:23:09.491Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 0,
|
"DocumentIndex": 1,
|
||||||
"Title": "Safer_PawnFlyer.cs",
|
"Title": "ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs",
|
||||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\Safer_PawnFlyer.cs",
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs",
|
||||||
"RelativeDocumentMoniker": "Abilities\\ARA_FanShapedStunKnockback\\Safer_PawnFlyer.cs",
|
"RelativeDocumentMoniker": "Jobs\\JobDriver_Plant\\ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs",
|
||||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_FanShapedStunKnockback\\Safer_PawnFlyer.cs",
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Plant\\ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs",
|
||||||
"RelativeToolTip": "Abilities\\ARA_FanShapedStunKnockback\\Safer_PawnFlyer.cs",
|
"RelativeToolTip": "Jobs\\JobDriver_Plant\\ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA0AAAAJAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAABQAAABPAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-03-27T07:30:02.935Z",
|
"WhenOpened": "2026-03-29T09:22:20.81Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 2,
|
"DocumentIndex": 2,
|
||||||
"Title": "CompGestalt.cs",
|
"Title": "ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs",
|
||||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\CompGestalt.cs",
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs",
|
||||||
"RelativeDocumentMoniker": "Hediffs\\ARA_GestaltNode\\CompGestalt.cs",
|
"RelativeDocumentMoniker": "Jobs\\JobDriver_Clean\\ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs",
|
||||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_GestaltNode\\CompGestalt.cs",
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Jobs\\JobDriver_Clean\\ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs",
|
||||||
"RelativeToolTip": "Hediffs\\ARA_GestaltNode\\CompGestalt.cs",
|
"RelativeToolTip": "Jobs\\JobDriver_Clean\\ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs",
|
||||||
"ViewState": "AgIAAEIAAAAAAAAAAAAQwD0AAABCAAAAAAAAAA==",
|
"ViewState": "AgIAAAoAAAAAAAAAAAAAABEAAAAgAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-03-27T03:57:27.664Z",
|
"WhenOpened": "2026-03-29T09:22:16.941Z",
|
||||||
"EditorCaption": ""
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 3,
|
"DocumentIndex": 3,
|
||||||
"Title": "Hediff_HiveMindMaster.cs",
|
"Title": "HediffComp_Spawner.cs",
|
||||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HiveMind\\Hediff_HiveMindMaster.cs",
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
|
||||||
"RelativeDocumentMoniker": "Hediffs\\ARA_HiveMind\\Hediff_HiveMindMaster.cs",
|
"RelativeDocumentMoniker": "Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
|
||||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_HiveMind\\Hediff_HiveMindMaster.cs",
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
|
||||||
"RelativeToolTip": "Hediffs\\ARA_HiveMind\\Hediff_HiveMindMaster.cs",
|
"RelativeToolTip": "Hediffs\\ARA_Spawner\\HediffComp_Spawner.cs",
|
||||||
"ViewState": "AgIAADQAAAAAAAAAAAAuwFkAAAAuAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAIcBAAAmAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-03-27T03:54:02.567Z"
|
"WhenOpened": "2026-03-29T09:22:11.004Z",
|
||||||
|
"EditorCaption": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$type": "Document",
|
"$type": "Document",
|
||||||
"DocumentIndex": 4,
|
"DocumentIndex": 4,
|
||||||
"Title": "ArachnaeLog.cs",
|
"Title": "CompAdvancedTraining.cs",
|
||||||
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ArachnaeLog.cs",
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_TrainingWork\\CompAdvancedTraining.cs",
|
||||||
"RelativeDocumentMoniker": "ArachnaeLog.cs",
|
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_TrainingWork\\CompAdvancedTraining.cs",
|
||||||
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ArachnaeLog.cs",
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_TrainingWork\\CompAdvancedTraining.cs",
|
||||||
"RelativeToolTip": "ArachnaeLog.cs",
|
"RelativeToolTip": "Pawn_Comps\\ARA_TrainingWork\\CompAdvancedTraining.cs",
|
||||||
"ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAANAAAAAAAAAA==",
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAYAAAAwAAAAAAAAAA==",
|
||||||
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
"WhenOpened": "2026-03-26T06:10:50.583Z"
|
"WhenOpened": "2026-03-29T09:21:10.952Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 5,
|
||||||
|
"Title": "CompAbilityEffect_ShowInteractiveThing.cs",
|
||||||
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowInteractiveThing\\CompAbilityEffect_ShowInteractiveThing.cs",
|
||||||
|
"RelativeDocumentMoniker": "Abilities\\ARA_ShowInteractiveThing\\CompAbilityEffect_ShowInteractiveThing.cs",
|
||||||
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowInteractiveThing\\CompAbilityEffect_ShowInteractiveThing.cs",
|
||||||
|
"RelativeToolTip": "Abilities\\ARA_ShowInteractiveThing\\CompAbilityEffect_ShowInteractiveThing.cs",
|
||||||
|
"ViewState": "AgIAAD4AAAAAAAAAAAAAAFIAAAAiAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-29T09:21:03.275Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 6,
|
||||||
|
"Title": "ARA_DefOf.cs",
|
||||||
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
|
||||||
|
"RelativeDocumentMoniker": "ARA_DefOf.cs",
|
||||||
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\ARA_DefOf.cs",
|
||||||
|
"RelativeToolTip": "ARA_DefOf.cs",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA4AAABAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-29T09:20:59.349Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 8,
|
||||||
|
"Title": "CompProducedByMechCarrier.cs",
|
||||||
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompProducedByMechCarrier.cs",
|
||||||
|
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompProducedByMechCarrier.cs",
|
||||||
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompProducedByMechCarrier.cs",
|
||||||
|
"RelativeToolTip": "Pawn_Comps\\ARA_AutoMechCarrier\\CompProducedByMechCarrier.cs",
|
||||||
|
"ViewState": "AgIAAJQAAAAAAAAAAAAowOoAAAARAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-29T09:06:28.908Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 7,
|
||||||
|
"Title": "CompAutoMechCarrier.cs",
|
||||||
|
"DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
|
||||||
|
"RelativeDocumentMoniker": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
|
||||||
|
"ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
|
||||||
|
"RelativeToolTip": "Pawn_Comps\\ARA_AutoMechCarrier\\CompAutoMechCarrier.cs",
|
||||||
|
"ViewState": "AgIAAIACAAAAAAAAAAAqwI8CAAAAAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2026-03-29T08:49:14.026Z",
|
||||||
|
"EditorCaption": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,19 +238,6 @@
|
|||||||
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\CompRefuelableWithKey.cs" />
|
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\CompRefuelableWithKey.cs" />
|
||||||
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\IFuelSource.cs" />
|
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\IFuelSource.cs" />
|
||||||
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\Patch_CompRefuelableWithKey.cs" />
|
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\Patch_CompRefuelableWithKey.cs" />
|
||||||
<Compile Include="EventSystem\CompOpenCustomUI.cs" />
|
|
||||||
<Compile Include="EventSystem\Condition.cs" />
|
|
||||||
<Compile Include="EventSystem\DebugActions.cs" />
|
|
||||||
<Compile Include="EventSystem\DelayedActionManager.cs" />
|
|
||||||
<Compile Include="EventSystem\Dialog_CustomDisplay.cs" />
|
|
||||||
<Compile Include="EventSystem\Dialog_ManageEventVariables.cs" />
|
|
||||||
<Compile Include="EventSystem\Dialog_NewLayoutDisplay.cs" />
|
|
||||||
<Compile Include="EventSystem\Effect.cs" />
|
|
||||||
<Compile Include="EventSystem\EventDef.cs" />
|
|
||||||
<Compile Include="EventSystem\EventUIConfigDef.cs" />
|
|
||||||
<Compile Include="EventSystem\EventVariableManager.cs" />
|
|
||||||
<Compile Include="EventSystem\Letter_EventChoice.cs" />
|
|
||||||
<Compile Include="EventSystem\QuestNode_Root_EventLetter.cs" />
|
|
||||||
<Compile Include="FacialAnimation\FaceAnimationStaticGenerator.cs" />
|
<Compile Include="FacialAnimation\FaceAnimationStaticGenerator.cs" />
|
||||||
<Compile Include="Flyover\ARA_AircraftHangar\CompAbilityEffect_AircraftStrike.cs" />
|
<Compile Include="Flyover\ARA_AircraftHangar\CompAbilityEffect_AircraftStrike.cs" />
|
||||||
<Compile Include="Flyover\ARA_AircraftHangar\CompAircraftHangar.cs" />
|
<Compile Include="Flyover\ARA_AircraftHangar\CompAircraftHangar.cs" />
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
using System; // Required for Activator
|
|
||||||
using RimWorld;
|
|
||||||
using Verse;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Verse.AI;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class CompProperties_OpenCustomUI : CompProperties
|
|
||||||
{
|
|
||||||
public string uiDefName;
|
|
||||||
public string label; // The text to display in the float menu
|
|
||||||
public string failReason; // Optional: Custom text to show if the pawn can't reach the building
|
|
||||||
|
|
||||||
public CompProperties_OpenCustomUI()
|
|
||||||
{
|
|
||||||
this.compClass = typeof(CompOpenCustomUI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CompOpenCustomUI : ThingComp
|
|
||||||
{
|
|
||||||
public CompProperties_OpenCustomUI Props => (CompProperties_OpenCustomUI)this.props;
|
|
||||||
|
|
||||||
public override IEnumerable<FloatMenuOption> CompFloatMenuOptions(Pawn selPawn)
|
|
||||||
{
|
|
||||||
// Check if the pawn can interact with the building
|
|
||||||
if (!selPawn.CanReserveAndReach(this.parent, PathEndMode.InteractionCell, Danger.Deadly))
|
|
||||||
{
|
|
||||||
string reason = Props.failReason ?? "CannotUseNoPath".Translate();
|
|
||||||
yield return new FloatMenuOption(reason, null);
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for power if the building has a power component
|
|
||||||
CompPowerTrader powerComp = this.parent.GetComp<CompPowerTrader>();
|
|
||||||
if (powerComp != null && !powerComp.PowerOn)
|
|
||||||
{
|
|
||||||
yield return new FloatMenuOption("CannotUseNoPower".Translate(), null);
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string label = Props.label ?? "Open Custom UI"; // Use default label if not provided
|
|
||||||
|
|
||||||
FloatMenuOption option = new FloatMenuOption(label, delegate()
|
|
||||||
{
|
|
||||||
EventDef uiDef = DefDatabase<EventDef>.GetNamed(Props.uiDefName, false);
|
|
||||||
if (uiDef != null)
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add((Window)Activator.CreateInstance(uiDef.windowType, uiDef));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[CompOpenCustomUI] Could not find EventDef named '{Props.uiDefName}'.");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
yield return option;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
using Verse;
|
|
||||||
using RimWorld;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public abstract class Condition
|
|
||||||
{
|
|
||||||
public abstract bool IsMet(out string reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableEquals : Condition
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public string value;
|
|
||||||
public string valueVariableName;
|
|
||||||
|
|
||||||
public override bool IsMet(out string reason)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!eventVarManager.HasVariable(name))
|
|
||||||
{
|
|
||||||
reason = $"Variable '{name}' not found.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
object variable = eventVarManager.GetVariable<object>(name);
|
|
||||||
string compareValueStr = value;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(valueVariableName))
|
|
||||||
{
|
|
||||||
compareValueStr = eventVarManager.GetVariable<object>(valueVariableName)?.ToString();
|
|
||||||
if (compareValueStr == null)
|
|
||||||
{
|
|
||||||
reason = $"Comparison variable '{valueVariableName}' not set.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool met = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (variable is int)
|
|
||||||
{
|
|
||||||
met = (int)variable == int.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else if (variable is float)
|
|
||||||
{
|
|
||||||
met = (float)variable == float.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else if (variable is bool)
|
|
||||||
{
|
|
||||||
met = (bool)variable == bool.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
met = variable?.ToString() == compareValueStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Condition_VariableEquals: Could not compare '{variable}' and '{compareValueStr}'. Error: {e.Message}");
|
|
||||||
reason = "Type mismatch or parsing error during comparison.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!met)
|
|
||||||
{
|
|
||||||
reason = $"Requires {name} = {compareValueStr} (Current: {variable})";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
}
|
|
||||||
return met;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class Condition_CompareVariable : Condition
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public float value;
|
|
||||||
public string valueVariableName;
|
|
||||||
|
|
||||||
protected abstract bool Compare(float var1, float var2);
|
|
||||||
protected abstract string GetOperatorString();
|
|
||||||
|
|
||||||
public override bool IsMet(out string reason)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!eventVarManager.HasVariable(name))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] {GetType().Name}: Variable '{name}' not found, defaulting to 0f.");
|
|
||||||
eventVarManager.SetVariable(name, 0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
float variable = eventVarManager.GetVariable<float>(name);
|
|
||||||
|
|
||||||
float compareValue = value;
|
|
||||||
if (!string.IsNullOrEmpty(valueVariableName))
|
|
||||||
{
|
|
||||||
compareValue = eventVarManager.GetVariable<float>(valueVariableName, float.NaN);
|
|
||||||
if (float.IsNaN(compareValue))
|
|
||||||
{
|
|
||||||
reason = $"Comparison variable '{valueVariableName}' not set or not a number.";
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] {GetType().Name} check for '{name}' failed: {reason}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool met = Compare(variable, compareValue);
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] {GetType().Name} check: Name='{name}', CurrentValue='{variable}', CompareValue='{compareValue}', Met={met}");
|
|
||||||
if (!met)
|
|
||||||
{
|
|
||||||
reason = $"Requires {name} {GetOperatorString()} {compareValue} (Current: {variable})";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
}
|
|
||||||
return met;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableGreaterThan : Condition_CompareVariable
|
|
||||||
{
|
|
||||||
protected override bool Compare(float var1, float var2) => var1 > var2;
|
|
||||||
protected override string GetOperatorString() => ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableLessThan : Condition_CompareVariable
|
|
||||||
{
|
|
||||||
protected override bool Compare(float var1, float var2) => var1 < var2;
|
|
||||||
protected override string GetOperatorString() => "<";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableGreaterThanOrEqual : Condition_CompareVariable
|
|
||||||
{
|
|
||||||
protected override bool Compare(float var1, float var2) => var1 >= var2;
|
|
||||||
protected override string GetOperatorString() => ">=";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableLessThanOrEqual : Condition_CompareVariable
|
|
||||||
{
|
|
||||||
protected override bool Compare(float var1, float var2) => var1 <= var2;
|
|
||||||
protected override string GetOperatorString() => "<=";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_VariableNotEqual : Condition
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public string value;
|
|
||||||
public string valueVariableName;
|
|
||||||
|
|
||||||
public override bool IsMet(out string reason)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!eventVarManager.HasVariable(name))
|
|
||||||
{
|
|
||||||
reason = $"Variable '{name}' not found.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
object variable = eventVarManager.GetVariable<object>(name);
|
|
||||||
string compareValueStr = value;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(valueVariableName))
|
|
||||||
{
|
|
||||||
compareValueStr = eventVarManager.GetVariable<object>(valueVariableName)?.ToString();
|
|
||||||
if (compareValueStr == null)
|
|
||||||
{
|
|
||||||
reason = $"Comparison variable '{valueVariableName}' not set.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool met = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (variable is int)
|
|
||||||
{
|
|
||||||
met = (int)variable != int.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else if (variable is float)
|
|
||||||
{
|
|
||||||
met = (float)variable != float.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else if (variable is bool)
|
|
||||||
{
|
|
||||||
met = (bool)variable != bool.Parse(compareValueStr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
met = variable?.ToString() != compareValueStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Condition_VariableNotEqual: Could not compare '{variable}' and '{compareValueStr}'. Error: {e.Message}");
|
|
||||||
reason = "Type mismatch or parsing error during comparison.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Condition_VariableNotEqual check: Name='{name}', Type='{variable?.GetType().Name ?? "null"}', CurrentValue='{variable}', CompareValue='{compareValueStr}', Met={met}");
|
|
||||||
if (!met)
|
|
||||||
{
|
|
||||||
reason = $"Requires {name} != {compareValueStr} (Current: {variable})";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
}
|
|
||||||
return met;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Condition_FactionExists : Condition
|
|
||||||
{
|
|
||||||
public FactionDef factionDef;
|
|
||||||
|
|
||||||
public override bool IsMet(out string reason)
|
|
||||||
{
|
|
||||||
if (factionDef == null)
|
|
||||||
{
|
|
||||||
reason = "FactionDef not specified in Condition_FactionExists.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool exists = Find.FactionManager.FirstFactionOfDef(factionDef) != null;
|
|
||||||
if (!exists)
|
|
||||||
{
|
|
||||||
reason = $"Faction '{factionDef.label}' does not exist in the world.";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
}
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
using System; // Required for Activator
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using LudeonTK;
|
|
||||||
using Verse;
|
|
||||||
using RimWorld;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public static class WulaDebugActions
|
|
||||||
{
|
|
||||||
[DebugAction("Wula Fallen Empire", "Open Custom UI...", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Playing)]
|
|
||||||
private static void OpenCustomUI()
|
|
||||||
{
|
|
||||||
List<DebugMenuOption> list = new List<DebugMenuOption>();
|
|
||||||
foreach (EventDef localDef in DefDatabase<EventDef>.AllDefs)
|
|
||||||
{
|
|
||||||
EventDef currentDef = localDef;
|
|
||||||
list.Add(new DebugMenuOption(currentDef.defName, DebugMenuOptionMode.Action, delegate
|
|
||||||
{
|
|
||||||
if (currentDef.hiddenWindow)
|
|
||||||
{
|
|
||||||
if (!currentDef.dismissEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var conditionalEffect in currentDef.dismissEffects)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
bool conditionsMet = true;
|
|
||||||
if (!conditionalEffect.conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var condition in conditionalEffect.conditions)
|
|
||||||
{
|
|
||||||
if (!condition.IsMet(out reason))
|
|
||||||
{
|
|
||||||
conditionsMet = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conditionsMet)
|
|
||||||
{
|
|
||||||
conditionalEffect.Execute(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add((Window)Activator.CreateInstance(currentDef.windowType, currentDef));
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
Find.WindowStack.Add(new Dialog_DebugOptionListLister(list));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class WulaDebugActionsVariables
|
|
||||||
{
|
|
||||||
[DebugAction("Wula Fallen Empire", "Manage Event Variables", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.PlayingOnMap)]
|
|
||||||
private static void ManageEventVariables()
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add(new Dialog_ManageEventVariables());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using RimWorld;
|
|
||||||
using RimWorld.Planet;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class DelayedActionManager : WorldComponent
|
|
||||||
{
|
|
||||||
// Nested class must be public to be accessible for serialization
|
|
||||||
public class DelayedAction : IExposable
|
|
||||||
{
|
|
||||||
public int TicksRemaining;
|
|
||||||
public string eventDefName;
|
|
||||||
|
|
||||||
// Parameterless constructor for Scribe
|
|
||||||
public DelayedAction() { }
|
|
||||||
|
|
||||||
public DelayedAction(string eventDefName, int ticks)
|
|
||||||
{
|
|
||||||
this.eventDefName = eventDefName;
|
|
||||||
this.TicksRemaining = ticks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ExposeData()
|
|
||||||
{
|
|
||||||
Scribe_Values.Look(ref TicksRemaining, "ticksRemaining", 0);
|
|
||||||
Scribe_Values.Look(ref eventDefName, "eventDefName");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<DelayedAction> actions = new List<DelayedAction>();
|
|
||||||
|
|
||||||
public DelayedActionManager(World world) : base(world)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddAction(string eventDefName, int delayTicks)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(eventDefName) || delayTicks <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
actions.Add(new DelayedAction(eventDefName, delayTicks));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WorldComponentTick()
|
|
||||||
{
|
|
||||||
base.WorldComponentTick();
|
|
||||||
for (int i = actions.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
DelayedAction delayedAction = actions[i];
|
|
||||||
delayedAction.TicksRemaining--;
|
|
||||||
if (delayedAction.TicksRemaining <= 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ExecuteAction(delayedAction.eventDefName);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Error executing delayed action for event '{delayedAction.eventDefName}': {ex}");
|
|
||||||
}
|
|
||||||
actions.RemoveAt(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteAction(string defName)
|
|
||||||
{
|
|
||||||
EventDef nextDef = DefDatabase<EventDef>.GetNamed(defName, false);
|
|
||||||
if (nextDef != null)
|
|
||||||
{
|
|
||||||
// This logic is simplified from Effect_OpenCustomUI.OpenUI
|
|
||||||
// It assumes delayed actions always open a new dialog.
|
|
||||||
Find.WindowStack.Add((Window)Activator.CreateInstance(nextDef.windowType, nextDef));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] DelayedActionManager could not find EventDef named '{defName}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData()
|
|
||||||
{
|
|
||||||
base.ExposeData();
|
|
||||||
Scribe_Collections.Look(ref actions, "delayedActions", LookMode.Deep);
|
|
||||||
if (actions == null)
|
|
||||||
{
|
|
||||||
actions = new List<DelayedAction>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,274 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class Dialog_CustomDisplay : Window
|
|
||||||
{
|
|
||||||
private EventDef def;
|
|
||||||
private Texture2D portrait;
|
|
||||||
private Texture2D background;
|
|
||||||
private string selectedDescription;
|
|
||||||
|
|
||||||
private static EventUIConfigDef config;
|
|
||||||
public static EventUIConfigDef Config
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (config == null)
|
|
||||||
{
|
|
||||||
config = DefDatabase<EventUIConfigDef>.GetNamed("ARA_EventUIConfig");
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Vector2 InitialSize
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (def.windowSize != Vector2.zero)
|
|
||||||
{
|
|
||||||
return def.windowSize;
|
|
||||||
}
|
|
||||||
return Config.defaultWindowSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dialog_CustomDisplay(EventDef def)
|
|
||||||
{
|
|
||||||
this.def = def;
|
|
||||||
this.forcePause = true;
|
|
||||||
this.absorbInputAroundWindow = true;
|
|
||||||
this.doCloseX = true;
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!def.descriptions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
if (def.descriptionMode == DescriptionSelectionMode.Random)
|
|
||||||
{
|
|
||||||
selectedDescription = def.descriptions.RandomElement();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string indexVarName = $"_seq_desc_index_{def.defName}";
|
|
||||||
int currentIndex = eventVarManager.GetVariable<int>(indexVarName, 0);
|
|
||||||
|
|
||||||
selectedDescription = def.descriptions[currentIndex];
|
|
||||||
|
|
||||||
int nextIndex = (currentIndex + 1) % def.descriptions.Count;
|
|
||||||
eventVarManager.SetVariable(indexVarName, nextIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selectedDescription = "Error: No descriptions found in def.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PreOpen()
|
|
||||||
{
|
|
||||||
base.PreOpen();
|
|
||||||
if (!def.portraitPath.NullOrEmpty())
|
|
||||||
{
|
|
||||||
portrait = ContentFinder<Texture2D>.Get(def.portraitPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
string bgPath = !def.backgroundImagePath.NullOrEmpty() ? def.backgroundImagePath : Config.defaultBackgroundImagePath;
|
|
||||||
if (!bgPath.NullOrEmpty())
|
|
||||||
{
|
|
||||||
background = ContentFinder<Texture2D>.Get(bgPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleAction(def.immediateEffects);
|
|
||||||
|
|
||||||
if (!def.conditionalDescriptions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var condDesc in def.conditionalDescriptions)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
if (AreConditionsMet(condDesc.conditions, out reason))
|
|
||||||
{
|
|
||||||
selectedDescription += "\n\n" + condDesc.text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedDescription = FormatDescription(selectedDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DoWindowContents(Rect inRect)
|
|
||||||
{
|
|
||||||
if (background != null)
|
|
||||||
{
|
|
||||||
GUI.DrawTexture(inRect, background, ScaleMode.ScaleToFit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.showDefName)
|
|
||||||
{
|
|
||||||
Text.Font = GameFont.Tiny;
|
|
||||||
GUI.color = Color.gray;
|
|
||||||
Widgets.Label(new Rect(5, 5, inRect.width - 10, 20f), def.defName);
|
|
||||||
GUI.color = Color.white;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.showLabel)
|
|
||||||
{
|
|
||||||
Text.Font = Config.labelFont;
|
|
||||||
Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label);
|
|
||||||
Text.Font = GameFont.Small;
|
|
||||||
}
|
|
||||||
|
|
||||||
float virtualWidth = Config.lihuiSize.x + Config.textSize.x;
|
|
||||||
float virtualHeight = Config.lihuiSize.y;
|
|
||||||
|
|
||||||
float scaleX = inRect.width / virtualWidth;
|
|
||||||
float scaleY = inRect.height / virtualHeight;
|
|
||||||
float scale = Mathf.Min(scaleX, scaleY) * 0.95f;
|
|
||||||
|
|
||||||
float scaledLihuiWidth = Config.lihuiSize.x * scale;
|
|
||||||
float scaledLihuiHeight = Config.lihuiSize.y * scale;
|
|
||||||
float scaledNameWidth = Config.nameSize.x * scale;
|
|
||||||
float scaledNameHeight = Config.nameSize.y * scale;
|
|
||||||
float scaledTextWidth = Config.textSize.x * scale;
|
|
||||||
float scaledTextHeight = Config.textSize.y * scale;
|
|
||||||
float scaledOptionsWidth = Config.optionsWidth * scale;
|
|
||||||
|
|
||||||
float totalContentWidth = scaledLihuiWidth + scaledTextWidth;
|
|
||||||
float totalContentHeight = scaledLihuiHeight;
|
|
||||||
float startX = (inRect.width - totalContentWidth) / 2;
|
|
||||||
float startY = (inRect.height - totalContentHeight) / 2;
|
|
||||||
|
|
||||||
Rect lihuiRect = new Rect(startX, startY, scaledLihuiWidth, scaledLihuiHeight);
|
|
||||||
if (portrait != null)
|
|
||||||
{
|
|
||||||
GUI.DrawTexture(lihuiRect, portrait, ScaleMode.ScaleToFit);
|
|
||||||
}
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(lihuiRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rect nameRect = new Rect(lihuiRect.xMax, lihuiRect.y, scaledNameWidth, scaledNameHeight);
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(nameRect);
|
|
||||||
}
|
|
||||||
Text.Anchor = TextAnchor.MiddleCenter;
|
|
||||||
Text.Font = GameFont.Medium;
|
|
||||||
Widgets.Label(nameRect, def.characterName);
|
|
||||||
Text.Font = GameFont.Small;
|
|
||||||
Text.Anchor = TextAnchor.UpperLeft;
|
|
||||||
|
|
||||||
Rect textRect = new Rect(nameRect.x, nameRect.yMax + Config.textNameOffset * scale, scaledTextWidth, scaledTextHeight);
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(textRect);
|
|
||||||
}
|
|
||||||
Rect textInnerRect = textRect.ContractedBy(10f * scale);
|
|
||||||
Widgets.Label(textInnerRect, selectedDescription);
|
|
||||||
|
|
||||||
Rect optionRect = new Rect(nameRect.x, textRect.yMax + Config.optionsTextOffset * scale, scaledOptionsWidth, lihuiRect.height - nameRect.height - textRect.height - (Config.textNameOffset + Config.optionsTextOffset) * scale);
|
|
||||||
|
|
||||||
Listing_Standard listing = new Listing_Standard();
|
|
||||||
listing.Begin(optionRect.ContractedBy(10f * scale));
|
|
||||||
if (def.options != null)
|
|
||||||
{
|
|
||||||
foreach (var option in def.options)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
bool conditionsMet = AreConditionsMet(option.conditions, out reason);
|
|
||||||
|
|
||||||
if (conditionsMet)
|
|
||||||
{
|
|
||||||
if (listing.ButtonText(option.label))
|
|
||||||
{
|
|
||||||
HandleAction(option.optionEffects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (option.hideWhenDisabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Rect rect = listing.GetRect(30f);
|
|
||||||
Widgets.ButtonText(rect, option.label, false, true, false);
|
|
||||||
TooltipHandler.TipRegion(rect, GetDisabledReason(option, reason));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listing.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleAction(List<ConditionalEffects> conditionalEffects)
|
|
||||||
{
|
|
||||||
if (conditionalEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var ce in conditionalEffects)
|
|
||||||
{
|
|
||||||
if (AreConditionsMet(ce.conditions, out _))
|
|
||||||
{
|
|
||||||
ce.Execute(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AreConditionsMet(List<Condition> conditions, out string reason)
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
if (conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var condition in conditions)
|
|
||||||
{
|
|
||||||
if (!condition.IsMet(out string singleReason))
|
|
||||||
{
|
|
||||||
reason = singleReason;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetDisabledReason(EventOption option, string reason)
|
|
||||||
{
|
|
||||||
if (!option.disabledReason.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return option.disabledReason;
|
|
||||||
}
|
|
||||||
return reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PostClose()
|
|
||||||
{
|
|
||||||
base.PostClose();
|
|
||||||
HandleAction(def.dismissEffects);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatDescription(string description)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
// Use regex to find all placeholders like {variableName}
|
|
||||||
return Regex.Replace(description, @"\{(.+?)\}", match =>
|
|
||||||
{
|
|
||||||
string varName = match.Groups[1].Value;
|
|
||||||
if (eventVarManager.HasVariable(varName))
|
|
||||||
{
|
|
||||||
// Important: GetVariable<object> to get any type
|
|
||||||
return eventVarManager.GetVariable<object>(varName)?.ToString() ?? "";
|
|
||||||
}
|
|
||||||
return match.Value; // Keep placeholder if variable not found
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class Dialog_ManageEventVariables : Window
|
|
||||||
{
|
|
||||||
private Vector2 scrollPosition;
|
|
||||||
private Dictionary<string, string> editBuffers = new Dictionary<string, string>();
|
|
||||||
private EventVariableManager manager;
|
|
||||||
|
|
||||||
public override Vector2 InitialSize => new Vector2(800f, 600f);
|
|
||||||
|
|
||||||
public Dialog_ManageEventVariables()
|
|
||||||
{
|
|
||||||
forcePause = true;
|
|
||||||
doCloseX = true;
|
|
||||||
doCloseButton = true;
|
|
||||||
closeOnClickedOutside = true;
|
|
||||||
absorbInputAroundWindow = true;
|
|
||||||
manager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
RefreshBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshBuffers()
|
|
||||||
{
|
|
||||||
editBuffers.Clear();
|
|
||||||
foreach (var kvp in manager.GetAllVariables())
|
|
||||||
{
|
|
||||||
editBuffers[kvp.Key] = kvp.Value?.ToString() ?? "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DoWindowContents(Rect inRect)
|
|
||||||
{
|
|
||||||
Listing_Standard listing = new Listing_Standard();
|
|
||||||
listing.Begin(inRect);
|
|
||||||
|
|
||||||
if (listing.ButtonText("Refresh"))
|
|
||||||
{
|
|
||||||
RefreshBuffers();
|
|
||||||
}
|
|
||||||
if (listing.ButtonText("Clear All Variables"))
|
|
||||||
{
|
|
||||||
manager.ClearAll();
|
|
||||||
RefreshBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
listing.GapLine();
|
|
||||||
|
|
||||||
Rect viewRect = new Rect(0f, 0f, inRect.width - 16f, manager.GetAllVariables().Count * 32f);
|
|
||||||
Widgets.BeginScrollView(listing.GetRect(inRect.height - 100f), ref scrollPosition, viewRect);
|
|
||||||
|
|
||||||
Listing_Standard varListing = new Listing_Standard();
|
|
||||||
varListing.Begin(viewRect);
|
|
||||||
|
|
||||||
var allVars = manager.GetAllVariables().OrderBy(kvp => kvp.Key).ToList();
|
|
||||||
|
|
||||||
foreach (var kvp in allVars)
|
|
||||||
{
|
|
||||||
Rect rowRect = varListing.GetRect(30f);
|
|
||||||
string key = kvp.Key;
|
|
||||||
object value = kvp.Value;
|
|
||||||
string typeName = value?.GetType().Name ?? "null";
|
|
||||||
|
|
||||||
Widgets.Label(rowRect.LeftPart(0.4f).Rounded(), $"{key} ({typeName})");
|
|
||||||
|
|
||||||
string buffer = editBuffers[key];
|
|
||||||
string newValue = Widgets.TextField(rowRect.RightPart(0.6f).LeftPart(0.8f).Rounded(), buffer);
|
|
||||||
editBuffers[key] = newValue;
|
|
||||||
|
|
||||||
if (Widgets.ButtonText(rowRect.RightPart(0.1f).Rounded(), "Set"))
|
|
||||||
{
|
|
||||||
// Attempt to parse and set the variable
|
|
||||||
if (value is int)
|
|
||||||
{
|
|
||||||
if (int.TryParse(newValue, out int intVal)) manager.SetVariable(key, intVal);
|
|
||||||
}
|
|
||||||
else if (value is float)
|
|
||||||
{
|
|
||||||
if (float.TryParse(newValue, out float floatVal)) manager.SetVariable(key, floatVal);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
manager.SetVariable(key, newValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
varListing.End();
|
|
||||||
Widgets.EndScrollView();
|
|
||||||
listing.End();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class Dialog_NewLayoutDisplay : Window
|
|
||||||
{
|
|
||||||
private EventDef def;
|
|
||||||
private Texture2D portrait;
|
|
||||||
private Texture2D background;
|
|
||||||
private string selectedDescription;
|
|
||||||
|
|
||||||
private static EventUIConfigDef config;
|
|
||||||
public static EventUIConfigDef Config
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (config == null)
|
|
||||||
{
|
|
||||||
config = DefDatabase<EventUIConfigDef>.GetNamed("ARA_EventUIConfig");
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Vector2 InitialSize
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (def.windowSize != Vector2.zero)
|
|
||||||
{
|
|
||||||
return def.windowSize;
|
|
||||||
}
|
|
||||||
return Config.defaultWindowSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dialog_NewLayoutDisplay(EventDef def)
|
|
||||||
{
|
|
||||||
this.def = def;
|
|
||||||
this.forcePause = true;
|
|
||||||
this.absorbInputAroundWindow = true;
|
|
||||||
this.doCloseX = true;
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!def.descriptions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
if (def.descriptionMode == DescriptionSelectionMode.Random)
|
|
||||||
{
|
|
||||||
selectedDescription = def.descriptions.RandomElement();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string indexVarName = $"_seq_desc_index_{def.defName}";
|
|
||||||
int currentIndex = eventVarManager.GetVariable<int>(indexVarName, 0);
|
|
||||||
|
|
||||||
selectedDescription = def.descriptions[currentIndex];
|
|
||||||
|
|
||||||
int nextIndex = (currentIndex + 1) % def.descriptions.Count;
|
|
||||||
eventVarManager.SetVariable(indexVarName, nextIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
selectedDescription = "Error: No descriptions found in def.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PreOpen()
|
|
||||||
{
|
|
||||||
base.PreOpen();
|
|
||||||
if (!def.portraitPath.NullOrEmpty())
|
|
||||||
{
|
|
||||||
portrait = ContentFinder<Texture2D>.Get(def.portraitPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
string bgPath = !def.backgroundImagePath.NullOrEmpty() ? def.backgroundImagePath : Config.defaultBackgroundImagePath;
|
|
||||||
if (!bgPath.NullOrEmpty())
|
|
||||||
{
|
|
||||||
background = ContentFinder<Texture2D>.Get(bgPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleAction(def.immediateEffects);
|
|
||||||
|
|
||||||
if (!def.conditionalDescriptions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var condDesc in def.conditionalDescriptions)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
if (AreConditionsMet(condDesc.conditions, out reason))
|
|
||||||
{
|
|
||||||
selectedDescription += "\n\n" + condDesc.text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectedDescription = FormatDescription(selectedDescription);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DoWindowContents(Rect inRect)
|
|
||||||
{
|
|
||||||
if (background != null)
|
|
||||||
{
|
|
||||||
GUI.DrawTexture(inRect, background, ScaleMode.ScaleToFit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.showDefName)
|
|
||||||
{
|
|
||||||
Text.Font = GameFont.Tiny;
|
|
||||||
GUI.color = Color.gray;
|
|
||||||
Widgets.Label(new Rect(5, 5, inRect.width - 10, 20f), def.defName);
|
|
||||||
GUI.color = Color.white;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Config.showLabel)
|
|
||||||
{
|
|
||||||
Text.Font = Config.labelFont;
|
|
||||||
Widgets.Label(new Rect(5, 20f, inRect.width - 10, 30f), def.label);
|
|
||||||
Text.Font = GameFont.Small;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 假设一个统一的边距
|
|
||||||
float padding = Config.newLayoutPadding;
|
|
||||||
|
|
||||||
// 名称区域
|
|
||||||
float nameHeight = Config.newLayoutNameSize.y;
|
|
||||||
float nameWidth = Config.newLayoutNameSize.x;
|
|
||||||
Rect nameRect = new Rect(inRect.x + (inRect.width - nameWidth) / 2f, inRect.y + padding, nameWidth, nameHeight);
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(nameRect);
|
|
||||||
}
|
|
||||||
Text.Anchor = TextAnchor.MiddleCenter;
|
|
||||||
Text.Font = GameFont.Medium;
|
|
||||||
Widgets.Label(nameRect, def.characterName);
|
|
||||||
Text.Font = GameFont.Small;
|
|
||||||
Text.Anchor = TextAnchor.UpperLeft;
|
|
||||||
|
|
||||||
// 立绘区域
|
|
||||||
float lihuiWidth = Config.newLayoutLihuiSize.x;
|
|
||||||
float lihuiHeight = Config.newLayoutLihuiSize.y;
|
|
||||||
Rect lihuiRect = new Rect(inRect.x + (inRect.width - lihuiWidth) / 2f, nameRect.yMax + padding, lihuiWidth, lihuiHeight);
|
|
||||||
if (portrait != null)
|
|
||||||
{
|
|
||||||
GUI.DrawTexture(lihuiRect, portrait, ScaleMode.ScaleToFit);
|
|
||||||
}
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(lihuiRect);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选项区域 (预先计算高度)
|
|
||||||
float optionButtonHeight = 30f; // 每个按钮的高度
|
|
||||||
float optionSpacing = 5f; // 按钮之间的间距
|
|
||||||
float calculatedOptionHeight = 0f;
|
|
||||||
if (def.options != null && def.options.Any())
|
|
||||||
{
|
|
||||||
calculatedOptionHeight = def.options.Count * optionButtonHeight + (def.options.Count - 1) * optionSpacing;
|
|
||||||
}
|
|
||||||
calculatedOptionHeight = Mathf.Max(calculatedOptionHeight, 100f); // 最小高度
|
|
||||||
|
|
||||||
float optionsWidth = Config.newLayoutOptionsWidth;
|
|
||||||
Rect optionRect = new Rect(inRect.x + (inRect.width - optionsWidth) / 2f, inRect.yMax - padding - calculatedOptionHeight, optionsWidth, calculatedOptionHeight);
|
|
||||||
|
|
||||||
// 描述区域
|
|
||||||
float textWidth = Config.newLayoutTextSize.x;
|
|
||||||
Rect textRect = new Rect(inRect.x + (inRect.width - textWidth) / 2f, lihuiRect.yMax + padding, textWidth, optionRect.y - (lihuiRect.yMax + padding) - padding);
|
|
||||||
if (Config.drawBorders)
|
|
||||||
{
|
|
||||||
Widgets.DrawBox(textRect);
|
|
||||||
}
|
|
||||||
Rect textInnerRect = textRect.ContractedBy(padding);
|
|
||||||
Widgets.Label(textInnerRect, selectedDescription);
|
|
||||||
|
|
||||||
// 选项列表的绘制
|
|
||||||
Listing_Standard listing = new Listing_Standard();
|
|
||||||
listing.Begin(optionRect); // 使用完整的 optionRect
|
|
||||||
if (def.options != null)
|
|
||||||
{
|
|
||||||
foreach (var option in def.options)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
bool conditionsMet = AreConditionsMet(option.conditions, out reason);
|
|
||||||
|
|
||||||
if (conditionsMet)
|
|
||||||
{
|
|
||||||
if (listing.ButtonText(option.label))
|
|
||||||
{
|
|
||||||
HandleAction(option.optionEffects);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (option.hideWhenDisabled)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Rect rect = listing.GetRect(30f);
|
|
||||||
Widgets.ButtonText(rect, option.label, false, true, false);
|
|
||||||
TooltipHandler.TipRegion(rect, GetDisabledReason(option, reason));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
listing.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleAction(List<ConditionalEffects> conditionalEffects)
|
|
||||||
{
|
|
||||||
if (conditionalEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var ce in conditionalEffects)
|
|
||||||
{
|
|
||||||
if (AreConditionsMet(ce.conditions, out _))
|
|
||||||
{
|
|
||||||
ce.Execute(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AreConditionsMet(List<Condition> conditions, out string reason)
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
if (conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var condition in conditions)
|
|
||||||
{
|
|
||||||
if (!condition.IsMet(out string singleReason))
|
|
||||||
{
|
|
||||||
reason = singleReason;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private string GetDisabledReason(EventOption option, string reason)
|
|
||||||
{
|
|
||||||
if (!option.disabledReason.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return option.disabledReason;
|
|
||||||
}
|
|
||||||
return reason;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void PostClose()
|
|
||||||
{
|
|
||||||
base.PostClose();
|
|
||||||
HandleAction(def.dismissEffects);
|
|
||||||
}
|
|
||||||
|
|
||||||
private string FormatDescription(string description)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
// Use regex to find all placeholders like {variableName}
|
|
||||||
return Regex.Replace(description, @"\{(.+?)\}", match =>
|
|
||||||
{
|
|
||||||
string varName = match.Groups[1].Value;
|
|
||||||
if (eventVarManager.HasVariable(varName))
|
|
||||||
{
|
|
||||||
// Important: GetVariable<object> to get any type
|
|
||||||
return eventVarManager.GetVariable<object>(varName)?.ToString() ?? "";
|
|
||||||
}
|
|
||||||
return match.Value; // Keep placeholder if variable not found
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,655 +0,0 @@
|
|||||||
using System; // Required for Activator
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
using RimWorld;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public abstract class Effect
|
|
||||||
{
|
|
||||||
public float weight = 1.0f;
|
|
||||||
public abstract void Execute(Window dialog = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_OpenCustomUI : Effect
|
|
||||||
{
|
|
||||||
public string defName;
|
|
||||||
public int delayTicks = 0;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (delayTicks > 0)
|
|
||||||
{
|
|
||||||
var actionManager = Find.World.GetComponent<DelayedActionManager>();
|
|
||||||
if (actionManager != null)
|
|
||||||
{
|
|
||||||
actionManager.AddAction(defName, delayTicks);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] DelayedActionManager not found. Cannot schedule delayed UI opening.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OpenUI();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenUI()
|
|
||||||
{
|
|
||||||
EventDef nextDef = DefDatabase<EventDef>.GetNamed(defName);
|
|
||||||
if (nextDef != null)
|
|
||||||
{
|
|
||||||
if (nextDef.hiddenWindow)
|
|
||||||
{
|
|
||||||
if (!nextDef.dismissEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var conditionalEffect in nextDef.dismissEffects)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
if (AreConditionsMet(conditionalEffect.conditions, out reason))
|
|
||||||
{
|
|
||||||
conditionalEffect.Execute(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Find.WindowStack.Add((Window)Activator.CreateInstance(nextDef.windowType, nextDef));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Effect_OpenCustomUI could not find EventDef named '{defName}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AreConditionsMet(List<Condition> conditions, out string reason)
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
if (conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var condition in conditions)
|
|
||||||
{
|
|
||||||
if (!condition.IsMet(out string singleReason))
|
|
||||||
{
|
|
||||||
reason = singleReason;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_CloseDialog : Effect
|
|
||||||
{
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
dialog?.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_ShowMessage : Effect
|
|
||||||
{
|
|
||||||
public string message;
|
|
||||||
public MessageTypeDef messageTypeDef;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (messageTypeDef == null)
|
|
||||||
{
|
|
||||||
messageTypeDef = MessageTypeDefOf.PositiveEvent;
|
|
||||||
}
|
|
||||||
Messages.Message(message, messageTypeDef);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_FireIncident : Effect
|
|
||||||
{
|
|
||||||
public IncidentDef incident;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (incident == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_FireIncident has a null incident Def.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IncidentParms parms = new IncidentParms
|
|
||||||
{
|
|
||||||
target = Find.CurrentMap,
|
|
||||||
forced = true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!incident.Worker.TryExecute(parms))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Could not fire incident {incident.defName}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_ChangeFactionRelation : Effect
|
|
||||||
{
|
|
||||||
public FactionDef faction;
|
|
||||||
public int goodwillChange;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (faction == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_ChangeFactionRelation has a null faction Def.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction targetFaction = Find.FactionManager.FirstFactionOfDef(faction);
|
|
||||||
if (targetFaction == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{faction.defName}'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_SetVariable : Effect
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public string value;
|
|
||||||
public string type; // Int, Float, String, Bool
|
|
||||||
public bool forceSet = false;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
if (!forceSet && eventVarManager.HasVariable(name))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
object realValue = value;
|
|
||||||
if (!string.IsNullOrEmpty(type))
|
|
||||||
{
|
|
||||||
if (type.Equals("int", System.StringComparison.OrdinalIgnoreCase) && int.TryParse(value, out int intVal))
|
|
||||||
{
|
|
||||||
realValue = intVal;
|
|
||||||
}
|
|
||||||
else if (type.Equals("float", System.StringComparison.OrdinalIgnoreCase) && float.TryParse(value, out float floatVal))
|
|
||||||
{
|
|
||||||
realValue = floatVal;
|
|
||||||
}
|
|
||||||
else if (type.Equals("bool", System.StringComparison.OrdinalIgnoreCase) && bool.TryParse(value, out bool boolVal))
|
|
||||||
{
|
|
||||||
realValue = boolVal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventVarManager.SetVariable(name, realValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_ChangeFactionRelation_FromVariable : Effect
|
|
||||||
{
|
|
||||||
public FactionDef faction;
|
|
||||||
public string goodwillVariableName;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (faction == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_ChangeFactionRelation_FromVariable has a null faction Def.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction targetFaction = Find.FactionManager.FirstFactionOfDef(faction);
|
|
||||||
if (targetFaction == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Could not find an active faction for FactionDef '{faction.defName}'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int goodwillChange = Find.World.GetComponent<EventVariableManager>().GetVariable<int>(goodwillVariableName);
|
|
||||||
Faction.OfPlayer.TryAffectGoodwillWith(targetFaction, goodwillChange, canSendMessage: true, canSendHostilityLetter: true, reason: null, lookTarget: null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_SpawnPawnAndStore : Effect
|
|
||||||
{
|
|
||||||
public PawnKindDef kindDef;
|
|
||||||
public int count = 1;
|
|
||||||
public string storeAs;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (kindDef == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_SpawnPawnAndStore has a null kindDef.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (storeAs.NullOrEmpty())
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_SpawnPawnAndStore needs a 'storeAs' variable name.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
List<Pawn> spawnedPawns = new List<Pawn>();
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
Pawn newPawn = PawnGenerator.GeneratePawn(kindDef, Faction.OfPlayer);
|
|
||||||
IntVec3 loc = CellFinder.RandomSpawnCellForPawnNear(Find.CurrentMap.mapPawns.FreeColonists.First().Position, Find.CurrentMap, 10);
|
|
||||||
GenSpawn.Spawn(newPawn, loc, Find.CurrentMap);
|
|
||||||
spawnedPawns.Add(newPawn);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count == 1)
|
|
||||||
{
|
|
||||||
eventVarManager.SetVariable(storeAs, spawnedPawns.First());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
eventVarManager.SetVariable(storeAs, spawnedPawns);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_GiveThing : Effect
|
|
||||||
{
|
|
||||||
public ThingDef thingDef;
|
|
||||||
public int count = 1;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (thingDef == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_GiveThing has a null thingDef.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map currentMap = Find.CurrentMap;
|
|
||||||
if (currentMap == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_GiveThing cannot execute without a current map.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Thing thing = ThingMaker.MakeThing(thingDef);
|
|
||||||
thing.stackCount = count;
|
|
||||||
|
|
||||||
IntVec3 dropCenter = DropCellFinder.TradeDropSpot(currentMap);
|
|
||||||
DropPodUtility.DropThingsNear(dropCenter, currentMap, new List<Thing> { thing }, 110, false, false, false, false);
|
|
||||||
|
|
||||||
Messages.Message("LetterLabelCargoPodCrash".Translate(), new TargetInfo(dropCenter, currentMap), MessageTypeDefOf.PositiveEvent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_SpawnPawn : Effect
|
|
||||||
{
|
|
||||||
public PawnKindDef kindDef;
|
|
||||||
public int count = 1;
|
|
||||||
public bool joinPlayerFaction = true;
|
|
||||||
public string letterLabel;
|
|
||||||
public string letterText;
|
|
||||||
public LetterDef letterDef;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (kindDef == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_SpawnPawn has a null kindDef.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map map = Find.CurrentMap;
|
|
||||||
if (map == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_SpawnPawn cannot execute without a current map.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
Faction faction = joinPlayerFaction ? Faction.OfPlayer : null;
|
|
||||||
PawnGenerationRequest request = new PawnGenerationRequest(
|
|
||||||
kindDef, faction, PawnGenerationContext.NonPlayer, -1, true, false, false, false,
|
|
||||||
true, 20f, false, true, false, true, true, false, false, false, false, 0f, 0f, null, 1f,
|
|
||||||
null, null, null, null, null, null, null, null, null, null, null, null, false
|
|
||||||
);
|
|
||||||
Pawn pawn = PawnGenerator.GeneratePawn(request);
|
|
||||||
|
|
||||||
if (!CellFinder.TryFindRandomEdgeCellWith((IntVec3 c) => map.reachability.CanReachColony(c) && !c.Fogged(map), map, CellFinder.EdgeRoadChance_Neutral, out IntVec3 cell))
|
|
||||||
{
|
|
||||||
cell = DropCellFinder.RandomDropSpot(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
GenSpawn.Spawn(pawn, cell, map, WipeMode.Vanish);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(letterLabel) && !string.IsNullOrEmpty(letterText))
|
|
||||||
{
|
|
||||||
TaggedString finalLabel = letterLabel.Formatted(pawn.Named("PAWN")).AdjustedFor(pawn);
|
|
||||||
TaggedString finalText = letterText.Formatted(pawn.Named("PAWN")).AdjustedFor(pawn);
|
|
||||||
PawnRelationUtility.TryAppendRelationsWithColonistsInfo(ref finalText, ref finalLabel, pawn);
|
|
||||||
Find.LetterStack.ReceiveLetter(finalLabel, finalText, letterDef ?? LetterDefOf.PositiveEvent, pawn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum VariableOperation
|
|
||||||
{
|
|
||||||
Add,
|
|
||||||
Subtract,
|
|
||||||
Multiply,
|
|
||||||
Divide
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_ModifyVariable : Effect
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
public string value;
|
|
||||||
public string valueVariableName;
|
|
||||||
public VariableOperation operation;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_ModifyVariable has a null or empty name.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
|
|
||||||
// Determine the value to modify by
|
|
||||||
string valueStr = value;
|
|
||||||
if (!string.IsNullOrEmpty(valueVariableName))
|
|
||||||
{
|
|
||||||
valueStr = eventVarManager.GetVariable<object>(valueVariableName)?.ToString();
|
|
||||||
if (valueStr == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Effect_ModifyVariable: valueVariableName '{valueVariableName}' not found.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the target variable, or initialize it
|
|
||||||
object variable = eventVarManager.GetVariable<object>(name);
|
|
||||||
if (variable == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Effect_ModifyVariable: Variable '{name}' not found, initializing to 0.");
|
|
||||||
variable = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
object originalValue = variable;
|
|
||||||
object newValue = null;
|
|
||||||
|
|
||||||
// Perform operation based on type
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (variable is int || (variable is float && !valueStr.Contains("."))) // Allow int ops
|
|
||||||
{
|
|
||||||
int currentVal = System.Convert.ToInt32(variable);
|
|
||||||
int modVal = int.Parse(valueStr);
|
|
||||||
newValue = (int)Modify((float)currentVal, (float)modVal, operation);
|
|
||||||
}
|
|
||||||
else // Default to float operation
|
|
||||||
{
|
|
||||||
float currentVal = System.Convert.ToSingle(variable);
|
|
||||||
float modVal = float.Parse(valueStr);
|
|
||||||
newValue = Modify(currentVal, modVal, operation);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Modifying variable '{name}'. Operation: {operation}. Value: {valueStr}. From: {originalValue} To: {newValue}");
|
|
||||||
eventVarManager.SetVariable(name, newValue);
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Effect_ModifyVariable: Could not parse or operate on value '{valueStr}' for variable '{name}'. Error: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float Modify(float current, float modifier, VariableOperation op)
|
|
||||||
{
|
|
||||||
switch (op)
|
|
||||||
{
|
|
||||||
case VariableOperation.Add: return current + modifier;
|
|
||||||
case VariableOperation.Subtract: return current - modifier;
|
|
||||||
case VariableOperation.Multiply: return current * modifier;
|
|
||||||
case VariableOperation.Divide:
|
|
||||||
if (modifier != 0) return current / modifier;
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Effect_ModifyVariable tried to divide by zero.");
|
|
||||||
return current;
|
|
||||||
default: return current;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_ClearVariable : Effect
|
|
||||||
{
|
|
||||||
public string name;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_ClearVariable has a null or empty name.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Find.World.GetComponent<EventVariableManager>().ClearVariable(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_AddQuest : Effect
|
|
||||||
{
|
|
||||||
public QuestScriptDef quest;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (quest == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_AddQuest has a null quest Def.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Quest newQuest = Quest.MakeRaw();
|
|
||||||
newQuest.root = quest;
|
|
||||||
newQuest.id = Find.UniqueIDsManager.GetNextQuestID();
|
|
||||||
Find.QuestManager.Add(newQuest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_FinishResearch : Effect
|
|
||||||
{
|
|
||||||
public ResearchProjectDef research;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (research == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_FinishResearch has a null research Def.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Find.ResearchManager.FinishProject(research);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public class Effect_TriggerRaid : Effect
|
|
||||||
{
|
|
||||||
public float points;
|
|
||||||
public FactionDef faction;
|
|
||||||
public RaidStrategyDef raidStrategy;
|
|
||||||
public PawnsArrivalModeDef raidArrivalMode;
|
|
||||||
public PawnGroupKindDef groupKind;
|
|
||||||
public List<PawnGroupMaker> pawnGroupMakers;
|
|
||||||
public string letterLabel;
|
|
||||||
public string letterText;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
Map map = Find.CurrentMap;
|
|
||||||
if (map == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_TriggerRaid cannot execute without a current map.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Faction factionInst = Find.FactionManager.FirstFactionOfDef(this.faction);
|
|
||||||
if (factionInst == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] Effect_TriggerRaid could not find an active faction for FactionDef '{this.faction?.defName}'.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IncidentParms parms = new IncidentParms
|
|
||||||
{
|
|
||||||
target = map,
|
|
||||||
points = this.points,
|
|
||||||
faction = factionInst,
|
|
||||||
raidStrategy = this.raidStrategy,
|
|
||||||
raidArrivalMode = this.raidArrivalMode,
|
|
||||||
pawnGroupMakerSeed = Rand.Int,
|
|
||||||
forced = true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!RCellFinder.TryFindRandomPawnEntryCell(out parms.spawnCenter, map, CellFinder.EdgeRoadChance_Hostile))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_TriggerRaid could not find a valid spawn center.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
PawnGroupMakerParms groupMakerParms = new PawnGroupMakerParms
|
|
||||||
{
|
|
||||||
groupKind = this.groupKind ?? PawnGroupKindDefOf.Combat,
|
|
||||||
tile = map.Tile,
|
|
||||||
points = this.points,
|
|
||||||
faction = factionInst,
|
|
||||||
raidStrategy = this.raidStrategy,
|
|
||||||
seed = parms.pawnGroupMakerSeed
|
|
||||||
};
|
|
||||||
|
|
||||||
List<Pawn> pawns;
|
|
||||||
if (!pawnGroupMakers.NullOrEmpty())
|
|
||||||
{
|
|
||||||
var groupMaker = pawnGroupMakers.RandomElementByWeight(x => x.commonality);
|
|
||||||
pawns = groupMaker.GeneratePawns(groupMakerParms).ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pawns = PawnGroupMakerUtility.GeneratePawns(groupMakerParms).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pawns.Any())
|
|
||||||
{
|
|
||||||
raidArrivalMode.Worker.Arrive(pawns, parms);
|
|
||||||
// Assign Lord and LordJob to make the pawns actually perform the raid.
|
|
||||||
raidStrategy.Worker.MakeLords(parms, pawns);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(letterLabel) && !string.IsNullOrEmpty(letterText))
|
|
||||||
{
|
|
||||||
Find.LetterStack.ReceiveLetter(letterLabel, letterText, LetterDefOf.ThreatBig, pawns[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_CheckFactionGoodwill : Effect
|
|
||||||
{
|
|
||||||
public FactionDef factionDef;
|
|
||||||
public string variableName;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (factionDef == null || string.IsNullOrEmpty(variableName))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_CheckFactionGoodwill is not configured correctly.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
Faction faction = Find.FactionManager.FirstFactionOfDef(factionDef);
|
|
||||||
|
|
||||||
if (faction != null)
|
|
||||||
{
|
|
||||||
int goodwill = faction.GoodwillWith(Faction.OfPlayer);
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Storing goodwill for faction '{faction.Name}' ({goodwill}) into variable '{variableName}'.");
|
|
||||||
eventVarManager.SetVariable(variableName, goodwill);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Effect_CheckFactionGoodwill: Faction '{factionDef.defName}' not found. Storing 0 in variable '{variableName}'.");
|
|
||||||
eventVarManager.SetVariable(variableName, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_StoreRealPlayTime : Effect
|
|
||||||
{
|
|
||||||
public string variableName;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(variableName))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_StoreRealPlayTime is not configured correctly (missing variableName).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
float realPlayTime = Find.GameInfo.RealPlayTimeInteracting;
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Storing real play time ({realPlayTime}s) into variable '{variableName}'.");
|
|
||||||
eventVarManager.SetVariable(variableName, realPlayTime);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_StoreDaysPassed : Effect
|
|
||||||
{
|
|
||||||
public string variableName;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(variableName))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_StoreDaysPassed is not configured correctly (missing variableName).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
int daysPassed = GenDate.DaysPassed;
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Storing days passed ({daysPassed}) into variable '{variableName}'.");
|
|
||||||
eventVarManager.SetVariable(variableName, daysPassed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Effect_StoreColonyWealth : Effect
|
|
||||||
{
|
|
||||||
public string variableName;
|
|
||||||
|
|
||||||
public override void Execute(Window dialog = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(variableName))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_StoreColonyWealth is not configured correctly (missing variableName).");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map currentMap = Find.CurrentMap;
|
|
||||||
if (currentMap == null)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug("[WulaFallenEmpire] Effect_StoreColonyWealth cannot execute without a current map.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
float wealth = currentMap.wealthWatcher.WealthTotal;
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Storing colony wealth ({wealth}) into variable '{variableName}'.");
|
|
||||||
eventVarManager.SetVariable(variableName, wealth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,148 +0,0 @@
|
|||||||
using System; // Add this line
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public enum DescriptionSelectionMode
|
|
||||||
{
|
|
||||||
Random,
|
|
||||||
Sequential
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventDef : Def
|
|
||||||
{
|
|
||||||
public string portraitPath;
|
|
||||||
public string characterName;
|
|
||||||
|
|
||||||
// New system: list of descriptions
|
|
||||||
public List<string> descriptions;
|
|
||||||
public DescriptionSelectionMode descriptionMode = DescriptionSelectionMode.Random;
|
|
||||||
public bool hiddenWindow = false;
|
|
||||||
|
|
||||||
// Backwards compatibility: old single description field
|
|
||||||
public new string description = null;
|
|
||||||
|
|
||||||
public Vector2 windowSize = Vector2.zero;
|
|
||||||
|
|
||||||
public Type windowType = typeof(Dialog_CustomDisplay); // 默认窗口类型
|
|
||||||
public List<EventOption> options;
|
|
||||||
public string backgroundImagePath;
|
|
||||||
public List<ConditionalEffects> immediateEffects;
|
|
||||||
public List<ConditionalEffects> dismissEffects;
|
|
||||||
public List<ConditionalDescription> conditionalDescriptions;
|
|
||||||
|
|
||||||
public override void PostLoad()
|
|
||||||
{
|
|
||||||
base.PostLoad();
|
|
||||||
#pragma warning disable 0618
|
|
||||||
// If the old description field is used, move its value to the new list for processing.
|
|
||||||
if (!description.NullOrEmpty())
|
|
||||||
{
|
|
||||||
if (descriptions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
descriptions = new List<string>();
|
|
||||||
}
|
|
||||||
descriptions.Insert(0, description);
|
|
||||||
description = null; // Clear the old field to prevent confusion
|
|
||||||
}
|
|
||||||
#pragma warning restore 0618
|
|
||||||
// If hiddenWindow is true, merge immediateEffects into dismissEffects at load time.
|
|
||||||
if (hiddenWindow && !immediateEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
if (dismissEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
dismissEffects = new List<ConditionalEffects>();
|
|
||||||
}
|
|
||||||
dismissEffects.AddRange(immediateEffects);
|
|
||||||
immediateEffects = null; // Clear to prevent double execution
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EventOption
|
|
||||||
{
|
|
||||||
public string label;
|
|
||||||
public List<ConditionalEffects> optionEffects;
|
|
||||||
public List<Condition> conditions;
|
|
||||||
public string disabledReason;
|
|
||||||
public bool hideWhenDisabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoopEffects
|
|
||||||
{
|
|
||||||
public int count = 1;
|
|
||||||
public string countVariableName;
|
|
||||||
public List<Effect> effects;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ConditionalEffects
|
|
||||||
{
|
|
||||||
public List<Condition> conditions;
|
|
||||||
public List<Effect> effects;
|
|
||||||
public List<Effect> randomlistEffects;
|
|
||||||
public List<LoopEffects> loopEffects;
|
|
||||||
|
|
||||||
public void Execute(Window dialog)
|
|
||||||
{
|
|
||||||
// Execute all standard effects
|
|
||||||
if (!effects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var effect in effects)
|
|
||||||
{
|
|
||||||
effect.Execute(dialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute one random effect from the random list
|
|
||||||
if (!randomlistEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
float totalWeight = randomlistEffects.Sum(e => e.weight);
|
|
||||||
float randomPoint = Rand.Value * totalWeight;
|
|
||||||
|
|
||||||
foreach (var effect in randomlistEffects)
|
|
||||||
{
|
|
||||||
if (randomPoint < effect.weight)
|
|
||||||
{
|
|
||||||
effect.Execute(dialog);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
randomPoint -= effect.weight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute looped effects
|
|
||||||
if (!loopEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
var eventVarManager = Find.World.GetComponent<EventVariableManager>();
|
|
||||||
foreach (var loop in loopEffects)
|
|
||||||
{
|
|
||||||
int loopCount = loop.count;
|
|
||||||
if (!loop.countVariableName.NullOrEmpty() && eventVarManager.HasVariable(loop.countVariableName))
|
|
||||||
{
|
|
||||||
loopCount = eventVarManager.GetVariable<int>(loop.countVariableName);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < loopCount; i++)
|
|
||||||
{
|
|
||||||
if (!loop.effects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var effect in loop.effects)
|
|
||||||
{
|
|
||||||
effect.Execute(dialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ConditionalDescription
|
|
||||||
{
|
|
||||||
public List<Condition> conditions;
|
|
||||||
public string text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class EventUIConfigDef : Def
|
|
||||||
{
|
|
||||||
// General Style
|
|
||||||
public GameFont labelFont = GameFont.Small;
|
|
||||||
public bool drawBorders = true;
|
|
||||||
public bool showDefName = true;
|
|
||||||
public bool showLabel = true;
|
|
||||||
public string defaultBackgroundImagePath;
|
|
||||||
public Vector2 defaultWindowSize = new Vector2(750f, 500f);
|
|
||||||
|
|
||||||
// Virtual Layout Dimensions
|
|
||||||
public Vector2 lihuiSize = new Vector2(500f, 800f);
|
|
||||||
public Vector2 nameSize = new Vector2(260f, 130f);
|
|
||||||
public Vector2 textSize = new Vector2(650f, 500f);
|
|
||||||
public float optionsWidth = 610f;
|
|
||||||
|
|
||||||
// Virtual Layout Offsets
|
|
||||||
public float textNameOffset = 20f;
|
|
||||||
public float optionsTextOffset = 20f;
|
|
||||||
// New Layout Dimensions
|
|
||||||
public Vector2 newLayoutNameSize = new Vector2(200f, 50f);
|
|
||||||
public Vector2 newLayoutLihuiSize = new Vector2(300f, 400f);
|
|
||||||
public Vector2 newLayoutTextSize = new Vector2(600f, 200f);
|
|
||||||
public float newLayoutOptionsWidth = 600f;
|
|
||||||
public float newLayoutPadding = 20f;
|
|
||||||
public float newLayoutTextNameOffset = 20f;
|
|
||||||
public float newLayoutOptionsTextOffset = 20f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,177 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using Verse;
|
|
||||||
using RimWorld;
|
|
||||||
using RimWorld.Planet;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class EventVariableManager : WorldComponent
|
|
||||||
{
|
|
||||||
private Dictionary<string, int> intVars = new Dictionary<string, int>();
|
|
||||||
private Dictionary<string, float> floatVars = new Dictionary<string, float>();
|
|
||||||
private Dictionary<string, string> stringVars = new Dictionary<string, string>();
|
|
||||||
private Dictionary<string, Pawn> pawnVars = new Dictionary<string, Pawn>();
|
|
||||||
private Dictionary<string, List<Pawn>> pawnListVars = new Dictionary<string, List<Pawn>>();
|
|
||||||
|
|
||||||
// 用于Scribe的辅助列表
|
|
||||||
private List<string> pawnVarKeys;
|
|
||||||
private List<Pawn> pawnVarValues;
|
|
||||||
private List<string> pawnListVarKeys;
|
|
||||||
private List<List<Pawn>> pawnListVarValues;
|
|
||||||
|
|
||||||
// Required for WorldComponent
|
|
||||||
public EventVariableManager(World world) : base(world)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData()
|
|
||||||
{
|
|
||||||
base.ExposeData();
|
|
||||||
Scribe_Collections.Look(ref intVars, "intVars", LookMode.Value, LookMode.Value);
|
|
||||||
Scribe_Collections.Look(ref floatVars, "floatVars", LookMode.Value, LookMode.Value);
|
|
||||||
Scribe_Collections.Look(ref stringVars, "stringVars", LookMode.Value, LookMode.Value);
|
|
||||||
Scribe_Collections.Look(ref pawnVars, "pawnVars", LookMode.Value, LookMode.Reference, ref pawnVarKeys, ref pawnVarValues);
|
|
||||||
Scribe_Collections.Look(ref pawnListVars, "pawnListVars", LookMode.Value, LookMode.Reference, ref pawnListVarKeys, ref pawnListVarValues);
|
|
||||||
|
|
||||||
// Ensure dictionaries are not null after loading
|
|
||||||
if (Scribe.mode == LoadSaveMode.PostLoadInit)
|
|
||||||
{
|
|
||||||
intVars ??= new Dictionary<string, int>();
|
|
||||||
floatVars ??= new Dictionary<string, float>();
|
|
||||||
stringVars ??= new Dictionary<string, string>();
|
|
||||||
pawnVars ??= new Dictionary<string, Pawn>();
|
|
||||||
pawnListVars ??= new Dictionary<string, List<Pawn>>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetVariable(string name, object value)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(name)) return;
|
|
||||||
|
|
||||||
// Log the variable change
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Setting variable '{name}' to value '{value}' of type {value?.GetType().Name ?? "null"}.");
|
|
||||||
|
|
||||||
// Clear any existing variable with the same name to prevent type confusion
|
|
||||||
ClearVariable(name);
|
|
||||||
|
|
||||||
if (value is int intValue)
|
|
||||||
{
|
|
||||||
intVars[name] = intValue;
|
|
||||||
}
|
|
||||||
else if (value is float floatValue)
|
|
||||||
{
|
|
||||||
floatVars[name] = floatValue;
|
|
||||||
}
|
|
||||||
else if (value is string stringValue)
|
|
||||||
{
|
|
||||||
stringVars[name] = stringValue;
|
|
||||||
}
|
|
||||||
else if (value is Pawn pawnValue)
|
|
||||||
{
|
|
||||||
pawnVars[name] = pawnValue;
|
|
||||||
}
|
|
||||||
else if (value is List<Pawn> pawnListValue)
|
|
||||||
{
|
|
||||||
pawnListVars[name] = pawnListValue;
|
|
||||||
}
|
|
||||||
else if (value != null)
|
|
||||||
{
|
|
||||||
stringVars[name] = value.ToString();
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} was converted to string for storage. This may lead to unexpected behavior.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetVariable<T>(string name, T defaultValue = default)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(name)) return defaultValue;
|
|
||||||
|
|
||||||
object value = null;
|
|
||||||
if (pawnListVars.TryGetValue(name, out var pawnListVal))
|
|
||||||
{
|
|
||||||
value = pawnListVal;
|
|
||||||
}
|
|
||||||
else if (pawnVars.TryGetValue(name, out var pawnVal))
|
|
||||||
{
|
|
||||||
value = pawnVal;
|
|
||||||
}
|
|
||||||
else if (floatVars.TryGetValue(name, out var floatVal))
|
|
||||||
{
|
|
||||||
value = floatVal;
|
|
||||||
}
|
|
||||||
else if (intVars.TryGetValue(name, out var intVal))
|
|
||||||
{
|
|
||||||
value = intVal;
|
|
||||||
}
|
|
||||||
else if (stringVars.TryGetValue(name, out var stringVal))
|
|
||||||
{
|
|
||||||
value = stringVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
if (value is T typedValue)
|
|
||||||
{
|
|
||||||
return typedValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Handle cases where T is object but the stored value is, e.g., an int
|
|
||||||
if (typeof(T) == typeof(object))
|
|
||||||
{
|
|
||||||
return (T)value;
|
|
||||||
}
|
|
||||||
return (T)System.Convert.ChangeType(value, typeof(T));
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[WulaFallenEmpire] EventVariableManager: Variable '{name}' of type {value.GetType()} could not be converted to {typeof(T)}. Error: {e.Message}");
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasVariable(string name)
|
|
||||||
{
|
|
||||||
return intVars.ContainsKey(name) ||
|
|
||||||
floatVars.ContainsKey(name) ||
|
|
||||||
stringVars.ContainsKey(name) ||
|
|
||||||
pawnVars.ContainsKey(name) ||
|
|
||||||
pawnListVars.ContainsKey(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearVariable(string name)
|
|
||||||
{
|
|
||||||
if (HasVariable(name))
|
|
||||||
{
|
|
||||||
ArachnaeLog.Debug($"[EventSystem] Clearing variable '{name}'.");
|
|
||||||
}
|
|
||||||
intVars.Remove(name);
|
|
||||||
floatVars.Remove(name);
|
|
||||||
stringVars.Remove(name);
|
|
||||||
pawnVars.Remove(name);
|
|
||||||
pawnListVars.Remove(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearAll()
|
|
||||||
{
|
|
||||||
intVars.Clear();
|
|
||||||
floatVars.Clear();
|
|
||||||
stringVars.Clear();
|
|
||||||
pawnVars.Clear();
|
|
||||||
pawnListVars.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Dictionary<string, object> GetAllVariables()
|
|
||||||
{
|
|
||||||
var allVars = new Dictionary<string, object>();
|
|
||||||
foreach (var kvp in intVars) allVars[kvp.Key] = kvp.Value;
|
|
||||||
foreach (var kvp in floatVars) allVars[kvp.Key] = kvp.Value;
|
|
||||||
foreach (var kvp in stringVars) allVars[kvp.Key] = kvp.Value;
|
|
||||||
foreach (var kvp in pawnVars) allVars[kvp.Key] = kvp.Value;
|
|
||||||
foreach (var kvp in pawnListVars) allVars[kvp.Key] = kvp.Value;
|
|
||||||
return allVars;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
using RimWorld;
|
|
||||||
using RimWorld.QuestGen;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class Letter_EventChoice : ChoiceLetter
|
|
||||||
{
|
|
||||||
// These fields are now inherited from the base Letter class
|
|
||||||
// public string letterLabel;
|
|
||||||
// public string letterTitle;
|
|
||||||
// public string letterText;
|
|
||||||
public List<QuestNode_Root_EventLetter.Option> options;
|
|
||||||
public new Quest quest;
|
|
||||||
|
|
||||||
public override IEnumerable<DiaOption> Choices
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (options.NullOrEmpty())
|
|
||||||
{
|
|
||||||
yield break;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var optionDef in options)
|
|
||||||
{
|
|
||||||
var currentOption = optionDef;
|
|
||||||
Action choiceAction = delegate
|
|
||||||
{
|
|
||||||
if (!currentOption.optionEffects.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var conditionalEffect in currentOption.optionEffects)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
if (AreConditionsMet(conditionalEffect.conditions, out reason))
|
|
||||||
{
|
|
||||||
conditionalEffect.Execute(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (quest != null && !quest.hidden && !quest.Historical)
|
|
||||||
{
|
|
||||||
quest.End(QuestEndOutcome.Success);
|
|
||||||
}
|
|
||||||
Find.LetterStack.RemoveLetter(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
var diaOption = new DiaOption(currentOption.label)
|
|
||||||
{
|
|
||||||
action = choiceAction,
|
|
||||||
resolveTree = true
|
|
||||||
};
|
|
||||||
yield return diaOption;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanDismissWithRightClick => false;
|
|
||||||
|
|
||||||
private bool AreConditionsMet(List<Condition> conditions, out string reason)
|
|
||||||
{
|
|
||||||
reason = "";
|
|
||||||
if (conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var condition in conditions)
|
|
||||||
{
|
|
||||||
if (!condition.IsMet(out string singleReason))
|
|
||||||
{
|
|
||||||
reason = singleReason;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ExposeData()
|
|
||||||
{
|
|
||||||
base.ExposeData();
|
|
||||||
// Scribe_Values.Look(ref letterLabel, "letterLabel"); // Now uses base.label
|
|
||||||
// Scribe_Values.Look(ref letterTitle, "letterTitle"); // Now uses base.title
|
|
||||||
// Scribe_Values.Look(ref letterText, "letterText"); // Now uses base.text
|
|
||||||
Scribe_Collections.Look(ref options, "options", LookMode.Deep);
|
|
||||||
if (Scribe.mode != LoadSaveMode.Saving || quest != null)
|
|
||||||
{
|
|
||||||
Scribe_References.Look(ref quest, "quest");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
using RimWorld;
|
|
||||||
using RimWorld.QuestGen;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Verse;
|
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
|
||||||
{
|
|
||||||
public class QuestNode_Root_EventLetter : QuestNode
|
|
||||||
{
|
|
||||||
// Fields to be set from the QuestScriptDef XML
|
|
||||||
public SlateRef<string> letterLabel;
|
|
||||||
public SlateRef<string> letterTitle;
|
|
||||||
public SlateRef<string> letterText;
|
|
||||||
public List<Option> options = new List<Option>();
|
|
||||||
|
|
||||||
// This is a root node, so it doesn't have a parent signal.
|
|
||||||
// It runs immediately when the quest starts.
|
|
||||||
protected override void RunInt()
|
|
||||||
{
|
|
||||||
// Get the current slate
|
|
||||||
Slate slate = QuestGen.slate;
|
|
||||||
|
|
||||||
var letter = (Letter_EventChoice)LetterMaker.MakeLetter(DefDatabase<LetterDef>.GetNamed("ARA_EventChoiceLetter"));
|
|
||||||
letter.Label = letterLabel.GetValue(slate);
|
|
||||||
letter.title = letterTitle.GetValue(slate);
|
|
||||||
letter.Text = letterText.GetValue(slate);
|
|
||||||
letter.options = options;
|
|
||||||
letter.quest = QuestGen.quest;
|
|
||||||
letter.lookTargets = slate.Get<LookTargets>("lookTargets");
|
|
||||||
|
|
||||||
Find.LetterStack.ReceiveLetter(letter);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool TestRunInt(Slate slate)
|
|
||||||
{
|
|
||||||
// This node can always run as long as the slate refs are valid.
|
|
||||||
// We can add more complex checks here if needed.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inner class to hold option data from XML
|
|
||||||
public class Option
|
|
||||||
{
|
|
||||||
public string label;
|
|
||||||
public List<ConditionalEffects> optionEffects;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -128,7 +128,6 @@ namespace ArachnaeSwarm
|
|||||||
count = entry.count,
|
count = entry.count,
|
||||||
cost = entry.cost,
|
cost = entry.cost,
|
||||||
cooldownTicks = entry.cooldownTicks,
|
cooldownTicks = entry.cooldownTicks,
|
||||||
conditions = entry.conditions?.ToList(), // 复制条件列表
|
|
||||||
customInfo = entry.customInfo
|
customInfo = entry.customInfo
|
||||||
};
|
};
|
||||||
entryMap[entry.pawnKind] = newEntry;
|
entryMap[entry.pawnKind] = newEntry;
|
||||||
|
|||||||
@@ -32,37 +32,12 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
foreach (var entry in queue)
|
foreach (var entry in queue)
|
||||||
{
|
{
|
||||||
// 检查前置条件
|
availableQueue.Add(entry);
|
||||||
if (CheckEntryConditions(entry, pawn))
|
|
||||||
{
|
|
||||||
availableQueue.Add(entry);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return availableQueue;
|
return availableQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查条目条件是否满足
|
|
||||||
/// </summary>
|
|
||||||
private bool CheckEntryConditions(PawnProductionEntry entry, Pawn pawn)
|
|
||||||
{
|
|
||||||
// 检查自定义条件
|
|
||||||
if (!entry.conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var condition in entry.conditions)
|
|
||||||
{
|
|
||||||
string reason;
|
|
||||||
if (!condition.IsMet(out reason))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 根据PawnKindDef查找生产队列条目
|
/// 根据PawnKindDef查找生产队列条目
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace ArachnaeSwarm
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// 检查是否和喂养者同一派系
|
// 检查是否和喂养者同一派系
|
||||||
if (target.Faction != null && target.Faction == feeder.Faction)
|
if (target.Faction != null && target.Faction == feeder.Faction && !target.IsAnimal)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Verse;
|
using Verse;
|
||||||
|
using Verse.AI;
|
||||||
using Verse.AI.Group;
|
using Verse.AI.Group;
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
namespace ArachnaeSwarm
|
||||||
@@ -654,7 +655,13 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parent is Pawn p && p.GetLord() != null)
|
if (parent is Pawn p && p.GetLord() != null)
|
||||||
|
{
|
||||||
p.GetLord().AddPawn(pawn);
|
p.GetLord().AddPawn(pawn);
|
||||||
|
if (pawn.mindState.duty == null && p.mindState.duty != null)
|
||||||
|
{
|
||||||
|
pawn.mindState.duty = p.mindState.duty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!AutoProps.freeProduction)
|
if (!AutoProps.freeProduction)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -230,11 +230,19 @@ namespace ArachnaeSwarm
|
|||||||
// 检查生产者是否仍然有效
|
// 检查生产者是否仍然有效
|
||||||
if (producer != null && (producer.Destroyed || (producer is Pawn p && (p.Dead || p.Downed))))
|
if (producer != null && (producer.Destroyed || (producer is Pawn p && (p.Dead || p.Downed))))
|
||||||
{
|
{
|
||||||
Log.Warning($"生产者无效: {producer?.LabelCap}, 清除引用");
|
|
||||||
producer = null;
|
producer = null;
|
||||||
producerComp = null;
|
producerComp = null;
|
||||||
}
|
}
|
||||||
|
else if (producer != null && producer is Pawn)
|
||||||
|
{
|
||||||
|
Pawn pawnProducer = producer as Pawn;
|
||||||
|
Pawn creation = parent as Pawn;
|
||||||
|
if (creation.mindState.duty == null && pawnProducer.mindState.duty != null)
|
||||||
|
{
|
||||||
|
creation.mindState.duty = pawnProducer.mindState.duty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 检查自身状态
|
// 检查自身状态
|
||||||
CheckSelfStatus();
|
CheckSelfStatus();
|
||||||
}
|
}
|
||||||
@@ -252,7 +260,6 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
wasDead = true;
|
wasDead = true;
|
||||||
deathTick = Find.TickManager.TicksGame;
|
deathTick = Find.TickManager.TicksGame;
|
||||||
Log.Message($"子单位死亡: {pawn.LabelCap}, 准备通知生产者");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 死亡后延迟清理
|
// 死亡后延迟清理
|
||||||
|
|||||||
@@ -26,9 +26,6 @@ namespace ArachnaeSwarm
|
|||||||
// Optional: custom information for display
|
// Optional: custom information for display
|
||||||
public string customInfo;
|
public string customInfo;
|
||||||
|
|
||||||
// Optional: conditions that must be met for this entry to be available
|
|
||||||
public List<Condition> conditions;
|
|
||||||
|
|
||||||
// Optional: priority (lower number = higher priority)
|
// Optional: priority (lower number = higher priority)
|
||||||
public int priority = 0;
|
public int priority = 0;
|
||||||
|
|
||||||
@@ -76,21 +73,6 @@ namespace ArachnaeSwarm
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查自定义条件
|
|
||||||
if (!conditions.NullOrEmpty())
|
|
||||||
{
|
|
||||||
foreach (var condition in conditions)
|
|
||||||
{
|
|
||||||
string conditionReason;
|
|
||||||
if (!condition.IsMet(out conditionReason))
|
|
||||||
{
|
|
||||||
reason = conditionReason;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +88,6 @@ namespace ArachnaeSwarm
|
|||||||
cooldownTicks = cooldownTicks,
|
cooldownTicks = cooldownTicks,
|
||||||
cost = cost,
|
cost = cost,
|
||||||
customInfo = customInfo,
|
customInfo = customInfo,
|
||||||
conditions = conditions?.ToList(), // 深拷贝条件列表
|
|
||||||
priority = priority,
|
priority = priority,
|
||||||
weight = weight,
|
weight = weight,
|
||||||
enabled = enabled,
|
enabled = enabled,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user