diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 849f6821..08b2c20d 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml index 3172b084..67ecd702 100644 --- a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml +++ b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml @@ -23,24 +23,6 @@
  • -
  • - 陆行舰正在逼近 - 艾妮西娅按照要求,吸引了一艘乌拉帝国的陆行舰机械体攻击我们的殖民地! - 100 - Mechanoid - ImmediateAttack - EdgeWalkIn - Combat - -
  • - Combat - 100 - - 100 - -
  • - - @@ -80,6 +62,7 @@ + Wula_UI_Legion_30 diff --git a/1.6/1.6/Defs/QuestScriptDefs/Wula_Base_Events.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_QuestScript.xml similarity index 87% rename from 1.6/1.6/Defs/QuestScriptDefs/Wula_Base_Events.xml rename to 1.6/1.6/Defs/QuestScriptDefs/WULA_Base_QuestScript.xml index 2a2237b3..c6179df6 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/Wula_Base_Events.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_QuestScript.xml @@ -1,5 +1,6 @@ + WULA_GiveQuest_Intro_Spy GiveQuest @@ -12,23 +13,19 @@ 0 True - WULA_Intro_Spy - 1 - 2 - true - false - + 1 + 2 + true + false + -
  • questName->[QuestName]
  • - - -
  • QuestName->hunted
  • +
  • questName->WULA_Intro_Spy_questName
  • @@ -36,7 +33,7 @@
  • QuestHospitalityCommon
  • -
  • 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.
  • +
  • questDescription->WULA_Intro_Spy_questDescription
  • @@ -46,20 +43,6 @@
  • Wula_Intro_Spy_UI_1
  • -
  • - - -
  • questName->掩护帝国密探
  • - - - -
  • - - -
  • questDescription->乌拉帝国行星封锁机关的总控AI向殖民地发送了一个请求。一位乌拉帝国密探已经暴露,正在遭受未知派系追杀——密探手无寸铁且携带重要信息,殖民地需要掩护它直到乌拉帝国的穿梭机抵达并将其接走。袭击不会太剧烈,密探已经甩掉了大部分敌人。
  • - - -
  • Util_RandomizePointsChallengeRating @@ -99,11 +82,11 @@
  • Wula_PawnKind - asker + asker Wula_PIA_Legion_Faction 1 1 - false + false
  • @@ -130,7 +113,7 @@ 1800 - + Util_Raid raid @@ -141,39 +124,26 @@ $enemyFaction $walkInSpot {BASELABEL} chasing [../asker_nameDef] - {BASETEXT} - \nThe [enemyFaction_pawnsPlural] have come to get [../asker_nameDef]. + {BASETEXT}\nThe [enemyFaction_pawnsPlural] have come to get [../asker_nameDef]. - -
  • -
  • - $animalKindDef - peacefulAnimal -
  • -
  • - $peacefulAnimal - [animalKindDef_label] arrived - The [animalKindDef_label] that [asker_nameDef] was fleeing has arrived.\n\nIt turned out to be quite gentle and not aggressive at all. -
  • -
  • 7500 - $asker + $asker
  • Util_TransportShip_Pickup - 45000 - $asker - true + 45000 + $asker + true
  • @@ -637,4 +607,83 @@
    + + + + WULA_GiveQuest_Base_Tex + GiveQuest + + +
  • Map_PlayerHome
  • +
    + WULA_Base_Tex_Quest + IncidentWorker_GiveQuest + 0 + True +
    + + WULA_Base_Tex_Quest + 0 + true + false + 1 + true + false + + + +
  • questName->WULA_Base_Tex_Quest_questName
  • +
    +
    + + +
  • QuestHospitalityCommon
  • +
    + +
  • questDescription->WULA_Intro_Spy_questDescription
  • +
    +
    + + + + + +
  • + taxAmount + 100 +
  • +
  • + taxInterval + 250 +
  • + +
  • + Steel + $taxAmount + $taxInterval + TaxPaymentSuccess + TaxPaymentFailed + true + true +
  • + +
  • + TaxPaymentSuccess + + +
  • + + 已成功从全局储存中扣除100钢铁作为税款。 + PositiveEvent +
  • +
  • + Success + false +
  • +
    + + + +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Scripts_Utility.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Scripts_Utility.xml new file mode 100644 index 00000000..d7377068 --- /dev/null +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Scripts_Utility.xml @@ -0,0 +1,21 @@ + + + + + Util_Wula_GlobalResourceCheck + + + +
  • + $resourceDef + $requiredCount + $retryDelayTicks + $successSignal + $failSignal + $deductOnSuccess + $useInputStorage +
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml index 04254649..ad153e41 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml @@ -976,7 +976,7 @@ Wula_AI_Heavy_Panzer - 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用穿透力强大的战车炮和导弹打击敌方,是乌拉帝国前锋部队的中流砥柱。 + 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。 Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Heavy_Panzer_Icon 1 @@ -1519,10 +1519,10 @@
  • -
  • +
  • + CompMechanoid +
  • - true - 30 MechanoidsWakeUp
  • diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/DefInjected/QuestScriptDef/Wula_Base_QuestScript.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/DefInjected/QuestScriptDef/Wula_Base_QuestScript.xml new file mode 100644 index 00000000..4452ada8 --- /dev/null +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/DefInjected/QuestScriptDef/Wula_Base_QuestScript.xml @@ -0,0 +1,58 @@ + + + +
  • questName->掩护帝国密探
  • +
    + +
  • questDescription->乌拉帝国行星封锁机关的总控AI向殖民地发送了一个请求。一位乌拉帝国密探已经暴露,正在遭受其他派系追杀——密探手无寸铁且携带重要信息,殖民地需要掩护它直到乌拉帝国的穿梭机抵达并将其接走。虽然对方未透露更多信息,不过她指明袭击不会太剧烈,密探已经甩掉了大部分敌人。
  • +
    + {BASELABEL} 追捕[../asker_nameDef] + {BASETEXT}\n\n[enemyFaction_pawnsPlural]来此追捕[../asker_nameDef]。 + + + 应该乘坐穿梭机出发 + + 穿梭机已抵达 + + 前来迎接[asker_nameDef]的穿梭机已抵达。 + + 宾客已死亡:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}已经死亡。[failLetterEndingCommon] + + 宾客被遗弃:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}被遗弃。[failLetterEndingCommon] + + 未授权手术:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}接受了一次未授权的额外手术。因为你违规在先,[asker_pronoun]将要离开此处。[failLetterEndingCommon] + + 异种胚芽被吸收:{SUBJECT_definite} + + 指定由你保护的{SUBJECT_definite}在你的殖民地被吸收了异种胚芽。这是一种侵犯行为,{SUBJECT_pronoun}现在将会直接离开[failLetterEndingCommon]。 + + 已被俘:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}已被俘虏。[failLetterEndingCommon] + + 宾客失踪:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}在你的殖民地回归自然。[failLetterEndingCommon] + + 宾客失踪:{SUBJECT_definite} + + 需要你小心保护的{SUBJECT_definite}在你的殖民地回归自然。[failLetterEndingCommon] + + 穿梭机被毁 + + 前来迎接[asker_nameDef]的穿梭机已被毁。[asker_pronoun]现在只能走回去了。[failLetterEndingCommon] + + 穿梭机被遗弃 + + 前来迎接[asker_nameDef]的穿梭机已被遗弃。[asker_pronoun]现在只能走回去了。 + + 任务失败:[resolvedQuestName] + + 前来迎接[asker_nameDef]的穿梭机在离开时因为一些原因落下了[asker_objective]。[asker_pronoun]现在只能走回去了。[failLetterEndingCommon] +
    \ No newline at end of file diff --git a/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs b/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs index 175fb2f8..abf7e010 100644 --- a/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs +++ b/Source/WulaFallenEmpire/Flyover/ThingclassFlyOver.cs @@ -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(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(); 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; // 是否启用淡入效果 diff --git a/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs b/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs index 8f07dfba..22ed0263 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs @@ -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.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.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(); if (strafingComp != null) { - // 修复:计算扫射区域的所有单元格,以目标单元格为中心 Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized; List potentialTargetCells = CalculateStrafingImpactCells(targetCell, flightDirection); if (potentialTargetCells.Count > 0) { - // 预处理:根据概率筛选实际会被射击的单元格 List 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.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 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 CalculateStrafingImpactCells(IntVec3 targetCell, Vector3 flightDirection) { List cells = new List(); 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 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 CalculateRectangularPreviewArea(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection, Vector3 perpendicular) { List cells = new List(); 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 PreprocessStrafingTargets(List potentialTargets, float fireChance) { List confirmedTargets = new List(); List missedCells = new List(); + 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,23 +804,18 @@ namespace WulaFallenEmpire return GetSafeMapPosition(endPos, map); } - // 原有的辅助方法 private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos) { IntVec3 center = map.Center; Vector3 toCenter = (center.ToVector3() - startPos.ToVector3()).normalized; - + 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; diff --git a/Source/WulaFallenEmpire/Hediff/HediffGiver_NonPlayerFaction.cs b/Source/WulaFallenEmpire/Hediff/HediffGiver_NonPlayerFaction.cs deleted file mode 100644 index 88cfe2f7..00000000 --- a/Source/WulaFallenEmpire/Hediff/HediffGiver_NonPlayerFaction.cs +++ /dev/null @@ -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 targetFactions; - - // 新增:是否排除玩家派系(默认为true) - public bool excludePlayerFaction = true; - - // 新增:是否排除囚犯(默认为true) - public bool excludePrisoners = true; - - // 新增:记录已经处理过的 pawn,避免重复处理 - private HashSet processedPawns = new HashSet(); - - 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); - } - } -} diff --git a/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs b/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs index b1a0f0bf..85a6e988 100644 --- a/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs +++ b/Source/WulaFallenEmpire/HediffComp/HediffCompProperties_NanoRepair.cs @@ -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.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(); 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,14 +194,9 @@ 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,14 +218,9 @@ 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(); 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 }; diff --git a/Source/WulaFallenEmpire/HediffComp/WULA_HediffComp_TopTurret/HediffComp_TopTurret.cs b/Source/WulaFallenEmpire/HediffComp/WULA_HediffComp_TopTurret/HediffComp_TopTurret.cs index d96cb358..3ed7b89d 100644 --- a/Source/WulaFallenEmpire/HediffComp/WULA_HediffComp_TopTurret/HediffComp_TopTurret.cs +++ b/Source/WulaFallenEmpire/HediffComp/WULA_HediffComp_TopTurret/HediffComp_TopTurret.cs @@ -87,184 +87,12 @@ 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 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.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.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.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.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 { get { return turretEnabled; } - set - { + set + { turretEnabled = value; if (!turretEnabled) { @@ -366,7 +194,7 @@ namespace WulaFallenEmpire public override void CompPostTick(ref float severityAdjustment) { base.CompPostTick(ref severityAdjustment); - + // 新增:只在启用状态下执行攻击逻辑 if (!TurretEnabled) { @@ -432,7 +260,7 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref this.fireAtWill, "fireAtWill", true, false); // 新增:保存启用状态 Scribe_Values.Look(ref this.turretEnabled, "turretEnabled", Props.defaultEnabled, false); - + if (Scribe.mode == LoadSaveMode.PostLoadInit) { if (this.gun == null) @@ -486,11 +314,11 @@ namespace WulaFallenEmpire private LocalTargetInfo lastAttackedTarget = LocalTargetInfo.Invalid; private int lastAttackTargetTick; private float curRotation; - + // 新增:炮塔启用状态字段 private bool turretEnabled = true; [Unsaved(false)] public Material turretMat; } -} +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/QuestNodes/QuestNode_CheckGlobalResource.cs b/Source/WulaFallenEmpire/QuestNodes/QuestNode_CheckGlobalResource.cs new file mode 100644 index 00000000..6325dfe9 --- /dev/null +++ b/Source/WulaFallenEmpire/QuestNodes/QuestNode_CheckGlobalResource.cs @@ -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 resourceDef; + public SlateRef requiredCount; + public SlateRef retryDelayTicks = 60; // 默认60 ticks (1秒) + public SlateRef successSignal; + public SlateRef failSignal; + public SlateRef deductOnSuccess = true; + public SlateRef 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(); + 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"); + } + } +} diff --git a/Source/WulaFallenEmpire/QuestNodes/QuestPart_GlobalResourceCheck.cs b/Source/WulaFallenEmpire/QuestNodes/QuestPart_GlobalResourceCheck.cs new file mode 100644 index 00000000..d99764c6 --- /dev/null +++ b/Source/WulaFallenEmpire/QuestNodes/QuestPart_GlobalResourceCheck.cs @@ -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(); + 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}"; + } + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 107a03fc..d35b350b 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -208,6 +208,8 @@ + +