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 配置