This commit is contained in:
2025-10-30 11:43:20 +08:00
parent a3fb539bbe
commit f969798670
22 changed files with 1067 additions and 476 deletions

View File

@@ -3,56 +3,40 @@
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.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|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_aircrafthangar\\compaircrafthangar.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\compaircrafthangar.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_aircrafthangar\\compabilityeffect_aircraftstrike.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_aircrafthangar\\compabilityeffect_aircraftstrike.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\compabilityeffect_aircraftstrike.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\\building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_givehediffwithskillduration\\compabilityeffect_givehediffwithskillduration.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_givehediffwithskillduration\\compabilityeffect_givehediffwithskillduration.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|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_showtemperaturerange\\compabilityeffect_abilityshowtemperaturerange.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_showtemperaturerange\\compabilityeffect_abilityshowtemperaturerange.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|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\abilities\\ara_showspawnablepawnslist\\compabilityeffect_abilityshowspawnablepawns.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\ara_showspawnablepawnslist\\compabilityeffect_abilityshowspawnablepawns.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_aircrafthangar\\compaircrafthangar.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\compaircrafthangar.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|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_aircrafthangar\\worldcomponent_aircraftmanager.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|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|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}"
}
],
"DocumentGroupContainers": [
@@ -70,167 +54,112 @@
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CompAircraftHangar.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"ViewState": "AgIAAEoAAAAAAAAAAAAswFkAAAAdAAAAAAAAAA==",
"DocumentIndex": 2,
"Title": "CompAbilityEffect_GiveHediffWithSkillDuration.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
"RelativeToolTip": "Abilities\\ARA_GiveHediffWithSkillDuration\\CompAbilityEffect_GiveHediffWithSkillDuration.cs",
"ViewState": "AgIAAEsAAAAAAAAAAAAWwGAAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T06:31:52.619Z",
"EditorCaption": ""
"WhenOpened": "2025-10-29T14:40:47.422Z"
},
{
"$type": "Document",
"DocumentIndex": 3,
"Title": "CompRefuelableNutrition.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeDocumentMoniker": "Building_Comps\\CompRefuelableNutrition.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs",
"RelativeToolTip": "Building_Comps\\CompRefuelableNutrition.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAUAAAAXAAAAAAAAAA==",
"Title": "CompAbilityEffect_AbilityShowTemperatureRange.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
"RelativeToolTip": "Abilities\\ARA_ShowTemperatureRange\\CompAbilityEffect_AbilityShowTemperatureRange.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABcAAAArAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T06:31:46.148Z",
"EditorCaption": ""
"WhenOpened": "2025-10-29T14:40:43.525Z"
},
{
"$type": "Document",
"DocumentIndex": 2,
"DocumentIndex": 1,
"Title": "CompAbilityEffect_AircraftStrike.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\CompAbilityEffect_AircraftStrike.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAACMAAAAAAAAAAAAAAA==",
"ViewState": "AgIAAHYAAAAAAAAAAAAtwJcAAAArAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T06:30:49.523Z",
"EditorCaption": ""
"WhenOpened": "2025-10-29T11:22:34.783Z"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "WorldComponent_AircraftManager.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"ViewState": "AgIAAKsAAAAAAAAAAAAowBEAAAASAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T06:30:44.854Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 4,
"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": "AgIAAMYAAAAAAAAAAAAqwNUAAAARAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T02:30:42.063Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 8,
"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": 6,
"Title": "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": "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": 7,
"Title": "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": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs",
"RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompProperties_AbilitySpawnFlyOver.cs",
"ViewState": "AgIAABgAAAAAAAAAAAAswDQAAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-28T13:51:12.201Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "ThingclassFlyOver.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
"RelativeDocumentMoniker": "Flyover\\ThingclassFlyOver.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
"RelativeToolTip": "Flyover\\ThingclassFlyOver.cs",
"ViewState": "AgIAAAkCAAAAAAAAAAAqwCYCAAB/AAAAAAAAAA==",
"ViewState": "AgIAAC0CAAAAAAAAAAAawCUCAAANAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-28T09:09:22.03Z",
"WhenOpened": "2025-10-29T14:17:06.867Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 9,
"Title": "CompFlyOverEscort.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs",
"RelativeDocumentMoniker": "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==",
"DocumentIndex": 4,
"Title": "CompAbilityEffect_AbilityShowSpawnablePawns.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
"RelativeDocumentMoniker": "Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
"RelativeToolTip": "Abilities\\ARA_ShowSpawnablePawnsList\\CompAbilityEffect_AbilityShowSpawnablePawns.cs",
"ViewState": "AgIAABYAAAAAAAAAAAAuwBYAAAArAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-28T07:30:55.268Z"
"WhenOpened": "2025-10-29T14:40:40.237Z"
},
{
"$type": "Document",
"DocumentIndex": 10,
"DocumentIndex": 6,
"Title": "CompAircraftHangar.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\CompAircraftHangar.cs",
"ViewState": "AgIAABcAAAAAAAAAAAAQwCQAAAAnAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T11:39:22.563Z"
},
{
"$type": "Document",
"DocumentIndex": 5,
"Title": "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": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
"RelativeToolTip": "Flyover\\ARA_SpawnFlyOver\\CompAbilityEffect_SpawnFlyOver.cs",
"ViewState": "AgIAAFMDAAAAAAAAAAAawG8DAAAAAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T13:37:35.758Z"
},
{
"$type": "Document",
"DocumentIndex": 7,
"Title": "WorldComponent_AircraftManager.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"RelativeDocumentMoniker": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"RelativeToolTip": "Flyover\\ARA_AircraftHangar\\WorldComponent_AircraftManager.cs",
"ViewState": "AgIAAJUAAAAAAAAAAAAowK4AAAAUAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-29T14:05:39.817Z"
},
{
"$type": "Document",
"DocumentIndex": 8,
"Title": "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": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
"RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABgAAAAPAAAAAAAAAA==",
"ViewState": "AgIAAAAAAAAAAAAAAAAAABAAAAAvAAAAAAAAAA==",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
"WhenOpened": "2025-10-28T07:30:47.27Z"
},
{
"$type": "Document",
"DocumentIndex": 12,
"Title": "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": "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|",
"WhenOpened": "2025-10-28T06:21:06.271Z"
},
{
"$type": "Document",
"DocumentIndex": 11,
"Title": "CompShipArtillery.cs",
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs",
"RelativeDocumentMoniker": "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|",
"WhenOpened": "2025-10-28T06:21:04.222Z"
"WhenOpened": "2025-10-29T12:59:07.753Z"
}
]
}

View File

@@ -2,6 +2,7 @@ using RimWorld;
using Verse;
using RimWorld.Planet;
using System.Collections.Generic;
using System.Text;
namespace ArachnaeSwarm
{
@@ -30,40 +31,24 @@ namespace ArachnaeSwarm
if (aircraftManager == null)
{
Log.Error("Aircraft manager not found!");
Log.Error("AircraftManagerNotFound".Translate());
return;
}
// 检查并消耗战机
if (aircraftManager.TryUseAircraft(Props.requiredAircraftType, Props.aircraftsPerUse, parent.pawn.Faction, Props.aircraftCooldownTicks))
{
// 执行打击效果
ExecuteStrikeEffect(target);
Messages.Message($"Aircraft strike initiated: {Props.requiredAircraftType.LabelCap}", MessageTypeDefOf.PositiveEvent);
// 成功消耗战机,发送消息
Messages.Message("AircraftStrikeInitiated".Translate(Props.requiredAircraftType.LabelCap), MessageTypeDefOf.PositiveEvent);
Log.Message("AircraftStrikeSuccess".Translate(Props.aircraftsPerUse, Props.requiredAircraftType.LabelCap));
}
else
{
Messages.Message($"No available aircraft: {Props.requiredAircraftType.LabelCap}", MessageTypeDefOf.NegativeEvent);
Messages.Message("NoAvailableAircraft".Translate(Props.requiredAircraftType.LabelCap), MessageTypeDefOf.NegativeEvent);
Log.Warning("AircraftStrikeFailed".Translate(Props.requiredAircraftType.LabelCap, parent.pawn.Faction?.Name ?? "UnknownFaction".Translate()));
}
}
private void ExecuteStrikeEffect(LocalTargetInfo target)
{
// 这里实现具体的打击效果
// 例如:轰炸、空投、侦察等
// 示例:在目标位置创建爆炸效果
GenExplosion.DoExplosion(
target.Cell,
parent.pawn.Map,
radius: 3.5f,
DamageDefOf.Bomb,
instigator: parent.pawn,
damAmount: 50
);
}
public override bool CanApplyOn(LocalTargetInfo target, LocalTargetInfo dest)
{
// 检查是否有可用的战机
@@ -81,10 +66,97 @@ namespace ArachnaeSwarm
if (aircraftManager != null)
{
int available = aircraftManager.GetAvailableAircraftCount(Props.requiredAircraftType, parent.pawn.Faction);
return $"Available {Props.requiredAircraftType.LabelCap}: {available}";
int onCooldown = aircraftManager.GetCooldownAircraftCount(Props.requiredAircraftType, parent.pawn.Faction);
// 使用符号显示飞机状态
string availableSymbols = GetAircraftSymbols(available, "◆");
string cooldownSymbols = GetAircraftSymbols(onCooldown, "◇");
StringBuilder sb = new StringBuilder();
sb.AppendLine("AvailableAircraft".Translate(Props.requiredAircraftType.LabelCap, availableSymbols));
sb.AppendLine("CooldownAircraft".Translate(cooldownSymbols));
sb.Append("CostPerUse".Translate(Props.aircraftsPerUse));
return sb.ToString();
}
return base.ExtraLabelMouseAttachment(target);
}
// 生成飞机符号表示
private string GetAircraftSymbols(int count, string symbol)
{
if (count <= 0) return "—"; // 无飞机时显示破折号
StringBuilder sb = new StringBuilder();
int displayCount = count;
// 如果数量过多,用数字+符号表示
if (count > 10)
{
return $"{count}{symbol}";
}
// 直接显示符号
for (int i = 0; i < displayCount; i++)
{
sb.Append(symbol);
}
return sb.ToString();
}
public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
{
if (!base.Valid(target, throwMessages))
return false;
// 检查战机可用性
WorldComponent_AircraftManager aircraftManager = Find.World.GetComponent<WorldComponent_AircraftManager>();
if (aircraftManager == null || !aircraftManager.HasAvailableAircraft(Props.requiredAircraftType, Props.aircraftsPerUse, parent.pawn.Faction))
{
if (throwMessages)
{
Messages.Message("NoAircraftForStrike".Translate(Props.requiredAircraftType.LabelCap), MessageTypeDefOf.RejectInput);
}
return false;
}
return true;
}
// 鼠标悬停时的工具提示
public override string ExtraTooltipPart()
{
WorldComponent_AircraftManager aircraftManager = Find.World.GetComponent<WorldComponent_AircraftManager>();
if (aircraftManager != null)
{
int available = aircraftManager.GetAvailableAircraftCount(Props.requiredAircraftType, parent.pawn.Faction);
int onCooldown = aircraftManager.GetCooldownAircraftCount(Props.requiredAircraftType, parent.pawn.Faction);
int total = available + onCooldown;
// 将冷却时间从 tick 转换为小时
float cooldownHours = TicksToHours(Props.aircraftCooldownTicks);
StringBuilder sb = new StringBuilder();
sb.AppendLine("AircraftStatusTooltip".Translate());
sb.AppendLine("• " + "TotalAircraft".Translate(total));
sb.AppendLine("• " + "ReadyAircraft".Translate(available));
sb.AppendLine("• " + "CooldownAircraft".Translate(onCooldown));
sb.AppendLine("AircraftAbilityDescription".Translate(Props.requiredAircraftType.LabelCap, Props.aircraftsPerUse, cooldownHours.ToString("F1")));
return sb.ToString();
}
return base.ExtraTooltipPart();
}
// 将 tick 转换为小时
private float TicksToHours(int ticks)
{
// RimWorld 中 1 小时 = 2500 tick
return ticks / 2500f;
}
}
}

View File

@@ -31,8 +31,8 @@ namespace ArachnaeSwarm
// 起飞命令
Command_Action launchCommand = new Command_Action
{
defaultLabel = "Launch Aircraft",
defaultDesc = "Launch aircraft for orbital support",
defaultLabel = "LaunchAircraft".Translate(),
defaultDesc = "LaunchAircraftDesc".Translate(),
icon = TexCommand.Attack,
action = LaunchAircraft
};
@@ -40,7 +40,7 @@ namespace ArachnaeSwarm
// 检查条件:建筑完好
if (parent.HitPoints <= 0)
{
launchCommand.Disable("Hangar damaged");
launchCommand.Disable("HangarDamaged".Translate());
}
yield return launchCommand;
@@ -53,15 +53,15 @@ namespace ArachnaeSwarm
if (aircraftManager == null)
{
Log.Error("Aircraft manager not found!");
Log.Error("AircraftManagerNotFound".Translate());
return;
}
// 立即向全局管理器注册战机(在创建 Skyfaller 之前)
// 立即向全局管理器注册战机
aircraftManager.AddAircraft(Props.aircraftDef, Props.aircraftCount, parent.Faction);
// 显示消息
Messages.Message($"Aircraft launched: {Props.aircraftCount}x {Props.aircraftDef.LabelCap}", MessageTypeDefOf.PositiveEvent);
Messages.Message("AircraftLaunched".Translate(Props.aircraftCount, Props.aircraftDef.LabelCap), MessageTypeDefOf.PositiveEvent);
// 创建起飞效果(仅视觉效果)
if (Props.skyfallerLeaving != null)
@@ -77,17 +77,39 @@ namespace ArachnaeSwarm
private void CreateTakeoffEffect()
{
// 创建起飞天空坠落者
Skyfaller skyfaller = SkyfallerMaker.MakeSkyfaller(Props.skyfallerLeaving, parent);
// 设置起飞位置(建筑当前位置)
IntVec3 takeoffPos = parent.Position;
// 生成 Skyfaller
GenSpawn.Spawn(skyfaller, takeoffPos, parent.Map);
// 立即销毁原建筑Skyfaller 只是视觉效果
parent.Destroy();
try
{
// 创建 1 单位 Chemfuel 作为 Skyfaller 的内容物
Thing chemfuel = ThingMaker.MakeThing(ThingDefOf.Chemfuel);
chemfuel.stackCount = 1;
// 创建包含 Chemfuel 的 Skyfaller
Skyfaller skyfaller = SkyfallerMaker.MakeSkyfaller(Props.skyfallerLeaving, chemfuel);
// 设置起飞位置(建筑当前位置
IntVec3 takeoffPos = parent.Position;
// 检查地图是否有效
if (parent.Map == null)
{
Log.Error("TakeoffEffectMapNull".Translate());
return;
}
// 生成 Skyfaller
GenSpawn.Spawn(skyfaller, takeoffPos, parent.Map);
Log.Message("TakeoffSkyfallerCreated".Translate(takeoffPos));
// 销毁原建筑
parent.Destroy(DestroyMode.Vanish);
}
catch (System.Exception ex)
{
Log.Error("TakeoffEffectError".Translate(ex.Message));
// 如果Skyfaller创建失败直接销毁建筑
parent.Destroy(DestroyMode.Vanish);
}
}
public override void PostExposeData()

View File

@@ -8,55 +8,43 @@ namespace ArachnaeSwarm
{
public class WorldComponent_AircraftManager : WorldComponent
{
private Dictionary<Faction, Dictionary<ThingDef, AircraftFactionData>> factionAircraftData =
new Dictionary<Faction, Dictionary<ThingDef, AircraftFactionData>>();
// 使用列表而不是嵌套字典,更容易序列化
private List<FactionAircraftData> allFactionAircraftData = new List<FactionAircraftData>();
private List<AircraftCooldownEvent> cooldownEvents = new List<AircraftCooldownEvent>();
public WorldComponent_AircraftManager(World world) : base(world) { }
// 战机派系数据
private class AircraftFactionData : IExposable
// 派系战机数据
private class FactionAircraftData : IExposable
{
public int totalCount; // 总战机数量
public int availableCount; // 可用战机数量
public Faction faction;
public ThingDef aircraftDef;
public int totalCount;
public int availableCount;
public void ExposeData()
{
Scribe_Values.Look(ref totalCount, "totalCount");
Scribe_Values.Look(ref availableCount, "availableCount");
Scribe_References.Look(ref faction, "faction");
Scribe_Defs.Look(ref aircraftDef, "aircraftDef");
Scribe_Values.Look(ref totalCount, "totalCount", 0);
Scribe_Values.Look(ref availableCount, "availableCount", 0);
}
}
// 冷却事件
// 冷却事件
private class AircraftCooldownEvent : IExposable
{
public Faction faction;
public ThingDef aircraftDef;
public int endTick;
public int aircraftCount; // 冷却中的战机数量
public int aircraftCount;
public void ExposeData()
{
Scribe_References.Look(ref faction, "faction");
Scribe_Defs.Look(ref aircraftDef, "aircraftDef");
Scribe_Values.Look(ref endTick, "endTick");
Scribe_Values.Look(ref aircraftCount, "aircraftCount");
}
}
// 用于序列化的包装类
private class SerializableFactionAircraftData : IExposable
{
public Faction faction;
public ThingDef aircraftDef;
public AircraftFactionData data;
public void ExposeData()
{
Scribe_References.Look(ref faction, "faction");
Scribe_Defs.Look(ref aircraftDef, "aircraftDef");
Scribe_Deep.Look(ref data, "data");
Scribe_Values.Look(ref endTick, "endTick", 0);
Scribe_Values.Look(ref aircraftCount, "aircraftCount", 0);
}
}
@@ -64,50 +52,25 @@ namespace ArachnaeSwarm
{
base.ExposeData();
// 保存派系战机数据
List<SerializableFactionAircraftData> serializableData = new List<SerializableFactionAircraftData>();
// 使用简单的列表序列化
Scribe_Collections.Look(ref allFactionAircraftData, "allFactionAircraftData", LookMode.Deep);
Scribe_Collections.Look(ref cooldownEvents, "cooldownEvents", LookMode.Deep);
// 确保列表不为null
if (allFactionAircraftData == null)
allFactionAircraftData = new List<FactionAircraftData>();
if (cooldownEvents == null)
cooldownEvents = new List<AircraftCooldownEvent>();
// 调试日志
if (Scribe.mode == LoadSaveMode.Saving)
{
// 将字典数据转换为可序列化的列表
foreach (var factionPair in factionAircraftData)
{
foreach (var aircraftPair in factionPair.Value)
{
serializableData.Add(new SerializableFactionAircraftData
{
faction = factionPair.Key,
aircraftDef = aircraftPair.Key,
data = aircraftPair.Value
});
}
}
Log.Message($"Saving aircraft data: {allFactionAircraftData.Count} faction entries, {cooldownEvents.Count} cooldown events");
}
Scribe_Collections.Look(ref serializableData, "factionAircraftData", LookMode.Deep);
if (Scribe.mode == LoadSaveMode.LoadingVars)
else if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
// 从序列化数据重建字典
factionAircraftData.Clear();
if (serializableData != null)
{
foreach (var item in serializableData)
{
if (item.faction != null && item.aircraftDef != null && item.data != null)
{
if (!factionAircraftData.ContainsKey(item.faction))
{
factionAircraftData[item.faction] = new Dictionary<ThingDef, AircraftFactionData>();
}
factionAircraftData[item.faction][item.aircraftDef] = item.data;
}
}
}
Log.Message($"Loaded aircraft data: {allFactionAircraftData.Count} faction entries, {cooldownEvents.Count} cooldown events");
}
// 保存冷却事件 - 显式指定泛型类型
Scribe_Collections.Look(ref cooldownEvents, "cooldownEvents", LookMode.Deep);
}
public override void WorldComponentTick()
@@ -122,35 +85,50 @@ namespace ArachnaeSwarm
if (currentTick >= cooldownEvent.endTick)
{
// 冷却结束,恢复战机可用性
RestoreAircraftAfterCooldown(cooldownEvent);
cooldownEvents.RemoveAt(i);
}
}
}
// 获取或创建派系战机数据
private FactionAircraftData GetOrCreateFactionAircraftData(Faction faction, ThingDef aircraftDef)
{
var data = allFactionAircraftData.FirstOrDefault(x => x.faction == faction && x.aircraftDef == aircraftDef);
if (data == null)
{
data = new FactionAircraftData
{
faction = faction,
aircraftDef = aircraftDef,
totalCount = 0,
availableCount = 0
};
allFactionAircraftData.Add(data);
}
return data;
}
// 获取派系战机数据可能为null
private FactionAircraftData GetFactionAircraftData(Faction faction, ThingDef aircraftDef)
{
return allFactionAircraftData.FirstOrDefault(x => x.faction == faction && x.aircraftDef == aircraftDef);
}
// 添加战机到派系
public void AddAircraft(ThingDef aircraftDef, int count, Faction faction)
{
if (faction == null)
{
Log.Error("Attempted to add aircraft to null faction");
Log.Error("AddAircraftNullFaction".Translate());
return;
}
if (!factionAircraftData.ContainsKey(faction))
{
factionAircraftData[faction] = new Dictionary<ThingDef, AircraftFactionData>();
}
if (!factionAircraftData[faction].ContainsKey(aircraftDef))
{
factionAircraftData[faction][aircraftDef] = new AircraftFactionData();
}
var data = factionAircraftData[faction][aircraftDef];
var data = GetOrCreateFactionAircraftData(faction, aircraftDef);
data.totalCount += count;
data.availableCount += count;
Log.Message($"Added {count} {aircraftDef.LabelCap} to {faction.Name}. Total: {data.totalCount}, Available: {data.availableCount}");
}
// 尝试使用战机
@@ -159,10 +137,9 @@ namespace ArachnaeSwarm
if (!HasAvailableAircraft(aircraftDef, count, faction))
return false;
var data = factionAircraftData[faction][aircraftDef];
var data = GetFactionAircraftData(faction, aircraftDef);
data.availableCount -= count;
// 创建冷却事件
AircraftCooldownEvent cooldownEvent = new AircraftCooldownEvent
{
faction = faction,
@@ -173,86 +150,75 @@ namespace ArachnaeSwarm
cooldownEvents.Add(cooldownEvent);
Log.Message($"Used {count} {aircraftDef.LabelCap} from {faction.Name}. Available now: {data.availableCount}, Cooldown until: {cooldownEvent.endTick}");
return true;
}
// 检查是否有可用战机
public bool HasAvailableAircraft(ThingDef aircraftDef, int count, Faction faction)
{
return factionAircraftData.ContainsKey(faction) &&
factionAircraftData[faction].ContainsKey(aircraftDef) &&
factionAircraftData[faction][aircraftDef].availableCount >= count;
var data = GetFactionAircraftData(faction, aircraftDef);
return data != null && data.availableCount >= count;
}
// 获取可用战机数量
public int GetAvailableAircraftCount(ThingDef aircraftDef, Faction faction)
{
if (factionAircraftData.ContainsKey(faction) &&
factionAircraftData[faction].ContainsKey(aircraftDef))
{
return factionAircraftData[faction][aircraftDef].availableCount;
}
return 0;
var data = GetFactionAircraftData(faction, aircraftDef);
return data?.availableCount ?? 0;
}
// 获取总战机数量
public int GetTotalAircraftCount(ThingDef aircraftDef, Faction faction)
{
if (factionAircraftData.ContainsKey(faction) &&
factionAircraftData[faction].ContainsKey(aircraftDef))
{
return factionAircraftData[faction][aircraftDef].totalCount;
}
return 0;
var data = GetFactionAircraftData(faction, aircraftDef);
return data?.totalCount ?? 0;
}
// 冷却结束后恢复战机
private void RestoreAircraftAfterCooldown(AircraftCooldownEvent cooldownEvent)
{
if (cooldownEvent.faction != null &&
factionAircraftData.ContainsKey(cooldownEvent.faction) &&
factionAircraftData[cooldownEvent.faction].ContainsKey(cooldownEvent.aircraftDef))
var data = GetFactionAircraftData(cooldownEvent.faction, cooldownEvent.aircraftDef);
if (data != null)
{
var data = factionAircraftData[cooldownEvent.faction][cooldownEvent.aircraftDef];
data.availableCount += cooldownEvent.aircraftCount;
// 可选:显示冷却结束消息
if (cooldownEvent.aircraftDef != null)
{
Messages.Message($"{cooldownEvent.aircraftDef.LabelCap} cooldown ended", MessageTypeDefOf.PositiveEvent);
Messages.Message("AircraftCooldownEnded".Translate(cooldownEvent.aircraftDef.LabelCap), MessageTypeDefOf.PositiveEvent);
Log.Message($"Cooldown ended for {cooldownEvent.aircraftCount} {cooldownEvent.aircraftDef.LabelCap}. Available now: {data.availableCount}");
}
}
}
// 获取战机状态信息用于调试或UI显示
public string GetAircraftStatus(Faction faction)
{
if (!factionAircraftData.ContainsKey(faction))
return "No aircraft";
var status = new List<string>();
foreach (var kvp in factionAircraftData[faction])
{
var data = kvp.Value;
int inCooldown = data.totalCount - data.availableCount;
status.Add($"{kvp.Key.LabelCap}: {data.availableCount}/{data.totalCount} (In cooldown: {inCooldown})");
}
return string.Join("\n", status);
}
// 获取冷却中的战机数量
public int GetCooldownAircraftCount(ThingDef aircraftDef, Faction faction)
{
int totalCooldown = 0;
foreach (var cooldownEvent in cooldownEvents)
return cooldownEvents
.Where(e => e.faction == faction && e.aircraftDef == aircraftDef)
.Sum(e => e.aircraftCount);
}
// 调试方法:显示当前状态
public void DebugLogStatus()
{
Log.Message("=== Aircraft Manager Status ===");
Log.Message($"Total faction entries: {allFactionAircraftData.Count}");
var factions = allFactionAircraftData.Select(x => x.faction).Distinct();
foreach (var faction in factions)
{
if (cooldownEvent.faction == faction && cooldownEvent.aircraftDef == aircraftDef)
Log.Message($"Faction: {faction?.Name ?? "Unknown"}");
var factionData = allFactionAircraftData.Where(x => x.faction == faction);
foreach (var data in factionData)
{
totalCooldown += cooldownEvent.aircraftCount;
Log.Message($" {data.aircraftDef.LabelCap}: {data.availableCount}/{data.totalCount} available");
}
}
return totalCooldown;
Log.Message($"Active cooldown events: {cooldownEvents.Count}");
Log.Message("===============================");
}
}
}

View File

@@ -31,6 +31,7 @@ namespace ArachnaeSwarm
}
Log.Message($"FlyOver Escort initialized: {Props.spawnIntervalTicks} ticks interval, max {Props.maxEscorts} escorts");
Log.Message($"Safe distances - From Main: {Props.minSafeDistanceFromMain}, Between Escorts: {Props.minSafeDistanceBetweenEscorts}");
}
public override void CompTick()
@@ -97,8 +98,10 @@ namespace ArachnaeSwarm
private void SpawnEscorts(FlyOver mainFlyOver)
{
int escortsToSpawn = Mathf.Min(Props.spawnCount, Props.maxEscorts - activeEscorts.Count);
int successfulSpawns = 0;
int maxAttempts = escortsToSpawn * 5; // 最多尝试5倍的数量
for (int i = 0; i < escortsToSpawn; i++)
for (int attempt = 0; attempt < maxAttempts && successfulSpawns < escortsToSpawn; attempt++)
{
// 先生成视觉数据
EscortVisualData visualData = GenerateEscortVisualData();
@@ -106,12 +109,68 @@ namespace ArachnaeSwarm
FlyOver escort = CreateEscort(mainFlyOver, visualData);
if (escort != null)
{
activeEscorts.Add(escort);
escortVisualData[escort] = visualData;
Log.Message($"Spawned escort #{i+1} for FlyOver at {mainFlyOver.DrawPos}, scale: {visualData.scale:F2}, maskAlpha: {visualData.heightMaskAlpha:F2}");
// 检查安全距离
if (IsSafeDistance(escort, mainFlyOver))
{
activeEscorts.Add(escort);
escortVisualData[escort] = visualData;
successfulSpawns++;
Log.Message($"Spawned escort #{successfulSpawns} for FlyOver at {mainFlyOver.DrawPos}, scale: {visualData.scale:F2}, maskAlpha: {visualData.heightMaskAlpha:F2}");
}
else
{
// 不安全,销毁这个伴飞
escort.Destroy();
Log.Message($"Escort spawn attempt {attempt + 1}: Position too close to existing escort, trying again");
}
}
// 如果已经生成足够数量,提前退出
if (successfulSpawns >= escortsToSpawn)
break;
}
if (successfulSpawns < escortsToSpawn)
{
Log.Message($"Spawned {successfulSpawns}/{escortsToSpawn} escorts (some positions were too close to existing escorts)");
}
}
// 修改:分别检查与主飞行物和伴飞物的安全距离
private bool IsSafeDistance(FlyOver newEscort, FlyOver mainFlyOver)
{
Vector3 newPos = newEscort.DrawPos;
// 检查与主FlyOver的距离
if (Props.minSafeDistanceFromMain > 0)
{
float distToMain = Vector3.Distance(newPos, mainFlyOver.DrawPos);
if (distToMain < Props.minSafeDistanceFromMain)
{
Log.Message($"Escort too close to main FlyOver: {distToMain:F1} < {Props.minSafeDistanceFromMain}");
return false;
}
}
// 检查与其他伴飞的距离
if (Props.minSafeDistanceBetweenEscorts > 0)
{
foreach (FlyOver existingEscort in activeEscorts)
{
if (existingEscort == null || existingEscort.Destroyed)
continue;
float distToEscort = Vector3.Distance(newPos, existingEscort.DrawPos);
if (distToEscort < Props.minSafeDistanceBetweenEscorts)
{
Log.Message($"Escort too close to existing escort: {distToEscort:F1} < {Props.minSafeDistanceBetweenEscorts}");
return false;
}
}
}
return true;
}
private EscortVisualData GenerateEscortVisualData()
@@ -131,7 +190,6 @@ namespace ArachnaeSwarm
return data;
}
// 修改:添加 visualData 参数
private FlyOver CreateEscort(FlyOver mainFlyOver, EscortVisualData visualData)
{
try
@@ -275,7 +333,6 @@ namespace ArachnaeSwarm
);
}
// 修改:添加 visualData 参数
private void SetupEscortProperties(FlyOver escort, FlyOver mainFlyOver, EscortVisualData visualData)
{
// 设置伴飞缩放 - 现在直接从参数获取

View File

@@ -22,6 +22,10 @@ namespace ArachnaeSwarm
public float verticalOffset = 2f; // 垂直偏移量(高度差)
public bool useRandomOffset = true; // 是否使用随机偏移
// 修改:独立的安全距离配置
public float minSafeDistanceFromMain = 8f; // 与主飞行物的最小安全距离(单元格)
public float minSafeDistanceBetweenEscorts = 3f; // 伴飞物之间的最小安全距离(单元格)
// 飞行配置
public float escortSpeedMultiplier = 1f; // 速度乘数相对于主FlyOver
public float escortAltitudeOffset = 0f; // 高度偏移

View File

@@ -36,6 +36,10 @@ namespace ArachnaeSwarm
endPos = CalculateEndPosition(target, startPos);
}
// 确保位置安全
startPos = GetSafeMapPosition(startPos, parent.pawn.Map);
endPos = GetSafeMapPosition(endPos, parent.pawn.Map);
Log.Message($"Final positions - Start: {startPos}, End: {endPos}");
// 验证位置是否有效
@@ -57,10 +61,7 @@ namespace ArachnaeSwarm
Log.Warning($"FlyOver start and end positions are the same: {startPos}. Adjusting end position.");
IntVec3 randomOffset = new IntVec3(Rand.Range(-10, 11), 0, Rand.Range(-10, 11));
endPos += randomOffset;
if (!endPos.InBounds(parent.pawn.Map))
{
endPos = parent.pawn.Map.Center;
}
endPos = GetSafeMapPosition(endPos, parent.pawn.Map);
}
// 根据类型创建不同的飞越物体
@@ -71,15 +72,12 @@ namespace ArachnaeSwarm
CreateStandardFlyOver(startPos, endPos);
break;
case FlyOverType.GroundStrafing:
CreateGroundStrafingFlyOver(startPos, endPos);
CreateGroundStrafingFlyOver(startPos, endPos, target.Cell);
break;
case FlyOverType.SectorSurveillance:
CreateSectorSurveillanceFlyOver(startPos, endPos);
break;
}
// 显示效果消息
ShowEffectMessage();
}
catch (System.Exception ex)
{
@@ -87,39 +85,88 @@ namespace ArachnaeSwarm
}
}
// 新增:在目标选择时显示预览
// 修复的预览绘制方法
public override void DrawEffectPreview(LocalTargetInfo target)
{
base.DrawEffectPreview(target);
if (parent.pawn != null && parent.pawn.Map != null)
{
// 计算飞行路径
IntVec3 startPos, endPos;
if (Props.approachType == ApproachType.Perpendicular)
Map map = parent.pawn.Map;
try
{
CalculatePerpendicularPath(target, out startPos, out endPos);
}
else
{
startPos = CalculateStartPosition(target);
endPos = CalculateEndPosition(target, startPos);
}
// 计算飞行路径
IntVec3 startPos, endPos;
if (Props.approachType == ApproachType.Perpendicular)
{
CalculatePerpendicularPath(target, out startPos, out endPos);
}
else
{
startPos = CalculateStartPosition(target);
endPos = CalculateEndPosition(target, startPos);
}
// 根据不同类型显示不同的预览
if (Props.enableGroundStrafing && Props.showStrafePreview)
{
DrawStrafingAreaPreview(startPos, endPos);
// 确保位置在地图范围内
startPos = GetSafeMapPosition(startPos, map);
endPos = GetSafeMapPosition(endPos, map);
// 检查预览稳定性
if (!IsPreviewStable(startPos, endPos, map))
{
return;
}
// 根据不同类型显示不同的预览
if (Props.enableGroundStrafing && Props.showStrafePreview)
{
DrawStrafingAreaPreview(startPos, endPos, target.Cell);
}
else if (Props.enableSectorSurveillance && Props.showSectorPreview)
{
DrawSectorAreaPreview(startPos, endPos);
}
}
else if (Props.enableSectorSurveillance && Props.showSectorPreview)
catch (System.Exception)
{
DrawSectorAreaPreview(startPos, endPos);
// 忽略预览绘制中的错误,避免影响游戏体验
}
}
}
// 绘制地面扫射预览
private void DrawStrafingAreaPreview(IntVec3 startPos, IntVec3 endPos)
// 安全的位置计算方法
private IntVec3 GetSafeMapPosition(IntVec3 pos, Map map)
{
if (map == null) return pos;
// 确保位置在地图范围内
pos.x = Mathf.Clamp(pos.x, 0, map.Size.x - 1);
pos.z = Mathf.Clamp(pos.z, 0, map.Size.z - 1);
return pos;
}
// 预览绘制稳定性检查
private bool IsPreviewStable(IntVec3 startPos, IntVec3 endPos, Map map)
{
if (map == null) return false;
// 检查位置是否有效
if (!startPos.IsValid || !endPos.IsValid) return false;
// 检查位置是否在地图范围内
if (!startPos.InBounds(map) || !endPos.InBounds(map)) return false;
// 检查距离是否合理(避免过短的路径)
float distance = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
if (distance < 5f) return false;
return true;
}
// 修复:绘制地面扫射预览,现在接受目标单元格参数
private void DrawStrafingAreaPreview(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
{
Map map = parent.pawn.Map;
@@ -131,7 +178,7 @@ namespace ArachnaeSwarm
}
// 只计算扫射影响区域的单元格
List<IntVec3> strafeImpactCells = CalculateStrafingImpactCells(startPos, endPos, flightDirection);
List<IntVec3> strafeImpactCells = CalculateStrafingImpactCells(targetCell, flightDirection);
// 绘制扫射影响区域的预览单元格
foreach (IntVec3 cell in strafeImpactCells)
@@ -146,11 +193,11 @@ namespace ArachnaeSwarm
GenDraw.DrawLineBetween(startPos.ToVector3Shifted(), endPos.ToVector3Shifted(), SimpleColor.Red, 0.2f);
// 绘制扫射范围边界
DrawStrafingBoundaries(startPos, endPos, flightDirection);
DrawStrafingBoundaries(targetCell, flightDirection);
}
// 计算扫射影响区域的单元格
private List<IntVec3> CalculateStrafingImpactCells(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection)
// 修复:计算扫射影响区域的单元格,现在以目标单元格为中心
private List<IntVec3> CalculateStrafingImpactCells(IntVec3 targetCell, Vector3 flightDirection)
{
List<IntVec3> cells = new List<IntVec3>();
Map map = parent.pawn.Map;
@@ -158,19 +205,16 @@ namespace ArachnaeSwarm
// 计算垂直于飞行方向的方向
Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
// 计算飞行路径的总长度
float totalPathLength = startPos.DistanceTo(endPos);
// 修复:以目标单元格为中心计算扫射区域
Vector3 targetCenter = targetCell.ToVector3();
// 计算扫射区域的中心点(目标位置附近
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);
// 使用整数步进避免浮点精度问题
int steps = Mathf.Max(1, Mathf.CeilToInt(Props.strafeLength));
for (int i = 0; i <= steps; i++)
{
float progress = (float)i / steps;
@@ -181,7 +225,13 @@ namespace ArachnaeSwarm
{
Vector3 offset = perpendicular * w;
Vector3 cellPos = centerPoint + offset;
IntVec3 cell = new IntVec3((int)cellPos.x, (int)cellPos.y, (int)cellPos.z);
// 使用更精确的单元格转换
IntVec3 cell = new IntVec3(
Mathf.RoundToInt(cellPos.x),
Mathf.RoundToInt(cellPos.y),
Mathf.RoundToInt(cellPos.z)
);
if (cell.InBounds(map) && !cells.Contains(cell))
{
@@ -190,18 +240,18 @@ namespace ArachnaeSwarm
}
}
Log.Message($"Strafing Area: Calculated {cells.Count} impact cells ({Props.strafeWidth * 2 + 1}x{Props.strafeLength})");
Log.Message($"Strafing Area: Calculated {cells.Count} impact cells centered at {targetCell}");
return cells;
}
// 绘制扫射范围边界
private void DrawStrafingBoundaries(IntVec3 startPos, IntVec3 endPos, Vector3 flightDirection)
// 修复:绘制扫射范围边界,现在以目标单元格为中心
private void DrawStrafingBoundaries(IntVec3 targetCell, Vector3 flightDirection)
{
Map map = parent.pawn.Map;
Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
// 计算扫射区域的中心
Vector3 targetCenter = Vector3.Lerp(startPos.ToVector3(), endPos.ToVector3(), 0.5f);
// 修复:以目标单元格为中心
Vector3 targetCenter = targetCell.ToVector3();
// 计算扫射区域的起始和结束位置
float strafeHalfLength = Props.strafeLength * 0.5f;
@@ -214,20 +264,27 @@ namespace ArachnaeSwarm
Vector3 endLeft = strafeEnd + perpendicular * Props.strafeWidth;
Vector3 endRight = strafeEnd - 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);
// 转换为 IntVec3 并确保在地图范围内
IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map);
IntVec3 startRightCell = GetSafeMapPosition(new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z), map);
IntVec3 endLeftCell = GetSafeMapPosition(new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z), map);
IntVec3 endRightCell = GetSafeMapPosition(new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z), map);
// 绘制边界线
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);
// 绘制边界线 - 只绘制在地图范围内的线段
if (startLeftCell.InBounds(map) && endLeftCell.InBounds(map))
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
if (startRightCell.InBounds(map) && endRightCell.InBounds(map))
GenDraw.DrawLineBetween(startRightCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
if (startLeftCell.InBounds(map) && startRightCell.InBounds(map))
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), startRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
if (endLeftCell.InBounds(map) && endRightCell.InBounds(map))
GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Red, 0.2f);
}
// 新增:绘制扇形区域预览 - 使用strafeWidth来近似扇形扫过的区域宽度
// 绘制扇形区域预览
private void DrawSectorAreaPreview(IntVec3 startPos, IntVec3 endPos)
{
Map map = parent.pawn.Map;
@@ -268,10 +325,10 @@ namespace ArachnaeSwarm
Map map = parent.pawn.Map;
// 计算飞行路径的总长度
float totalPathLength = startPos.DistanceTo(endPos);
float totalPathLength = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
// 沿着飞行路径计算预览单元格
int steps = Mathf.CeilToInt(totalPathLength / 1f);
int steps = Mathf.Max(1, Mathf.CeilToInt(totalPathLength));
for (int i = 0; i <= steps; i++)
{
float progress = (float)i / steps;
@@ -282,7 +339,13 @@ namespace ArachnaeSwarm
{
Vector3 offset = perpendicular * w;
Vector3 cellPos = centerPoint + offset;
IntVec3 cell = new IntVec3((int)cellPos.x, (int)cellPos.y, (int)cellPos.z);
// 使用精确的单元格转换
IntVec3 cell = new IntVec3(
Mathf.RoundToInt(cellPos.x),
Mathf.RoundToInt(cellPos.y),
Mathf.RoundToInt(cellPos.z)
);
if (cell.InBounds(map) && !cells.Contains(cell))
{
@@ -305,17 +368,24 @@ namespace ArachnaeSwarm
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);
// 转换为 IntVec3 并确保在地图范围内
IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map);
IntVec3 startRightCell = GetSafeMapPosition(new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z), map);
IntVec3 endLeftCell = GetSafeMapPosition(new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z), map);
IntVec3 endRightCell = GetSafeMapPosition(new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z), map);
// 绘制边界线
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);
// 绘制边界线 - 只绘制在地图范围内的线段
if (startLeftCell.InBounds(map) && endLeftCell.InBounds(map))
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
if (startRightCell.InBounds(map) && endRightCell.InBounds(map))
GenDraw.DrawLineBetween(startRightCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
if (startLeftCell.InBounds(map) && startRightCell.InBounds(map))
GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), startRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
if (endLeftCell.InBounds(map) && endRightCell.InBounds(map))
GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Blue, 0.2f);
}
// 预处理扫射目标单元格
@@ -335,8 +405,8 @@ namespace ArachnaeSwarm
return confirmedTargets;
}
// 创建地面扫射飞越
private void CreateGroundStrafingFlyOver(IntVec3 startPos, IntVec3 endPos)
// 修复:创建地面扫射飞越,现在接受目标单元格参数
private void CreateGroundStrafingFlyOver(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
{
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveCorvette");
if (flyOverDef == null)
@@ -363,9 +433,9 @@ namespace ArachnaeSwarm
CompGroundStrafing strafingComp = flyOver.GetComp<CompGroundStrafing>();
if (strafingComp != null)
{
// 计算扫射区域的所有单元格
// 修复:计算扫射区域的所有单元格,以目标单元格为中心
Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
List<IntVec3> potentialTargetCells = CalculateStrafingImpactCells(startPos, endPos, flightDirection);
List<IntVec3> potentialTargetCells = CalculateStrafingImpactCells(targetCell, flightDirection);
if (potentialTargetCells.Count > 0)
{
@@ -395,7 +465,7 @@ namespace ArachnaeSwarm
}
}
// 新增:创建扇形监视飞越
// 创建扇形监视飞越
private void CreateSectorSurveillanceFlyOver(IntVec3 startPos, IntVec3 endPos)
{
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveCorvette");
@@ -420,9 +490,6 @@ namespace ArachnaeSwarm
flyOver.playFlyOverSound = Props.playFlyOverSound;
Log.Message($"SectorSurveillance FlyOver created: {flyOver} from {startPos} to {endPos}");
// 注意扇形监视的具体参数角度、射程、发射次数等在FlyOver的CompProperties_SectorSurveillance中定义
// 这里只负责创建FlyOver不传递具体参数
}
// 计算垂直线进场路径
@@ -471,27 +538,107 @@ namespace ArachnaeSwarm
// 在指定方向上找到地图边缘
private IntVec3 FindMapEdgeInDirection(Map map, IntVec3 fromPos, Vector3 direction)
{
// 计算最大搜索距离(地图对角线的一半)
float maxDistance = Mathf.Sqrt(map.Size.x * map.Size.x + map.Size.z * map.Size.z) * 0.6f;
// 沿着方向逐步搜索,直到找到地图边界
for (float distance = 10f; distance <= maxDistance; distance += 5f)
// 确保方向向量有效
if (direction == Vector3.zero)
{
IntVec3 testPos = fromPos + new IntVec3(
Mathf.RoundToInt(direction.x * distance),
0,
Mathf.RoundToInt(direction.z * distance));
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
}
// 使用更精确的地图边界计算
IntVec3 mapCenter = map.Center;
IntVec3 mapSize = new IntVec3(map.Size.x, 0, map.Size.z);
// 计算与地图边界的交点
Vector3 fromVec = fromPos.ToVector3();
Vector3 dirNormalized = direction.normalized;
// 计算到各个边界的距离
float tMin = float.MaxValue;
IntVec3? bestEdgePos = null;
// 检查四个边界
for (int i = 0; i < 4; i++)
{
float t = 0f;
IntVec3 edgePos = IntVec3.Invalid;
if (!testPos.InBounds(map))
switch (i)
{
// 找到边界,返回最近的有效位置
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
Log.Message($"Found map edge at {edgePos} (direction: {direction}, distance: {distance})");
return edgePos;
case 0: // 左边界 (x = 0)
if (Mathf.Abs(dirNormalized.x) > 0.001f)
{
t = (0 - fromVec.x) / dirNormalized.x;
if (t > 0)
{
float z = fromVec.z + dirNormalized.z * t;
if (z >= 0 && z < map.Size.z)
{
edgePos = new IntVec3(0, 0, Mathf.RoundToInt(z));
}
}
}
break;
case 1: // 右边界 (x = map.Size.x - 1)
if (Mathf.Abs(dirNormalized.x) > 0.001f)
{
t = (map.Size.x - 1 - fromVec.x) / dirNormalized.x;
if (t > 0)
{
float z = fromVec.z + dirNormalized.z * t;
if (z >= 0 && z < map.Size.z)
{
edgePos = new IntVec3(map.Size.x - 1, 0, Mathf.RoundToInt(z));
}
}
}
break;
case 2: // 下边界 (z = 0)
if (Mathf.Abs(dirNormalized.z) > 0.001f)
{
t = (0 - fromVec.z) / dirNormalized.z;
if (t > 0)
{
float x = fromVec.x + dirNormalized.x * t;
if (x >= 0 && x < map.Size.x)
{
edgePos = new IntVec3(Mathf.RoundToInt(x), 0, 0);
}
}
}
break;
case 3: // 上边界 (z = map.Size.z - 1)
if (Mathf.Abs(dirNormalized.z) > 0.001f)
{
t = (map.Size.z - 1 - fromVec.z) / dirNormalized.z;
if (t > 0)
{
float x = fromVec.x + dirNormalized.x * t;
if (x >= 0 && x < map.Size.x)
{
edgePos = new IntVec3(Mathf.RoundToInt(x), 0, map.Size.z - 1);
}
}
}
break;
}
// 找到最近的有效边界点
if (edgePos.IsValid && edgePos.InBounds(map) && t > 0 && t < tMin)
{
tMin = t;
bestEdgePos = edgePos;
}
}
// 如果没找到边界,使用随机边缘位置
if (bestEdgePos.HasValue)
{
return bestEdgePos.Value;
}
// 如果没找到合适的边界点,使用随机边缘位置
Log.Warning($"Could not find map edge in direction {direction}, using random edge");
return GetRandomMapEdgePosition(map);
}
@@ -510,7 +657,7 @@ namespace ArachnaeSwarm
return GetMapEdgePosition(map, GetDirectionFromCasterToTarget(target));
case StartPosition.CustomOffset:
return parent.pawn.Position + Props.customStartOffset;
return GetSafeMapPosition(parent.pawn.Position + Props.customStartOffset, map);
case StartPosition.RandomMapEdge:
return GetRandomMapEdgePosition(map);
@@ -536,7 +683,7 @@ namespace ArachnaeSwarm
break;
case EndPosition.CustomOffset:
endPos = target.Cell + Props.customEndOffset;
endPos = GetSafeMapPosition(target.Cell + Props.customEndOffset, map);
break;
case EndPosition.FixedDistance:
@@ -553,10 +700,10 @@ namespace ArachnaeSwarm
break;
}
return endPos;
return GetSafeMapPosition(endPos, map);
}
// 原有的辅助方法保持不变
// 原有的辅助方法
private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos)
{
IntVec3 center = map.Center;
@@ -731,34 +878,6 @@ namespace ArachnaeSwarm
Log.Message($"Standard FlyOver created: {flyOver} from {startPos} to {endPos}");
}
private void ShowEffectMessage()
{
string message = GetFlyOverMessage();
Messages.Message(message, parent.pawn, MessageTypeDefOf.NeutralEvent);
}
private string GetFlyOverMessage()
{
switch (Props.flyOverType)
{
case FlyOverType.HighAltitude:
return "HighAltitudeReconArrival".Translate(parent.pawn.LabelShort);
case FlyOverType.CargoDrop:
return "CargoDropIncoming".Translate(parent.pawn.LabelShort);
case FlyOverType.BombingRun:
return "BombingRunInitiated".Translate(parent.pawn.LabelShort);
case FlyOverType.Reconnaissance:
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)
{

View File

@@ -575,7 +575,7 @@ namespace ArachnaeSwarm
public float minShadowScale = 0.5f;
public float maxShadowScale = 1.0f;
public float defaultFadeInDuration = 1.5f;
public float defaultFadeOutDuration = 1.5f;
public float defaultFadeOutDuration = 0.5f;
public float fadeOutStartProgress = 0.98f;
// 动态淡出配置