diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 4d4fd13..6215955 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Defs/AbilityDefs/Ability_Flyover.xml b/1.6/1.6/Defs/AbilityDefs/Ability_Flyover.xml new file mode 100644 index 0000000..d66199a --- /dev/null +++ b/1.6/1.6/Defs/AbilityDefs/Ability_Flyover.xml @@ -0,0 +1,162 @@ + + + + + ARA_SpawnFlyOverTest + + 测试召唤不同类型的飞越物体 + ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph + 1 + Misc12 + false + + Verb_CastAbility + false + false + true + 1 + 19.9 + true + + True + + + +
  • + ARA_HiveShip + Standard + 0.01 + 20 + MapEdge + OppositeMapEdge + true +
  • +
    +
    + + + ARA_Spawn_ARA_HiveCorvette_Rocket + + 召唤天巫种兽虫,高速掠过战场,使用其迅捷天灾炮对目标区域发起打击 + ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph + 1 + Misc12 + false + + Verb_CastAbility + false + false + 1 + 120 + true + + false + true + + + +
  • + ARA_HiveCorvette + GroundStrafing + 5 + 20 + true + Perpendicular + + + true + 3 + 25 + Proj_ARA_HiveCorvette + 0.23 + + + true + (1.0,0.3,0.1,0.2) +
  • +
    +
    + + + ARA_Spawn_ARA_HiveCorvette_Bombardment + + 召唤天巫种兽虫,慢速掠过战场,对大范围目标区域进行酸团轰炸 + ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph + 1 + Misc12 + false + + Verb_CastAbility + false + false + 1 + 120 + true + + false + true + + + +
  • + ARA_HiveCorvette_Bombardment + GroundStrafing + 2 + 20 + true + Perpendicular + + + true + 6 + 15 + Bullet_ARA_RW_Acid_Mortar + 0.3 + + + true + (1.0,0.3,0.1,0.2) +
  • +
    +
    + + + ARA_Spawn_ARA_HiveCorvette_Watch + + 召唤天巫种兽虫,中速掠过战场,使用血链棘刺炮监视并射击路径上的所有敌人。 + ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph + 1 + Misc12 + false + + Verb_CastAbility + false + false + 1 + 120 + true + + false + true + + + +
  • + ARA_HiveCorvette + SectorSurveillance + 3.5 + 20 + true + Perpendicular + + + true + + + true + 4 + (0.3,0.7,1.0,0.3) +
  • +
    +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/AbilityDefs/Ability_Morph.xml b/1.6/1.6/Defs/AbilityDefs/Ability_Morph.xml index 4fd0bfd..4c870e8 100644 --- a/1.6/1.6/Defs/AbilityDefs/Ability_Morph.xml +++ b/1.6/1.6/Defs/AbilityDefs/Ability_Morph.xml @@ -37,82 +37,4 @@ - - - - - ARA_SpawnFlyOverTest - - 测试召唤不同类型的飞越物体 - ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph - 1 - Misc12 - false - - Verb_CastAbility - false - false - true - 1 - 19.9 - true - - True - - - -
  • - ARA_HiveShip - Standard - 0.01 - 20 - MapEdge - OppositeMapEdge - true -
  • -
    -
    - - - ARA_SpawnFlyAttackerTest - - 测试召唤不同类型的飞越物体 - ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph - 1 - Misc12 - false - - Verb_CastAbility - false - false - 1 - 19.9 - true - - false - true - - - -
  • - ARA_HiveCorvette - GroundStrafing - 1 - 20 - true - Perpendicular - - - true - 0.5 - 1 - Bullet_Shell_AntigrainWarhead - 1 - - - true - (1.0,0.3,0.1,0.2) -
  • -
    -
    \ No newline at end of file diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_Flyover_Item.xml b/1.6/1.6/Defs/Thing_Misc/ARA_Flyover_Item.xml index 12e9c8f..58d265d 100644 --- a/1.6/1.6/Defs/Thing_Misc/ARA_Flyover_Item.xml +++ b/1.6/1.6/Defs/Thing_Misc/ARA_Flyover_Item.xml @@ -176,7 +176,7 @@ ARA_HiveCorvette - + ArachnaeSwarm.FlyOver Normal RealtimeOnly @@ -215,8 +215,61 @@ MetaOverlays
  • - Bullet_Shell_AntigrainWarhead - 35 + Proj_ARA_HiveCorvette + 50 +
  • +
  • + ARA_Bullet_SniperCannon + 90 + 50 + 3 + 0.3 +
  • +
    +
    + + ARA_HiveCorvette_Bombardment + + ArachnaeSwarm.FlyOver + Normal + RealtimeOnly + + + ArachnaeSwarm/FlyOverThing/ARA_HiveCorvette_Shadow + Graphic_Single + TransparentPostLight + (20,30) + (195,195,195,45) + + false + 0 + + ArachnaeSwarm/Weapon/ARA_Weapon_Empty + (0, 0) + 0 + FlyOver/Flying + FlyOver/Landing + + +
  • + ArachnaeSwarm/Weapon/ARA_Weapon_Empty + true + 0.8 + 0 + 0 + 0 + 0 +
  • +
    + true + false + false + false + MetaOverlays + +
  • + Bullet_ARA_RW_Acid_Mortar + 15
  • @@ -266,7 +319,7 @@ Bomb 2.9 - 120 + 320 Filth_SpentAcid 2 true diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index ad89863..8f1554e 100644 Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json index d2d7ab9..7451b50 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -1,37 +1,41 @@ { "Version": 1, - "WorkspaceRootPath": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", + "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_groundstrafing\\compgroundstrafing.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_groundstrafing\\compgroundstrafing.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_sectorsurveillance\\compsectorsurveillance.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_sectorsurveillance\\compsectorsurveillance.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_spawnflyover\\compproperties_abilityspawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_spawnflyover\\compproperties_abilityspawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|e:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_flyoverescort\\compflyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_spawnflyover\\compabilityeffect_spawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_spawnflyover\\compproperties_abilityspawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_spawnflyover\\compproperties_abilityspawnflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_groundstrafing\\compgroundstrafing.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_groundstrafing\\compgroundstrafing.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + }, + { + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_flyoverescort\\compflyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_flyoverescort\\compflyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_shipartillery\\compshipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_shipartillery\\compshipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_shipartillery\\compshipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" }, { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_shipartillery\\compproperties_shipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_shipartillery\\compproperties_shipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_shipartillery\\compproperties_shipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" } ], @@ -51,62 +55,74 @@ { "$type": "Document", "DocumentIndex": 0, - "Title": "CompGroundStrafing.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", - "RelativeDocumentMoniker": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", - "RelativeToolTip": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", - "ViewState": "AgIAAB0AAAAAAAAAAAAQwCkAAAAIAAAAAAAAAA==", + "Title": "CompSectorSurveillance.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs", + "RelativeDocumentMoniker": "Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs", + "RelativeToolTip": "Flyover\\ARA_SectorSurveillance\\CompSectorSurveillance.cs", + "ViewState": "AgIAACMBAAAAAAAAAAAqwDkBAAANAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-28T16:19:23.118Z", + "WhenOpened": "2025-10-29T02:30:42.063Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 1, + "DocumentIndex": 4, + "Title": "CompGroundStrafing.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", + "RelativeDocumentMoniker": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", + "RelativeToolTip": "Flyover\\ARA_GroundStrafing\\CompGroundStrafing.cs", + "ViewState": "AgIAAB0AAAAAAAAAAAAQwCYAAABFAAAAAAAAAA==", + "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", + "WhenOpened": "2025-10-28T16:19:23.118Z" + }, + { + "$type": "Document", + "DocumentIndex": 2, "Title": "CompAbilityEffect_SpawnFlyOver.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs", "RelativeDocumentMoniker": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs*", - "RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs*", - "ViewState": "AgIAAPEAAAAAAAAAAAAawAsBAAAWAAAAAAAAAA==", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs", + "RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs", + "ViewState": "AgIAAAAAAAAAAAAAAAAAABYAAABOAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-10-28T14:51:14.836Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 2, + "DocumentIndex": 3, "Title": "CompProperties_AbilitySpawnFlyOver.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", "RelativeDocumentMoniker": "Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", "RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAACsAAAAJAAAAAAAAAA==", + "ViewState": "AgIAABgAAAAAAAAAAAAswDQAAAAAAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-10-28T13:51:12.201Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 3, + "DocumentIndex": 1, "Title": "ThingclassFlyOver.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs", "RelativeDocumentMoniker": "Flyover\\ThingclassFlyOver.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs", "RelativeToolTip": "Flyover\\ThingclassFlyOver.cs", - "ViewState": "AgIAALAAAAAAAAAAAAAWwNQAAAAlAAAAAAAAAA==", + "ViewState": "AgIAAAkCAAAAAAAAAAAqwCYCAAB/AAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", "WhenOpened": "2025-10-28T09:09:22.03Z", "EditorCaption": "" }, { "$type": "Document", - "DocumentIndex": 4, + "DocumentIndex": 5, "Title": "CompFlyOverEscort.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", "RelativeDocumentMoniker": "Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", "RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs", "ViewState": "AgIAAKYBAAAAAAAAAAAWwNEBAAAAAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", @@ -114,11 +130,11 @@ }, { "$type": "Document", - "DocumentIndex": 5, + "DocumentIndex": 6, "Title": "CompProperties_FlyOverEscort.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", "RelativeDocumentMoniker": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", "RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs", "ViewState": "AgIAAAAAAAAAAAAAAAAAABgAAAAPAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", @@ -126,11 +142,11 @@ }, { "$type": "Document", - "DocumentIndex": 7, + "DocumentIndex": 8, "Title": "CompProperties_ShipArtillery.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", "RelativeDocumentMoniker": "Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", "RelativeToolTip": "Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs", "ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAhAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", @@ -138,11 +154,11 @@ }, { "$type": "Document", - "DocumentIndex": 6, + "DocumentIndex": 7, "Title": "CompShipArtillery.cs", - "DocumentMoniker": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", "RelativeDocumentMoniker": "Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", - "ToolTip": "E:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", "RelativeToolTip": "Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs", "ViewState": "AgIAALEAAAAAAAAAAAAywNEAAABcAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index 5a1c934..4a5a491 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -141,6 +141,7 @@ + diff --git a/Source/ArachnaeSwarm/Flyover/ARA_SectorSurveillance/CompSectorSurveillance.cs b/Source/ArachnaeSwarm/Flyover/ARA_SectorSurveillance/CompSectorSurveillance.cs new file mode 100644 index 0000000..cc7846b --- /dev/null +++ b/Source/ArachnaeSwarm/Flyover/ARA_SectorSurveillance/CompSectorSurveillance.cs @@ -0,0 +1,565 @@ +using System.Collections.Generic; +using RimWorld; +using UnityEngine; +using Verse; + +namespace ArachnaeSwarm +{ + public class CompSectorSurveillance : ThingComp + { + public CompProperties_SectorSurveillance Props => (CompProperties_SectorSurveillance)props; + + // 监视状态 + private HashSet attackedPawns = new HashSet(); + private Dictionary activeTargets = new Dictionary(); + private Dictionary shotCooldowns = new Dictionary(); + + // 性能优化 + private int checkInterval = 10; + private int lastCheckTick = 0; + + // 调试状态 + private int totalFramesProcessed = 0; + private int totalTargetsFound = 0; + private int totalShotsFired = 0; + + // 派系缓存 + private Faction cachedFaction = null; + private bool factionInitialized = false; + + // 新增:射弹数量跟踪 + private int remainingProjectiles = -1; // -1 表示无限 + private bool ammoExhausted = false; + + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + + // 初始化射弹数量 + if (!respawningAfterLoad) + { + remainingProjectiles = Props.maxProjectiles; + ammoExhausted = false; + } + + Log.Message($"SectorSurveillance: Initialized - Angle: {Props.sectorAngle}°, Range: {Props.sectorRange}, Shots: {Props.shotCount}, Interval: {Props.shotInterval}s"); + Log.Message($"SectorSurveillance: ProjectileDef = {Props.projectileDef?.defName ?? "NULL"}"); + Log.Message($"SectorSurveillance: Parent = {parent?.def?.defName ?? "NULL"} at {parent?.Position.ToString() ?? "NULL"}"); + Log.Message($"SectorSurveillance: Max Projectiles = {Props.maxProjectiles}, Remaining = {remainingProjectiles}"); + + InitializeFactionCache(); + } + + private void InitializeFactionCache() + { + Log.Message($"SectorSurveillance: Initializing faction cache..."); + + if (parent.Faction != null) + { + cachedFaction = parent.Faction; + Log.Message($"SectorSurveillance: Using parent.Faction: {cachedFaction?.Name ?? "NULL"}"); + } + else + { + FlyOver flyOver = parent as FlyOver; + if (flyOver?.caster != null && flyOver.caster.Faction != null) + { + cachedFaction = flyOver.caster.Faction; + Log.Message($"SectorSurveillance: Using caster.Faction: {cachedFaction?.Name ?? "NULL"}"); + } + else if (flyOver?.faction != null) + { + cachedFaction = flyOver.faction; + Log.Message($"SectorSurveillance: Using flyOver.faction: {cachedFaction?.Name ?? "NULL"}"); + } + else + { + Log.Error($"SectorSurveillance: CRITICAL - No faction found!"); + } + } + + factionInitialized = true; + Log.Message($"SectorSurveillance: Faction cache initialized: {cachedFaction?.Name ?? "NULL"}"); + } + + private Faction GetEffectiveFaction() + { + if (!factionInitialized) + { + InitializeFactionCache(); + } + + if (cachedFaction == null) + { + Log.Warning("SectorSurveillance: Cached faction is null, reinitializing..."); + InitializeFactionCache(); + } + + return cachedFaction; + } + + public override void CompTick() + { + base.CompTick(); + totalFramesProcessed++; + + // 每60帧输出一次状态摘要 + if (Find.TickManager.TicksGame % 60 == 0) + { + Faction currentFaction = GetEffectiveFaction(); + Log.Message($"SectorSurveillance Status: Frames={totalFramesProcessed}, TargetsFound={totalTargetsFound}, ShotsFired={totalShotsFired}, ActiveTargets={activeTargets.Count}, Cooldowns={shotCooldowns.Count}, Faction={currentFaction?.Name ?? "NULL"}, RemainingProjectiles={remainingProjectiles}, AmmoExhausted={ammoExhausted}"); + } + + UpdateShotCooldowns(); + + if (Find.TickManager.TicksGame - lastCheckTick >= checkInterval) + { + CheckSectorForTargets(); + lastCheckTick = Find.TickManager.TicksGame; + } + + ExecuteAttacks(); + } + + private void UpdateShotCooldowns() + { + List toRemove = new List(); + + // 关键修复:创建键的副本 + List cooldownKeys = new List(shotCooldowns.Keys); + + foreach (Pawn pawn in cooldownKeys) + { + // 检查pawn是否仍然有效(可能已被爆炸杀死) + if (pawn == null || pawn.Destroyed || pawn.Dead || !pawn.Spawned) + { + toRemove.Add(pawn); + continue; + } + + // 检查键是否仍在字典中 + if (!shotCooldowns.ContainsKey(pawn)) + { + continue; + } + + shotCooldowns[pawn]--; + if (shotCooldowns[pawn] <= 0) + { + toRemove.Add(pawn); + } + } + + foreach (Pawn pawn in toRemove) + { + shotCooldowns.Remove(pawn); + Log.Message($"SectorSurveillance: Cooldown finished for {pawn?.Label ?? "NULL"}"); + } + } + + private void CheckSectorForTargets() + { + // 如果弹药耗尽,不再检查新目标 + if (ammoExhausted) + { + return; + } + + List enemiesInSector = GetEnemiesInSector(); + Log.Message($"SectorSurveillance: Found {enemiesInSector.Count} enemies in sector"); + + if (enemiesInSector.Count > 0) + { + Log.Message($"SectorSurveillance: Enemies in sector: {string.Join(", ", enemiesInSector.ConvertAll(p => p.Label))}"); + } + + foreach (Pawn enemy in enemiesInSector) + { + totalTargetsFound++; + + if (!attackedPawns.Contains(enemy) && + !activeTargets.ContainsKey(enemy) && + !shotCooldowns.ContainsKey(enemy)) + { + activeTargets[enemy] = Props.shotCount; + Log.Message($"SectorSurveillance: Starting attack sequence on {enemy.Label} at {enemy.Position} - {Props.shotCount} shots"); + } + } + } + + private void ExecuteAttacks() + { + // 如果弹药耗尽,不再执行攻击 + if (ammoExhausted) + { + return; + } + + List completedTargets = new List(); + + // 关键修复:在枚举之前创建键的副本 + List targetsToProcess = new List(activeTargets.Keys); + + foreach (Pawn enemy in targetsToProcess) + { + // 检查目标是否仍然有效(可能已被爆炸杀死) + if (enemy == null || enemy.Destroyed || enemy.Dead || !enemy.Spawned) + { + completedTargets.Add(enemy); + continue; + } + + // 检查目标是否仍在字典中 + if (!activeTargets.ContainsKey(enemy)) + { + continue; + } + + int remainingShots = activeTargets[enemy]; + + if (!IsInSector(enemy.Position)) + { + Log.Message($"SectorSurveillance: Target {enemy.Label} left sector, cancelling attack"); + completedTargets.Add(enemy); + continue; + } + + if (shotCooldowns.ContainsKey(enemy)) + { + Log.Message($"SectorSurveillance: Target {enemy.Label} in cooldown, skipping this frame"); + continue; + } + + // 新增:检查剩余射弹数量 + if (remainingProjectiles == 0) + { + Log.Message($"SectorSurveillance: Ammo exhausted, cannot fire at {enemy.Label}"); + ammoExhausted = true; + break; // 跳出循环,不再发射任何射弹 + } + + Log.Message($"SectorSurveillance: Attempting to fire at {enemy.Label}, remaining shots: {remainingShots}, remaining projectiles: {remainingProjectiles}"); + if (LaunchProjectileAt(enemy)) + { + totalShotsFired++; + remainingShots--; + activeTargets[enemy] = remainingShots; + + // 新增:减少剩余射弹数量(如果不是无限) + if (remainingProjectiles > 0) + { + remainingProjectiles--; + Log.Message($"SectorSurveillance: Remaining projectiles: {remainingProjectiles}"); + + // 检查是否耗尽弹药 + if (remainingProjectiles == 0) + { + ammoExhausted = true; + Log.Message($"SectorSurveillance: AMMO EXHAUSTED - No more projectiles available"); + } + } + + int cooldownTicks = Mathf.RoundToInt(Props.shotInterval * 60f); + shotCooldowns[enemy] = cooldownTicks; + + Log.Message($"SectorSurveillance: Successfully fired at {enemy.Label}, {remainingShots} shots remaining, cooldown: {cooldownTicks} ticks"); + + if (remainingShots <= 0) + { + attackedPawns.Add(enemy); + completedTargets.Add(enemy); + Log.Message($"SectorSurveillance: Completed attack sequence on {enemy.Label}"); + } + } + else + { + Log.Error($"SectorSurveillance: Failed to fire projectile at {enemy.Label}"); + } + } + + // 清理已完成的目标 + foreach (Pawn enemy in completedTargets) + { + // 再次检查目标是否有效 + if (enemy != null) + { + activeTargets.Remove(enemy); + Log.Message($"SectorSurveillance: Removed {enemy.Label} from active targets"); + } + else + { + // 如果目标已不存在,直接从字典中移除对应的键 + activeTargets.Remove(enemy); + Log.Message($"SectorSurveillance: Removed null target from active targets"); + } + } + } + + private List GetEnemiesInSector() + { + List enemies = new List(); + Map map = parent.Map; + + if (map == null) + { + Log.Error("SectorSurveillance: Map is null!"); + return enemies; + } + + FlyOver flyOver = parent as FlyOver; + if (flyOver == null) + { + Log.Error("SectorSurveillance: Parent is not a FlyOver!"); + return enemies; + } + + Vector3 center = parent.DrawPos; + Vector3 flightDirection = flyOver.MovementDirection; + float range = Props.sectorRange; + float halfAngle = Props.sectorAngle * 0.5f; + + Log.Message($"SectorSurveillance: Checking sector - Center: {center}, Direction: {flightDirection}, Range: {range}, HalfAngle: {halfAngle}"); + + int totalEnemiesChecked = 0; + + // 关键修复:创建pawn列表的副本,避免在枚举时集合被修改 + List allPawns = new List(map.mapPawns.AllPawnsSpawned); + + foreach (Pawn pawn in allPawns) + { + totalEnemiesChecked++; + if (IsValidTarget(pawn)) + { + bool inSector = IsInSector(pawn.Position); + if (inSector) + { + enemies.Add(pawn); + Log.Message($"SectorSurveillance: Valid target found - {pawn.Label} at {pawn.Position}, in sector: {inSector}"); + } + } + } + + Log.Message($"SectorSurveillance: Checked {totalEnemiesChecked} pawns, found {enemies.Count} valid targets in sector"); + return enemies; + } + + private bool IsValidTarget(Pawn pawn) + { + if (pawn == null) + { + Log.Message("SectorSurveillance: IsValidTarget - pawn is null"); + return false; + } + + // 关键修复:检查pawn是否已被销毁或死亡 + if (pawn.Destroyed || pawn.Dead || !pawn.Spawned) + { + Log.Message($"SectorSurveillance: IsValidTarget - {pawn.Label} is destroyed/dead/unspawned"); + return false; + } + + if (pawn.Downed) + { + Log.Message($"SectorSurveillance: IsValidTarget - {pawn.Label} is downed"); + return false; + } + + Faction effectiveFaction = GetEffectiveFaction(); + if (effectiveFaction == null) + { + Log.Error($"SectorSurveillance: IsValidTarget - No effective faction found for {pawn.Label}"); + return false; + } + + bool hostile = pawn.HostileTo(effectiveFaction); + Log.Message($"SectorSurveillance: IsValidTarget - {pawn.Label} from {pawn.Faction?.Name ?? "NULL"} is hostile to {effectiveFaction.Name}: {hostile}"); + + return hostile; + } + + private bool IsInSector(IntVec3 targetPos) + { + FlyOver flyOver = parent as FlyOver; + if (flyOver == null) + { + Log.Error("SectorSurveillance: IsInSector - Parent is not a FlyOver!"); + return false; + } + + Vector3 flyOverPos = parent.DrawPos; + Vector3 targetVector = targetPos.ToVector3() - flyOverPos; + targetVector.y = 0; + + float distance = targetVector.magnitude; + if (distance > Props.sectorRange) + { + Log.Message($"SectorSurveillance: IsInSector - Target at {targetPos} is out of range: {distance:F1} > {Props.sectorRange}"); + return false; + } + + Vector3 flightDirection = flyOver.MovementDirection; + float angle = Vector3.Angle(flightDirection, targetVector); + + bool inAngle = angle <= Props.sectorAngle * 0.5f; + + Log.Message($"SectorSurveillance: IsInSector - Target at {targetPos}, distance: {distance:F1}, angle: {angle:F1}°, inAngle: {inAngle}"); + + return inAngle; + } + + private bool LaunchProjectileAt(Pawn target) + { + if (Props.projectileDef == null) + { + Log.Error("SectorSurveillance: No projectile defined for sector surveillance"); + return false; + } + + Log.Message($"SectorSurveillance: LaunchProjectileAt - Starting launch for target {target?.Label ?? "NULL"}"); + + try + { + Vector3 spawnPos = parent.DrawPos; + IntVec3 spawnCell = spawnPos.ToIntVec3(); + + Log.Message($"SectorSurveillance: Spawn position - World: {spawnPos}, Cell: {spawnCell}"); + + if (parent.Map == null) + { + Log.Error("SectorSurveillance: Map is null during projectile launch"); + return false; + } + + if (!spawnCell.InBounds(parent.Map)) + { + Log.Error($"SectorSurveillance: Spawn cell {spawnCell} is out of bounds"); + return false; + } + + Log.Message($"SectorSurveillance: Attempting to spawn projectile: {Props.projectileDef.defName}"); + Projectile projectile = (Projectile)GenSpawn.Spawn(Props.projectileDef, spawnCell, parent.Map); + + if (projectile != null) + { + Log.Message($"SectorSurveillance: Projectile spawned successfully: {projectile}"); + + Thing launcher = GetLauncher(); + Vector3 launchPos = parent.DrawPos; + + LocalTargetInfo targetInfo = new LocalTargetInfo(target); + + Log.Message($"SectorSurveillance: Launching projectile - Launcher: {launcher?.def?.defName ?? "NULL"}, LaunchPos: {launchPos}, Target: {targetInfo.Cell}"); + + projectile.Launch( + launcher, + launchPos, + targetInfo, + targetInfo, + ProjectileHitFlags.IntendedTarget, + false + ); + + Log.Message($"SectorSurveillance: Projectile launched successfully"); + return true; + } + else + { + Log.Error("SectorSurveillance: Failed to spawn projectile - GenSpawn.Spawn returned null"); + return false; + } + } + catch (System.Exception ex) + { + Log.Error($"SectorSurveillance: Exception launching projectile: {ex}"); + Log.Error($"SectorSurveillance: Stack trace: {ex.StackTrace}"); + return false; + } + } + + private Thing GetLauncher() + { + FlyOver flyOver = parent as FlyOver; + if (flyOver != null && flyOver.caster != null) + { + Log.Message($"SectorSurveillance: Using caster as launcher: {flyOver.caster.Label}"); + return flyOver.caster; + } + + Log.Message($"SectorSurveillance: Using parent as launcher: {parent.Label}"); + return parent; + } + + // 新增:获取剩余射弹数量的方法(用于UI显示等) + public int GetRemainingProjectiles() + { + return remainingProjectiles; + } + + // 新增:检查是否还有弹药 + public bool HasAmmo() + { + return !ammoExhausted; + } + + public override void PostExposeData() + { + base.PostExposeData(); + + Scribe_Collections.Look(ref attackedPawns, "attackedPawns", LookMode.Reference); + Scribe_Collections.Look(ref activeTargets, "activeTargets", LookMode.Reference, LookMode.Value); + Scribe_Collections.Look(ref shotCooldowns, "shotCooldowns", LookMode.Reference, LookMode.Value); + Scribe_Values.Look(ref lastCheckTick, "lastCheckTick", 0); + Scribe_Values.Look(ref totalFramesProcessed, "totalFramesProcessed", 0); + Scribe_Values.Look(ref totalTargetsFound, "totalTargetsFound", 0); + Scribe_Values.Look(ref totalShotsFired, "totalShotsFired", 0); + Scribe_References.Look(ref cachedFaction, "cachedFaction"); + Scribe_Values.Look(ref factionInitialized, "factionInitialized", false); + + // 新增:保存和加载射弹数量状态 + Scribe_Values.Look(ref remainingProjectiles, "remainingProjectiles", -1); + Scribe_Values.Look(ref ammoExhausted, "ammoExhausted", false); + } + + public override string CompInspectStringExtra() + { + string baseString = base.CompInspectStringExtra(); + string ammoString = ""; + + if (Props.maxProjectiles == -1) + { + ammoString = "Ammo: Unlimited"; + } + else + { + ammoString = $"Ammo: {remainingProjectiles}/{Props.maxProjectiles}"; + if (ammoExhausted) + { + ammoString += " (EXHAUSTED)"; + } + } + + if (!string.IsNullOrEmpty(baseString)) + { + return baseString + "\n" + ammoString; + } + return ammoString; + } + } + + public class CompProperties_SectorSurveillance : CompProperties + { + public ThingDef projectileDef; + public float sectorAngle = 90f; + public float sectorRange = 25f; + public int shotCount = 3; + public float shotInterval = 0.3f; + + // 新增:最大射弹数量限制 + public int maxProjectiles = -1; // -1 表示无限开火 + + public CompProperties_SectorSurveillance() + { + compClass = typeof(CompSectorSurveillance); + } + } +} diff --git a/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs b/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs index 959c559..099224e 100644 --- a/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs +++ b/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompAbilityEffect_SpawnFlyOver.cs @@ -73,6 +73,9 @@ namespace ArachnaeSwarm case FlyOverType.GroundStrafing: CreateGroundStrafingFlyOver(startPos, endPos); break; + case FlyOverType.SectorSurveillance: + CreateSectorSurveillanceFlyOver(startPos, endPos); + break; } // 显示效果消息 @@ -84,13 +87,12 @@ namespace ArachnaeSwarm } } - - // 新增:在目标选择时显示扫射范围预览 + // 新增:在目标选择时显示预览 public override void DrawEffectPreview(LocalTargetInfo target) { base.DrawEffectPreview(target); - if (Props.enableGroundStrafing && Props.showStrafePreview && parent.pawn != null && parent.pawn.Map != null) + if (parent.pawn != null && parent.pawn.Map != null) { // 计算飞行路径 IntVec3 startPos, endPos; @@ -104,12 +106,19 @@ namespace ArachnaeSwarm endPos = CalculateEndPosition(target, startPos); } - // 绘制扫射区域预览 - DrawStrafingAreaPreview(startPos, endPos); + // 根据不同类型显示不同的预览 + if (Props.enableGroundStrafing && Props.showStrafePreview) + { + DrawStrafingAreaPreview(startPos, endPos); + } + else if (Props.enableSectorSurveillance && Props.showSectorPreview) + { + DrawSectorAreaPreview(startPos, endPos); + } } } - // 新增:绘制扫射区域预览 + // 绘制地面扫射预览 private void DrawStrafingAreaPreview(IntVec3 startPos, IntVec3 endPos) { Map map = parent.pawn.Map; @@ -120,7 +129,8 @@ namespace ArachnaeSwarm { flightDirection = Vector3.forward; } - // 只计算扫射影响区域的单元格(不是整个飞行路径) + + // 只计算扫射影响区域的单元格 List strafeImpactCells = CalculateStrafingImpactCells(startPos, endPos, flightDirection); // 绘制扫射影响区域的预览单元格 @@ -128,94 +138,187 @@ namespace ArachnaeSwarm { if (cell.InBounds(map)) { - // 使用更明显的预览效果 GenDraw.DrawFieldEdges(new List { cell }, Props.strafePreviewColor, 0.5f); } } - // 绘制飞行路径线(只显示线条,不显示格子) + // 绘制飞行路径线 GenDraw.DrawLineBetween(startPos.ToVector3Shifted(), endPos.ToVector3Shifted(), SimpleColor.Red, 0.2f); // 绘制扫射范围边界 DrawStrafingBoundaries(startPos, endPos, flightDirection); } - // 新增:计算扫射影响区域的单元格(只计算扫射实际影响的区域,不是整个路径) + + // 计算扫射影响区域的单元格 private List CalculateStrafingImpactCells(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection) { List cells = new List(); Map map = parent.pawn.Map; + // 计算垂直于飞行方向的方向 Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized; + // 计算飞行路径的总长度 float totalPathLength = startPos.DistanceTo(endPos); + // 计算扫射区域的中心点(目标位置附近) Vector3 targetCenter = Vector3.Lerp(startPos.ToVector3(), endPos.ToVector3(), 0.5f); + // 计算扫射区域的起始和结束位置(基于扫射长度) float strafeHalfLength = Props.strafeLength * 0.5f; Vector3 strafeStart = targetCenter - flightDirection * strafeHalfLength; Vector3 strafeEnd = targetCenter + flightDirection * strafeHalfLength; - // 沿着扫射区域计算单元格(不是整个飞行路径) + + // 沿着扫射区域计算单元格 int steps = Mathf.CeilToInt(Props.strafeLength / 1f); 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((int)cellPos.x, (int)cellPos.y, (int)cellPos.z); - if (cell.InBounds(map)) + + if (cell.InBounds(map) && !cells.Contains(cell)) { - if (!cells.Contains(cell)) - { - cells.Add(cell); - } + cells.Add(cell); } } } - // 只输出最终结果 + Log.Message($"Strafing Area: Calculated {cells.Count} impact cells ({Props.strafeWidth * 2 + 1}x{Props.strafeLength})"); return cells; } - - // 新增:绘制扫射范围边界 + // 绘制扫射范围边界 private void DrawStrafingBoundaries(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection) { Map map = parent.pawn.Map; Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized; - // 计算飞行路径的总长度 - float totalPathLength = startPos.DistanceTo(endPos); - - // 计算扫射区域的中心点(目标位置附近) + + // 计算扫射区域的中心点 Vector3 targetCenter = Vector3.Lerp(startPos.ToVector3(), endPos.ToVector3(), 0.5f); - - // 计算扫射区域的起始和结束位置(基于扫射长度) + + // 计算扫射区域的起始和结束位置 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 来使用 ToVector3Shifted + + // 转换为 IntVec3 IntVec3 startLeftCell = new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z); IntVec3 startRightCell = new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z); IntVec3 endLeftCell = new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z); IntVec3 endRightCell = new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z); - // 使用带颜色的绘制方法 + + // 绘制边界线 GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Red, 0.2f); GenDraw.DrawLineBetween(startRightCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f); - - // 绘制起始和结束边界 GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), startRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f); GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f); } - // 新增:预处理扫射目标单元格 + // 新增:绘制扇形区域预览 - 使用strafeWidth来近似扇形扫过的区域宽度 + 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)) + { + GenDraw.DrawFieldEdges(new List { cell }, Props.sectorPreviewColor, 0.3f); + } + } + + // 绘制飞行路径线 + 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 = startPos.DistanceTo(endPos); + + // 沿着飞行路径计算预览单元格 + int steps = Mathf.CeilToInt(totalPathLength / 1f); + 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((int)cellPos.x, (int)cellPos.y, (int)cellPos.z); + + if (cell.InBounds(map) && !cells.Contains(cell)) + { + cells.Add(cell); + } + } + } + + 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 = new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z); + IntVec3 startRightCell = new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z); + IntVec3 endLeftCell = new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z); + IntVec3 endRightCell = new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z); + + // 绘制边界线 + GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f); + GenDraw.DrawLineBetween(startRightCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f); + GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), startRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f); + GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f); + } + + // 预处理扫射目标单元格 private List PreprocessStrafingTargets(List potentialTargets, float fireChance) { List confirmedTargets = new List(); @@ -227,11 +330,12 @@ namespace ArachnaeSwarm confirmedTargets.Add(cell); } } - // 只输出预处理结果 + Log.Message($"Strafing Preprocess: {confirmedTargets.Count}/{potentialTargets.Count} cells confirmed ({fireChance:P0} chance)"); return confirmedTargets; } - // 修改后的创建地面扫射飞越方法 + + // 创建地面扫射飞越 private void CreateGroundStrafingFlyOver(IntVec3 startPos, IntVec3 endPos) { ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase.GetNamedSilentFail("ARA_HiveCorvette"); @@ -240,6 +344,7 @@ namespace ArachnaeSwarm Log.Warning("No fly over def specified for ground strafing fly over"); return; } + FlyOver flyOver = FlyOver.MakeFlyOver( flyOverDef, startPos, @@ -249,9 +354,11 @@ namespace ArachnaeSwarm Props.altitude, casterPawn: parent.pawn ); + // 设置基本属性 flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact; flyOver.playFlyOverSound = Props.playFlyOverSound; + // 获取扫射组件并设置预处理后的目标单元格 CompGroundStrafing strafingComp = flyOver.GetComp(); if (strafingComp != null) @@ -259,6 +366,7 @@ namespace ArachnaeSwarm // 计算扫射区域的所有单元格 Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized; List potentialTargetCells = CalculateStrafingImpactCells(startPos, endPos, flightDirection); + if (potentialTargetCells.Count > 0) { // 预处理:根据概率筛选实际会被射击的单元格 @@ -266,6 +374,7 @@ namespace ArachnaeSwarm potentialTargetCells, Props.strafeFireChance ); + if (confirmedTargetCells.Count > 0) { strafingComp.SetConfirmedTargets(confirmedTargetCells); @@ -286,23 +395,37 @@ namespace ArachnaeSwarm } } - // 新增:获取扫射区域描述(用于技能提示) - public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + // 新增:创建扇形监视飞越 + private void CreateSectorSurveillanceFlyOver(IntVec3 startPos, IntVec3 endPos) { - if (Props.enableGroundStrafing) + ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase.GetNamedSilentFail("ARA_HiveCorvette"); + if (flyOverDef == null) { - string projectileInfo = Props.strafeProjectile != null ? - $"抛射体: {Props.strafeProjectile.label}" : - "抛射体: 无"; - - return $"扫射区域: {Props.strafeWidth * 2 + 1}x{Props.strafeLength} 单元格\n{projectileInfo}"; + Log.Warning("No fly over def specified for sector surveillance fly over"); + return; } - return base.ExtraLabelMouseAttachment(target); + + FlyOver flyOver = FlyOver.MakeFlyOver( + flyOverDef, + startPos, + endPos, + parent.pawn.Map, + Props.flightSpeed, + Props.altitude, + casterPawn: parent.pawn + ); + + // 设置基本属性 + flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact; + flyOver.playFlyOverSound = Props.playFlyOverSound; + + Log.Message($"SectorSurveillance FlyOver created: {flyOver} from {startPos} to {endPos}"); + + // 注意:扇形监视的具体参数(角度、射程、发射次数等)在FlyOver的CompProperties_SectorSurveillance中定义 + // 这里只负责创建FlyOver,不传递具体参数 } - - - // 原有的其他方法保持不变... + // 计算垂直线进场路径 private void CalculatePerpendicularPath(LocalTargetInfo target, out IntVec3 startPos, out IntVec3 endPos) { Map map = parent.pawn.Map; @@ -345,6 +468,7 @@ namespace ArachnaeSwarm Log.Message($"Perpendicular path: {startPos} -> {targetPos} -> {endPos}"); } + // 在指定方向上找到地图边缘 private IntVec3 FindMapEdgeInDirection(Map map, IntVec3 fromPos, Vector3 direction) { // 计算最大搜索距离(地图对角线的一半) @@ -372,6 +496,7 @@ namespace ArachnaeSwarm return GetRandomMapEdgePosition(map); } + // 原有的位置计算方法 private IntVec3 CalculateStartPosition(LocalTargetInfo target) { Map map = parent.pawn.Map; @@ -431,7 +556,7 @@ namespace ArachnaeSwarm return endPos; } - // 原有的辅助方法保持不变... + // 原有的辅助方法保持不变 private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos) { IntVec3 center = map.Center; @@ -626,12 +751,29 @@ namespace ArachnaeSwarm return "ReconnaissanceFlyOver".Translate(parent.pawn.LabelShort); case FlyOverType.GroundStrafing: return "GroundStrafingIncoming".Translate(parent.pawn.LabelShort); + case FlyOverType.SectorSurveillance: + return "SectorSurveillanceActive".Translate(parent.pawn.LabelShort); case FlyOverType.Standard: default: return "FlyOverInitiated".Translate(parent.pawn.LabelShort); } } + // 更新技能提示信息 + public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + { + if (Props.enableGroundStrafing) + { + return $"扫射区域: {Props.strafeWidth * 2 + 1}格宽度"; + } + else if (Props.enableSectorSurveillance) + { + return $"扇形监视: 约{Props.strafeWidth * 2 + 1}格宽度\n(具体参数在飞行物定义中)"; + } + + return base.ExtraLabelMouseAttachment(target); + } + public override bool Valid(LocalTargetInfo target, bool throwMessages = false) { return base.Valid(target, throwMessages) && diff --git a/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs b/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs index a87737a..b190c2c 100644 --- a/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs +++ b/Source/ArachnaeSwarm/Flyover/ARA_SpawnFlyOver/CompProperties_AbilitySpawnFlyOver.cs @@ -27,16 +27,23 @@ namespace ArachnaeSwarm public IntVec3 customEndOffset = IntVec3.Zero; public int flyOverDistance = 30; // 飞越距离(当终点为自定义时) - // 新增:简化的地面扫射配置 + // 地面扫射配置 public bool enableGroundStrafing = false; // 是否启用地面扫射 - public int strafeWidth = 3; // 扫射宽度(垂直于飞行方向的单元格数) - public int strafeLength = 15; // 扫射长度(沿着飞行方向的单元格数) - public float strafeFireChance = 0.7f; // 扫射发射概率(用于预处理) - public ThingDef strafeProjectile; // 抛射体定义(用于后续攻击) + public int strafeWidth = 3; // 扫射宽度(用于预览) + public int strafeLength = 15; // 扫射长度 + public float strafeFireChance = 0.7f; // 扫射发射概率 + public ThingDef strafeProjectile; // 抛射体定义 - // 新增:扫射可视化 + // 地面扫射可视化 public bool showStrafePreview = true; // 是否显示扫射预览 - public Color strafePreviewColor = new Color(1f, 0.3f, 0.3f, 0.3f); // 扫射预览颜色 + public Color strafePreviewColor = new Color(1f, 0.3f, 0.3f, 0.3f); + + // 扇形监视配置 - 只传递信号,不传递具体参数 + public bool enableSectorSurveillance = false; // 是否启用扇形区域监视 + + // 扇形监视可视化 - 使用strafeWidth来近似预览区域宽度 + public bool showSectorPreview = true; // 是否显示扇形预览 + public Color sectorPreviewColor = new Color(0.3f, 0.7f, 1f, 0.3f); public CompProperties_AbilitySpawnFlyOver() { @@ -52,7 +59,8 @@ namespace ArachnaeSwarm CargoDrop, // 货运飞越 BombingRun, // 轰炸飞越 Reconnaissance, // 侦察飞越 - GroundStrafing // 地面扫射 + GroundStrafing, // 地面扫射 + SectorSurveillance // 扇形区域监视 } // 进场类型枚举 diff --git a/Source/ArachnaeSwarm/Flyover/ThingclassFlyOver.cs b/Source/ArachnaeSwarm/Flyover/ThingclassFlyOver.cs index b29d2b6..3961b91 100644 --- a/Source/ArachnaeSwarm/Flyover/ThingclassFlyOver.cs +++ b/Source/ArachnaeSwarm/Flyover/ThingclassFlyOver.cs @@ -16,6 +16,7 @@ namespace ArachnaeSwarm public float flightSpeed = 1f; // 飞行速度 public float currentProgress = 0f; // 当前进度 (0-1) public float altitude = 10f; // 飞行高度 + public Faction faction; // 派系引用 // 淡入效果相关 public float fadeInDuration = 1.5f; // 淡入持续时间(秒) @@ -29,7 +30,7 @@ namespace ArachnaeSwarm public bool fadeOutCompleted = false; // 淡出是否完成 public float fadeOutStartProgress = 0.7f; // 开始淡出的进度阈值(0-1) public float defaultFadeOutDuration = 1.5f; // 默认淡出持续时间(仅用于销毁) - + // 伴飞相关 public float escortScale = 1f; // 伴飞缩放比例 public bool isEscort = false; // 是否是伴飞 @@ -50,7 +51,7 @@ namespace ArachnaeSwarm public bool spawnContentsOnImpact = false; // 是否在结束时生成内容物 public bool playFlyOverSound = true; // 是否播放飞越音效 public bool createShadow = true; // 是否创建阴影 - + public Pawn caster; // 施法者引用 // 属性 @@ -165,10 +166,10 @@ namespace ArachnaeSwarm // 计算剩余飞行时间 float remainingTime = RemainingFlightTime; - + // 使用剩余时间的一部分作为淡出持续时间 float dynamicDuration = remainingTime * fadeOutDistanceFactor; - + // 限制在最小和最大范围内 return Mathf.Clamp(dynamicDuration, minFadeOutDuration, maxFadeOutDuration); } @@ -193,7 +194,7 @@ namespace ArachnaeSwarm 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); @@ -203,6 +204,7 @@ namespace ArachnaeSwarm Scribe_Values.Look(ref defaultFadeOutDuration, "defaultFadeOutDuration", 1.5f); Scribe_References.Look(ref caster, "caster"); + Scribe_References.Look(ref faction, "faction"); } public override void SpawnSetup(Map map, bool respawningAfterLoad) @@ -213,15 +215,15 @@ namespace ArachnaeSwarm if (!respawningAfterLoad) { Log.Message($"FlyOver Direction - Vector: {MovementDirection}, Rotation: {ExactRotation.eulerAngles}"); - + // 设置初始位置 base.Position = startPosition; hasStarted = true; - + // 重置淡入状态 currentFadeInTime = 0f; fadeInCompleted = false; - + // 重置淡出状态 currentFadeOutTime = 0f; fadeOutStarted = false; @@ -297,10 +299,10 @@ namespace ArachnaeSwarm private void StartFadeOut() { fadeOutStarted = true; - + // 基于剩余距离动态计算淡出持续时间 fadeOutDuration = CalculateDynamicFadeOutDuration(); - + Log.Message($"FlyOver started fade out at progress {currentProgress:F2}, duration: {fadeOutDuration:F2}s, remaining time: {RemainingFlightTime:F2}s"); } @@ -362,7 +364,7 @@ namespace ArachnaeSwarm fadeOutDuration = defaultFadeOutDuration; Log.Message($"FlyOver emergency destroy with default fade out: {defaultFadeOutDuration}s"); } - + // 设置标记,下一帧会处理淡出 hasCompleted = true; } @@ -386,7 +388,7 @@ namespace ArachnaeSwarm { Vector3 effectPos = DrawPos; effectPos.y = AltitudeLayer.MoteOverhead.AltitudeFor(); - + // 淡出时减少粒子效果强度 float effectIntensity = fadeOutStarted ? FadeOutAlpha : 1f; FleckMaker.ThrowSmoke(effectPos, base.Map, 1f * effectIntensity); @@ -526,7 +528,7 @@ namespace ArachnaeSwarm // 工具方法:创建飞越物体 public static FlyOver MakeFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map, - float speed = 1f, float height = 10f, ThingOwner contents = null, + float speed = 1f, float height = 10f, ThingOwner contents = null, float fadeInDuration = 1.5f, float defaultFadeOutDuration = 1.5f, Pawn casterPawn = null) { FlyOver flyOver = (FlyOver)ThingMaker.MakeThing(flyOverDef); @@ -538,16 +540,28 @@ namespace ArachnaeSwarm flyOver.defaultFadeOutDuration = defaultFadeOutDuration; flyOver.caster = casterPawn; + // 简化派系设置 - 直接设置 faction 字段 + 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}"); + + Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height}, Faction: {flyOver.faction?.Name ?? "NULL"}"); return flyOver; } + } // ModExtension 配置