1
This commit is contained in:
Binary file not shown.
@@ -23,24 +23,6 @@
|
||||
<li>
|
||||
<effects>
|
||||
<li Class="WulaFallenEmpire.Effect_CloseDialog" />
|
||||
<li Class="WulaFallenEmpire.Effect_TriggerRaid">
|
||||
<letterLabel>陆行舰正在逼近</letterLabel>
|
||||
<letterText>艾妮西娅按照要求,吸引了一艘乌拉帝国的陆行舰机械体攻击我们的殖民地!</letterText>
|
||||
<points>100</points>
|
||||
<faction>Mechanoid</faction>
|
||||
<raidStrategy>ImmediateAttack</raidStrategy>
|
||||
<raidArrivalMode>EdgeWalkIn</raidArrivalMode>
|
||||
<groupKind>Combat</groupKind>
|
||||
<pawnGroupMakers>
|
||||
<li>
|
||||
<kindDef>Combat</kindDef>
|
||||
<commonality>100</commonality>
|
||||
<options>
|
||||
<Wula_Mech_Mobile_Factory_1>100</Wula_Mech_Mobile_Factory_1>
|
||||
</options>
|
||||
</li>
|
||||
</pawnGroupMakers>
|
||||
</li>
|
||||
</effects>
|
||||
</li>
|
||||
</optionEffects>
|
||||
@@ -80,6 +62,7 @@
|
||||
</li>
|
||||
</options>
|
||||
</WulaFallenEmpire.EventDef>
|
||||
|
||||
<WulaFallenEmpire.EventDef>
|
||||
<defName>Wula_UI_Legion_30</defName>
|
||||
<label>和P.I.A的通讯</label>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Defs>
|
||||
<!-- 初始任务 -->
|
||||
<IncidentDef>
|
||||
<defName>WULA_GiveQuest_Intro_Spy</defName>
|
||||
<category>GiveQuest</category>
|
||||
@@ -12,7 +13,6 @@
|
||||
<baseChance>0</baseChance>
|
||||
<requireColonistsPresent>True</requireColonistsPresent>
|
||||
</IncidentDef>
|
||||
|
||||
<QuestScriptDef>
|
||||
<defName>WULA_Intro_Spy</defName>
|
||||
<defaultChallengeRating>1</defaultChallengeRating> <!-- 挑战等级(星级) -->
|
||||
@@ -25,10 +25,7 @@
|
||||
<!-- 命名规则 -->
|
||||
<questNameRules>
|
||||
<rulesStrings>
|
||||
<li>questName->[QuestName]</li>
|
||||
|
||||
<!-- Pieces -->
|
||||
<li>QuestName->hunted</li>
|
||||
<li>questName->WULA_Intro_Spy_questName</li>
|
||||
</rulesStrings>
|
||||
</questNameRules>
|
||||
<questDescriptionRules>
|
||||
@@ -36,7 +33,7 @@
|
||||
<li>QuestHospitalityCommon</li>
|
||||
</include>
|
||||
<rulesStrings>
|
||||
<li>questDescription->[asker_nameFull], a [asker_royalTitleInCurrentFaction] of [asker_faction_name] is calling from nearby. [asker_possessive] guards were killed in an ambush. [asker_pronoun] escaped, but is now being followed by (*Threat)a manhunting [animalKindDef_label](/Threat).\n\n[asker_nameDef] wants you to keep [asker_objective] safe at [map_definite] for a few hours until [asker_possessive] shuttle can come pick [asker_objective] up.\n[asker_pronoun] will bestow [royalFavorReward] [asker_faction_royalFavorLabel] on whoever accepts this quest. This is enough [asker_faction_royalFavorLabel] to receive the royal title of Novice, and all benefits that come with it - including the first level of psychic powers.</li>
|
||||
<li>questDescription->WULA_Intro_Spy_questDescription</li>
|
||||
</rulesStrings>
|
||||
</questDescriptionRules>
|
||||
|
||||
@@ -46,20 +43,6 @@
|
||||
<li Class="WulaFallenEmpire.QuestNode_Root_EventLetter">
|
||||
<eventDefName>Wula_Intro_Spy_UI_1</eventDefName>
|
||||
</li>
|
||||
<li Class="QuestNode_ResolveQuestName">
|
||||
<rules>
|
||||
<rulesStrings>
|
||||
<li>questName->掩护帝国密探</li>
|
||||
</rulesStrings>
|
||||
</rules>
|
||||
</li>
|
||||
<li Class="QuestNode_ResolveQuestDescription">
|
||||
<rules>
|
||||
<rulesStrings>
|
||||
<li>questDescription->乌拉帝国行星封锁机关的总控AI向殖民地发送了一个请求。一位乌拉帝国密探已经暴露,正在遭受未知派系追杀——密探手无寸铁且携带重要信息,殖民地需要掩护它直到乌拉帝国的穿梭机抵达并将其接走。袭击不会太剧烈,密探已经甩掉了大部分敌人。</li>
|
||||
</rulesStrings>
|
||||
</rules>
|
||||
</li>
|
||||
|
||||
<li Class="QuestNode_SubScript">
|
||||
<def>Util_RandomizePointsChallengeRating</def>
|
||||
@@ -130,7 +113,7 @@
|
||||
<delayTicks>1800</delayTicks>
|
||||
<!-- 判断条件:是否允许暴力行为(游戏设置) -->
|
||||
<node Class="QuestNode_ViolentQuestsAllowed">
|
||||
<!-- 允许暴力则生成狂暴动物袭击 -->
|
||||
<!-- 允许暴力则生成袭击 -->
|
||||
<node Class="QuestNode_SubScript">
|
||||
<def>Util_Raid</def>
|
||||
<prefix>raid</prefix>
|
||||
@@ -141,24 +124,11 @@
|
||||
<enemyFaction>$enemyFaction</enemyFaction>
|
||||
<walkInSpot>$walkInSpot</walkInSpot>
|
||||
<customLetterLabel TKey="LetterLabelChasing">{BASELABEL} chasing [../asker_nameDef]</customLetterLabel>
|
||||
<customLetterText TKey="LetterTextChasing">{BASETEXT}
|
||||
\nThe [enemyFaction_pawnsPlural] have come to get [../asker_nameDef].</customLetterText>
|
||||
<customLetterText TKey="LetterTextChasing">{BASETEXT}\nThe [enemyFaction_pawnsPlural] have come to get [../asker_nameDef].</customLetterText>
|
||||
</parms>
|
||||
</node>
|
||||
<!-- 不允许暴力则生成温和动物 -->
|
||||
<elseNode Class="QuestNode_Sequence">
|
||||
<nodes>
|
||||
<li Class="QuestNode_GetAnimalKindByPoints" />
|
||||
<li Class="QuestNode_GeneratePawn">
|
||||
<kindDef>$animalKindDef</kindDef>
|
||||
<storeAs>peacefulAnimal</storeAs>
|
||||
</li>
|
||||
<li Class="QuestNode_PawnsArrive">
|
||||
<pawns>$peacefulAnimal</pawns>
|
||||
<customLetterLabel TKey="LetterLabelAnimalArrived">[animalKindDef_label] arrived</customLetterLabel>
|
||||
<customLetterText TKey="LetterTextAnimalArrived">The [animalKindDef_label] that [asker_nameDef] was fleeing has arrived.\n\nIt turned out to be quite gentle and not aggressive at all.</customLetterText>
|
||||
</li>
|
||||
</nodes>
|
||||
</elseNode>
|
||||
</node>
|
||||
</li>
|
||||
@@ -637,4 +607,83 @@
|
||||
</li>
|
||||
</options>
|
||||
</WulaFallenEmpire.EventDef>
|
||||
|
||||
<!-- 纳税 -->
|
||||
<IncidentDef>
|
||||
<defName>WULA_GiveQuest_Base_Tex</defName>
|
||||
<category>GiveQuest</category>
|
||||
<label>纳税</label>
|
||||
<targetTags>
|
||||
<li>Map_PlayerHome</li>
|
||||
</targetTags>
|
||||
<questScriptDef>WULA_Base_Tex_Quest</questScriptDef>
|
||||
<workerClass>IncidentWorker_GiveQuest</workerClass>
|
||||
<baseChance>0</baseChance>
|
||||
<requireColonistsPresent>True</requireColonistsPresent>
|
||||
</IncidentDef>
|
||||
<QuestScriptDef>
|
||||
<defName>WULA_Base_Tex_Quest</defName>
|
||||
<rootSelectionWeight>0</rootSelectionWeight>
|
||||
<autoAccept>true</autoAccept>
|
||||
<sendAvailableLetter>false</sendAvailableLetter>
|
||||
<defaultChallengeRating>1</defaultChallengeRating> <!-- 挑战等级(星级) -->
|
||||
<isRootSpecial>true</isRootSpecial> <!-- 特殊任务 -->
|
||||
<defaultCharity>false</defaultCharity> <!-- 是否仁善 -->
|
||||
<!-- 命名规则 -->
|
||||
<questNameRules>
|
||||
<rulesStrings>
|
||||
<li>questName->WULA_Base_Tex_Quest_questName</li>
|
||||
</rulesStrings>
|
||||
</questNameRules>
|
||||
<questDescriptionRules>
|
||||
<include>
|
||||
<li>QuestHospitalityCommon</li>
|
||||
</include>
|
||||
<rulesStrings>
|
||||
<li>questDescription->WULA_Intro_Spy_questDescription</li>
|
||||
</rulesStrings>
|
||||
</questDescriptionRules>
|
||||
|
||||
<!-- 运行规则 -->
|
||||
<root Class="QuestNode_Sequence">
|
||||
<nodes>
|
||||
<!-- 设置钢铁需求 -->
|
||||
<li Class="QuestNode_Set">
|
||||
<name>taxAmount</name>
|
||||
<value>100</value>
|
||||
</li>
|
||||
<li Class="QuestNode_Set">
|
||||
<name>taxInterval</name>
|
||||
<value>250</value> <!-- 较短的测试间隔 -->
|
||||
</li>
|
||||
<!-- 检查全局资源 -->
|
||||
<li Class="WulaFallenEmpire.QuestNode_CheckGlobalResource">
|
||||
<resourceDef>Steel</resourceDef>
|
||||
<requiredCount>$taxAmount</requiredCount>
|
||||
<retryDelayTicks>$taxInterval</retryDelayTicks>
|
||||
<successSignal>TaxPaymentSuccess</successSignal>
|
||||
<failSignal>TaxPaymentFailed</failSignal>
|
||||
<deductOnSuccess>true</deductOnSuccess>
|
||||
<useInputStorage>true</useInputStorage>
|
||||
</li>
|
||||
<!-- 支付成功处理 -->
|
||||
<li Class="QuestNode_Signal">
|
||||
<inSignal>TaxPaymentSuccess</inSignal>
|
||||
<node Class="QuestNode_Sequence">
|
||||
<nodes>
|
||||
<li Class="QuestNode_Letter">
|
||||
<label>纳税完成</label>
|
||||
<text>已成功从全局储存中扣除100钢铁作为税款。</text>
|
||||
<letterDef>PositiveEvent</letterDef>
|
||||
</li>
|
||||
<li Class="QuestNode_End">
|
||||
<outcome>Success</outcome>
|
||||
<sendStandardLetter>false</sendStandardLetter>
|
||||
</li>
|
||||
</nodes>
|
||||
</node>
|
||||
</li>
|
||||
</nodes>
|
||||
</root>
|
||||
</QuestScriptDef>
|
||||
</Defs>
|
||||
21
1.6/1.6/Defs/QuestScriptDefs/WULA_Scripts_Utility.xml
Normal file
21
1.6/1.6/Defs/QuestScriptDefs/WULA_Scripts_Utility.xml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Defs>
|
||||
<!-- 全局资源检查工具 -->
|
||||
<QuestScriptDef>
|
||||
<defName>Util_Wula_GlobalResourceCheck</defName>
|
||||
<root Class="QuestNode_Sequence">
|
||||
<nodes>
|
||||
<!-- 检查全局资源 -->
|
||||
<li Class="WulaFallenEmpire.QuestNode_CheckGlobalResource">
|
||||
<resourceDef>$resourceDef</resourceDef>
|
||||
<requiredCount>$requiredCount</requiredCount>
|
||||
<retryDelayTicks>$retryDelayTicks</retryDelayTicks>
|
||||
<successSignal>$successSignal</successSignal>
|
||||
<failSignal>$failSignal</failSignal>
|
||||
<deductOnSuccess>$deductOnSuccess</deductOnSuccess>
|
||||
<useInputStorage>$useInputStorage</useInputStorage>
|
||||
</li>
|
||||
</nodes>
|
||||
</root>
|
||||
</QuestScriptDef>
|
||||
</Defs>
|
||||
@@ -976,7 +976,7 @@
|
||||
<ThingDef Name="Wula_AI_Heavy_Panzer" ParentName="WULA_BaseMechanoid">
|
||||
<defName>Wula_AI_Heavy_Panzer</defName> <!-- 修改了defName以避免冲突 -->
|
||||
<label>HAp-6"战车"</label>
|
||||
<description>乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用穿透力强大的战车炮和导弹打击敌方,是乌拉帝国前锋部队的中流砥柱。</description>
|
||||
<description>乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。</description>
|
||||
<uiIconPath>Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Heavy_Panzer_Icon</uiIconPath>
|
||||
<statBases>
|
||||
<BandwidthCost>1</BandwidthCost>
|
||||
@@ -1519,10 +1519,10 @@
|
||||
<comps Inherit="False">
|
||||
<!--加上这个组件的机械体可以更换武器-->
|
||||
<li Class="WulaFallenEmpire.CompProperties_MechWeapon" />
|
||||
<li Class="CompProperties_CanBeDormant" />
|
||||
<li Class="CompProperties_CanBeDormant">
|
||||
<compClass>CompMechanoid</compClass>
|
||||
</li>
|
||||
<li Class="CompProperties_WakeUpDormant">
|
||||
<wakeUpOnDamage>true</wakeUpOnDamage>
|
||||
<wakeUpCheckRadius>30</wakeUpCheckRadius>
|
||||
<wakeUpSound>MechanoidsWakeUp</wakeUpSound>
|
||||
</li>
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LanguageData>
|
||||
<WULA_Intro_Spy.questNameRules.rulesStrings>
|
||||
<li>questName->掩护帝国密探</li>
|
||||
</WULA_Intro_Spy.questNameRules.rulesStrings>
|
||||
<WULA_Intro_Spy.questDescriptionRules.rulesStrings>
|
||||
<li>questDescription->乌拉帝国行星封锁机关的总控AI向殖民地发送了一个请求。一位乌拉帝国密探已经暴露,正在遭受其他派系追杀——密探手无寸铁且携带重要信息,殖民地需要掩护它直到乌拉帝国的穿梭机抵达并将其接走。虽然对方未透露更多信息,不过她指明袭击不会太剧烈,密探已经甩掉了大部分敌人。</li>
|
||||
</WULA_Intro_Spy.questDescriptionRules.rulesStrings>
|
||||
<WULA_Intro_Spy.LetterLabelChasing.slateRef>{BASELABEL} 追捕[../asker_nameDef]</WULA_Intro_Spy.LetterLabelChasing.slateRef>
|
||||
<WULA_Intro_Spy.LetterTextChasing.slateRef>{BASETEXT}\n\n[enemyFaction_pawnsPlural]来此追捕[../asker_nameDef]。</WULA_Intro_Spy.LetterTextChasing.slateRef>
|
||||
|
||||
|
||||
<WULA_Intro_Spy.InspectStringDepartShuttle.slateRef>应该乘坐穿梭机出发</WULA_Intro_Spy.InspectStringDepartShuttle.slateRef>
|
||||
<!-- EN: Shuttle arrived -->
|
||||
<WULA_Intro_Spy.LetterLabelShuttleArrived.slateRef>穿梭机已抵达</WULA_Intro_Spy.LetterLabelShuttleArrived.slateRef>
|
||||
<!-- EN: The shuttle has arrived to collect [asker_nameDef]. -->
|
||||
<WULA_Intro_Spy.LetterTextShuttleArrived.slateRef>前来迎接[asker_nameDef]的穿梭机已抵达。</WULA_Intro_Spy.LetterTextShuttleArrived.slateRef>
|
||||
<!-- EN: Guest died: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.LetterLabelGuestDied.slateRef>宾客已死亡:{SUBJECT_definite}</WULA_Intro_Spy.LetterLabelGuestDied.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to protect, has died. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextGuestDied.slateRef>需要你小心保护的{SUBJECT_definite}已经死亡。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextGuestDied.slateRef>
|
||||
<!-- EN: Guest left behind: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.root.nodes.askerLeftBehind.node.nodes.Letter.label.slateRef>宾客被遗弃:{SUBJECT_definite}</WULA_Intro_Spy.root.nodes.askerLeftBehind.node.nodes.Letter.label.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to protect, has been left behind. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.root.nodes.askerLeftBehind.node.nodes.Letter.text.slateRef>需要你小心保护的{SUBJECT_definite}被遗弃。[failLetterEndingCommon]</WULA_Intro_Spy.root.nodes.askerLeftBehind.node.nodes.Letter.text.slateRef>
|
||||
<!-- EN: Unauthorized surgery: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.LetterLabelUnauthorizedSurgery.slateRef>未授权手术:{SUBJECT_definite}</WULA_Intro_Spy.LetterLabelUnauthorizedSurgery.slateRef>
|
||||
<!-- EN: Unauthorized, violating surgery has been performed on {SUBJECT_definite}, who you were charged to protect. Because of this violation, [asker_pronoun] will now attempt to leave. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextUnauthorizedSurgery.slateRef>需要你小心保护的{SUBJECT_definite}接受了一次未授权的额外手术。因为你违规在先,[asker_pronoun]将要离开此处。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextUnauthorizedSurgery.slateRef>
|
||||
<!-- EN: Xenogerm absorbed: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.root.nodes.askerXenogermAbsorbed.node.nodes.Letter.label.slateRef>异种胚芽被吸收:{SUBJECT_definite}</WULA_Intro_Spy.root.nodes.askerXenogermAbsorbed.node.nodes.Letter.label.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to protect, has had {SUBJECT_possessive} xenogerm forcibly absorbed. Because of this violation, {SUBJECT_pronoun} will now attempt to leave. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.root.nodes.askerXenogermAbsorbed.node.nodes.Letter.text.slateRef>指定由你保护的{SUBJECT_definite}在你的殖民地被吸收了异种胚芽。这是一种侵犯行为,{SUBJECT_pronoun}现在将会直接离开[failLetterEndingCommon]。</WULA_Intro_Spy.root.nodes.askerXenogermAbsorbed.node.nodes.Letter.text.slateRef>
|
||||
<!-- EN: Captured: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.LetterLabelCaptured.slateRef>已被俘:{SUBJECT_definite}</WULA_Intro_Spy.LetterLabelCaptured.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to host, has been arrested. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextCaptured.slateRef>需要你小心保护的{SUBJECT_definite}已被俘虏。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextCaptured.slateRef>
|
||||
<!-- EN: Guest lost: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.LetterLabelGuestLost.slateRef>宾客失踪:{SUBJECT_definite}</WULA_Intro_Spy.LetterLabelGuestLost.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to protect, has left the designated settlement. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextGuestLost.slateRef>需要你小心保护的{SUBJECT_definite}在你的殖民地回归自然。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextGuestLost.slateRef>
|
||||
<!-- EN: Guest lost: {SUBJECT_definite} -->
|
||||
<WULA_Intro_Spy.LetterLabelLodgerRanWild.slateRef>宾客失踪:{SUBJECT_definite}</WULA_Intro_Spy.LetterLabelLodgerRanWild.slateRef>
|
||||
<!-- EN: {SUBJECT_definite}, who you were charged to protect, has run wild. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextLodgerRanWild.slateRef>需要你小心保护的{SUBJECT_definite}在你的殖民地回归自然。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextLodgerRanWild.slateRef>
|
||||
<!-- EN: Shuttle destroyed -->
|
||||
<WULA_Intro_Spy.LetterLabelShuttleDestroyed.slateRef>穿梭机被毁</WULA_Intro_Spy.LetterLabelShuttleDestroyed.slateRef>
|
||||
<!-- EN: The shuttle sent to collect [asker_nameDef] has been destroyed. [asker_pronoun] will now leave on foot. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextShuttleDestroyed.slateRef>前来迎接[asker_nameDef]的穿梭机已被毁。[asker_pronoun]现在只能走回去了。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextShuttleDestroyed.slateRef>
|
||||
<!-- EN: Shuttle left behind -->
|
||||
<WULA_Intro_Spy.root.nodes.pickupShipThingLeftBehind.node.nodes.Letter.label.slateRef>穿梭机被遗弃</WULA_Intro_Spy.root.nodes.pickupShipThingLeftBehind.node.nodes.Letter.label.slateRef>
|
||||
<!-- EN: The shuttle sent to collect [asker_nameDef] has been left behind. [asker_pronoun] will now leave on foot. -->
|
||||
<WULA_Intro_Spy.root.nodes.pickupShipThingLeftBehind.node.nodes.Letter.text.slateRef>前来迎接[asker_nameDef]的穿梭机已被遗弃。[asker_pronoun]现在只能走回去了。</WULA_Intro_Spy.root.nodes.pickupShipThingLeftBehind.node.nodes.Letter.text.slateRef>
|
||||
<!-- EN: Quest failed: [resolvedQuestName] -->
|
||||
<WULA_Intro_Spy.LetterLabelQuestFailed.slateRef>任务失败:[resolvedQuestName]</WULA_Intro_Spy.LetterLabelQuestFailed.slateRef>
|
||||
<!-- EN: The shuttle sent to collect [asker_nameDef] has departed without [asker_objective]. [asker_pronoun] will now leave on foot. [failLetterEndingCommon] -->
|
||||
<WULA_Intro_Spy.LetterTextQuestFailed.slateRef>前来迎接[asker_nameDef]的穿梭机在离开时因为一些原因落下了[asker_objective]。[asker_pronoun]现在只能走回去了。[failLetterEndingCommon]</WULA_Intro_Spy.LetterTextQuestFailed.slateRef>
|
||||
</LanguageData>
|
||||
@@ -197,6 +197,7 @@ namespace WulaFallenEmpire
|
||||
return Mathf.Clamp01(currentFadeInTime / fadeInDuration);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:计算剩余飞行时间(秒)
|
||||
public float RemainingFlightTime
|
||||
{
|
||||
@@ -206,16 +207,16 @@ namespace WulaFallenEmpire
|
||||
return remainingProgress / (flightSpeed * 0.001f) * (1f / 60f);
|
||||
}
|
||||
}
|
||||
|
||||
// 修改后的紧急销毁方法 - 急速加速版本
|
||||
public void EmergencyDestroy()
|
||||
{
|
||||
if (Destroyed || hasCompleted) return;
|
||||
|
||||
// 计算剩余进度
|
||||
float remainingProgress = 1f - currentProgress;
|
||||
|
||||
// 计算需要的速度:确保在1秒内完成剩余进度
|
||||
// 每帧增加 flightSpeed * 0.001,1秒60帧,所以需要:remainingProgress = flightSpeed * 0.001 * 60
|
||||
// 因此:flightSpeed = remainingProgress / (0.001 * 60) = remainingProgress / 0.06
|
||||
float requiredSpeed = remainingProgress / 0.06f;
|
||||
|
||||
// 设置新的飞行速度,确保至少是当前速度的2倍
|
||||
@@ -223,11 +224,8 @@ namespace WulaFallenEmpire
|
||||
|
||||
// 标记为紧急销毁状态
|
||||
hasCompleted = false; // 确保可以继续飞行
|
||||
|
||||
Log.Message($"FlyOver emergency destroy: accelerating to complete in 1 second. " +
|
||||
$"Current progress: {currentProgress:F2}, Required speed: {requiredSpeed:F2}, " +
|
||||
$"Actual speed: {flightSpeed:F2}");
|
||||
}
|
||||
|
||||
// 修改后的淡出透明度属性 - 紧急销毁时强制启用淡出
|
||||
public float FadeOutAlpha
|
||||
{
|
||||
@@ -239,6 +237,7 @@ namespace WulaFallenEmpire
|
||||
return Mathf.Clamp01(1f - (currentFadeOutTime / fadeOutDuration));
|
||||
}
|
||||
}
|
||||
|
||||
// 修改后的总体透明度属性 - 紧急销毁时强制计算淡出
|
||||
public float OverallAlpha
|
||||
{
|
||||
@@ -248,6 +247,7 @@ namespace WulaFallenEmpire
|
||||
return FadeInAlpha * FadeOutAlpha;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改后的 Tick 方法,优化紧急销毁逻辑
|
||||
protected override void Tick()
|
||||
{
|
||||
@@ -313,6 +313,7 @@ namespace WulaFallenEmpire
|
||||
// 生成飞行轨迹特效
|
||||
CreateFlightEffects();
|
||||
}
|
||||
|
||||
// 修改后的 CompleteFlyOver 方法,添加紧急销毁处理
|
||||
private void CompleteFlyOver()
|
||||
{
|
||||
@@ -333,8 +334,6 @@ namespace WulaFallenEmpire
|
||||
SoundInfo.InMap(new TargetInfo(endPosition, base.Map)));
|
||||
}
|
||||
|
||||
Log.Message($"FlyOver completed at {endPosition}");
|
||||
|
||||
// 立即销毁
|
||||
Destroy();
|
||||
}
|
||||
@@ -375,6 +374,7 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
innerContainer = new ThingOwner<Thing>(this);
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
@@ -390,6 +390,7 @@ namespace WulaFallenEmpire
|
||||
Scribe_Values.Look(ref fadeInDuration, "fadeInDuration", 1.5f);
|
||||
Scribe_Values.Look(ref currentFadeInTime, "currentFadeInTime", 0f);
|
||||
Scribe_Values.Look(ref fadeInCompleted, "fadeInCompleted", false);
|
||||
|
||||
// 淡出效果数据保存
|
||||
Scribe_Values.Look(ref fadeOutDuration, "fadeOutDuration", 0f);
|
||||
Scribe_Values.Look(ref currentFadeOutTime, "currentFadeOutTime", 0f);
|
||||
@@ -397,12 +398,14 @@ namespace WulaFallenEmpire
|
||||
Scribe_Values.Look(ref fadeOutCompleted, "fadeOutCompleted", false);
|
||||
Scribe_Values.Look(ref fadeOutStartProgress, "fadeOutStartProgress", 0.7f);
|
||||
Scribe_Values.Look(ref defaultFadeOutDuration, "defaultFadeOutDuration", 1.5f);
|
||||
|
||||
// 进场动画数据保存
|
||||
Scribe_Values.Look(ref approachDuration, "approachDuration", 1.0f);
|
||||
Scribe_Values.Look(ref currentApproachTime, "currentApproachTime", 0f);
|
||||
Scribe_Values.Look(ref approachCompleted, "approachCompleted", false);
|
||||
Scribe_Values.Look(ref approachOffsetDistance, "approachOffsetDistance", 3f);
|
||||
Scribe_Values.Look(ref useApproachAnimation, "useApproachAnimation", true);
|
||||
|
||||
// 新增:淡入淡出开关保存
|
||||
Scribe_Values.Look(ref useFadeEffects, "useFadeEffects", true);
|
||||
Scribe_Values.Look(ref useFadeIn, "useFadeIn", true);
|
||||
@@ -410,16 +413,17 @@ namespace WulaFallenEmpire
|
||||
Scribe_References.Look(ref caster, "caster");
|
||||
Scribe_References.Look(ref faction, "faction");
|
||||
}
|
||||
|
||||
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||
{
|
||||
base.SpawnSetup(map, respawningAfterLoad);
|
||||
Log.Message($"FlyOver Spawned - Start: {startPosition}, End: {endPosition}, Speed: {flightSpeed}, Altitude: {altitude}");
|
||||
|
||||
if (!respawningAfterLoad)
|
||||
{
|
||||
Log.Message($"FlyOver Direction - Vector: {MovementDirection}, Rotation: {ExactRotation.eulerAngles}");
|
||||
// 设置初始位置
|
||||
base.Position = startPosition;
|
||||
hasStarted = true;
|
||||
|
||||
// 从 ModExtension 加载配置
|
||||
var extension = def.GetModExtension<FlyOverShadowExtension>();
|
||||
if (extension != null)
|
||||
@@ -438,28 +442,30 @@ namespace WulaFallenEmpire
|
||||
defaultFadeOutDuration = extension.defaultFadeOutDuration;
|
||||
fadeOutStartProgress = extension.fadeOutStartProgress;
|
||||
}
|
||||
|
||||
// 重置淡入状态
|
||||
currentFadeInTime = 0f;
|
||||
fadeInCompleted = !useFadeIn; // 如果不使用淡入,直接标记为完成
|
||||
|
||||
// 重置淡出状态
|
||||
currentFadeOutTime = 0f;
|
||||
fadeOutStarted = false;
|
||||
fadeOutCompleted = false;
|
||||
fadeOutDuration = 0f;
|
||||
|
||||
// 重置进场动画状态
|
||||
currentApproachTime = 0f;
|
||||
approachCompleted = !useApproachAnimation; // 如果不使用进场动画,直接标记为完成
|
||||
Log.Message($"FlyOver fade effects: {useFadeEffects}, fadeIn: {useFadeIn}, fadeOut: {useFadeOut}");
|
||||
Log.Message($"FlyOver approach animation: {useApproachAnimation}, duration: {approachDuration}s, offset: {approachOffsetDistance}");
|
||||
|
||||
// 开始飞行音效
|
||||
if (playFlyOverSound && def.skyfaller?.floatingSound != null)
|
||||
{
|
||||
flightSoundPlaying = def.skyfaller.floatingSound.TrySpawnSustainer(
|
||||
SoundInfo.InMap(new TargetInfo(startPosition, map), MaintenanceType.PerTick));
|
||||
Log.Message("FlyOver sound started");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:开始淡出效果
|
||||
private void StartFadeOut()
|
||||
{
|
||||
@@ -467,8 +473,6 @@ namespace WulaFallenEmpire
|
||||
|
||||
// 基于剩余距离动态计算淡出持续时间
|
||||
fadeOutDuration = CalculateDynamicFadeOutDuration();
|
||||
|
||||
Log.Message($"FlyOver started fade out at progress {currentProgress:F2}, duration: {fadeOutDuration:F2}s, remaining time: {RemainingFlightTime:F2}s");
|
||||
}
|
||||
|
||||
// 修改后的 UpdateFlightSound 方法,添加紧急销毁时的音效处理
|
||||
@@ -567,6 +571,7 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
fadePropertyBlock.SetColor(ShaderPropertyIDs.Color,
|
||||
new Color(graphic.Color.r, graphic.Color.g, graphic.Color.b, graphic.Color.a * alpha));
|
||||
|
||||
// 应用伴飞缩放
|
||||
Vector3 scale = Vector3.one;
|
||||
if (def.graphicData != null)
|
||||
@@ -577,6 +582,7 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
scale = new Vector3(escortScale, 1f, escortScale);
|
||||
}
|
||||
|
||||
Vector3 highPos = drawPos;
|
||||
highPos.y = AltitudeLayer.MetaOverlays.AltitudeFor();
|
||||
Matrix4x4 matrix2 = Matrix4x4.TRS(highPos, ExactRotation, scale);
|
||||
@@ -664,27 +670,24 @@ namespace WulaFallenEmpire
|
||||
flyOver.useApproachAnimation = useApproachAnimation;
|
||||
flyOver.approachDuration = approachDuration;
|
||||
flyOver.approachOffsetDistance = approachOffsetDistance;
|
||||
|
||||
// 淡入淡出参数 - 新增
|
||||
if (useFadeEffects.HasValue) flyOver.useFadeEffects = useFadeEffects.Value;
|
||||
if (useFadeIn.HasValue) flyOver.useFadeIn = useFadeIn.Value;
|
||||
if (useFadeOut.HasValue) flyOver.useFadeOut = useFadeOut.Value;
|
||||
|
||||
// 简化派系设置
|
||||
if (casterPawn != null && casterPawn.Faction != null)
|
||||
{
|
||||
flyOver.faction = casterPawn.Faction;
|
||||
Log.Message($"FlyOver faction set to: {casterPawn.Faction.Name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning($"FlyOver: Cannot set faction - casterPawn: {casterPawn?.Label ?? "NULL"}, casterFaction: {casterPawn?.Faction?.Name ?? "NULL"}");
|
||||
}
|
||||
|
||||
if (contents != null)
|
||||
{
|
||||
flyOver.innerContainer.TryAddRangeOrTransfer(contents);
|
||||
}
|
||||
|
||||
GenSpawn.Spawn(flyOver, start, map);
|
||||
Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height}, " +
|
||||
$"FadeEffects: {flyOver.useFadeEffects}, FadeIn: {flyOver.useFadeIn}, FadeOut: {flyOver.useFadeOut}");
|
||||
return flyOver;
|
||||
}
|
||||
}
|
||||
@@ -709,10 +712,12 @@ namespace WulaFallenEmpire
|
||||
public float fadeOutDistanceFactor = 0.01f;
|
||||
|
||||
public float ActuallyHeight = 150f;
|
||||
|
||||
// 进场动画配置
|
||||
public bool useApproachAnimation = true;
|
||||
public float approachDuration = 1.0f;
|
||||
public float approachOffsetDistance = 3f;
|
||||
|
||||
// 新增:淡入淡出开关
|
||||
public bool useFadeEffects = true; // 是否启用淡入淡出效果
|
||||
public bool useFadeIn = true; // 是否启用淡入效果
|
||||
|
||||
@@ -9,27 +9,24 @@ namespace WulaFallenEmpire
|
||||
public class CompAbilityEffect_SpawnFlyOver : CompAbilityEffect
|
||||
{
|
||||
public new CompProperties_AbilitySpawnFlyOver Props => (CompProperties_AbilitySpawnFlyOver)props;
|
||||
// 新增:检查航道等级限制
|
||||
|
||||
public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
if (!base.CanApplyOn(target, dest))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// 在 CompAbilityEffect_SpawnFlyOver.cs 中修改航道检查方法:
|
||||
// 修改 DestroyLowerLevelFlyOvers 方法(现在由全局管理器处理):
|
||||
|
||||
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
|
||||
{
|
||||
base.Apply(target, dest);
|
||||
if (parent.pawn == null || parent.pawn.Map == null)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Log.Message($"FlyOver skill activated by {parent.pawn.Label} at position {parent.pawn.Position}");
|
||||
Log.Message($"Target cell: {target.Cell}, Dest: {dest.Cell}");
|
||||
// 计算起始和结束位置
|
||||
IntVec3 startPos, endPos;
|
||||
// 根据进场类型选择不同的计算方法
|
||||
if (Props.approachType == ApproachType.Perpendicular)
|
||||
{
|
||||
CalculatePerpendicularPath(target, out startPos, out endPos);
|
||||
@@ -39,16 +36,17 @@ namespace WulaFallenEmpire
|
||||
startPos = CalculateStartPosition(target);
|
||||
endPos = CalculateEndPosition(target, startPos);
|
||||
}
|
||||
|
||||
// 确保位置安全
|
||||
startPos = GetSafeMapPosition(startPos, parent.pawn.Map);
|
||||
endPos = GetSafeMapPosition(endPos, parent.pawn.Map);
|
||||
|
||||
// 验证并优化飞行路径
|
||||
if (!ValidateAndOptimizePath(ref startPos, ref endPos, target.Cell))
|
||||
{
|
||||
Log.Warning("FlyOver path validation failed, using fallback path");
|
||||
CalculateFallbackPath(target, out startPos, out endPos);
|
||||
}
|
||||
Log.Message($"Final positions - Start: {startPos}, End: {endPos}");
|
||||
|
||||
// 根据类型创建不同的飞越物体
|
||||
switch (Props.flyOverType)
|
||||
{
|
||||
@@ -69,7 +67,7 @@ namespace WulaFallenEmpire
|
||||
Log.Error($"Error spawning fly over: {ex}");
|
||||
}
|
||||
}
|
||||
// 更新:技能提示信息,包含航道等级信息
|
||||
|
||||
public override string ExtraLabelMouseAttachment(LocalTargetInfo target)
|
||||
{
|
||||
string baseInfo = "";
|
||||
@@ -83,7 +81,7 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
return baseInfo;
|
||||
}
|
||||
// 更新:验证方法,包含航道等级检查
|
||||
|
||||
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
|
||||
{
|
||||
if (!base.Valid(target, throwMessages))
|
||||
@@ -94,7 +92,7 @@ namespace WulaFallenEmpire
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// 更新:创建标准飞越方法,添加航道等级组件
|
||||
|
||||
private void CreateStandardFlyOver(IntVec3 startPos, IntVec3 endPos)
|
||||
{
|
||||
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveShip");
|
||||
@@ -103,6 +101,7 @@ namespace WulaFallenEmpire
|
||||
Log.Warning("No fly over def specified for standard fly over");
|
||||
return;
|
||||
}
|
||||
|
||||
FlyOver flyOver = FlyOver.MakeFlyOver(
|
||||
flyOverDef,
|
||||
startPos,
|
||||
@@ -113,13 +112,8 @@ namespace WulaFallenEmpire
|
||||
);
|
||||
flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
|
||||
flyOver.playFlyOverSound = Props.playFlyOverSound;
|
||||
if (Props.customSound != null)
|
||||
{
|
||||
// 自定义音效逻辑
|
||||
}
|
||||
Log.Message($"Standard FlyOver created: {flyOver} from {startPos} to {endPos}");
|
||||
}
|
||||
// 更新:创建地面扫射飞越,添加航道等级组件
|
||||
|
||||
private void CreateGroundStrafingFlyOver(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
|
||||
{
|
||||
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveCorvette");
|
||||
@@ -128,6 +122,7 @@ namespace WulaFallenEmpire
|
||||
Log.Warning("No fly over def specified for ground strafing fly over");
|
||||
return;
|
||||
}
|
||||
|
||||
FlyOver flyOver = FlyOver.MakeFlyOver(
|
||||
flyOverDef,
|
||||
startPos,
|
||||
@@ -137,19 +132,17 @@ namespace WulaFallenEmpire
|
||||
Props.altitude,
|
||||
casterPawn: parent.pawn
|
||||
);
|
||||
// 设置基本属性
|
||||
|
||||
flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
|
||||
flyOver.playFlyOverSound = Props.playFlyOverSound;
|
||||
// 获取扫射组件并设置预处理后的目标单元格
|
||||
|
||||
CompGroundStrafing strafingComp = flyOver.GetComp<CompGroundStrafing>();
|
||||
if (strafingComp != null)
|
||||
{
|
||||
// 修复:计算扫射区域的所有单元格,以目标单元格为中心
|
||||
Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
List<IntVec3> potentialTargetCells = CalculateStrafingImpactCells(targetCell, flightDirection);
|
||||
if (potentialTargetCells.Count > 0)
|
||||
{
|
||||
// 预处理:根据概率筛选实际会被射击的单元格
|
||||
List<IntVec3> confirmedTargetCells = PreprocessStrafingTargets(
|
||||
potentialTargetCells,
|
||||
Props.strafeFireChance
|
||||
@@ -158,22 +151,10 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
strafingComp.SetConfirmedTargets(confirmedTargetCells);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Warning("No confirmed target cells after preprocessing!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("No potential target cells calculated for ground strafing!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error("FlyOver def does not have CompGroundStrafing component!");
|
||||
}
|
||||
}
|
||||
// 更新:创建扇形监视飞越,添加航道等级组件
|
||||
|
||||
private void CreateSectorSurveillanceFlyOver(IntVec3 startPos, IntVec3 endPos)
|
||||
{
|
||||
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveCorvette");
|
||||
@@ -182,6 +163,7 @@ namespace WulaFallenEmpire
|
||||
Log.Warning("No fly over def specified for sector surveillance fly over");
|
||||
return;
|
||||
}
|
||||
|
||||
FlyOver flyOver = FlyOver.MakeFlyOver(
|
||||
flyOverDef,
|
||||
startPos,
|
||||
@@ -191,76 +173,64 @@ namespace WulaFallenEmpire
|
||||
Props.altitude,
|
||||
casterPawn: parent.pawn
|
||||
);
|
||||
// 设置基本属性
|
||||
|
||||
flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
|
||||
flyOver.playFlyOverSound = Props.playFlyOverSound;
|
||||
Log.Message($"SectorSurveillance FlyOver created: {flyOver} from {startPos} to {endPos}");
|
||||
}
|
||||
// 新增:验证和优化飞行路径
|
||||
|
||||
private bool ValidateAndOptimizePath(ref IntVec3 startPos, ref IntVec3 endPos, IntVec3 targetCell)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 检查路径是否有效
|
||||
if (!startPos.InBounds(map) || !endPos.InBounds(map))
|
||||
return false;
|
||||
|
||||
// 检查起点和终点是否相同
|
||||
if (startPos == endPos)
|
||||
return false;
|
||||
|
||||
// 检查路径长度是否合理
|
||||
float distance = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
|
||||
if (distance < 10f) // 最小飞行距离
|
||||
if (distance < 10f)
|
||||
return false;
|
||||
|
||||
// 检查路径是否经过目标区域附近
|
||||
if (!IsPathNearTarget(startPos, endPos, targetCell))
|
||||
{
|
||||
// 优化路径使其经过目标区域
|
||||
OptimizePathForTarget(ref startPos, ref endPos, targetCell);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
// 新增:检查路径是否经过目标区域
|
||||
|
||||
private bool IsPathNearTarget(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
|
||||
{
|
||||
Vector3 start = startPos.ToVector3();
|
||||
Vector3 end = endPos.ToVector3();
|
||||
Vector3 target = targetCell.ToVector3();
|
||||
|
||||
// 计算点到直线的距离
|
||||
Vector3 lineDirection = (end - start).normalized;
|
||||
Vector3 pointToLine = target - start;
|
||||
Vector3 projection = Vector3.Project(pointToLine, lineDirection);
|
||||
Vector3 perpendicular = pointToLine - projection;
|
||||
|
||||
float distanceToLine = perpendicular.magnitude;
|
||||
|
||||
// 检查投影是否在线段内
|
||||
float projectionLength = projection.magnitude;
|
||||
float lineLength = (end - start).magnitude;
|
||||
bool isWithinSegment = projectionLength >= 0 && projectionLength <= lineLength;
|
||||
|
||||
// 如果距离小于15格且在路径线段内,则认为路径经过目标
|
||||
return distanceToLine <= 15f && isWithinSegment;
|
||||
}
|
||||
// 新增:优化路径使其经过目标区域
|
||||
|
||||
private void OptimizePathForTarget(ref IntVec3 startPos, ref IntVec3 endPos, IntVec3 targetCell)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
Vector3 target = targetCell.ToVector3();
|
||||
|
||||
// 计算从目标点到地图边缘的方向
|
||||
Vector3[] directions = {
|
||||
new Vector3(1, 0, 0), // 右
|
||||
new Vector3(-1, 0, 0), // 左
|
||||
new Vector3(0, 0, 1), // 上
|
||||
new Vector3(0, 0, -1) // 下
|
||||
new Vector3(1, 0, 0),
|
||||
new Vector3(-1, 0, 0),
|
||||
new Vector3(0, 0, 1),
|
||||
new Vector3(0, 0, -1)
|
||||
};
|
||||
|
||||
// 找到两个相对的方向,确保路径穿过目标
|
||||
Vector3 bestStartDir = Vector3.zero;
|
||||
Vector3 bestEndDir = Vector3.zero;
|
||||
float bestScore = float.MinValue;
|
||||
@@ -272,19 +242,16 @@ namespace WulaFallenEmpire
|
||||
Vector3 dir1 = directions[i];
|
||||
Vector3 dir2 = directions[j];
|
||||
|
||||
// 检查两个方向是否相对(夹角接近180度)
|
||||
float dot = Vector3.Dot(dir1, dir2);
|
||||
if (dot < -0.5f) // 相对方向
|
||||
if (dot < -0.5f)
|
||||
{
|
||||
IntVec3 testStart = FindMapEdgeInDirection(map, targetCell, dir1);
|
||||
IntVec3 testEnd = FindMapEdgeInDirection(map, targetCell, dir2);
|
||||
|
||||
if (testStart.InBounds(map) && testEnd.InBounds(map))
|
||||
{
|
||||
// 计算路径质量:路径长度和是否经过目标
|
||||
float pathLength = Vector3.Distance(testStart.ToVector3(), testEnd.ToVector3());
|
||||
bool passesNearTarget = IsPathNearTarget(testStart, testEnd, targetCell);
|
||||
|
||||
float score = pathLength + (passesNearTarget ? 50f : 0f);
|
||||
|
||||
if (score > bestScore)
|
||||
@@ -298,95 +265,73 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
// 应用最佳路径
|
||||
if (bestStartDir != Vector3.zero && bestEndDir != Vector3.zero)
|
||||
{
|
||||
startPos = FindMapEdgeInDirection(map, targetCell, bestStartDir);
|
||||
endPos = FindMapEdgeInDirection(map, targetCell, bestEndDir);
|
||||
Log.Message($"Optimized path: {startPos} -> {targetCell} -> {endPos}");
|
||||
}
|
||||
}
|
||||
// 新增:备用路径计算方法
|
||||
|
||||
private void CalculateFallbackPath(LocalTargetInfo target, out IntVec3 startPos, out IntVec3 endPos)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
IntVec3 targetPos = target.Cell;
|
||||
|
||||
// 使用简单的对角路径
|
||||
if (Rand.Value < 0.5f)
|
||||
{
|
||||
// 从左下到右上
|
||||
startPos = new IntVec3(0, 0, 0);
|
||||
endPos = new IntVec3(map.Size.x - 1, 0, map.Size.z - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 从右下到左上
|
||||
startPos = new IntVec3(map.Size.x - 1, 0, 0);
|
||||
endPos = new IntVec3(0, 0, map.Size.z - 1);
|
||||
}
|
||||
|
||||
// 确保位置在地图范围内
|
||||
startPos = GetSafeMapPosition(startPos, map);
|
||||
endPos = GetSafeMapPosition(endPos, map);
|
||||
|
||||
Log.Message($"Fallback path: {startPos} -> {endPos}");
|
||||
}
|
||||
// 改进的垂直线进场路径计算方法
|
||||
|
||||
private void CalculatePerpendicularPath(LocalTargetInfo target, out IntVec3 startPos, out IntVec3 endPos)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
IntVec3 casterPos = parent.pawn.Position;
|
||||
IntVec3 targetPos = target.Cell;
|
||||
Log.Message($"Calculating perpendicular path: Caster={casterPos}, Target={targetPos}");
|
||||
// 计算施法者到目标的方向向量
|
||||
Vector3 directionToTarget = (targetPos.ToVector3() - casterPos.ToVector3()).normalized;
|
||||
|
||||
// 如果方向为零向量,使用随机方向
|
||||
Vector3 directionToTarget = (targetPos.ToVector3() - casterPos.ToVector3()).normalized;
|
||||
if (directionToTarget == Vector3.zero)
|
||||
{
|
||||
directionToTarget = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||
Log.Message($"Using random direction: {directionToTarget}");
|
||||
}
|
||||
// 计算垂直于施法者-目标连线的方向(旋转90度)
|
||||
|
||||
Vector3 perpendicularDirection = new Vector3(-directionToTarget.z, 0, directionToTarget.x).normalized;
|
||||
|
||||
Log.Message($"Perpendicular direction: {perpendicularDirection}");
|
||||
// 改进:从目标点出发,向垂直方向的两侧延伸找到地图边缘
|
||||
// 确保两个边缘点在目标点的相对两侧
|
||||
IntVec3 edge1 = FindMapEdgeInDirection(map, targetPos, perpendicularDirection);
|
||||
IntVec3 edge2 = FindMapEdgeInDirection(map, targetPos, -perpendicularDirection);
|
||||
// 验证路径质量
|
||||
|
||||
Vector3 edge1Vec = edge1.ToVector3();
|
||||
Vector3 edge2Vec = edge2.ToVector3();
|
||||
Vector3 targetVec = targetPos.ToVector3();
|
||||
|
||||
// 检查两个边缘点是否在目标点的相对两侧
|
||||
Vector3 toEdge1 = (edge1Vec - targetVec).normalized;
|
||||
Vector3 toEdge2 = (edge2Vec - targetVec).normalized;
|
||||
float dot = Vector3.Dot(toEdge1, toEdge2);
|
||||
|
||||
// 如果两个方向相似(夹角小于90度),说明路径有问题
|
||||
if (dot > -0.3f)
|
||||
{
|
||||
Log.Warning($"Perpendicular path may not cross target properly (dot: {dot}), adjusting...");
|
||||
|
||||
// 强制使用相对方向
|
||||
if (perpendicularDirection.x != 0)
|
||||
{
|
||||
// 如果原方向主要是水平,改用垂直方向
|
||||
perpendicularDirection = new Vector3(0, 0, 1f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果原方向主要是垂直,改用水平方向
|
||||
perpendicularDirection = new Vector3(1f, 0, 0);
|
||||
}
|
||||
|
||||
edge1 = FindMapEdgeInDirection(map, targetPos, perpendicularDirection);
|
||||
edge2 = FindMapEdgeInDirection(map, targetPos, -perpendicularDirection);
|
||||
}
|
||||
// 随机选择起点和终点(确保目标点在路径上)
|
||||
|
||||
if (Rand.Value < 0.5f)
|
||||
{
|
||||
startPos = edge1;
|
||||
@@ -397,26 +342,21 @@ namespace WulaFallenEmpire
|
||||
startPos = edge2;
|
||||
endPos = edge1;
|
||||
}
|
||||
Log.Message($"Perpendicular path: {startPos} -> {targetPos} -> {endPos}, path length: {Vector3.Distance(startPos.ToVector3(), endPos.ToVector3())}");
|
||||
}
|
||||
// 改进的地图边缘查找方法
|
||||
|
||||
private IntVec3 FindMapEdgeInDirection(Map map, IntVec3 fromPos, Vector3 direction)
|
||||
{
|
||||
// 确保方向向量有效
|
||||
if (direction == Vector3.zero)
|
||||
{
|
||||
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||
}
|
||||
|
||||
// 使用精确的射线投射方法找到地图边缘
|
||||
Vector3 fromVec = fromPos.ToVector3();
|
||||
Vector3 dirNormalized = direction.normalized;
|
||||
|
||||
// 计算与地图边界的交点
|
||||
float minT = float.MaxValue;
|
||||
IntVec3? bestEdgePos = null;
|
||||
|
||||
// 检查四个边界
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
float t = 0f;
|
||||
@@ -424,7 +364,7 @@ namespace WulaFallenEmpire
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0: // 左边界 (x = 0)
|
||||
case 0:
|
||||
if (Mathf.Abs(dirNormalized.x) > 0.001f)
|
||||
{
|
||||
t = (0 - fromVec.x) / dirNormalized.x;
|
||||
@@ -439,7 +379,7 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 右边界 (x = map.Size.x - 1)
|
||||
case 1:
|
||||
if (Mathf.Abs(dirNormalized.x) > 0.001f)
|
||||
{
|
||||
t = (map.Size.x - 1 - fromVec.x) / dirNormalized.x;
|
||||
@@ -454,7 +394,7 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 下边界 (z = 0)
|
||||
case 2:
|
||||
if (Mathf.Abs(dirNormalized.z) > 0.001f)
|
||||
{
|
||||
t = (0 - fromVec.z) / dirNormalized.z;
|
||||
@@ -469,7 +409,7 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 上边界 (z = map.Size.z - 1)
|
||||
case 3:
|
||||
if (Mathf.Abs(dirNormalized.z) > 0.001f)
|
||||
{
|
||||
t = (map.Size.z - 1 - fromVec.z) / dirNormalized.z;
|
||||
@@ -485,7 +425,6 @@ namespace WulaFallenEmpire
|
||||
break;
|
||||
}
|
||||
|
||||
// 找到最近的有效边界点
|
||||
if (edgePos.IsValid && edgePos.InBounds(map) && t > 0 && t < minT)
|
||||
{
|
||||
minT = t;
|
||||
@@ -495,52 +434,44 @@ namespace WulaFallenEmpire
|
||||
|
||||
if (bestEdgePos.HasValue)
|
||||
{
|
||||
Log.Message($"Found map edge at {bestEdgePos.Value} in direction {direction}");
|
||||
return bestEdgePos.Value;
|
||||
}
|
||||
|
||||
// 如果没找到合适的边界点,使用随机边缘位置
|
||||
Log.Warning($"Could not find map edge in direction {direction}, using random edge");
|
||||
return GetRandomMapEdgePosition(map);
|
||||
}
|
||||
// 改进的随机地图边缘位置获取
|
||||
|
||||
private IntVec3 GetRandomMapEdgePosition(Map map)
|
||||
{
|
||||
// 避免选择角落位置,因为角落容易导致路径问题
|
||||
int edge = Rand.Range(0, 4);
|
||||
int x, z;
|
||||
|
||||
switch (edge)
|
||||
{
|
||||
case 0: // 上边 (避免左右角落)
|
||||
case 0:
|
||||
x = Rand.Range(5, map.Size.x - 5);
|
||||
z = 0;
|
||||
break;
|
||||
case 1: // 右边 (避免上下角落)
|
||||
case 1:
|
||||
x = map.Size.x - 1;
|
||||
z = Rand.Range(5, map.Size.z - 5);
|
||||
break;
|
||||
case 2: // 下边 (避免左右角落)
|
||||
case 2:
|
||||
x = Rand.Range(5, map.Size.x - 5);
|
||||
z = map.Size.z - 1;
|
||||
break;
|
||||
case 3: // 左边 (避免上下角落)
|
||||
case 3:
|
||||
default:
|
||||
x = 0;
|
||||
z = Rand.Range(5, map.Size.z - 5);
|
||||
break;
|
||||
}
|
||||
|
||||
// 确保位置有效
|
||||
x = Mathf.Clamp(x, 0, map.Size.x - 1);
|
||||
z = Mathf.Clamp(z, 0, map.Size.z - 1);
|
||||
|
||||
IntVec3 edgePos = new IntVec3(x, 0, z);
|
||||
Log.Message($"Random map edge position (avoiding corners): {edgePos}");
|
||||
return edgePos;
|
||||
return new IntVec3(x, 0, z);
|
||||
}
|
||||
|
||||
// 修复的预览绘制方法
|
||||
public override void DrawEffectPreview(LocalTargetInfo target)
|
||||
{
|
||||
base.DrawEffectPreview(target);
|
||||
@@ -551,7 +482,6 @@ namespace WulaFallenEmpire
|
||||
|
||||
try
|
||||
{
|
||||
// 计算飞行路径
|
||||
IntVec3 startPos, endPos;
|
||||
if (Props.approachType == ApproachType.Perpendicular)
|
||||
{
|
||||
@@ -563,17 +493,14 @@ namespace WulaFallenEmpire
|
||||
endPos = CalculateEndPosition(target, startPos);
|
||||
}
|
||||
|
||||
// 确保位置在地图范围内
|
||||
startPos = GetSafeMapPosition(startPos, map);
|
||||
endPos = GetSafeMapPosition(endPos, map);
|
||||
|
||||
// 检查预览稳定性
|
||||
if (!IsPreviewStable(startPos, endPos, map))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据不同类型显示不同的预览
|
||||
if (Props.enableGroundStrafing && Props.showStrafePreview)
|
||||
{
|
||||
DrawStrafingAreaPreview(startPos, endPos, target.Cell);
|
||||
@@ -585,57 +512,45 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// 忽略预览绘制中的错误,避免影响游戏体验
|
||||
// 忽略预览绘制中的错误
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 安全的位置计算方法
|
||||
private IntVec3 GetSafeMapPosition(IntVec3 pos, Map map)
|
||||
{
|
||||
if (map == null) return pos;
|
||||
|
||||
// 确保位置在地图范围内
|
||||
pos.x = Mathf.Clamp(pos.x, 0, map.Size.x - 1);
|
||||
pos.z = Mathf.Clamp(pos.z, 0, map.Size.z - 1);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
// 预览绘制稳定性检查
|
||||
private bool IsPreviewStable(IntVec3 startPos, IntVec3 endPos, Map map)
|
||||
{
|
||||
if (map == null) return false;
|
||||
|
||||
// 检查位置是否有效
|
||||
if (!startPos.IsValid || !endPos.IsValid) return false;
|
||||
|
||||
// 检查位置是否在地图范围内
|
||||
if (!startPos.InBounds(map) || !endPos.InBounds(map)) return false;
|
||||
|
||||
// 检查距离是否合理(避免过短的路径)
|
||||
float distance = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
|
||||
if (distance < 5f) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 修复:绘制地面扫射预览,现在接受目标单元格参数
|
||||
private void DrawStrafingAreaPreview(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算飞行方向
|
||||
Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
if (flightDirection == Vector3.zero)
|
||||
{
|
||||
flightDirection = Vector3.forward;
|
||||
}
|
||||
|
||||
// 只计算扫射影响区域的单元格
|
||||
List<IntVec3> strafeImpactCells = CalculateStrafingImpactCells(targetCell, flightDirection);
|
||||
|
||||
// 绘制扫射影响区域的预览单元格
|
||||
foreach (IntVec3 cell in strafeImpactCells)
|
||||
{
|
||||
if (cell.InBounds(map))
|
||||
@@ -644,44 +559,33 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制飞行路径线
|
||||
GenDraw.DrawLineBetween(startPos.ToVector3Shifted(), endPos.ToVector3Shifted(), SimpleColor.Red, 0.2f);
|
||||
|
||||
// 绘制扫射范围边界
|
||||
DrawStrafingBoundaries(targetCell, flightDirection);
|
||||
}
|
||||
|
||||
// 修复:计算扫射影响区域的单元格,现在以目标单元格为中心
|
||||
private List<IntVec3> CalculateStrafingImpactCells(IntVec3 targetCell, Vector3 flightDirection)
|
||||
{
|
||||
List<IntVec3> cells = new List<IntVec3>();
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算垂直于飞行方向的方向
|
||||
Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
|
||||
|
||||
// 修复:以目标单元格为中心计算扫射区域
|
||||
Vector3 targetCenter = targetCell.ToVector3();
|
||||
|
||||
// 计算扫射区域的起始和结束位置(基于扫射长度,以目标为中心)
|
||||
float strafeHalfLength = Props.strafeLength * 0.5f;
|
||||
Vector3 strafeStart = targetCenter - flightDirection * strafeHalfLength;
|
||||
Vector3 strafeEnd = targetCenter + flightDirection * strafeHalfLength;
|
||||
|
||||
// 使用整数步进避免浮点精度问题
|
||||
int steps = Mathf.Max(1, Mathf.CeilToInt(Props.strafeLength));
|
||||
for (int i = 0; i <= steps; i++)
|
||||
{
|
||||
float progress = (float)i / steps;
|
||||
Vector3 centerPoint = Vector3.Lerp(strafeStart, strafeEnd, progress);
|
||||
|
||||
// 在垂直方向扩展扫射宽度
|
||||
for (int w = -Props.strafeWidth; w <= Props.strafeWidth; w++)
|
||||
{
|
||||
Vector3 offset = perpendicular * w;
|
||||
Vector3 cellPos = centerPoint + offset;
|
||||
|
||||
// 使用更精确的单元格转换
|
||||
IntVec3 cell = new IntVec3(
|
||||
Mathf.RoundToInt(cellPos.x),
|
||||
Mathf.RoundToInt(cellPos.y),
|
||||
@@ -695,37 +599,29 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
Log.Message($"Strafing Area: Calculated {cells.Count} impact cells centered at {targetCell}");
|
||||
return cells;
|
||||
}
|
||||
|
||||
// 修复:绘制扫射范围边界,现在以目标单元格为中心
|
||||
private void DrawStrafingBoundaries(IntVec3 targetCell, Vector3 flightDirection)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
|
||||
|
||||
// 修复:以目标单元格为中心
|
||||
Vector3 targetCenter = targetCell.ToVector3();
|
||||
|
||||
// 计算扫射区域的起始和结束位置
|
||||
float strafeHalfLength = Props.strafeLength * 0.5f;
|
||||
Vector3 strafeStart = targetCenter - flightDirection * strafeHalfLength;
|
||||
Vector3 strafeEnd = targetCenter + flightDirection * strafeHalfLength;
|
||||
|
||||
// 计算扫射区域的四个角
|
||||
Vector3 startLeft = strafeStart + perpendicular * Props.strafeWidth;
|
||||
Vector3 startRight = strafeStart - perpendicular * Props.strafeWidth;
|
||||
Vector3 endLeft = strafeEnd + perpendicular * Props.strafeWidth;
|
||||
Vector3 endRight = strafeEnd - perpendicular * Props.strafeWidth;
|
||||
|
||||
// 转换为 IntVec3 并确保在地图范围内
|
||||
IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map);
|
||||
IntVec3 startRightCell = GetSafeMapPosition(new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z), map);
|
||||
IntVec3 endLeftCell = GetSafeMapPosition(new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z), map);
|
||||
IntVec3 endRightCell = GetSafeMapPosition(new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z), map);
|
||||
|
||||
// 绘制边界线 - 只绘制在地图范围内的线段
|
||||
if (startLeftCell.InBounds(map) && endLeftCell.InBounds(map))
|
||||
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
|
||||
|
||||
@@ -739,25 +635,19 @@ namespace WulaFallenEmpire
|
||||
GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
|
||||
}
|
||||
|
||||
// 绘制扇形区域预览
|
||||
private void DrawSectorAreaPreview(IntVec3 startPos, IntVec3 endPos)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算飞行方向
|
||||
Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
if (flightDirection == Vector3.zero)
|
||||
{
|
||||
flightDirection = Vector3.forward;
|
||||
}
|
||||
|
||||
// 计算垂直于飞行方向的方向
|
||||
Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
|
||||
|
||||
// 使用strafeWidth来近似扇形扫过的区域宽度
|
||||
List<IntVec3> previewCells = CalculateRectangularPreviewArea(startPos, endPos, flightDirection, perpendicular);
|
||||
|
||||
// 绘制预览区域
|
||||
foreach (IntVec3 cell in previewCells)
|
||||
{
|
||||
if (cell.InBounds(map))
|
||||
@@ -766,36 +656,28 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制飞行路径线
|
||||
GenDraw.DrawLineBetween(startPos.ToVector3Shifted(), endPos.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
|
||||
|
||||
// 绘制预览区域边界
|
||||
DrawRectangularPreviewBoundaries(startPos, endPos, flightDirection, perpendicular);
|
||||
}
|
||||
|
||||
// 计算矩形预览区域(近似扇形扫过的区域)
|
||||
private List<IntVec3> CalculateRectangularPreviewArea(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection, Vector3 perpendicular)
|
||||
{
|
||||
List<IntVec3> cells = new List<IntVec3>();
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算飞行路径的总长度
|
||||
float totalPathLength = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
|
||||
|
||||
// 沿着飞行路径计算预览单元格
|
||||
int steps = Mathf.Max(1, Mathf.CeilToInt(totalPathLength));
|
||||
|
||||
for (int i = 0; i <= steps; i++)
|
||||
{
|
||||
float progress = (float)i / steps;
|
||||
Vector3 centerPoint = Vector3.Lerp(startPos.ToVector3(), endPos.ToVector3(), progress);
|
||||
|
||||
// 在垂直方向扩展预览宽度(使用strafeWidth)
|
||||
for (int w = -Props.strafeWidth; w <= Props.strafeWidth; w++)
|
||||
{
|
||||
Vector3 offset = perpendicular * w;
|
||||
Vector3 cellPos = centerPoint + offset;
|
||||
|
||||
// 使用精确的单元格转换
|
||||
IntVec3 cell = new IntVec3(
|
||||
Mathf.RoundToInt(cellPos.x),
|
||||
Mathf.RoundToInt(cellPos.y),
|
||||
@@ -812,24 +694,20 @@ namespace WulaFallenEmpire
|
||||
return cells;
|
||||
}
|
||||
|
||||
// 绘制矩形预览边界
|
||||
private void DrawRectangularPreviewBoundaries(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection, Vector3 perpendicular)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
|
||||
// 计算预览区域的四个角
|
||||
Vector3 startLeft = startPos.ToVector3() + perpendicular * Props.strafeWidth;
|
||||
Vector3 startRight = startPos.ToVector3() - perpendicular * Props.strafeWidth;
|
||||
Vector3 endLeft = endPos.ToVector3() + perpendicular * Props.strafeWidth;
|
||||
Vector3 endRight = endPos.ToVector3() - perpendicular * Props.strafeWidth;
|
||||
|
||||
// 转换为 IntVec3 并确保在地图范围内
|
||||
IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map);
|
||||
IntVec3 startRightCell = GetSafeMapPosition(new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z), map);
|
||||
IntVec3 endLeftCell = GetSafeMapPosition(new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z), map);
|
||||
IntVec3 endRightCell = GetSafeMapPosition(new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z), map);
|
||||
|
||||
// 绘制边界线 - 只绘制在地图范围内的线段
|
||||
if (startLeftCell.InBounds(map) && endLeftCell.InBounds(map))
|
||||
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
|
||||
|
||||
@@ -843,11 +721,11 @@ namespace WulaFallenEmpire
|
||||
GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
|
||||
}
|
||||
|
||||
// 预处理扫射目标单元格
|
||||
private List<IntVec3> PreprocessStrafingTargets(List<IntVec3> potentialTargets, float fireChance)
|
||||
{
|
||||
List<IntVec3> confirmedTargets = new List<IntVec3>();
|
||||
List<IntVec3> missedCells = new List<IntVec3>();
|
||||
|
||||
foreach (IntVec3 cell in potentialTargets)
|
||||
{
|
||||
if (Rand.Value <= fireChance)
|
||||
@@ -860,16 +738,13 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
// 应用最小和最大射弹数限制
|
||||
if (Props.maxStrafeProjectiles > -1 && confirmedTargets.Count > Props.maxStrafeProjectiles)
|
||||
{
|
||||
// 如果超出最大值,随机丢弃一些目标
|
||||
confirmedTargets = confirmedTargets.InRandomOrder().Take(Props.maxStrafeProjectiles).ToList();
|
||||
}
|
||||
|
||||
if (Props.minStrafeProjectiles > -1 && confirmedTargets.Count < Props.minStrafeProjectiles)
|
||||
{
|
||||
// 如果不足最小值,从之前未选中的格子里补充
|
||||
int needed = Props.minStrafeProjectiles - confirmedTargets.Count;
|
||||
if (needed > 0 && missedCells.Count > 0)
|
||||
{
|
||||
@@ -877,11 +752,9 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
Log.Message($"Strafing Preprocess: {confirmedTargets.Count}/{potentialTargets.Count} cells confirmed after min/max adjustment.");
|
||||
return confirmedTargets;
|
||||
}
|
||||
|
||||
// 原有的位置计算方法
|
||||
private IntVec3 CalculateStartPosition(LocalTargetInfo target)
|
||||
{
|
||||
Map map = parent.pawn.Map;
|
||||
@@ -890,16 +763,12 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
case StartPosition.Caster:
|
||||
return parent.pawn.Position;
|
||||
|
||||
case StartPosition.MapEdge:
|
||||
return GetMapEdgePosition(map, GetDirectionFromCasterToTarget(target));
|
||||
|
||||
case StartPosition.CustomOffset:
|
||||
return GetSafeMapPosition(parent.pawn.Position + Props.customStartOffset, map);
|
||||
|
||||
case StartPosition.RandomMapEdge:
|
||||
return GetRandomMapEdgePosition(map);
|
||||
|
||||
default:
|
||||
return parent.pawn.Position;
|
||||
}
|
||||
@@ -915,24 +784,18 @@ namespace WulaFallenEmpire
|
||||
case EndPosition.TargetCell:
|
||||
endPos = target.Cell;
|
||||
break;
|
||||
|
||||
case EndPosition.OppositeMapEdge:
|
||||
endPos = GetOppositeMapEdgeThroughCenter(map, startPos);
|
||||
break;
|
||||
|
||||
case EndPosition.CustomOffset:
|
||||
endPos = GetSafeMapPosition(target.Cell + Props.customEndOffset, map);
|
||||
break;
|
||||
|
||||
case EndPosition.FixedDistance:
|
||||
endPos = GetFixedDistancePosition(startPos, target.Cell);
|
||||
break;
|
||||
|
||||
case EndPosition.RandomMapEdge:
|
||||
endPos = GetRandomMapEdgePosition(map);
|
||||
Log.Message($"Random map edge selected as end position: {endPos}");
|
||||
break;
|
||||
|
||||
default:
|
||||
endPos = target.Cell;
|
||||
break;
|
||||
@@ -941,7 +804,6 @@ namespace WulaFallenEmpire
|
||||
return GetSafeMapPosition(endPos, map);
|
||||
}
|
||||
|
||||
// 原有的辅助方法
|
||||
private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos)
|
||||
{
|
||||
IntVec3 center = map.Center;
|
||||
@@ -950,14 +812,10 @@ namespace WulaFallenEmpire
|
||||
if (toCenter == Vector3.zero)
|
||||
{
|
||||
toCenter = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||
Log.Message($"Using random direction to center: {toCenter}");
|
||||
}
|
||||
|
||||
Vector3 fromCenter = toCenter;
|
||||
IntVec3 oppositeEdge = GetMapEdgePositionFromCenter(map, fromCenter);
|
||||
|
||||
Log.Message($"Found opposite edge through center: {oppositeEdge}");
|
||||
return oppositeEdge;
|
||||
return GetMapEdgePositionFromCenter(map, fromCenter);
|
||||
}
|
||||
|
||||
private IntVec3 GetMapEdgePositionFromCenter(Map map, Vector3 direction)
|
||||
@@ -974,13 +832,10 @@ namespace WulaFallenEmpire
|
||||
|
||||
if (!testPos.InBounds(map))
|
||||
{
|
||||
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
||||
Log.Message($"Found map edge from center: {edgePos} (direction: {direction}, distance: {i})");
|
||||
return edgePos;
|
||||
return FindClosestValidPosition(testPos, map);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Warning("Could not find map edge from center, using random edge");
|
||||
return GetRandomMapEdgePosition(map);
|
||||
}
|
||||
|
||||
@@ -989,7 +844,6 @@ namespace WulaFallenEmpire
|
||||
if (direction == Vector3.zero)
|
||||
{
|
||||
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||
Log.Message($"Using random direction: {direction}");
|
||||
}
|
||||
|
||||
IntVec3 center = map.Center;
|
||||
@@ -1004,13 +858,10 @@ namespace WulaFallenEmpire
|
||||
|
||||
if (!testPos.InBounds(map))
|
||||
{
|
||||
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
||||
Log.Message($"Found map edge position: {edgePos} (direction: {direction}, distance: {i})");
|
||||
return edgePos;
|
||||
return FindClosestValidPosition(testPos, map);
|
||||
}
|
||||
}
|
||||
|
||||
Log.Warning("Could not find map edge in direction, using random edge");
|
||||
return GetRandomMapEdgePosition(map);
|
||||
}
|
||||
|
||||
@@ -1030,16 +881,14 @@ namespace WulaFallenEmpire
|
||||
|
||||
return map.Center;
|
||||
}
|
||||
|
||||
private IntVec3 GetFixedDistancePosition(IntVec3 startPos, IntVec3 targetPos)
|
||||
{
|
||||
Vector3 direction = (targetPos.ToVector3() - startPos.ToVector3()).normalized;
|
||||
IntVec3 endPos = startPos + new IntVec3(
|
||||
return startPos + new IntVec3(
|
||||
(int)(direction.x * Props.flyOverDistance),
|
||||
0,
|
||||
(int)(direction.z * Props.flyOverDistance));
|
||||
|
||||
Log.Message($"Fixed distance position: {endPos} (from {startPos}, distance: {Props.flyOverDistance})");
|
||||
return endPos;
|
||||
}
|
||||
|
||||
private Vector3 GetDirectionFromCasterToTarget(LocalTargetInfo target)
|
||||
@@ -1049,7 +898,6 @@ namespace WulaFallenEmpire
|
||||
if (direction == Vector3.zero)
|
||||
{
|
||||
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||
Log.Message($"Using random direction: {direction}");
|
||||
}
|
||||
|
||||
return direction;
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class HediffGiver_NonPlayerFaction : HediffGiver
|
||||
{
|
||||
// 显式重新定义这些字段,确保 XML 解析器能找到它们
|
||||
public float mtbDays;
|
||||
public new HediffDef hediff;
|
||||
|
||||
// 新增:目标派系列表
|
||||
public List<FactionDef> targetFactions;
|
||||
|
||||
// 新增:是否排除玩家派系(默认为true)
|
||||
public bool excludePlayerFaction = true;
|
||||
|
||||
// 新增:是否排除囚犯(默认为true)
|
||||
public bool excludePrisoners = true;
|
||||
|
||||
// 新增:记录已经处理过的 pawn,避免重复处理
|
||||
private HashSet<Pawn> processedPawns = new HashSet<Pawn>();
|
||||
|
||||
public override void OnIntervalPassed(Pawn pawn, Hediff cause)
|
||||
{
|
||||
// 检查 pawn 是否已经处理过
|
||||
if (processedPawns.Contains(pawn))
|
||||
{
|
||||
// 如果已经处理过,检查 hediff 是否还存在
|
||||
Hediff existingHediff = pawn.health?.hediffSet?.GetFirstHediffOfDef(this.hediff);
|
||||
if (existingHediff != null)
|
||||
{
|
||||
// hediff 还存在,不需要再次处理
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// hediff 被移除了,从记录中移除这个 pawn
|
||||
processedPawns.Remove(pawn);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查派系条件
|
||||
if (ShouldHaveHediff(pawn))
|
||||
{
|
||||
// 检查是否已经有这个 hediff
|
||||
Hediff existing = pawn.health?.hediffSet?.GetFirstHediffOfDef(this.hediff);
|
||||
if (existing == null)
|
||||
{
|
||||
// 给予 hediff
|
||||
HealthUtility.AdjustSeverity(pawn, this.hediff, 1.0f);
|
||||
// 标记为已处理
|
||||
processedPawns.Add(pawn);
|
||||
Log.Message($"Added hediff {this.hediff.defName} to pawn {pawn.Label}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 移除 hediff
|
||||
if (RemoveHediffIfExists(pawn))
|
||||
{
|
||||
// 如果成功移除了 hediff,也从记录中移除
|
||||
processedPawns.Remove(pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldHaveHediff(Pawn pawn)
|
||||
{
|
||||
// 检查派系是否存在
|
||||
if (pawn.Faction == null)
|
||||
return false;
|
||||
|
||||
// 检查是否排除玩家派系
|
||||
if (excludePlayerFaction && pawn.Faction == Faction.OfPlayer)
|
||||
return false;
|
||||
|
||||
// 检查是否排除囚犯
|
||||
if (excludePrisoners && pawn.IsPrisonerOfColony)
|
||||
return false;
|
||||
|
||||
// 检查目标派系
|
||||
if (targetFactions != null && targetFactions.Count > 0)
|
||||
{
|
||||
// 如果指定了目标派系,只给这些派系添加 hediff
|
||||
return targetFactions.Contains(pawn.Faction.def);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果没有指定目标派系,保持原来的行为:给所有非玩家派系添加
|
||||
return pawn.Faction != Faction.OfPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
private bool RemoveHediffIfExists(Pawn pawn)
|
||||
{
|
||||
Hediff existing = pawn.health?.hediffSet?.GetFirstHediffOfDef(this.hediff);
|
||||
if (existing != null)
|
||||
{
|
||||
pawn.health.RemoveHediff(existing);
|
||||
Log.Message($"Removed hediff {this.hediff.defName} from pawn {pawn.Label}");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 新增:在 pawn 死亡或被销毁时清理记录
|
||||
public override void Notify_PawnDied(Pawn pawn, DamageInfo? dinfo)
|
||||
{
|
||||
base.Notify_PawnDied(pawn, dinfo);
|
||||
processedPawns.Remove(pawn);
|
||||
}
|
||||
|
||||
public override void Notify_PawnDespawned(Pawn pawn, Map map)
|
||||
{
|
||||
base.Notify_PawnDespawned(pawn, map);
|
||||
processedPawns.Remove(pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// HediffCompProperties_NanoRepair.cs
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
@@ -44,8 +43,6 @@ namespace WulaFallenEmpire
|
||||
var wulaEnergy = Pawn.needs.TryGetNeed(DefDatabase<NeedDef>.GetNamedSilentFail("WULA_Energy"));
|
||||
if (wulaEnergy != null)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 使用 WULA_Energy 作为能量源");
|
||||
return wulaEnergy;
|
||||
}
|
||||
|
||||
@@ -53,13 +50,9 @@ namespace WulaFallenEmpire
|
||||
var mechEnergy = Pawn.needs?.TryGetNeed<Need_MechEnergy>();
|
||||
if (mechEnergy != null)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 使用 MechEnergy 作为能量源");
|
||||
return mechEnergy;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有找到可用的能量源");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -88,8 +81,6 @@ namespace WulaFallenEmpire
|
||||
if (parent.Severity != Props.inactiveSeverity)
|
||||
{
|
||||
parent.Severity = Props.inactiveSeverity;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 修复系统已关闭,设置为不活跃状态");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -98,10 +89,6 @@ namespace WulaFallenEmpire
|
||||
if (Find.TickManager.TicksGame % CheckInterval == 0)
|
||||
{
|
||||
debugCounter++;
|
||||
if (debugCounter % 10 == 0)
|
||||
{
|
||||
Log.Message($"[NanoRepair] Tick {Find.TickManager.TicksGame} - 开始检查修复状态");
|
||||
}
|
||||
UpdateSeverityAndRepair();
|
||||
}
|
||||
}
|
||||
@@ -110,8 +97,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
if (Pawn == null || Pawn.Dead)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] Pawn为null或已死亡");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -122,22 +107,13 @@ namespace WulaFallenEmpire
|
||||
if (parent.Severity != targetSeverity)
|
||||
{
|
||||
parent.Severity = targetSeverity;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 更新严重性: {parent.Severity} -> {targetSeverity}");
|
||||
}
|
||||
|
||||
// 如果处于活跃状态,执行修复
|
||||
if (shouldBeActive)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 系统活跃,尝试修复损伤");
|
||||
TryRepairDamage();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 系统不活跃,跳过修复");
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldBeActive()
|
||||
@@ -145,8 +121,6 @@ namespace WulaFallenEmpire
|
||||
// 如果修复系统关闭,直接返回不活跃
|
||||
if (!repairSystemEnabled)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 修复系统已关闭,系统不活跃");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,15 +128,11 @@ namespace WulaFallenEmpire
|
||||
var energyNeed = GetEnergyNeed();
|
||||
if (energyNeed == null)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有能量需求,系统不活跃");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (energyNeed.CurLevelPercentage < Props.minEnergyThreshold)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 能量不足: {energyNeed.CurLevelPercentage:P0} < {Props.minEnergyThreshold:P0},系统不活跃");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -170,21 +140,15 @@ namespace WulaFallenEmpire
|
||||
int cooldownRemaining = ActualRepairCooldownAfterDamage - (Find.TickManager.TicksGame - lastDamageTick);
|
||||
if (cooldownRemaining > 0)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 冷却中: {cooldownRemaining} ticks剩余,系统不活跃");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查是否有需要修复的损伤
|
||||
if (!HasDamageToRepair())
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有需要修复的损伤,系统不活跃");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 所有条件满足,系统活跃");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -192,8 +156,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
if (Pawn.health == null || Pawn.health.hediffSet == null)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] Health或HediffSet为null");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,22 +163,16 @@ namespace WulaFallenEmpire
|
||||
var missingParts = Pawn.health.hediffSet.GetMissingPartsCommonAncestors();
|
||||
if (missingParts.Count > 0)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 检测到缺失部件: {missingParts.Count}个");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 检查是否有损伤
|
||||
if (HasDamagedParts())
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 检测到损伤部位");
|
||||
return true;
|
||||
}
|
||||
|
||||
// 不再检查疾病
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有检测到任何需要修复的损伤");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -238,15 +194,10 @@ namespace WulaFallenEmpire
|
||||
if (currentHealth < maxHealth)
|
||||
{
|
||||
damagedCount++;
|
||||
if (debugCounter % 10 == 0 && damagedCount == 1)
|
||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 有损伤: {currentHealth}/{maxHealth}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0 && damagedCount > 0)
|
||||
Log.Message($"[NanoRepair] 总共检测到 {damagedCount} 个损伤部位");
|
||||
|
||||
return damagedCount > 0;
|
||||
}
|
||||
|
||||
@@ -267,15 +218,10 @@ namespace WulaFallenEmpire
|
||||
if (currentHealth < maxHealth)
|
||||
{
|
||||
damagedParts.Add(part);
|
||||
if (debugCounter % 10 == 0 && damagedParts.Count <= 3)
|
||||
Log.Message($"[NanoRepair] 损伤部位: {part.def.defName} ({currentHealth}/{maxHealth})");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0 && damagedParts.Count > 3)
|
||||
Log.Message($"[NanoRepair] ... 还有 {damagedParts.Count - 3} 个损伤部位");
|
||||
|
||||
return damagedParts;
|
||||
}
|
||||
|
||||
@@ -284,34 +230,22 @@ namespace WulaFallenEmpire
|
||||
var energyNeed = GetEnergyNeed();
|
||||
if (energyNeed == null)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 能量需求为null,无法修复");
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 当前能量({GetEnergyNeedName()}): {energyNeed.CurLevel:F1}/{energyNeed.MaxLevel:F1} ({energyNeed.CurLevelPercentage:P0})");
|
||||
|
||||
// 优先修复缺失部件
|
||||
if (TryRepairMissingParts(energyNeed))
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 已修复缺失部件");
|
||||
return;
|
||||
}
|
||||
|
||||
// 然后修复损伤
|
||||
if (TryRepairDamagedParts(energyNeed))
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 已修复损伤部位");
|
||||
return;
|
||||
}
|
||||
|
||||
// 不再修复疾病
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有执行任何修复");
|
||||
}
|
||||
|
||||
private bool TryRepairMissingParts(Need energyNeed)
|
||||
@@ -319,14 +253,9 @@ namespace WulaFallenEmpire
|
||||
var missingParts = Pawn.health.hediffSet.GetMissingPartsCommonAncestors();
|
||||
if (missingParts == null || missingParts.Count == 0)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有缺失部件需要修复");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 检查修复缺失部件,共有 {missingParts.Count} 个");
|
||||
|
||||
// 选择最小的缺失部件进行修复(成本较低)
|
||||
Hediff_MissingPart partToRepair = null;
|
||||
float minHealth = float.MaxValue;
|
||||
@@ -353,24 +282,14 @@ namespace WulaFallenEmpire
|
||||
repairCost *= mechEnergyLoss;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 尝试修复缺失部件 {partToRepair.Part.def.defName}, 成本: {repairCost:F2}, 当前能量: {energyNeed.CurLevel:F2}");
|
||||
|
||||
if (energyNeed.CurLevel >= repairCost)
|
||||
{
|
||||
if (ConvertMissingPartToInjury(partToRepair, repairCost))
|
||||
{
|
||||
energyNeed.CurLevel -= repairCost;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 成功将缺失部件 {partToRepair.Part.def.defName} 转换为损伤, 消耗能量: {repairCost:F2}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 能量不足修复缺失部件: {energyNeed.CurLevel:F2} < {repairCost:F2}");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -380,14 +299,9 @@ namespace WulaFallenEmpire
|
||||
var damagedParts = GetDamagedParts();
|
||||
if (damagedParts.Count == 0)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 没有损伤部位需要修复");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 检查修复损伤部位,共有 {damagedParts.Count} 个");
|
||||
|
||||
// 选择健康值最低的部位进行修复
|
||||
BodyPartRecord partToRepair = null;
|
||||
float minHealthRatio = float.MaxValue;
|
||||
@@ -421,24 +335,14 @@ namespace WulaFallenEmpire
|
||||
repairCost *= mechEnergyLoss;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 尝试修复部位 {partToRepair.def.defName}, 健康: {currentHealth:F1}/{maxHealth:F1}, 修复量: {healthToRepair:F1}, 成本: {repairCost:F2}");
|
||||
|
||||
if (energyNeed.CurLevel >= repairCost)
|
||||
{
|
||||
if (RepairDamagedPart(partToRepair, repairCost))
|
||||
{
|
||||
energyNeed.CurLevel -= repairCost;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 成功修复部位 {partToRepair.def.defName}, 消耗能量: {repairCost:F2}");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 能量不足修复损伤: {energyNeed.CurLevel:F2} < {repairCost:F2}");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -451,9 +355,6 @@ namespace WulaFallenEmpire
|
||||
float maxHealth = part.def.GetMaxHealth(Pawn);
|
||||
float currentHealth = Pawn.health.hediffSet.GetPartHealth(part);
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 开始修复部位 {part.def.defName}, 当前健康: {currentHealth:F1}/{maxHealth:F1}");
|
||||
|
||||
// 获取该部位的所有hediff
|
||||
var hediffsOnPart = new List<Hediff>();
|
||||
foreach (var hediff in Pawn.health.hediffSet.hediffs)
|
||||
@@ -461,21 +362,14 @@ namespace WulaFallenEmpire
|
||||
if (hediff.Part == part)
|
||||
{
|
||||
hediffsOnPart.Add(hediff);
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 上的hediff: {hediff.def.defName}, 类型: {hediff.GetType()}, 严重性: {hediff.Severity}");
|
||||
}
|
||||
}
|
||||
|
||||
if (hediffsOnPart.Count == 0)
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 上没有找到任何hediff");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 在部位 {part.def.defName} 上找到 {hediffsOnPart.Count} 个hediff");
|
||||
|
||||
bool anyRepairDone = false;
|
||||
|
||||
foreach (var hediff in hediffsOnPart)
|
||||
@@ -483,8 +377,6 @@ namespace WulaFallenEmpire
|
||||
// 检查hediff是否可修复
|
||||
if (!CanRepairHediff(hediff))
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 跳过不可修复的hediff: {hediff.def.defName}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -493,8 +385,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
Pawn.health.RemoveHediff(hediff);
|
||||
anyRepairDone = true;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 删除严重性小于1的hediff: {hediff.def.defName} (严重性: {hediff.Severity:F2})");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -503,14 +393,9 @@ namespace WulaFallenEmpire
|
||||
hediff.Severity = 0f;
|
||||
Pawn.health.RemoveHediff(hediff);
|
||||
anyRepairDone = true;
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 完全修复hediff: {hediff.def.defName} (严重性: {originalSeverity:F2} -> 0)");
|
||||
}
|
||||
}
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 部位 {part.def.defName} 修复完成,执行了 {anyRepairDone} 次修复");
|
||||
|
||||
return anyRepairDone;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
@@ -526,8 +411,6 @@ namespace WulaFallenEmpire
|
||||
// 跳过疾病
|
||||
if (IsDisease(hediff))
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 跳过疾病: {hediff.def.defName}");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -568,9 +451,6 @@ namespace WulaFallenEmpire
|
||||
{
|
||||
try
|
||||
{
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 开始将缺失部件 {missingPart.Part.def.defName} 转换为损伤");
|
||||
|
||||
float partMaxHealth = missingPart.Part.def.GetMaxHealth(Pawn);
|
||||
|
||||
// 关键修复:确保转换后的损伤不会导致部位再次缺失
|
||||
@@ -600,9 +480,6 @@ namespace WulaFallenEmpire
|
||||
|
||||
Pawn.health.AddHediff(injury);
|
||||
|
||||
if (debugCounter % 10 == 0)
|
||||
Log.Message($"[NanoRepair] 成功将缺失部件 {missingPart.Part.def.defName} 转换为 {injuryDef.defName} 损伤, 严重性: {injurySeverity} (最大健康值: {partMaxHealth})");
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
@@ -628,7 +505,6 @@ namespace WulaFallenEmpire
|
||||
|
||||
// 记录最后一次受到伤害的时间
|
||||
lastDamageTick = Find.TickManager.TicksGame;
|
||||
Log.Message($"[NanoRepair] 受到伤害,开始修复冷却: {lastDamageTick}");
|
||||
}
|
||||
|
||||
// 新增:动态获取属性值的方法
|
||||
@@ -675,7 +551,6 @@ namespace WulaFallenEmpire
|
||||
"WULA_NanoRepair_DisabledMsg".Translate(Pawn.LabelShort),
|
||||
MessageTypeDefOf.SilentInput
|
||||
);
|
||||
Log.Message($"[NanoRepair] 修复系统已{(repairSystemEnabled ? "启用" : "禁用")}");
|
||||
},
|
||||
hotKey = KeyBindingDefOf.Misc1
|
||||
};
|
||||
|
||||
@@ -87,178 +87,6 @@ namespace WulaFallenEmpire
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldAttackVolleyTarget
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!VolleyTargetManager.IsVolleyEnabled(Pawn))
|
||||
return false;
|
||||
|
||||
LocalTargetInfo volleyTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
|
||||
if (!volleyTarget.IsValid)
|
||||
return false;
|
||||
|
||||
// 检查目标是否在射程内
|
||||
float distance = Pawn.Position.DistanceTo(volleyTarget.Cell);
|
||||
if (distance > AttackVerb.verbProps.range)
|
||||
return false;
|
||||
|
||||
// 检查是否可以命中目标
|
||||
return AttackVerb.CanHitTarget(volleyTarget);
|
||||
}
|
||||
}
|
||||
public override void CompPostTick(ref float severityAdjustment)
|
||||
{
|
||||
base.CompPostTick(ref severityAdjustment);
|
||||
|
||||
if (!TurretEnabled)
|
||||
{
|
||||
ResetCurrentTarget();
|
||||
return;
|
||||
}
|
||||
if (!this.CanShoot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// 新增:优先处理齐射目标
|
||||
if (ShouldAttackVolleyTarget)
|
||||
{
|
||||
LocalTargetInfo volleyTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
|
||||
this.currentTarget = volleyTarget;
|
||||
this.curRotation = (volleyTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
|
||||
}
|
||||
else if (this.currentTarget.IsValid)
|
||||
{
|
||||
this.curRotation = (this.currentTarget.Cell.ToVector3Shifted() - this.Pawn.DrawPos).AngleFlat() + this.Props.angleOffset;
|
||||
}
|
||||
|
||||
this.AttackVerb.VerbTick();
|
||||
if (this.AttackVerb.state != VerbState.Bursting)
|
||||
{
|
||||
if (this.WarmingUp)
|
||||
{
|
||||
this.burstWarmupTicksLeft--;
|
||||
if (this.burstWarmupTicksLeft == 0)
|
||||
{
|
||||
this.AttackVerb.TryStartCastOn(this.currentTarget, false, true, false, true);
|
||||
this.lastAttackTargetTick = Find.TickManager.TicksGame;
|
||||
this.lastAttackedTarget = this.currentTarget;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.burstCooldownTicksLeft > 0)
|
||||
{
|
||||
this.burstCooldownTicksLeft--;
|
||||
}
|
||||
if (this.burstCooldownTicksLeft <= 0 && this.Pawn.IsHashIntervalTick(10))
|
||||
{
|
||||
// 只有在没有齐射目标时才寻找新目标
|
||||
if (!ShouldAttackVolleyTarget)
|
||||
{
|
||||
this.currentTarget = (Thing)AttackTargetFinder.BestShootTargetFromCurrentPosition(this, TargetScanFlags.NeedThreat | TargetScanFlags.NeedAutoTargetable, null, 0f, 9999f);
|
||||
if (this.currentTarget.IsValid)
|
||||
{
|
||||
this.burstWarmupTicksLeft = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.ResetCurrentTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 新增:齐射Gizmos
|
||||
public override IEnumerable<Gizmo> CompGetGizmos()
|
||||
{
|
||||
// 只有 pawn 被选中且是玩家派系时才显示按钮
|
||||
if (this.Pawn.Faction == Faction.OfPlayer && Find.Selector.IsSelected(this.Pawn))
|
||||
{
|
||||
// 原有开关按钮
|
||||
yield return new Command_Toggle
|
||||
{
|
||||
defaultLabel = "CommandToggleTurret".Translate(),
|
||||
defaultDesc = "CommandToggleTurretDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ToggleTurret"),
|
||||
isActive = () => TurretEnabled,
|
||||
toggleAction = () => TurretEnabled = !TurretEnabled,
|
||||
hotKey = KeyBindingDefOf.Misc1
|
||||
};
|
||||
// 新增:齐射开关按钮
|
||||
yield return new Command_Toggle
|
||||
{
|
||||
defaultLabel = "CommandToggleVolley".Translate(),
|
||||
defaultDesc = "CommandToggleVolleyDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/VolleyFire"),
|
||||
isActive = () => VolleyTargetManager.IsVolleyEnabled(Pawn),
|
||||
toggleAction = () => VolleyTargetManager.ToggleVolley(Pawn),
|
||||
hotKey = KeyBindingDefOf.Misc2
|
||||
};
|
||||
// 新增:设置齐射目标按钮(只在齐射启用时显示)
|
||||
if (VolleyTargetManager.IsVolleyEnabled(Pawn))
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "CommandSetVolleyTarget".Translate(),
|
||||
defaultDesc = "CommandSetVolleyTargetDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/SetTarget"),
|
||||
action = () => Find.Targeter.BeginTargeting(TargetingParameters.ForAttack(),
|
||||
delegate (LocalTargetInfo target)
|
||||
{
|
||||
VolleyTargetManager.SetVolleyTarget(Pawn, target);
|
||||
},
|
||||
null,
|
||||
null,
|
||||
"SetVolleyTarget".Translate()),
|
||||
hotKey = KeyBindingDefOf.Misc3
|
||||
};
|
||||
// 新增:清除齐射目标按钮
|
||||
LocalTargetInfo currentVolleyTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
|
||||
if (currentVolleyTarget.IsValid)
|
||||
{
|
||||
yield return new Command_Action
|
||||
{
|
||||
defaultLabel = "CommandClearVolleyTarget".Translate(),
|
||||
defaultDesc = "CommandClearVolleyTargetDesc".Translate(),
|
||||
icon = ContentFinder<Texture2D>.Get("UI/Gizmos/ClearTarget"),
|
||||
action = () => VolleyTargetManager.ClearVolleyTarget(Pawn),
|
||||
hotKey = KeyBindingDefOf.Misc4
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 新增:在提示中显示齐射状态
|
||||
public override string CompTipStringExtra
|
||||
{
|
||||
get
|
||||
{
|
||||
string baseString = base.CompTipStringExtra;
|
||||
string turretStatus = TurretEnabled ? "Turret: Active" : "Turret: Inactive";
|
||||
|
||||
string volleyStatus = "Volley: ";
|
||||
if (VolleyTargetManager.IsVolleyEnabled(Pawn))
|
||||
{
|
||||
LocalTargetInfo volleyTarget = VolleyTargetManager.GetVolleyTarget(Pawn);
|
||||
if (volleyTarget.IsValid)
|
||||
{
|
||||
volleyStatus += $"Targeting {volleyTarget.Thing?.LabelCap ?? volleyTarget.Cell.ToString()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
volleyStatus += "Enabled (No Target)";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
volleyStatus += "Disabled";
|
||||
}
|
||||
string result = turretStatus + "\n" + volleyStatus;
|
||||
return string.IsNullOrEmpty(baseString) ? result : baseString + "\n" + result;
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:炮塔启用状态
|
||||
public bool TurretEnabled
|
||||
{
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using RimWorld;
|
||||
using RimWorld.Planet;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using RimWorld.QuestGen;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class QuestNode_CheckGlobalResource : QuestNode
|
||||
{
|
||||
// 输入参数
|
||||
public SlateRef<ThingDef> resourceDef;
|
||||
public SlateRef<int> requiredCount;
|
||||
public SlateRef<int> retryDelayTicks = 60; // 默认60 ticks (1秒)
|
||||
public SlateRef<string> successSignal;
|
||||
public SlateRef<string> failSignal;
|
||||
public SlateRef<bool> deductOnSuccess = true;
|
||||
public SlateRef<bool> useInputStorage = true; // true=输入存储, false=输出存储
|
||||
|
||||
// 保护参数不被序列化
|
||||
[NoTranslate]
|
||||
private string debugInfo;
|
||||
|
||||
protected override bool TestRunInt(Slate slate)
|
||||
{
|
||||
// 测试模式下只检查参数是否有效
|
||||
if (resourceDef == null || resourceDef.GetValue(slate) == null)
|
||||
{
|
||||
Log.Error("QuestNode_CheckGlobalResource: resourceDef is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (requiredCount.GetValue(slate) <= 0)
|
||||
{
|
||||
Log.Error("QuestNode_CheckGlobalResource: requiredCount must be positive");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 测试全局存储组件是否存在
|
||||
var globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||
if (globalStorage == null)
|
||||
{
|
||||
Log.Error("QuestNode_CheckGlobalResource: GlobalStorageWorldComponent not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void RunInt()
|
||||
{
|
||||
Slate slate = QuestGen.slate;
|
||||
Quest quest = QuestGen.quest;
|
||||
|
||||
ThingDef actualResourceDef = resourceDef.GetValue(slate);
|
||||
int actualRequiredCount = requiredCount.GetValue(slate);
|
||||
int actualRetryDelay = retryDelayTicks.GetValue(slate);
|
||||
string actualSuccessSignal = successSignal.GetValue(slate);
|
||||
string actualFailSignal = failSignal.GetValue(slate);
|
||||
bool actualDeductOnSuccess = deductOnSuccess.GetValue(slate);
|
||||
bool actualUseInputStorage = useInputStorage.GetValue(slate);
|
||||
|
||||
// 创建调试信息
|
||||
debugInfo = $"Checking {actualRequiredCount} {actualResourceDef?.defName ?? "NULL"} in {(actualUseInputStorage ? "Input" : "Output")} Storage with retry delay {actualRetryDelay}";
|
||||
|
||||
// 添加任务部分
|
||||
QuestPart_GlobalResourceCheck part = new QuestPart_GlobalResourceCheck
|
||||
{
|
||||
resourceDef = actualResourceDef,
|
||||
requiredCount = actualRequiredCount,
|
||||
retryDelayTicks = actualRetryDelay,
|
||||
successSignal = actualSuccessSignal,
|
||||
failSignal = actualFailSignal,
|
||||
deductOnSuccess = actualDeductOnSuccess,
|
||||
useInputStorage = actualUseInputStorage,
|
||||
debugInfo = debugInfo
|
||||
};
|
||||
|
||||
quest.AddPart(part);
|
||||
|
||||
Log.Message($"QuestNode_CheckGlobalResource: Added resource check for {actualRequiredCount} {actualResourceDef.defName} in {(actualUseInputStorage ? "Input" : "Output")} Storage");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
using RimWorld;
|
||||
using RimWorld.Planet;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
using RimWorld.QuestGen;
|
||||
|
||||
namespace WulaFallenEmpire
|
||||
{
|
||||
public class QuestPart_GlobalResourceCheck : QuestPartActivable
|
||||
{
|
||||
// 配置参数
|
||||
public ThingDef resourceDef;
|
||||
public int requiredCount;
|
||||
public int retryDelayTicks = 60;
|
||||
public string successSignal;
|
||||
public string failSignal;
|
||||
public bool deductOnSuccess = true;
|
||||
public bool useInputStorage = true;
|
||||
public string debugInfo;
|
||||
|
||||
// 状态变量
|
||||
private int nextRetryTick = -1;
|
||||
private bool hasSucceeded = false;
|
||||
private bool hasFailed = false;
|
||||
private int retryCount = 0;
|
||||
private const int MAX_RETRY_COUNT = 1000;
|
||||
|
||||
protected override void Enable(SignalArgs receivedArgs)
|
||||
{
|
||||
base.Enable(receivedArgs);
|
||||
|
||||
// 激活时立即开始第一次检查
|
||||
nextRetryTick = Find.TickManager.TicksGame;
|
||||
Log.Message($"QuestPart_GlobalResourceCheck Enabled: Will check for {requiredCount} {resourceDef?.defName} in {(useInputStorage ? "Input" : "Output")} Storage");
|
||||
}
|
||||
|
||||
public override void Notify_QuestSignalReceived(Signal signal)
|
||||
{
|
||||
base.Notify_QuestSignalReceived(signal);
|
||||
|
||||
// 如果任务已经结束,停止所有操作
|
||||
if (quest.State != QuestState.Ongoing && quest.State != QuestState.NotYetAccepted)
|
||||
{
|
||||
DoCleanup();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public override void QuestPartTick()
|
||||
{
|
||||
base.QuestPartTick();
|
||||
|
||||
// 如果已经成功或失败,或者任务已结束,不再处理
|
||||
if (hasSucceeded || hasFailed || (quest.State != QuestState.Ongoing && quest.State != QuestState.NotYetAccepted))
|
||||
{
|
||||
DoCleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否到了重试时间
|
||||
if (Find.TickManager.TicksGame < nextRetryTick && nextRetryTick != -1)
|
||||
return;
|
||||
|
||||
// 执行资源检查
|
||||
CheckGlobalResource();
|
||||
}
|
||||
|
||||
private void CheckGlobalResource()
|
||||
{
|
||||
// 更新下次重试时间
|
||||
nextRetryTick = Find.TickManager.TicksGame + retryDelayTicks;
|
||||
retryCount++;
|
||||
|
||||
// 获取全局资源储存器
|
||||
GlobalStorageWorldComponent globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
|
||||
if (globalStorage == null)
|
||||
{
|
||||
Log.Error("QuestPart_GlobalResourceCheck: GlobalStorageWorldComponent not found");
|
||||
HandleFailure("Global storage component missing");
|
||||
return;
|
||||
}
|
||||
|
||||
if (resourceDef == null)
|
||||
{
|
||||
Log.Error("QuestPart_GlobalResourceCheck: resourceDef is null");
|
||||
HandleFailure("Resource definition is null");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查资源是否足够
|
||||
int currentAmount = useInputStorage ?
|
||||
globalStorage.GetInputStorageCount(resourceDef) :
|
||||
globalStorage.GetOutputStorageCount(resourceDef);
|
||||
|
||||
bool hasEnough = currentAmount >= requiredCount;
|
||||
|
||||
Log.Message($"GlobalResourceCheck [{retryCount}]: {currentAmount}/{requiredCount} {resourceDef.defName} in {(useInputStorage ? "Input" : "Output")} Storage - Enough: {hasEnough}");
|
||||
|
||||
if (hasEnough)
|
||||
{
|
||||
// 资源足够,处理成功
|
||||
HandleSuccess(globalStorage);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 资源不足,安排重试
|
||||
HandleFailure($"Insufficient resources: {currentAmount}/{requiredCount}");
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSuccess(GlobalStorageWorldComponent globalStorage)
|
||||
{
|
||||
hasSucceeded = true;
|
||||
|
||||
// 如果需要扣除资源
|
||||
if (deductOnSuccess)
|
||||
{
|
||||
bool deducted = useInputStorage ?
|
||||
globalStorage.RemoveFromInputStorage(resourceDef, requiredCount) :
|
||||
globalStorage.RemoveFromOutputStorage(resourceDef, requiredCount);
|
||||
|
||||
if (!deducted)
|
||||
{
|
||||
Log.Error($"QuestPart_GlobalResourceCheck: Failed to deduct {requiredCount} {resourceDef.defName} from {(useInputStorage ? "Input" : "Output")} Storage");
|
||||
}
|
||||
}
|
||||
|
||||
Log.Message($"GlobalResourceCheck: SUCCESS - {(deductOnSuccess ? "Deducted" : "Found")} {requiredCount} {resourceDef.defName} from {(useInputStorage ? "Input" : "Output")} Storage");
|
||||
|
||||
// 发送成功信号 - 使用 QuestGenUtility 来生成带任务前缀的信号
|
||||
if (!successSignal.NullOrEmpty())
|
||||
{
|
||||
string fullSignal = QuestGenUtility.HardcodedSignalWithQuestID(successSignal);
|
||||
Find.SignalManager.SendSignal(new Signal(fullSignal));
|
||||
Log.Message($"GlobalResourceCheck: Sent success signal '{fullSignal}'");
|
||||
}
|
||||
|
||||
// 清理这个任务部分
|
||||
DoCleanup();
|
||||
}
|
||||
|
||||
private void HandleFailure(string reason = "")
|
||||
{
|
||||
// 检查是否超过最大重试次数
|
||||
if (retryCount >= MAX_RETRY_COUNT)
|
||||
{
|
||||
Log.Warning($"GlobalResourceCheck: Max retry count ({MAX_RETRY_COUNT}) reached for {resourceDef.defName}. Reason: {reason}");
|
||||
hasFailed = true;
|
||||
|
||||
// 发送失败信号
|
||||
if (!failSignal.NullOrEmpty())
|
||||
{
|
||||
string fullSignal = QuestGenUtility.HardcodedSignalWithQuestID(failSignal);
|
||||
Find.SignalManager.SendSignal(new Signal(fullSignal));
|
||||
Log.Message($"GlobalResourceCheck: Sent fail signal '{fullSignal}' after max retries");
|
||||
}
|
||||
|
||||
DoCleanup();
|
||||
return;
|
||||
}
|
||||
|
||||
// 安排下次重试
|
||||
ScheduleRetry(reason);
|
||||
}
|
||||
|
||||
private void ScheduleRetry(string reason = "")
|
||||
{
|
||||
nextRetryTick = Find.TickManager.TicksGame + retryDelayTicks;
|
||||
|
||||
// 记录重试信息
|
||||
Log.Message($"GlobalResourceCheck: Scheduled retry #{retryCount + 1} in {retryDelayTicks} ticks for {requiredCount} {resourceDef.defName}. Reason: {reason}");
|
||||
}
|
||||
|
||||
// 使用新名称避免与基类冲突
|
||||
private void DoCleanup()
|
||||
{
|
||||
// 标记为已完成,停止tick更新
|
||||
nextRetryTick = -1;
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Defs.Look(ref resourceDef, "resourceDef");
|
||||
Scribe_Values.Look(ref requiredCount, "requiredCount");
|
||||
Scribe_Values.Look(ref retryDelayTicks, "retryDelayTicks");
|
||||
Scribe_Values.Look(ref successSignal, "successSignal");
|
||||
Scribe_Values.Look(ref failSignal, "failSignal");
|
||||
Scribe_Values.Look(ref deductOnSuccess, "deductOnSuccess");
|
||||
Scribe_Values.Look(ref useInputStorage, "useInputStorage");
|
||||
Scribe_Values.Look(ref debugInfo, "debugInfo");
|
||||
|
||||
Scribe_Values.Look(ref nextRetryTick, "nextRetryTick");
|
||||
Scribe_Values.Look(ref hasSucceeded, "hasSucceeded");
|
||||
Scribe_Values.Look(ref hasFailed, "hasFailed");
|
||||
Scribe_Values.Look(ref retryCount, "retryCount");
|
||||
}
|
||||
|
||||
public override void AssignDebugData()
|
||||
{
|
||||
base.AssignDebugData();
|
||||
|
||||
resourceDef = ThingDefOf.Steel;
|
||||
requiredCount = 100;
|
||||
retryDelayTicks = 60;
|
||||
successSignal = "TaxPaymentSuccess";
|
||||
failSignal = "TaxPaymentFailed";
|
||||
deductOnSuccess = true;
|
||||
useInputStorage = true;
|
||||
debugInfo = "Debug: Tax Collection Check";
|
||||
}
|
||||
|
||||
public override string DescriptionPart
|
||||
{
|
||||
get
|
||||
{
|
||||
string status = hasSucceeded ? "SUCCEEDED" :
|
||||
hasFailed ? "FAILED" :
|
||||
$"CHECKING (retry #{retryCount}, next in {nextRetryTick - Find.TickManager.TicksGame} ticks)";
|
||||
|
||||
return $"Tax Collection: {requiredCount} {resourceDef?.defName ?? "NULL"} - {status}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,6 +208,8 @@
|
||||
<Compile Include="Pawn\WULA_Maintenance\Need_Maintenance.cs" />
|
||||
<Compile Include="Pawn\WULA_Maintenance\WorkGiver_DoMaintenance.cs" />
|
||||
<Compile Include="Placeworker\CompProperties_CustomRadius.cs" />
|
||||
<Compile Include="QuestNodes\QuestNode_CheckGlobalResource.cs" />
|
||||
<Compile Include="QuestNodes\QuestPart_GlobalResourceCheck.cs" />
|
||||
<Compile Include="Stat\StatWorker_Energy.cs" />
|
||||
<Compile Include="Stat\StatWorker_Maintenance.cs" />
|
||||
<Compile Include="Stat\StatWorker_NanoRepair.cs" />
|
||||
|
||||
Reference in New Issue
Block a user