diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index ade5b720..688bbef5 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml b/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml index 4f045eef..3bdbe935 100644 --- a/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml +++ b/1.6/1.6/Defs/AbilityDefs/WULA_Flyover_Ability.xml @@ -1,58 +1,10 @@ - - - WULA_CallFleet - - 发送增援请求,呼叫乌拉帝国舰队前往殖民地的高空轨道,包含2艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器支援的航空舰。 - Wula/UI/Abilities/WULA_CallBattleShip - 1 - Misc12 - false - true - false - - Verb_CastAbility - true - false - true - 2 - -1 - false - - false - true - - - -
  • - WULA_AircraftCarrier_Entity - 320000 - 1 -
  • -
  • - WULA_AircraftCarrier - Standard - 0.03 - 20 - MapEdge - OppositeMapEdge - true -
  • -
  • - 航道堵塞:已经有一艘大型舰船在殖民地上空 - - - - -
  • -
    -
    WULA_CallMotherShip - - 发送增援请求,呼叫乌拉帝国母舰舰队前往殖民地的高空轨道,包含2艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器和炮击支援的母舰。 + + 发送增援请求,呼叫乌拉帝国母舰舰队前往殖民地的高空轨道,包含4艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器、炮击和轨道支援的母舰。 Wula/UI/Abilities/WULA_CallMotherShip 1 Misc12 @@ -96,11 +48,107 @@ + + + WULA_CallFleet + + 发送增援请求,呼叫乌拉帝国舰队前往殖民地的高空轨道,包含2艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器的航空舰。 + Wula/UI/Abilities/WULA_CallBattleShip + 1 + Misc12 + false + true + false + + Verb_CastAbility + true + false + true + 2 + -1 + false + + false + true + + + +
  • + WULA_AircraftCarrier_Entity + 320000 + 1 +
  • +
  • + WULA_AircraftCarrier + Standard + 0.03 + 20 + MapEdge + OppositeMapEdge + true +
  • +
  • + 航道堵塞:已经有一艘大型舰船在殖民地上空 + + + + +
  • +
    +
    + + + WULA_CallConstructionShip + + 发送增援请求,呼叫乌拉帝国拒止舰队前往殖民地的高空轨道,包含1艘可以提供轨道支援的拒止舰。 + Wula/UI/Abilities/WULA_CallConstructionShip + 1 + Misc12 + false + true + false + + Verb_CastAbility + true + false + true + 5 + -1 + false + + false + true + + + +
  • + WULA_ConstructionShip_Entity + 640000 + 1 +
  • +
  • + WULA_ConstructionShip + Standard + 0.01 + 20 + MapEdge + OppositeMapEdge + true +
  • +
  • + 航道堵塞:已经有一艘大型舰船在殖民地上空 + + + + +
  • +
    +
    WULA_ClearFlightPath 使近地轨道上的舰队离开,以使得其他乌拉帝国舰队可以入场 - Wula/UI/Abilities/WULA_CallConstructionShip + Wula/UI/Abilities/WULA_ClearFlightPath 1 Misc12 false @@ -125,6 +173,7 @@ + WULA_Spawn_BattleShip_Artillery @@ -851,7 +900,7 @@ WULA_Firepower_EnergyLance_Surveillance - 指挥战舰侧弦的副炮,监视一个区域1小时,对任何进入范围的敌对目标进行炮击。 + 指挥战舰侧弦的光矛阵列,监视一个区域1小时,对任何进入范围的敌对目标进行持续照射。 Wula/UI/Abilities/WULA_Firepower_EnergyLance_Surveillance 1 Misc12 @@ -918,8 +967,8 @@ 35 70 0.1 - 16 - 16 + 8 + 8 240 30 2 @@ -979,4 +1028,47 @@ + + + + WULA_Support_Shield_Projection + + 以启动拒止舰的止戈立场,在指定地点投射一面球形护盾,阻挡并反射所有的外来射弹。 + Wula/UI/Abilities/WULA_Firepower_Minigun_Strafe + 1 + Misc12 + false + + Verb_CastAbility + false + false + 1 + 120 + true + + false + true + + + +
  • + 1000 + BombardmentFacility +
  • +
  • + 0 + WULA_Support_Shield_Projection_Skyfaller + 12 + (0.6,0.8,0.8,0.5) +
  • +
  • + + FactoryFacility + 需要拥有<color=#BD2F31><i>支援设施</i></color>设施的战舰在地图上才能进行轨道炮击支援 +
  • + +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml index bf5b83d3..8599faa3 100644 --- a/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml +++ b/1.6/1.6/Defs/EventDefs/EventDef_Wula/Wula_MainEvent.xml @@ -52,10 +52,6 @@ false false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -77,15 +73,11 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • - WULA_GiveQuest_Colony_Promotion_UI_1 + WULA_Colony_Promotion_UI_1
  • @@ -95,10 +87,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -222,10 +210,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -670,10 +654,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • diff --git a/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml index fdd97d7a..d69355a4 100644 --- a/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml +++ b/1.6/1.6/Defs/HediffDefs/WULA_FM_Hediffs.xml @@ -57,6 +57,7 @@
  • Wula_FM_Switc_None
  • Wula_FM_Switc_Artillery
  • Wula_FM_Switc_Aircraft
  • +
  • Wula_FM_Switc_Construction
  • 0 Wula/UI/Commands/WULA_Antenna_Switch @@ -85,7 +86,7 @@ Wula_FM_Switc_Artillery - 允许乌拉帝国的合成人呼叫轨道火力支援,包含一系列精准度较差但是覆盖范围广的轰炸能力,一般需要有战舰部署在轨道上才能启动。 + 允许乌拉帝国的合成人呼叫轨道炮击,包含一系列精准度较差但是覆盖范围广的轰炸能力,一般需要有攻击型战舰部署在轨道上才能启动。 Hediff_High false false @@ -117,7 +118,7 @@ Wula_FM_Switc_Aircraft - 允许乌拉帝国的合成人呼叫空中火力,包含一系列精准迅速的近地密接支援,每一艘战机会独立计算袭击冷却。 + 允许乌拉帝国的合成人呼叫空中火力,包含一系列精准迅速的近地密接支援,每一艘战机会独立计算袭击冷却,一般需要有攻击型战舰部署在轨道上才能启动。 Hediff_High false false @@ -146,4 +147,29 @@ + + Wula_FM_Switc_Construction + + 允许乌拉帝国的合成人呼叫舰队支援,包含一系列防御性能力和生产加速能力,一般需要有拒止舰队部署在轨道上才能启动。 + Hediff_High + false + false + True + false + +
  • + false +
  • +
    + +
  • + +
  • WULA_CallMotherShip
  • +
  • WULA_CallConstructionShip
  • +
  • WULA_ClearFlightPath
  • +
  • WULA_Support_Shield_Projection
  • + + +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml index 94269dd3..28301f97 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Base_Tex_Quest.xml @@ -210,10 +210,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Colony_Promotion.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Colony_Promotion.xml index 75b72c15..46521c93 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Colony_Promotion.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Colony_Promotion.xml @@ -1,7 +1,7 @@ - WULA_GiveQuest_Colony_Promotion_UI_1 + WULA_Colony_Promotion_UI_1 Wula/Events/Portraits/WULA_Legion_2 「军团」,P.I.A @@ -12,17 +12,24 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255) + false + 我记得我已经送了一个分体去你们殖民地了?在30天内,我不会再派出审查队。 + +
  • + WULA_Colony_Promotion_Lock +
  • +
  • -
  • +
  • + WULA_Colony_Promotion_Lock + 1800000 +
  • WULA_Colony_Promotion
  • +
  • @@ -30,10 +37,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -328,9 +331,9 @@ Raids 1.0 - 0.5 + 1.5 0.04 - 1~1.5 + 1~1 1.1 500 @@ -375,7 +378,7 @@
  • Fail - -5 + -30 $asker QuestPawnArrested
  • @@ -395,7 +398,7 @@
  • Fail - -5 + -30 $asker PerformedHarmfulSurgery
  • @@ -415,7 +418,7 @@
  • Fail - -5 + -30 $asker XenogermAbsorbed
  • @@ -435,7 +438,7 @@
  • Fail - -5 + -30 $asker QuestPawnLost
  • @@ -455,7 +458,7 @@
  • Fail - -5 + -30 $asker ShuttleDestroyed
  • @@ -475,7 +478,7 @@
  • Fail - -5 + -30 $asker QuestPawnLost
  • @@ -493,7 +496,7 @@
  • pickupShipThing.SentSatisfied - WULA_GiveQuest_Colony_Promotion_UI_2 + WULA_Colony_Promotion_UI_2
  • Success @@ -513,7 +516,7 @@
  • Fail - -5 + -30 $asker MemberMissedShuttle
  • @@ -544,7 +547,7 @@ - WULA_GiveQuest_Colony_Promotion_UI_2 + WULA_Colony_Promotion_UI_2 Wula/Events/Portraits/WULA_Legion_2 「军团」,P.I.A @@ -576,10 +579,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_NewColony.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_NewColony.xml index 476d4bdd..945e7667 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_NewColony.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_NewColony.xml @@ -60,10 +60,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -78,10 +74,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -96,10 +88,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -125,10 +113,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -143,10 +127,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -161,10 +141,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -190,10 +166,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -208,10 +180,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -237,10 +205,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -255,10 +219,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -284,10 +244,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -302,10 +258,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -331,10 +283,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -349,10 +297,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -367,10 +311,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -396,10 +336,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_Spy.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_Spy.xml index d2242a58..cea32bb2 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_Spy.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Intro_Spy.xml @@ -418,10 +418,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -436,10 +432,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -454,10 +446,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -480,10 +468,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -509,10 +493,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -538,10 +518,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • @@ -595,10 +571,6 @@
  • false - (255,255,255,255) - (157,201,185,195) - (255,255,255,255) - (255,255,255,255)
  • diff --git a/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml b/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml index 4098226e..b980f9ee 100644 --- a/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml +++ b/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml @@ -204,6 +204,76 @@ + + + WULA_Firepower_Minigun_Fire_sound + MapOnly + 2 + +
  • + +
  • + Wula/WULA_Basttleship_Shootingsound_S +
  • + + 35 + 0.9~1.1 + True + + + + + WULA_Firepower_Cannon_Fire_sound + MapOnly + 2 + +
  • + +
  • + Wula/WULA_Basttleship_Shootingsound_M +
  • + + 45 + 0.9~1.1 + True + +
    +
    + + WULA_Firepower_Primary_Cannon_Fire_sound + MapOnly + 2 + +
  • + +
  • + Wula/WULA_Basttleship_Shootingsound_L +
  • + + 55 + 0.9~1.1 + True + +
    +
    + + WULA_MotherShip_Planet_Interdiction_IncomingSound + MapOnly + 2 + +
  • + +
  • + Wula/WULA_MotherShip_Planet_Interdiction_IncomingSound +
  • + + 55 + 0.9~1.1 + True + +
    +
    + Pawn_Wula_AI_Heavy_Panzer_Call diff --git a/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml b/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml index c45aa107..5f8a0e91 100644 --- a/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml +++ b/1.6/1.6/Defs/StoryTellers/WULA_Storytellers.xml @@ -180,41 +180,6 @@ 8 1 - - -
  • - 1 - WULA_GiveQuest_Intro_Spy - WULA_Intro_Spy - true - Allow - -
  • WULA_Awakened_Synth
  • - - - -
  • Map_PlayerHome
  • -
    - - - -
  • - WULA_Colony_License_LV1_Technology - WULA_GiveQuest_Base_Tex - WULA_Base_Tex_Quest - - - 0 - 15 - - - false - false - - Wula_PIA_Legion_Faction -
  • \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml index 029fe8ef..2d522680 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml @@ -996,7 +996,7 @@
  • CompPowerTrader - 400 + 100
  • diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml index 07a87676..e70803ca 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml @@ -74,7 +74,7 @@ WULA_Fake_AircraftCarrier_Beacon_Building - 用于向乌拉帝国舰队提交资源的信标,可以换取一支帝国舰队的额外征调权,包含2艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器支援的航空舰。 + 用于向乌拉帝国舰队提交资源的信标,可以换取一支帝国攻击舰队的额外征调权,包含2艘可以发起轨道炮击的巡洋舰和1艘可以提供航空器支援的航空舰。 Building true Building @@ -145,7 +145,85 @@ WULA_AircraftCarrier_Entity - + + 什么?这是个记录数量用的thingdef,你不应该在任何场合下看到这个。 + Thing + + + WULA_Fake_ConstructionShip_Beacon_Building + + 用于向乌拉帝国舰队提交资源的信标,可以换取一支帝国拒止舰队的额外征调权,包含1艘可以提供轨道支援的拒止舰。\n\n帝国拒止舰是搭载了移动工厂的防御型装舰种,它们可以为各殖民地提供非攻击性的支援,以从猛烈的袭击中保护殖民地或加速殖民地的生产发展。 + Building + true + Building + WULA_Buildings + +
  • WULA_ConstructionShip_Technology
  • +
    + 50 + true + PassThroughOnly + 1 + (3,3) + Wula/Building/WULA_Fake_ConstructionShip_Beacon_Building + true + (0.56, 0.62, 0.9) + + Wula/Building/WULA_Flyover_Beacon + Graphic_Single + (3,3) + (195,195,195,255) + + + 600 + 0.5 + 36000 + 125 + 0.65 + + + 300 + 6 + + Normal + true + false + false + North + true + Light + BulletImpact_Metal + true + RealtimeOnly + ConstructMetal + true + + false + BuildingDestroyed_Metal_Big + true + true + + +
  • + + true + false +
  • +
  • + WULA_ConstructionShip_Entity + 1 + + + true + 1 + true + false +
  • +
    +
    + + WULA_ConstructionShip_Entity + 什么?这是个记录数量用的thingdef,你不应该在任何场合下看到这个。 Thing @@ -216,84 +294,6 @@ 什么?这是个记录数量用的thingdef,你不应该在任何场合下看到这个。 Thing - - WULA_Fake_ConstructionShip_Beacon_Building - - 用于向乌拉帝国舰队提交资源的信标,可以换取一艘帝国工程舰的支援。\n\n帝国工程舰是搭载了移动工厂的无武装舰种,它们可以完整地使用乌拉帝国的锻造技术生产装备、护甲、建筑和机械体,并依照指令通过空投仓将其送至各殖民地。\n\n工程舰拥有以下设施:\n<color=#6BB7B7><i>-生产设施</i></color>\n<color=#DEC28F><i>-建筑空投设施</i></color> - Building - true - Building - - 50 - true - PassThroughOnly - 1 - (3,3) - Wula/Building/WULA_Fake_ConstructionShip_Beacon_Building - true - (0.56, 0.62, 0.9) - - Wula/Building/WULA_Flyover_Beacon - Graphic_Single - (3,3) - (195,195,195,255) - - - 600 - 0.5 - 36000 - 125 - 0.65 - - - 300 - 6 - - Normal - true - false - false - North - true - Light - BulletImpact_Metal - true - RealtimeOnly - ConstructMetal - true - - false - BuildingDestroyed_Metal_Big - true - true - - -
  • - - true - false -
  • -
  • - WULA_ConstructionShip_Entity - 1 - - - true - 1 - true - false -
  • -
    -
    - - WULA_ConstructionShip_Entity - - 什么?这是个记录数量用的thingdef,你不应该在任何场合下看到这个。 - Thing -
  • 60 - 帝国航空舰已抵达 - 一艘帝国航空舰响应请求抵达殖民地上空! + 帝国攻击舰队已抵达 + 帝国攻击舰队响应请求抵达殖民地上空! PositiveEvent true true @@ -510,10 +510,10 @@
  • - + WULA_ConstructionShip - + WulaFallenEmpire.FlyOver Normal RealtimeOnly @@ -559,13 +559,101 @@
  • 60 - 帝国工程舰已抵达 - 一艘帝国工程舰响应请求抵达殖民地上空! + 帝国拒止舰已抵达 + 帝国拒止舰队响应请求抵达殖民地上空! PositiveEvent true true false
  • +
  • + WULA_Striker_Escort + + + 1000 + 20 + 1 + + + 0 + 100 + 5 + true + 10 + 70 + + + 25 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • +
  • + WULA_Bomber_Escort + + + 1350 + 10 + 1 + + + 0 + 130 + 5 + true + 10 + 70 + + + 15 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • FactoryFacility
  • @@ -768,58 +856,8 @@ MetaOverlays -
  • - 60 - 全域封锁 - 全域封锁舰队已抵达,请自行寻找掩护! - PositiveEvent - true - true - false -
  • -
  • - WULA_Striker_Escort - - - 1000 - 30 - 2 - - - 0 - 100 - 5 - true - 10 - 70 - - - 50 - 10 - false - - - true - false - true - - - true - - - - 0.3 - 0.6 - - - - true - - 0.6 - 0.8 - - (0.7,0.85,1.0,1.0) - 1.3 +
  • + WULA_MotherShip_Planet_Interdiction_IncomingSound
  • WULA_BattleShip_Planet_Interdiction @@ -831,7 +869,7 @@ 0 - 80 + 70 5 true 30 @@ -865,6 +903,17 @@ (0.7,0.85,1.0,1.0) 1.3
  • +
  • + 300 + 300 + 65 + WULA_Firepower_Cannon_Salvo_Skyfaller + 12 + + + true + true +
  • @@ -912,6 +961,50 @@ false MetaOverlays +
  • + WULA_Striker_Escort + + + 1000 + 30 + 2 + + + 0 + 100 + 5 + true + 10 + 70 + + + 10 + 10 + false + + + true + false + true + + + true + + + + 0.3 + 0.6 + + + + true + + 0.6 + 0.8 + + (0.7,0.85,1.0,1.0) + 1.3 +
  • 300 300 @@ -1455,20 +1548,25 @@ 1 -
  • (0,180)
  • -
  • (1, 181)
  • +
  • (0,150)
  • +
  • (1, 151)
  • -
  • (0,0)
  • -
  • (1, 1)
  • +
  • (0,-30)
  • +
  • (1, -31)
  • 4 WULA_Firepower_Minigun_Strafe_Damage 1 + +
  • + WULA_Firepower_Minigun_Fire_sound +
  • +
    WULA_Firepower_Cannon_Salvo_Skyfaller @@ -1493,20 +1591,25 @@ 1 -
  • (0,180)
  • -
  • (1, 181)
  • +
  • (0,150)
  • +
  • (1, 151)
  • -
  • (0,0)
  • -
  • (1, 1)
  • +
  • (0,-30)
  • +
  • (1, -31)
  • 6 - Bomb - 0.85 + WULA_GiantBomb + 0.28 + +
  • + WULA_Firepower_Cannon_Fire_sound +
  • +
    WULA_Firepower_Cannon_Surveillance_Skyfaller @@ -1898,14 +2001,14 @@ 1 -
  • (0,180)
  • -
  • (1, 181)
  • +
  • (0,150)
  • +
  • (1, 151)
  • -
  • (0,0)
  • -
  • (1, 1)
  • +
  • (0,-30)
  • +
  • (1, -31)
  • 35 @@ -1913,6 +2016,11 @@ 1 CraterLarge + +
  • + WULA_Firepower_Primary_Cannon_Fire_sound +
  • +
    WULA_DarkMatterBomb_FlashStrong @@ -2048,19 +2156,185 @@ 1 -
  • (0,180)
  • -
  • (1, 181)
  • +
  • (0,150)
  • +
  • (1, 151)
  • -
  • (0,0)
  • -
  • (1, 1)
  • +
  • (0,-30)
  • +
  • (1, -31)
  • 35 EMP 10 + +
  • + WULA_Firepower_Primary_Cannon_Fire_sound +
  • +
    +
    + + + WULA_Support_Shield_Projection_Skyfaller + + (1,1) + + Wula/Building/Flag/WULA_Flag_Building_Mount + Graphic_Single + TransparentPostLight + (1,1) + + false + + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (0, 0) + DropPod_Fall + 100 + + 0.05 + 0 + 0 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    + WULA_Support_Shield +
    +
    + + WULA_Support_Shield + + 一面大型护盾,反射所有的敌方射弹,己方的开火不受影响。 + WulaFallenEmpire.Building_ExtraGraphics + true + BuildingOnTop + 50 + true + PassThroughOnly + 1 + (1,1) + true + (0.56, 0.62, 0.9) + Wula/Building/Flag/WULA_Flag_Building_A + false + + Wula/Building/Flag/WULA_Flag_Building_Mount + Graphic_Single + TransparentPostLight + (1,1) + + + 5 + + + 100 + 0.5 + 1000 + 125 + 0.65 + + Normal + true + false + North + true + Light + BulletImpact_Metal + true + RealtimeOnly + ConstructMetal + true + WULA_Buildings + + false + BuildingDestroyed_Metal_Big + true + true + + +
  • + 0 + 0 + + +
  • + Wula/Building/Flag/WULA_Flag_Building_A + (3,3) + 0 + (0,1,3) + 1.5 + 0.2 + 0 +
  • +
  • + Wula/Building/Flag/WULA_Flag_Building_Mount + (1,1) + 1 + (0,1,0) + 0 + 0 + 0 +
  • +
  • + Wula/Building/WULA_Support_Shield_Building + (24,24) + 2 + (0,1,0) + 0 + 0 + 0 +
  • + + +
    + +
  • + + true + false +
  • +
  • + 3 + (120,240,252,0) +
  • +
  • + 3600 +
  • + +
  • + 12 + 150000 + 2400 + 30 + + + Interceptor_BlockedProjectile + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + (0.9, 0.2, 0.2, 0.5) + + + true + false + true + + + true + 1 + 30 + 0 + Interceptor_BlockedProjectile +
  • +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml index 3e3d8ae4..b693e256 100644 --- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml +++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Manpack_Weapon.xml @@ -396,6 +396,8 @@ Graphic_Single CutoutComplex + true + None -65 Spacer false @@ -500,8 +502,8 @@ Bullet_WULA_RW_Base_AR 1 25 - 3 - 3 + 5 + 5 Shot_AssaultRifle GunTail_Medium 7 @@ -513,7 +515,6 @@
  • Wula_Ranged_Weapon_T1
  • -
  • Wula_Assault_Cat_Weapon
  • @@ -522,6 +523,59 @@
  • + + + true + WULA_RW_Base_AR_For_Cat + + 乌拉帝国的基础突击步枪,仍然使用可靠的导气式结构驱动自动射击构件,是一种便宜但好用的武器,通常派发给殖民地作自卫武器之用。 + Normal + Spacer + + Wula/Weapon/WULA_RW_Base_AR + Graphic_Single + + Interact_Rifle + None + + +
  • WULA_WeaponArmor_Productor
  • +
    + WULA_Synth_Weapon_1_Base_Technology + UnfinishedWeapon +
    + + 1300 + + 3.5 + 0.75 + 0.75 + 0.65 + 0.45 + 1.2 + + +
  • + Verb_Shoot + true + Bullet_WULA_RW_Base_AR + 1 + 25 + 5 + 5 + Shot_AssaultRifle + GunTail_Medium + 7 +
  • +
    + + 40 + 2 + + +
  • Wula_Assault_Cat_Weapon
  • +
    +
    Bullet_WULA_RW_Base_AR @@ -2195,7 +2249,7 @@ WULA_MW_Cheat_Weapon_Ability 使得目标立刻被放逐——无视一切保护措施,将其从存档中永远擦除。 - Wula/UI/Abilities/WULA_RW_Auto_GL_Smoke_Ability + Wula/UI/Commands/Wula_Psi_Titan_AreaDamage True False Misc11 diff --git a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml index 9ae39bce..bc433a7c 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml @@ -1454,13 +1454,32 @@ -
  • - 36000 - 8.2 - 8.4 - 0.01 - 4.0 - false + +
  • + 9 + 300 + 2400 + 30 + + + Interceptor_BlockedProjectile + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + (0.9, 0.2, 0.2, 0.5) + + + true + false + true + + + true + 0.6 + 30 + 0 + Interceptor_BlockedProjectile
  • @@ -1624,13 +1643,32 @@
  • -
  • - 36000 - 11.2 - 11.4 - 0.01 - 4.0 - false + +
  • + 9 + 500 + 2400 + 30 + + + Interceptor_BlockedProjectile + Interceptor_BlockedProjectile + Shield_Break + BulletShieldGenerator_Reactivate + + (0.9, 0.2, 0.2, 0.5) + + + true + false + true + + + true + 0.75 + 30 + 0 + Interceptor_BlockedProjectile
  • diff --git a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml index 9506574f..be17452a 100644 --- a/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml +++ b/1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/Misc_Gameplay.xml @@ -301,4 +301,9 @@ 启用或禁用区域伤害效果 区域伤害:已启用 区域伤害:已禁用 + + 更换武器 + 扔掉当前武器,并装备该单位的初始武器 + {0} 更换了武器为 {1} + {0} 没有可用的武器类型 \ No newline at end of file diff --git a/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml b/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml new file mode 100644 index 00000000..0dab8537 --- /dev/null +++ b/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml @@ -0,0 +1,44 @@ + + + + + Defs/StorytellerDef[@Name="BaseStoryteller"]/comps + +
  • + 1 + WULA_GiveQuest_Intro_Spy + WULA_Intro_Spy + true + Allow + +
  • WULA_Awakened_Synth
  • + + +
  • Map_PlayerHome
  • +
    + + + + + + + Defs/StorytellerDef[@Name="BaseStoryteller"]/comps + +
  • + WULA_Colony_License_LV1_Technology + WULA_GiveQuest_Base_Tex + WULA_Base_Tex_Quest + + + 0 + 15 + + + false + false + + Wula_PIA_Legion_Faction +
  • +
    +
    + \ No newline at end of file diff --git a/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_L.wav b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_L.wav new file mode 100644 index 00000000..3df8dae4 Binary files /dev/null and b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_L.wav differ diff --git a/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_M.wav b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_M.wav new file mode 100644 index 00000000..91df9773 Binary files /dev/null and b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_M.wav differ diff --git a/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_S.wav b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_S.wav new file mode 100644 index 00000000..cec2f3b2 Binary files /dev/null and b/Content/Sounds/Wula/WULA_Basttleship_Shootingsound_S.wav differ diff --git a/Content/Sounds/Wula/WULA_MotherShip_Planet_Interdiction_IncomingSound.wav b/Content/Sounds/Wula/WULA_MotherShip_Planet_Interdiction_IncomingSound.wav new file mode 100644 index 00000000..02e4e83e Binary files /dev/null and b/Content/Sounds/Wula/WULA_MotherShip_Planet_Interdiction_IncomingSound.wav differ diff --git a/Content/Textures/Wula/Building/WULA_Support_Shield_Building.png b/Content/Textures/Wula/Building/WULA_Support_Shield_Building.png new file mode 100644 index 00000000..ec0a3723 Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_Support_Shield_Building.png differ diff --git a/Content/Textures/Wula/UI/Abilities/WULA_ClearFlightPath.png b/Content/Textures/Wula/UI/Abilities/WULA_ClearFlightPath.png new file mode 100644 index 00000000..196571b4 Binary files /dev/null and b/Content/Textures/Wula/UI/Abilities/WULA_ClearFlightPath.png differ diff --git a/Source/WulaFallenEmpire/EventSystem/Condition.cs b/Source/WulaFallenEmpire/EventSystem/Condition/ConditionBase.cs similarity index 96% rename from Source/WulaFallenEmpire/EventSystem/Condition.cs rename to Source/WulaFallenEmpire/EventSystem/Condition/ConditionBase.cs index 4b8325da..4101f051 100644 --- a/Source/WulaFallenEmpire/EventSystem/Condition.cs +++ b/Source/WulaFallenEmpire/EventSystem/Condition/ConditionBase.cs @@ -3,12 +3,12 @@ using RimWorld; namespace WulaFallenEmpire { - public abstract class Condition + public abstract class ConditionBase { public abstract bool IsMet(out string reason); } - public class Condition_VariableEquals : Condition + public class Condition_VariableEquals : ConditionBase { public string name; public string value; @@ -75,7 +75,7 @@ namespace WulaFallenEmpire } } - public abstract class Condition_CompareVariable : Condition + public abstract class Condition_CompareVariable : ConditionBase { public string name; public float value; @@ -145,7 +145,7 @@ namespace WulaFallenEmpire protected override string GetOperatorString() => "<="; } - public class Condition_VariableNotEqual : Condition + public class Condition_VariableNotEqual : ConditionBase { public string name; public string value; @@ -213,7 +213,7 @@ namespace WulaFallenEmpire } } - public class Condition_FactionExists : Condition + public class Condition_FactionExists : ConditionBase { public FactionDef factionDef; diff --git a/Source/WulaFallenEmpire/EventSystem/Condition/Condition_FlagExists.cs b/Source/WulaFallenEmpire/EventSystem/Condition/Condition_FlagExists.cs new file mode 100644 index 00000000..68bef5a7 --- /dev/null +++ b/Source/WulaFallenEmpire/EventSystem/Condition/Condition_FlagExists.cs @@ -0,0 +1,83 @@ +using Verse; +using RimWorld; + +namespace WulaFallenEmpire +{ + public abstract class Condition + { + public abstract bool IsMet(out string reason); + } + + public class Condition_FlagExists : ConditionBase + { + public string flagName; + + public override bool IsMet(out string reason) + { + if (string.IsNullOrEmpty(flagName)) + { + reason = "Flag name is not specified."; + return false; + } + + var eventVarManager = Find.World.GetComponent(); + bool flagExists = eventVarManager.HasFlag(flagName); + + if (!flagExists) + { + reason = $"Flag '{flagName}' does not exist or has expired."; + } + else + { + int remainingTicks = eventVarManager.GetFlagRemainingTicks(flagName); + if (remainingTicks < 0) + { + reason = $"Flag '{flagName}' exists (permanent)."; + } + else + { + reason = $"Flag '{flagName}' exists (expires in {remainingTicks} ticks)."; + } + } + + Log.Message($"[EventSystem] Condition_FlagExists check: Flag='{flagName}', Exists={flagExists}, Reason='{reason}'"); + return flagExists; + } + } + + public class Condition_FlagNotExists : ConditionBase + { + public string flagName; + + public override bool IsMet(out string reason) + { + if (string.IsNullOrEmpty(flagName)) + { + reason = "Flag name is not specified."; + return false; + } + + var eventVarManager = Find.World.GetComponent(); + bool flagExists = eventVarManager.HasFlag(flagName); + + if (flagExists) + { + int remainingTicks = eventVarManager.GetFlagRemainingTicks(flagName); + if (remainingTicks < 0) + { + reason = $"Flag '{flagName}' exists (permanent)."; + } + else + { + reason = $"Flag '{flagName}' exists (expires in {remainingTicks} ticks)."; + } + return false; + } + else + { + reason = $"Flag '{flagName}' does not exist."; + return true; + } + } + } +} diff --git a/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs b/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs index 6df07b47..0f9cb584 100644 --- a/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs +++ b/Source/WulaFallenEmpire/EventSystem/Dialog_CustomDisplay.cs @@ -572,7 +572,7 @@ namespace WulaFallenEmpire } } - private bool AreConditionsMet(List conditions, out string reason) + private bool AreConditionsMet(List conditions, out string reason) { reason = ""; if (conditions.NullOrEmpty()) diff --git a/Source/WulaFallenEmpire/EventSystem/Effect/EffectBase.cs b/Source/WulaFallenEmpire/EventSystem/Effect/EffectBase.cs index 7259cf66..db193374 100644 --- a/Source/WulaFallenEmpire/EventSystem/Effect/EffectBase.cs +++ b/Source/WulaFallenEmpire/EventSystem/Effect/EffectBase.cs @@ -68,7 +68,7 @@ namespace WulaFallenEmpire } } - private bool AreConditionsMet(List conditions, out string reason) + private bool AreConditionsMet(List conditions, out string reason) { reason = ""; if (conditions.NullOrEmpty()) diff --git a/Source/WulaFallenEmpire/EventSystem/Effect/Effect_SetTimedFlag.cs b/Source/WulaFallenEmpire/EventSystem/Effect/Effect_SetTimedFlag.cs new file mode 100644 index 00000000..94bfe80f --- /dev/null +++ b/Source/WulaFallenEmpire/EventSystem/Effect/Effect_SetTimedFlag.cs @@ -0,0 +1,27 @@ +// 在 EffectBase.cs 中添加以下类 +using Verse; +using RimWorld; + +namespace WulaFallenEmpire +{ + public class Effect_SetTimedFlag : EffectBase + { + public string flagName; + public int durationTicks; // 持续时间(tick),负数表示永久 + + public override void Execute(Window dialog = null) + { + if (string.IsNullOrEmpty(flagName)) + { + Log.Error("[WulaFallenEmpire] Effect_SetTimedFlag has a null or empty flagName."); + return; + } + + var eventVarManager = Find.World.GetComponent(); + eventVarManager.SetTimedFlag(flagName, durationTicks); + + string durationInfo = durationTicks < 0 ? "permanent" : $"{durationTicks} ticks"; + Log.Message($"[EventSystem] Set timed flag '{flagName}' with duration: {durationInfo}"); + } + } +} \ No newline at end of file diff --git a/Source/WulaFallenEmpire/EventSystem/EventDef.cs b/Source/WulaFallenEmpire/EventSystem/EventDef.cs index 829a13db..3fd17931 100644 --- a/Source/WulaFallenEmpire/EventSystem/EventDef.cs +++ b/Source/WulaFallenEmpire/EventSystem/EventDef.cs @@ -71,7 +71,7 @@ namespace WulaFallenEmpire { [MustTranslate] public string label; - public List conditions; + public List conditions; [MustTranslate] public string disabledReason; public bool hideWhenDisabled = true; @@ -102,7 +102,7 @@ namespace WulaFallenEmpire public class ConditionalEffects { - public List conditions; + public List conditions; public List effects; public List randomlistEffects; public List loopEffects; @@ -164,7 +164,7 @@ namespace WulaFallenEmpire public class ConditionalDescription { - public List conditions; + public List conditions; [MustTranslate] public string text; } diff --git a/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs b/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs index de84903a..c64006e7 100644 --- a/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs +++ b/Source/WulaFallenEmpire/EventSystem/EventVariableManager.cs @@ -12,12 +12,17 @@ namespace WulaFallenEmpire private Dictionary stringVars = new Dictionary(); private Dictionary pawnVars = new Dictionary(); private Dictionary> pawnListVars = new Dictionary>(); + + // 新增:有时限的flag字典 + private Dictionary timedFlags = new Dictionary(); // 用于Scribe的辅助列表 private List pawnVarKeys; private List pawnVarValues; private List pawnListVarKeys; private List> pawnListVarValues; + private List timedFlagKeys; + private List timedFlagValues; // Required for WorldComponent public EventVariableManager(World world) : base(world) @@ -32,6 +37,7 @@ namespace WulaFallenEmpire Scribe_Collections.Look(ref stringVars, "stringVars", LookMode.Value, LookMode.Value); Scribe_Collections.Look(ref pawnVars, "pawnVars", LookMode.Value, LookMode.Reference, ref pawnVarKeys, ref pawnVarValues); Scribe_Collections.Look(ref pawnListVars, "pawnListVars", LookMode.Value, LookMode.Reference, ref pawnListVarKeys, ref pawnListVarValues); + Scribe_Collections.Look(ref timedFlags, "timedFlags", LookMode.Value, LookMode.Value, ref timedFlagKeys, ref timedFlagValues); // Ensure dictionaries are not null after loading if (Scribe.mode == LoadSaveMode.PostLoadInit) @@ -41,6 +47,43 @@ namespace WulaFallenEmpire stringVars ??= new Dictionary(); pawnVars ??= new Dictionary(); pawnListVars ??= new Dictionary>(); + timedFlags ??= new Dictionary(); + } + } + + public override void WorldComponentTick() + { + base.WorldComponentTick(); + + // 每60 tick检查一次过期flag + if (Find.TickManager.TicksGame % 60 == 0) + { + CheckExpiredFlags(); + } + } + + /// + /// 检查并清理过期的flag + /// + private void CheckExpiredFlags() + { + List flagsToRemove = new List(); + int currentTick = Find.TickManager.TicksGame; + + foreach (var kvp in timedFlags) + { + // 如果flag的过期时间不为负数且小于当前tick,则标记为需要移除 + if (kvp.Value >= 0 && currentTick >= kvp.Value) + { + flagsToRemove.Add(kvp.Key); + Log.Message($"[EventSystem] Flag '{kvp.Key}' expired and will be removed."); + } + } + + // 移除过期的flag + foreach (string flagName in flagsToRemove) + { + timedFlags.Remove(flagName); } } @@ -81,6 +124,80 @@ namespace WulaFallenEmpire } } + /// + /// 设置有时限的flag + /// + /// flag名称 + /// 持续时间(tick),负数表示永久 + public void SetTimedFlag(string flagName, int durationTicks) + { + if (string.IsNullOrEmpty(flagName)) return; + + int expiryTick; + if (durationTicks < 0) + { + // 负数表示永久flag + expiryTick = -1; + Log.Message($"[EventSystem] Setting permanent flag '{flagName}'."); + } + else + { + // 正数表示有时间限制的flag + expiryTick = Find.TickManager.TicksGame + durationTicks; + Log.Message($"[EventSystem] Setting timed flag '{flagName}' with duration {durationTicks} ticks (expires at tick {expiryTick})."); + } + + timedFlags[flagName] = expiryTick; + } + + /// + /// 检查flag是否存在且未过期 + /// + public bool HasFlag(string flagName) + { + if (string.IsNullOrEmpty(flagName)) return false; + + if (timedFlags.TryGetValue(flagName, out int expiryTick)) + { + if (expiryTick < 0) + { + // 永久flag + return true; + } + else + { + // 检查是否过期 + bool isActive = Find.TickManager.TicksGame < expiryTick; + if (!isActive) + { + // 如果过期了,移除它 + timedFlags.Remove(flagName); + Log.Message($"[EventSystem] Flag '{flagName}' has expired and was removed."); + } + return isActive; + } + } + return false; + } + + /// + /// 获取flag的剩余时间(tick) + /// + public int GetFlagRemainingTicks(string flagName) + { + if (string.IsNullOrEmpty(flagName) || !timedFlags.TryGetValue(flagName, out int expiryTick)) + return 0; + + if (expiryTick < 0) + { + // 永久flag + return -1; + } + + int remaining = expiryTick - Find.TickManager.TicksGame; + return remaining > 0 ? remaining : 0; + } + public T GetVariable(string name, T defaultValue = default) { if (string.IsNullOrEmpty(name)) return defaultValue; @@ -138,7 +255,8 @@ namespace WulaFallenEmpire floatVars.ContainsKey(name) || stringVars.ContainsKey(name) || pawnVars.ContainsKey(name) || - pawnListVars.ContainsKey(name); + pawnListVars.ContainsKey(name) || + timedFlags.ContainsKey(name); } public void ClearVariable(string name) @@ -152,6 +270,7 @@ namespace WulaFallenEmpire stringVars.Remove(name); pawnVars.Remove(name); pawnListVars.Remove(name); + timedFlags.Remove(name); } public void ClearAll() @@ -161,6 +280,7 @@ namespace WulaFallenEmpire stringVars.Clear(); pawnVars.Clear(); pawnListVars.Clear(); + timedFlags.Clear(); } public Dictionary GetAllVariables() @@ -171,7 +291,8 @@ namespace WulaFallenEmpire foreach (var kvp in stringVars) allVars[kvp.Key] = kvp.Value; foreach (var kvp in pawnVars) allVars[kvp.Key] = kvp.Value; foreach (var kvp in pawnListVars) allVars[kvp.Key] = kvp.Value; + foreach (var kvp in timedFlags) allVars[kvp.Key] = $"Flag (expires: {kvp.Value})"; return allVars; } } -} \ No newline at end of file +} diff --git a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs index 309e052f..0fe13585 100644 --- a/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs +++ b/Source/WulaFallenEmpire/Flyover/WULA_ShipArtillery/CompShipArtillery.cs @@ -24,20 +24,27 @@ namespace WulaFallenEmpire // 目标跟踪 private List previousTargets = new List(); - // 新增:微追踪目标列表 - private List microTrackingTargets = new List(); - private List microTrackingWeights = new List(); // 新增:权重列表 + // 优化:缓存目标列表,避免每帧重新计算 + private List cachedTargets = new List(); + private List cachedTargetWeights = new List(); + private int lastTargetUpdateTick = -9999; + private const int TARGET_UPDATE_INTERVAL = 60; // 每60 ticks更新一次目标列表 - // 新增:目标类型权重配置 - private const float PAWN_WEIGHT = 5.0f; // Pawn权重:5倍 - private const float OWNED_BUILDING_WEIGHT = 1.0f; // 有主建筑权重:1倍 - private const float UNOWNED_BUILDING_WEIGHT = 0.01f; // 无主建筑权重:0.01倍 - private const float OTHER_WEIGHT = 1.0f; // 其他目标权重:1倍 + // 优化:一轮炮击的目标缓存 + private IntVec3 currentVolleyCenter; + private List currentVolleyTargets = new List(); + private int currentVolleyIndex = 0; + + // 目标类型权重配置 + private const float PAWN_WEIGHT = 5.0f; + private const float OWNED_BUILDING_WEIGHT = 1.0f; + private const float UNOWNED_BUILDING_WEIGHT = 0.01f; + private const float WALL_WEIGHT = 0.001f; // 墙的权重极低 + private const float OTHER_WEIGHT = 1.0f; public override void Initialize(CompProperties props) { base.Initialize(props); - ticksUntilNextAttack = Props.ticksBetweenAttacks; Log.Message($"Ship Artillery initialized: {Props.ticksBetweenAttacks} ticks between attacks, {Props.attackRadius} radius"); @@ -51,10 +58,14 @@ namespace WulaFallenEmpire if (parent is not FlyOver flyOver || !flyOver.Spawned || flyOver.Map == null) return; - // 更新微追踪目标列表(如果需要) + // 优化:减少目标更新频率 if (Props.useMicroTracking && Props.useFactionDiscrimination) { - UpdateMicroTrackingTargets(flyOver); + if (Find.TickManager.TicksGame - lastTargetUpdateTick > TARGET_UPDATE_INTERVAL) + { + UpdateTargetCache(flyOver); + lastTargetUpdateTick = Find.TickManager.TicksGame; + } } // 更新预热状态 @@ -82,103 +93,99 @@ namespace WulaFallenEmpire } } - // 新增:更新微追踪目标列表 - private void UpdateMicroTrackingTargets(FlyOver flyOver) + // 优化:缓存目标列表 + private void UpdateTargetCache(FlyOver flyOver) { - microTrackingTargets.Clear(); - microTrackingWeights.Clear(); + cachedTargets.Clear(); + cachedTargetWeights.Clear(); Faction targetFaction = GetTargetFaction(flyOver); if (targetFaction == null) return; - // 获取飞越物体当前位置 IntVec3 center = GetFlyOverPosition(flyOver); - // 搜索范围内的所有潜在目标 - foreach (IntVec3 cell in GenRadial.RadialCellsAround(center, Props.attackRadius, true)) + // 优化:使用更高效的目标搜索 + var potentialTargets = GenRadial.RadialDistinctThingsAround(center, flyOver.Map, Props.attackRadius, true) + .Where(thing => IsValidMicroTrackingTarget(thing, targetFaction)) + .Distinct(); // 避免重复 + + foreach (Thing thing in potentialTargets) { - if (!cell.InBounds(flyOver.Map)) continue; - - // 检查建筑 - Building building = cell.GetEdifice(flyOver.Map); - if (building != null && IsValidMicroTrackingTarget(building, targetFaction)) - { - microTrackingTargets.Add(new LocalTargetInfo(building)); - float weight = GetTargetWeight(building); - microTrackingWeights.Add(weight); - } - - // 检查生物 - List thingList = cell.GetThingList(flyOver.Map); - foreach (Thing thing in thingList) - { - if (thing is Pawn pawn && IsValidMicroTrackingTarget(pawn, targetFaction)) - { - microTrackingTargets.Add(new LocalTargetInfo(pawn)); - float weight = GetTargetWeight(pawn); - microTrackingWeights.Add(weight); - } - } + cachedTargets.Add(new LocalTargetInfo(thing)); + cachedTargetWeights.Add(GetTargetWeight(thing)); } - // 移除重复目标(基于位置) - for (int i = microTrackingTargets.Count - 1; i >= 0; i--) + if (DebugSettings.godMode && cachedTargets.Count > 0) { - for (int j = 0; j < i; j++) - { - if (microTrackingTargets[i].Cell == microTrackingTargets[j].Cell) - { - microTrackingTargets.RemoveAt(i); - microTrackingWeights.RemoveAt(i); - break; - } - } - } - - if (DebugSettings.godMode) - { - Log.Message($"MicroTracking: Found {microTrackingTargets.Count} targets for faction {targetFaction.def.defName}"); - // 输出目标统计信息 - var targetStats = GetTargetStatistics(); - Log.Message($"Target Statistics - Pawns: {targetStats.pawnCount}, Owned Buildings: {targetStats.ownedBuildingCount}, Unowned Buildings: {targetStats.unownedBuildingCount}, Others: {targetStats.otherCount}"); + Log.Message($"Target Cache Updated: Found {cachedTargets.Count} targets"); + var stats = GetTargetStatistics(); + Log.Message($"Target Statistics - Pawns: {stats.pawnCount}, Owned Buildings: {stats.ownedBuildingCount}, Unowned Buildings: {stats.unownedBuildingCount}, Walls: {stats.wallCount}, Others: {stats.otherCount}"); } } - // 新增:获取目标权重 + // 优化:改进的目标有效性检查 + private bool IsValidMicroTrackingTarget(Thing thing, Faction targetFaction) + { + if (thing == null || thing.Destroyed) return false; + + // 修复1:无主建筑总是被排除 + if (thing is Building building && building.Faction == null) + return false; + + // 修复2:isWall的建筑总是不考虑 + if (thing.def?.building?.isWall == true) + return false; + + // 检查派系关系 + if (thing.Faction != null) + { + if (thing.Faction == targetFaction) return false; + if (thing.Faction.RelationKindWith(targetFaction) == FactionRelationKind.Ally) return false; + } + + // 检查保护范围 + if (Props.avoidPlayerAssets && IsNearPlayerAssets(thing.Position, thing.Map)) + return false; + + // 避免击中飞越物体本身 + if (Props.avoidHittingFlyOver && thing.Position.DistanceTo(parent.Position) < 10f) + return false; + + return true; + } + + // 优化:获取目标权重 private float GetTargetWeight(Thing thing) { if (thing is Pawn) - { return PAWN_WEIGHT; - } else if (thing is Building building) { + // 修复2:墙的权重极低 + if (building.def?.building?.isWall == true) + return WALL_WEIGHT; + if (building.Faction == null) - { return UNOWNED_BUILDING_WEIGHT; - } else - { return OWNED_BUILDING_WEIGHT; - } } else - { return OTHER_WEIGHT; - } } // 新增:获取目标统计信息 - private (int pawnCount, int ownedBuildingCount, int unownedBuildingCount, int otherCount) GetTargetStatistics() + private (int pawnCount, int ownedBuildingCount, int unownedBuildingCount, int wallCount, int otherCount) GetTargetStatistics() { int pawnCount = 0; int ownedBuildingCount = 0; int unownedBuildingCount = 0; + int wallCount = 0; int otherCount = 0; - for (int i = 0; i < microTrackingTargets.Count; i++) + foreach (var target in cachedTargets) { - Thing thing = microTrackingTargets[i].Thing; + Thing thing = target.Thing; if (thing == null) continue; if (thing is Pawn) @@ -187,7 +194,11 @@ namespace WulaFallenEmpire } else if (thing is Building building) { - if (building.Faction == null) + if (building.def?.building?.isWall == true) + { + wallCount++; + } + else if (building.Faction == null) { unownedBuildingCount++; } @@ -202,50 +213,20 @@ namespace WulaFallenEmpire } } - return (pawnCount, ownedBuildingCount, unownedBuildingCount, otherCount); + return (pawnCount, ownedBuildingCount, unownedBuildingCount, wallCount, otherCount); } - // 新增:检查是否为有效的微追踪目标 - private bool IsValidMicroTrackingTarget(Thing thing, Faction targetFaction) - { - if (thing == null || thing.Destroyed) return false; - - // 检查派系关系:目标派系的友军不应该被攻击 - if (thing.Faction != null) - { - if (thing.Faction == targetFaction) return false; - if (thing.Faction.RelationKindWith(targetFaction) == FactionRelationKind.Ally) return false; - } - - // 检查是否在保护范围内 - if (Props.avoidPlayerAssets && IsNearPlayerAssets(thing.Position, thing.Map)) - { - return false; - } - - // 避免击中飞越物体本身 - if (Props.avoidHittingFlyOver && thing.Position.DistanceTo(parent.Position) < 10f) - { - return false; - } - - return true; - } - - // 新增:获取目标派系 private Faction GetTargetFaction(FlyOver flyOver) { if (!Props.useFactionDiscrimination) return null; - // 如果指定了目标派系,使用指定的派系 if (Props.targetFaction != null) { Faction faction = Find.FactionManager.FirstFactionOfDef(Props.targetFaction); if (faction != null) return faction; } - // 否则使用玩家当前派系 return Faction.OfPlayer; } @@ -266,11 +247,15 @@ namespace WulaFallenEmpire Log.Message($"Ship Artillery starting attack on target area: {currentTarget} (attack radius: {Props.attackRadius})"); - // 开始预热 + // 修复3:在一轮炮击中,只进行一次目标选择 + currentVolleyCenter = currentTarget; + currentVolleyTargets.Clear(); + currentVolleyIndex = 0; + + // 预热阶段 isWarmingUp = true; warmupTicksRemaining = Props.warmupTicks; - // 启动预热效果 if (Props.warmupEffect != null) { warmupEffecter = Props.warmupEffect.Spawn(); @@ -282,19 +267,16 @@ namespace WulaFallenEmpire { warmupTicksRemaining--; - // 维持预热效果 if (warmupEffecter != null) { warmupEffecter.EffectTick(new TargetInfo(currentTarget, flyOver.Map), new TargetInfo(currentTarget, flyOver.Map)); } - // 生成预热粒子 if (Props.warmupFleck != null && Rand.MTBEventOccurs(0.1f, 1f, 1f)) { FleckMaker.Static(currentTarget.ToVector3Shifted(), flyOver.Map, Props.warmupFleck); } - // 预热完成,开始攻击 if (warmupTicksRemaining <= 0) { StartFiring(flyOver); @@ -307,11 +289,9 @@ namespace WulaFallenEmpire isAttacking = true; attackTicksRemaining = Props.attackDurationTicks; - // 清理预热效果 warmupEffecter?.Cleanup(); warmupEffecter = null; - // 启动攻击效果 if (Props.attackEffect != null) { attackEffecter = Props.attackEffect.Spawn(); @@ -333,26 +313,23 @@ namespace WulaFallenEmpire { attackTicksRemaining--; - // 维持攻击效果 if (attackEffecter != null) { attackEffecter.EffectTick(new TargetInfo(currentTarget, flyOver.Map), new TargetInfo(currentTarget, flyOver.Map)); } // 在攻击期间定期发射炮弹 - if (attackTicksRemaining % 60 == 0) // 每秒发射一次 + if (attackTicksRemaining % 60 == 0) { ExecuteVolley(flyOver); } - // 生成攻击粒子 if (Props.attackFleck != null && Rand.MTBEventOccurs(0.2f, 1f, 1f)) { Vector3 randomOffset = new Vector3(Rand.Range(-3f, 3f), 0f, Rand.Range(-3f, 3f)); FleckMaker.Static((currentTarget.ToVector3Shifted() + randomOffset), flyOver.Map, Props.attackFleck); } - // 攻击结束 if (attackTicksRemaining <= 0) { EndAttack(flyOver); @@ -361,17 +338,66 @@ namespace WulaFallenEmpire private void ExecuteVolley(FlyOver flyOver) { + // 修复3:为这一轮炮击生成所有目标 + if (currentVolleyTargets.Count == 0) + { + GenerateVolleyTargets(flyOver); + } + for (int i = 0; i < Props.shellsPerVolley; i++) { - FireShell(flyOver); + if (currentVolleyIndex < currentVolleyTargets.Count) + { + FireShell(flyOver, currentVolleyTargets[currentVolleyIndex]); + currentVolleyIndex++; + } + else + { + // 如果目标用完了,重新生成(对于持续攻击) + GenerateVolleyTargets(flyOver); + if (currentVolleyTargets.Count > 0) + { + FireShell(flyOver, currentVolleyTargets[0]); + currentVolleyIndex = 1; + } + } } } - private void FireShell(FlyOver flyOver) + // 修复3:生成一轮炮击的所有目标 + private void GenerateVolleyTargets(FlyOver flyOver) + { + currentVolleyTargets.Clear(); + currentVolleyIndex = 0; + + for (int i = 0; i < Props.shellsPerVolley * 3; i++) // 生成足够的目标 + { + IntVec3 target; + if (Props.useMicroTracking && Props.useFactionDiscrimination && cachedTargets.Count > 0) + { + target = SelectTargetFromCache(flyOver); + } + else + { + target = SelectRandomTargetInRadius(currentVolleyCenter, flyOver.Map, Props.attackRadius); + } + + if (target.IsValid && target.InBounds(flyOver.Map)) + { + currentVolleyTargets.Add(target); + } + } + + if (DebugSettings.godMode) + { + Log.Message($"Generated {currentVolleyTargets.Count} targets for volley around {currentVolleyCenter}"); + } + } + + private void FireShell(FlyOver flyOver, IntVec3 shellTarget) { try { - // 选择炮弹类型 ThingDef shellDef = SelectShellDef(); if (shellDef == null) { @@ -379,24 +405,14 @@ namespace WulaFallenEmpire return; } - // 选择目标 - IntVec3 shellTarget; - if (Props.useMicroTracking && Props.useFactionDiscrimination && microTrackingTargets.Count > 0) - { - shellTarget = SelectMicroTrackingTarget(flyOver); - } - else - { - shellTarget = SelectRandomTarget(flyOver); - } - - // 关键修复:使用 SkyfallerMaker 创建并立即生成 Skyfaller SkyfallerMaker.SpawnSkyfaller(shellDef, shellTarget, flyOver.Map); - float distanceFromCenter = shellTarget.DistanceTo(currentTarget); - Log.Message($"Ship Artillery fired shell at {shellTarget} (distance from center: {distanceFromCenter:F1})"); + float distanceFromCenter = shellTarget.DistanceTo(currentVolleyCenter); + if (DebugSettings.godMode) + { + Log.Message($"Ship Artillery fired shell at {shellTarget} (distance from center: {distanceFromCenter:F1})"); + } - // 播放音效 if (Props.attackSound != null) { Props.attackSound.PlayOneShot(new TargetInfo(shellTarget, flyOver.Map)); @@ -408,16 +424,15 @@ namespace WulaFallenEmpire } } - // 修改:微追踪目标选择 - 现在使用权重系统 - private IntVec3 SelectMicroTrackingTarget(FlyOver flyOver) + // 优化:从缓存中选择目标 + private IntVec3 SelectTargetFromCache(FlyOver flyOver) { - if (microTrackingTargets.Count == 0) + if (cachedTargets.Count == 0) { Log.Warning("MicroTracking: No targets available, falling back to random target"); - return SelectRandomTarget(flyOver); + return SelectRandomTargetInRadius(currentVolleyCenter, flyOver.Map, Props.attackRadius); } - // 使用权重系统选择目标 LocalTargetInfo selectedTarget = SelectTargetByWeight(); IntVec3 targetCell = selectedTarget.Cell; @@ -429,7 +444,6 @@ namespace WulaFallenEmpire offsetTarget.x += Mathf.RoundToInt(Mathf.Cos(angle * Mathf.Deg2Rad) * offsetDistance); offsetTarget.z += Mathf.RoundToInt(Mathf.Sin(angle * Mathf.Deg2Rad) * offsetDistance); - // 确保目标在地图内 if (!offsetTarget.InBounds(flyOver.Map)) { offsetTarget = targetCell; @@ -448,37 +462,34 @@ namespace WulaFallenEmpire return offsetTarget; } - // 新增:基于权重的目标选择 + // 基于权重的目标选择 private LocalTargetInfo SelectTargetByWeight() { - if (microTrackingTargets.Count == 0) + if (cachedTargets.Count == 0) return LocalTargetInfo.Invalid; - if (microTrackingTargets.Count == 1) - return microTrackingTargets[0]; + if (cachedTargets.Count == 1) + return cachedTargets[0]; - // 计算总权重 float totalWeight = 0f; - foreach (float weight in microTrackingWeights) + foreach (float weight in cachedTargetWeights) { totalWeight += weight; } - // 随机选择 float randomValue = Rand.Range(0f, totalWeight); float currentSum = 0f; - for (int i = 0; i < microTrackingTargets.Count; i++) + for (int i = 0; i < cachedTargets.Count; i++) { - currentSum += microTrackingWeights[i]; + currentSum += cachedTargetWeights[i]; if (randomValue <= currentSum) { - return microTrackingTargets[i]; + return cachedTargets[i]; } } - // 回退到最后一个目标 - return microTrackingTargets[microTrackingTargets.Count - 1]; + return cachedTargets[cachedTargets.Count - 1]; } private ThingDef SelectShellDef() @@ -512,26 +523,18 @@ namespace WulaFallenEmpire return launchPos; } - // 简化的目标选择 - 每次直接随机选择目标 - private IntVec3 SelectRandomTarget(FlyOver flyOver) + private IntVec3 SelectTarget(FlyOver flyOver) { IntVec3 center = GetFlyOverPosition(flyOver) + Props.targetOffset; return FindRandomTargetInRadius(center, flyOver.Map, Props.attackRadius); } - private IntVec3 SelectTarget(FlyOver flyOver) + // 简化的目标选择 - 每次直接随机选择目标 + private IntVec3 SelectRandomTargetInRadius(IntVec3 center, Map map, float radius) { - // 获取飞越物体当前位置作为基础中心 - IntVec3 flyOverPos = GetFlyOverPosition(flyOver); - IntVec3 center = flyOverPos + Props.targetOffset; - - Log.Message($"FlyOver position: {flyOverPos}, Center for targeting: {center}"); - - // 在攻击半径内选择随机目标 - return FindRandomTargetInRadius(center, flyOver.Map, Props.attackRadius); + return FindRandomTargetInRadius(center, map, radius); } - // 改进的飞越物体位置获取 private IntVec3 GetFlyOverPosition(FlyOver flyOver) { // 优先使用 DrawPos,因为它反映实际视觉位置 @@ -554,15 +557,13 @@ namespace WulaFallenEmpire // 目标查找逻辑 - 基于攻击半径 private IntVec3 FindRandomTargetInRadius(IntVec3 center, Map map, float radius) { - Log.Message($"Finding target around {center} with radius {radius}"); - - // 如果半径为0,直接返回中心 if (radius <= 0) return center; bool ignoreProtectionForThisTarget = Rand.Value < Props.ignoreProtectionChance; - for (int i = 0; i < 30; i++) + // 优化:减少尝试次数 + for (int i = 0; i < 15; i++) { // 在圆形区域内随机选择 float angle = Rand.Range(0f, 360f); @@ -582,12 +583,15 @@ namespace WulaFallenEmpire previousTargets.Add(potentialTarget); - float actualDistance = potentialTarget.DistanceTo(center); - Log.Message($"Found valid target at {potentialTarget} (distance from center: {actualDistance:F1})"); - - if (ignoreProtectionForThisTarget) + if (DebugSettings.godMode) { - Log.Warning($"Protection ignored for target selection! May target player assets."); + float actualDistance = potentialTarget.DistanceTo(center); + Log.Message($"Found valid target at {potentialTarget} (distance from center: {actualDistance:F1})"); + + if (ignoreProtectionForThisTarget) + { + Log.Warning($"Protection ignored for target selection! May target player assets."); + } } return potentialTarget; @@ -598,7 +602,7 @@ namespace WulaFallenEmpire // 回退:使用地图随机位置 Log.Warning("Could not find valid target in radius, using fallback"); CellRect mapRect = CellRect.WholeMap(map); - for (int i = 0; i < 10; i++) + for (int i = 0; i < 5; i++) { IntVec3 fallbackTarget = mapRect.RandomCell; if (IsValidTarget(fallbackTarget, map, ignoreProtectionForThisTarget)) @@ -731,6 +735,10 @@ namespace WulaFallenEmpire attackEffecter?.Cleanup(); attackEffecter = null; + // 清理缓存 + currentVolleyTargets.Clear(); + currentVolleyIndex = 0; + // 重置计时器 if (Props.continuousAttack && !flyOver.hasCompleted) { @@ -773,9 +781,13 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref isAttacking, "isAttacking", false); Scribe_Values.Look(ref isWarmingUp, "isWarmingUp", false); Scribe_Values.Look(ref currentTarget, "currentTarget"); + Scribe_Values.Look(ref currentVolleyCenter, "currentVolleyCenter"); + Scribe_Values.Look(ref currentVolleyIndex, "currentVolleyIndex"); + Scribe_Values.Look(ref lastTargetUpdateTick, "lastTargetUpdateTick", -9999); Scribe_Collections.Look(ref previousTargets, "previousTargets", LookMode.Value); - Scribe_Collections.Look(ref microTrackingTargets, "microTrackingTargets", LookMode.LocalTargetInfo); - Scribe_Collections.Look(ref microTrackingWeights, "microTrackingWeights", LookMode.Value); + Scribe_Collections.Look(ref cachedTargets, "cachedTargets", LookMode.LocalTargetInfo); + Scribe_Collections.Look(ref cachedTargetWeights, "cachedTargetWeights", LookMode.Value); + Scribe_Collections.Look(ref currentVolleyTargets, "currentVolleyTargets", LookMode.Value); } public override IEnumerable CompGetGizmosExtra() @@ -791,7 +803,14 @@ namespace WulaFallenEmpire yield return new Command_Action { defaultLabel = "Dev: Fire Single Shell", - action = () => FireShell(parent as FlyOver) + action = () => + { + if (parent is FlyOver flyOver) + { + IntVec3 target = SelectRandomTargetInRadius(GetFlyOverPosition(flyOver), flyOver.Map, Props.attackRadius); + FireShell(flyOver, target); + } + } }; yield return new Command_Action @@ -814,11 +833,14 @@ namespace WulaFallenEmpire // 显示派系甄别信息 Faction targetFaction = GetTargetFaction(flyOver); Log.Message($"Faction Discrimination: {Props.useFactionDiscrimination}, Target Faction: {targetFaction?.def.defName ?? "None"}"); - Log.Message($"Micro Tracking: {Props.useMicroTracking}, Targets Found: {microTrackingTargets.Count}"); + Log.Message($"Micro Tracking: {Props.useMicroTracking}, Targets Found: {cachedTargets.Count}"); // 显示目标统计 var stats = GetTargetStatistics(); - Log.Message($"Target Stats - Pawns: {stats.pawnCount}, Owned Buildings: {stats.ownedBuildingCount}, Unowned Buildings: {stats.unownedBuildingCount}, Others: {stats.otherCount}"); + Log.Message($"Target Stats - Pawns: {stats.pawnCount}, Owned Buildings: {stats.ownedBuildingCount}, Unowned Buildings: {stats.unownedBuildingCount}, Walls: {stats.wallCount}, Others: {stats.otherCount}"); + + // 显示炮击信息 + Log.Message($"Volley - Center: {currentVolleyCenter}, Targets: {currentVolleyTargets.Count}, Index: {currentVolleyIndex}"); } } }; @@ -828,26 +850,56 @@ namespace WulaFallenEmpire { yield return new Command_Action { - defaultLabel = $"Dev: Show Micro Targets ({microTrackingTargets.Count})", + defaultLabel = $"Dev: Show Cached Targets ({cachedTargets.Count})", action = () => { if (parent is FlyOver flyOver) { - for (int i = 0; i < microTrackingTargets.Count; i++) + for (int i = 0; i < cachedTargets.Count; i++) { - var target = microTrackingTargets[i]; - float weight = microTrackingWeights[i]; + var target = cachedTargets[i]; + float weight = cachedTargetWeights[i]; Thing thing = target.Thing; string type = thing is Pawn ? "Pawn" : thing is Building building ? (building.Faction == null ? "Unowned Building" : "Owned Building") : "Other"; - Log.Message($"Micro Target: {thing?.Label ?? "Unknown"} ({type}) at {target.Cell}, Weight: {weight:F2}"); + Log.Message($"Cached Target: {thing?.Label ?? "Unknown"} ({type}) at {target.Cell}, Weight: {weight:F2}"); } } } }; } + + // 显示当前炮击目标 + if (currentVolleyTargets.Count > 0) + { + yield return new Command_Action + { + defaultLabel = $"Dev: Show Volley Targets ({currentVolleyTargets.Count})", + action = () => + { + for (int i = 0; i < currentVolleyTargets.Count; i++) + { + Log.Message($"Volley Target {i}: {currentVolleyTargets[i]} ({(i == currentVolleyIndex ? "NEXT" : "queued")})"); + } + } + }; + } + + // 强制更新目标缓存 + yield return new Command_Action + { + defaultLabel = "Dev: Force Update Target Cache", + action = () => + { + if (parent is FlyOver flyOver) + { + UpdateTargetCache(flyOver); + Log.Message($"Force updated target cache: {cachedTargets.Count} targets found"); + } + } + }; } } @@ -863,5 +915,21 @@ namespace WulaFallenEmpire { currentTarget = target; } + + // 新增:获取当前状态信息 + public string GetStatusString() + { + if (parent is not FlyOver flyOver) + return "Invalid parent"; + + string status = isWarmingUp ? $"Warming up ({warmupTicksRemaining} ticks)" : + isAttacking ? $"Attacking ({attackTicksRemaining} ticks)" : + $"Next attack in {ticksUntilNextAttack} ticks"; + + string targetInfo = currentTarget.IsValid ? $"Target: {currentTarget}" : "No target"; + string volleyInfo = currentVolleyTargets.Count > 0 ? $", Volley: {currentVolleyIndex}/{currentVolleyTargets.Count}" : ""; + + return $"{status}, {targetInfo}{volleyInfo}"; + } } } diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs index 80fcdee1..31ff8394 100644 --- a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs +++ b/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs @@ -207,6 +207,112 @@ namespace WulaFallenEmpire { yield return new DroneGizmo(this); } + + // 更换武器按钮(仅当有装备武器时显示) + if (MechPawn.equipment?.Primary != null) + { + yield return CreateWeaponSwitchGizmo(); + } + } + + /// + /// 创建更换武器的Gizmo + /// + private Gizmo CreateWeaponSwitchGizmo() + { + Command_Action switchWeaponCommand = new Command_Action + { + defaultLabel = "WULA_SwitchWeapon".Translate(), + defaultDesc = "WULA_SwitchWeapon_Desc".Translate(), + icon = ContentFinder.Get("Wula/UI/Abilities/WULA_WeaponSwitchAbility", false) ?? BaseContent.BadTex, + action = SwitchWeapon + }; + + return switchWeaponCommand; + } + + /// + /// 更换武器逻辑 + /// + private void SwitchWeapon() + { + if (MechPawn == null || MechPawn.Destroyed || !MechPawn.Spawned) + return; + + try + { + // 1. 扔掉当前武器 + ThingWithComps currentWeapon = MechPawn.equipment?.Primary; + if (currentWeapon != null) + { + // 将武器扔在地上 + MechPawn.equipment.TryDropEquipment(currentWeapon, out ThingWithComps droppedWeapon, MechPawn.Position, true); + + if (Prefs.DevMode) + { + Log.Message($"[CompAutonomousMech] {MechPawn.LabelCap} dropped weapon: {currentWeapon.LabelCap}"); + } + } + + // 2. 从PawnKind允许的武器中生成新武器 + ThingDef newWeaponDef = GetRandomWeaponFromPawnKind(); + if (newWeaponDef != null) + { + // 生成新武器 + Thing newWeapon = ThingMaker.MakeThing(newWeaponDef); + if (newWeapon is ThingWithComps newWeaponWithComps) + { + // 使用 AddEquipment 方法装备新武器 + MechPawn.equipment.AddEquipment(newWeaponWithComps); + + Messages.Message("WULA_WeaponSwitched".Translate(MechPawn.LabelCap, newWeaponDef.LabelCap), + MechPawn, MessageTypeDefOf.PositiveEvent); + + if (Prefs.DevMode) + { + Log.Message($"[CompAutonomousMech] {MechPawn.LabelCap} equipped new weapon: {newWeaponDef.LabelCap}"); + } + } + } + else + { + Messages.Message("WULA_NoWeaponAvailable".Translate(MechPawn.LabelCap), + MechPawn, MessageTypeDefOf.NegativeEvent); + } + } + catch (System.Exception ex) + { + Log.Error($"[CompAutonomousMech] Error switching weapon for {MechPawn?.LabelCap}: {ex}"); + } + } + + /// + /// 从PawnKind允许的武器中随机获取一个武器定义 + /// + private ThingDef GetRandomWeaponFromPawnKind() + { + if (MechPawn.kindDef?.weaponTags == null || MechPawn.kindDef.weaponTags.Count == 0) + return null; + + // 收集所有匹配的武器 + List availableWeapons = new List(); + + foreach (string weaponTag in MechPawn.kindDef.weaponTags) + { + foreach (ThingDef thingDef in DefDatabase.AllDefs) + { + if (thingDef.IsWeapon && thingDef.weaponTags != null && thingDef.weaponTags.Contains(weaponTag)) + { + availableWeapons.Add(thingDef); + } + } + } + + if (availableWeapons.Count == 0) + return null; + + // 随机选择一个武器 + return availableWeapons.RandomElement(); } public void SetWorkMode(DroneWorkModeDef mode) diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/AreaShieldManager.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/AreaShieldManager.cs index 3424b995..335ec8ea 100644 --- a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/AreaShieldManager.cs +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/AreaShieldManager.cs @@ -16,11 +16,13 @@ namespace WulaFallenEmpire { if (map == null) yield break; + if (Find.TickManager.TicksGame - lastUpdateTick > UPDATE_INTERVAL_TICKS) { UpdateShieldCache(); lastUpdateTick = Find.TickManager.TicksGame; } + if (activeShieldsByMap.TryGetValue(map, out var shields)) { foreach (var shield in shields) @@ -30,36 +32,57 @@ namespace WulaFallenEmpire } } } + private static void UpdateShieldCache() { activeShieldsByMap.Clear(); + foreach (var map in Find.Maps) { if (map == null) continue; + var shieldSet = new HashSet(); + + // 搜索装备上的护盾 foreach (var pawn in map.mapPawns.AllPawnsSpawned) { if (pawn?.apparel == null || pawn.Destroyed) continue; + foreach (var apparel in pawn.apparel.WornApparel) { if (apparel == null || apparel.Destroyed) continue; + var shield = apparel.TryGetComp(); // 修改:只有立定且激活的护盾才加入缓存 - if (shield != null && shield.Active && !shield.IsWearerMoving) + if (shield != null && shield.Active && !shield.IsHolderMoving) { shieldSet.Add(shield); } } } + + // 搜索固定物品上的护盾(新增) + foreach (var thing in map.listerThings.AllThings) + { + if (thing == null || thing.Destroyed || thing is Apparel) + continue; + + var shield = thing.TryGetComp(); + if (shield != null && shield.Active) + { + shieldSet.Add(shield); + } + } + activeShieldsByMap[map] = shieldSet; } } public static void NotifyShieldStateChanged(ThingComp_AreaShield shield) { - if (shield?.Wearer?.Map != null) + if (shield?.Holder?.Map != null) { lastUpdateTick = 0; } diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/Gizmo_AreaShieldStatus.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/Gizmo_AreaShieldStatus.cs index e50718ab..6ccd2a74 100644 --- a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/Gizmo_AreaShieldStatus.cs +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/Gizmo_AreaShieldStatus.cs @@ -10,7 +10,8 @@ namespace WulaFallenEmpire public ThingComp_AreaShield shield; private static readonly Texture2D FullShieldBarTex = SolidColorMaterials.NewSolidColorMaterial(new Color(0.2f, 0.8f, 0.85f), ShaderDatabase.MetaOverlay).mainTexture as Texture2D; private static readonly Texture2D EmptyShieldBarTex = SolidColorMaterials.NewSolidColorMaterial(new Color(0.2f, 0.2f, 0.24f), ShaderDatabase.MetaOverlay).mainTexture as Texture2D; - // 新增:移动状态的颜色 + + // 新增:移动状态的颜色(仅对装备有效) private static readonly Texture2D MovingShieldBarTex = SolidColorMaterials.NewSolidColorMaterial(new Color(0.5f, 0.5f, 0.5f), ShaderDatabase.MetaOverlay).mainTexture as Texture2D; public override float GetWidth(float maxWidth) => 140f; @@ -39,11 +40,11 @@ namespace WulaFallenEmpire barTex = EmptyShieldBarTex; statusText = "ShieldOnCooldown".Translate(); } - else if (shield.IsWearerMoving) + else if (shield.IsEquipment && shield.IsHolderMoving) { - // 移动时显示灰色状态条和"移动中"文本 + // 移动时显示灰色状态条和"移动中"文本(仅对装备有效) barTex = MovingShieldBarTex; - statusText = "ShieldOfflineByMoving".Translate(); // 你可以根据需要修改这个文本 + statusText = "ShieldOfflineByMoving".Translate(); } else { diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs index 73985fd7..fd97d7c6 100644 --- a/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaShield/ThingComp_AreaShield.cs @@ -21,42 +21,205 @@ namespace WulaFallenEmpire private bool drawInterceptCone; public CompProperties_AreaShield Props => (CompProperties_AreaShield)props; + + // 回退机制:支持装备和普通物品 public Pawn Wearer => (parent as Apparel)?.Wearer; + public bool IsEquipment => parent is Apparel; + public bool IsStandalone => !IsEquipment; + + // 获取护盾持有者(回退机制) + public Thing Holder => IsEquipment ? (Thing)Wearer : parent; + public bool IsOnCooldown => ticksToReset > 0; public int HitPointsMax => Props.baseHitPoints; private bool initialized = false; private StunHandler stunner; - // 新增:移动状态检测 - public bool IsWearerMoving + // 材质定义 + private static readonly Material ForceFieldMat = MaterialPool.MatFrom("Other/ForceField", ShaderDatabase.MoteGlow); + private static readonly Material ForceFieldConeMat = MaterialPool.MatFrom("Other/ForceFieldCone", ShaderDatabase.MoteGlow); + private static readonly MaterialPropertyBlock MatPropertyBlock = new MaterialPropertyBlock(); + private const float TextureActualRingSizeFactor = 1.1601562f; + private static readonly Color InactiveColor = new Color(0.2f, 0.2f, 0.2f); + + // 护盾绘制方法 - 参考原版实现 + public override void CompDrawWornExtras() + { + base.CompDrawWornExtras(); + + if (!IsEquipment) return; // 只有装备使用这个方法 + + DrawShield(); + } + public override void PostDraw() + { + base.PostDraw(); + + if (IsEquipment) return; // 装备使用 CompDrawWornExtras + + DrawShield(); + } + /// + /// 统一的护盾绘制方法 - 参考原版实现 + /// + private void DrawShield() + { + if (!Active || Holder?.Map == null || Holder.Destroyed) + return; + Vector3 drawPos = GetHolderDrawPos(); + drawPos.y = AltitudeLayer.MoteOverhead.AltitudeFor(); + float currentAlpha = GetCurrentAlpha(); + if (currentAlpha > 0f) + { + // 参考原版:未激活但被选中时使用灰色 + Color color = (!Active && Find.Selector.IsSelected(parent)) ? InactiveColor : Props.color; + color.a *= currentAlpha; + MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); + + Matrix4x4 matrix = default; + float scale = Props.radius * 2f * TextureActualRingSizeFactor; + matrix.SetTRS(drawPos, Quaternion.identity, new Vector3(scale, 1f, scale)); + Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldMat, 0, null, 0, MatPropertyBlock); + } + // 添加拦截锥形效果 + float coneAlpha = GetCurrentConeAlpha(); + if (coneAlpha > 0f) + { + Color color = Props.color; + color.a *= coneAlpha; + MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); + + Matrix4x4 matrix = default; + float scale = Props.radius * 2f; + matrix.SetTRS(drawPos, Quaternion.Euler(0f, lastInterceptAngle - 90f, 0f), new Vector3(scale, 1f, scale)); + Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldConeMat, 0, null, 0, MatPropertyBlock); + } + } + /// + /// 获取当前透明度 - 参考原版的多状态叠加 + /// + private float GetCurrentAlpha() + { + // 多个透明度来源叠加,取最大值 + return Mathf.Max( + Mathf.Max( + Mathf.Max( + GetCurrentAlpha_Idle(), + GetCurrentAlpha_Selected() + ), + GetCurrentAlpha_RecentlyIntercepted() + ), + 0.1f // 最小透明度 + ); + } + /// + /// 空闲状态透明度 + /// + private float GetCurrentAlpha_Idle() + { + if (!Active) return 0f; + + // 固定物品:始终显示空闲状态 + if (IsStandalone) + { + // 脉冲效果 + return Mathf.Lerp(0.3f, 0.6f, + (Mathf.Sin((float)Gen.HashCombineInt(parent.thingIDNumber, 35990913) + Time.realtimeSinceStartup * 2f) + 1f) / 2f); + } + // 装备:只在特定条件下显示 + else if (IsEquipment) + { + // 装备护盾只在以下情况显示空闲状态: + if (Holder is Pawn pawn) + { + if (pawn.Drafted || pawn.InAggroMentalState || + (pawn.Faction != null && pawn.Faction.HostileTo(Faction.OfPlayer) && !pawn.IsPrisoner)) + { + return Mathf.Lerp(0.3f, 0.6f, + (Mathf.Sin((float)Gen.HashCombineInt(parent.thingIDNumber, 35990913) + Time.realtimeSinceStartup * 2f) + 1f) / 2f); + } + } + } + + return 0f; + } + /// + /// 被选中状态透明度 - 参考原版实现 + /// + private float GetCurrentAlpha_Selected() + { + // 如果被选中,显示更高的透明度 + if (Find.Selector.IsSelected(parent) && Active) + { + return Mathf.Lerp(0.4f, 0.8f, + (Mathf.Sin((float)Gen.HashCombineInt(parent.thingIDNumber, 96804938) + Time.realtimeSinceStartup * 2.5f) + 1f) / 2f); + } + + return 0f; + } + /// + /// 最近拦截状态透明度 + /// + private float GetCurrentAlpha_RecentlyIntercepted() + { + int ticksSinceIntercept = Find.TickManager.TicksGame - lastInterceptTicks; + return Mathf.Clamp01(1f - (float)ticksSinceIntercept / 40f) * 0.3f; + } + /// + /// 拦截锥形透明度 + /// + private float GetCurrentConeAlpha() + { + if (!drawInterceptCone) return 0f; + + int ticksSinceIntercept = Find.TickManager.TicksGame - lastInterceptTicks; + return Mathf.Clamp01(1f - (float)ticksSinceIntercept / 40f) * 0.82f; + } + /// + /// 获取持有者绘制位置(回退机制) + /// + private Vector3 GetHolderDrawPos() + { + if (Holder is Pawn pawn) + return pawn.Drawer?.DrawPos ?? pawn.Position.ToVector3Shifted(); + else + return Holder.DrawPos; + } + + // 移动状态检测(仅对装备有效) + public bool IsHolderMoving { get { + if (IsStandalone) return false; // 固定物品不会移动 if (Wearer == null || !Wearer.Spawned) return false; return Wearer.pather.Moving; } } - // 修改Active属性:只有在立定时才激活 + // 修改Active属性:装备只有在立定时才激活,固定物品始终激活 public bool Active { get { - if (Wearer == null || !Wearer.Spawned || Wearer.Dead || Wearer.Downed || IsOnCooldown) + if (Holder == null || !Holder.Spawned || Holder.Destroyed) return false; - // 新增:只有在立定时才激活 - if (IsWearerMoving) + + if (Holder is Pawn pawn && (pawn.Dead || pawn.Downed)) return false; + + if (IsOnCooldown) + return false; + + // 装备:只有在立定时才激活 + if (IsEquipment && IsHolderMoving) + return false; + return true; } } - // 材质定义 - private static readonly Material ForceFieldMat = MaterialPool.MatFrom("Other/ForceField", ShaderDatabase.MoteGlow); - private static readonly Material ForceFieldConeMat = MaterialPool.MatFrom("Other/ForceFieldCone", ShaderDatabase.MoteGlow); - private static readonly MaterialPropertyBlock MatPropertyBlock = new MaterialPropertyBlock(); - public override void PostPostMake() { base.PostPostMake(); @@ -84,7 +247,7 @@ namespace WulaFallenEmpire wasActiveLastCheck = isActive; } - if (Wearer == null) return; + if (Holder == null) return; if (IsOnCooldown) { @@ -125,14 +288,15 @@ namespace WulaFallenEmpire public bool TryIntercept(Projectile projectile, Vector3 lastExactPos, Vector3 newExactPos) { // 增强安全检查 - if (!Active || projectile == null || projectile.Destroyed || Wearer == null || Wearer.Map == null) + if (!Active || projectile == null || projectile.Destroyed || Holder == null || Holder.Map == null) return false; if (currentHitPoints <= 0) return false; + try { - if (!GenGeo.IntersectLineCircleOutline(Wearer.Position.ToVector2(), Props.radius, lastExactPos.ToVector2(), newExactPos.ToVector2())) + if (!GenGeo.IntersectLineCircleOutline(Holder.Position.ToVector2(), Props.radius, lastExactPos.ToVector2(), newExactPos.ToVector2())) { return false; } @@ -140,27 +304,27 @@ namespace WulaFallenEmpire return false; if (!projectile.def.projectile.flyOverhead && !Props.interceptGroundProjectiles) return false; - if (projectile.Launcher != null && !projectile.Launcher.HostileTo(Wearer.Faction) && !Props.interceptNonHostileProjectiles) + if (projectile.Launcher != null && !projectile.Launcher.HostileTo(Holder.Faction) && !Props.interceptNonHostileProjectiles) return false; lastInterceptTicks = Find.TickManager.TicksGame; // 记录拦截角度用于视觉效果 - lastInterceptAngle = projectile.ExactPosition.AngleToFlat(Wearer.TrueCenter()); + lastInterceptAngle = projectile.ExactPosition.AngleToFlat(GetHolderCenter()); drawInterceptCone = true; // 尝试反射 if (Props.canReflect && TryReflectProjectile(projectile, lastExactPos, newExactPos)) { // 反射成功,播放反射特效 - Props.reflectEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), Wearer.Map).Cleanup(); + Props.reflectEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), Holder.Map).Cleanup(); ApplyCosts(Props.reflectCost); return false; // 不销毁原抛射体,让它继续飞行(我们会在反射中销毁它) } else { // 普通拦截,播放拦截特效 - Props.interceptEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), Wearer.Map).Cleanup(); + Props.interceptEffecter?.Spawn(projectile.ExactPosition.ToIntVec3(), Holder.Map).Cleanup(); ApplyCosts(); return true; // 销毁抛射体 } @@ -172,6 +336,17 @@ namespace WulaFallenEmpire } } + /// + /// 获取持有者中心位置(回退机制) + /// + private Vector3 GetHolderCenter() + { + if (Holder is Pawn pawn) + return pawn.TrueCenter(); + else + return Holder.DrawPos; + } + /// /// 尝试反射抛射体 - 现在会创建新的抛射体 /// @@ -183,13 +358,14 @@ namespace WulaFallenEmpire // 检查反射概率 if (Rand.Value > Props.reflectChance) return false; + try { // 计算入射方向 Vector3 incomingDirection = (newExactPos - lastExactPos).normalized; // 计算法线方向(从护盾中心到碰撞点) - Vector3 normal = (newExactPos - Wearer.DrawPos).normalized; + Vector3 normal = (newExactPos - GetHolderCenter()).normalized; // 计算反射方向(镜面反射) Vector3 reflectDirection = Vector3.Reflect(incomingDirection, normal); @@ -216,28 +392,34 @@ namespace WulaFallenEmpire { try { - if (originalProjectile == null || originalProjectile.Destroyed || Wearer == null || Wearer.Map == null) + if (originalProjectile == null || originalProjectile.Destroyed || Holder == null || Holder.Map == null) return false; + // 计算新的发射位置(护盾位置附近) Vector3 spawnPosition = GetReflectSpawnPosition(collisionPoint); + // 确保位置在地图内 IntVec3 spawnCell = spawnPosition.ToIntVec3(); - if (!spawnCell.InBounds(Wearer.Map)) + if (!spawnCell.InBounds(Holder.Map)) { - spawnCell = Wearer.Position; + spawnCell = Holder.Position; } + // 计算新的目标位置 Vector3 targetPosition = spawnCell.ToVector3Shifted() + reflectDirection * 30f; IntVec3 targetCell = targetPosition.ToIntVec3(); + // 创建新的抛射体 - Projectile newProjectile = (Projectile)GenSpawn.Spawn(originalProjectile.def, spawnCell, Wearer.Map); + Projectile newProjectile = (Projectile)GenSpawn.Spawn(originalProjectile.def, spawnCell, Holder.Map); if (newProjectile == null) { Log.Warning("Failed to spawn reflected projectile"); return false; } - // 设置发射者为装备穿戴者 - Thing launcher = Wearer; + + // 设置发射者为护盾持有者 + Thing launcher = Holder; + // 发射新抛射体 newProjectile.Launch( launcher, @@ -247,11 +429,14 @@ namespace WulaFallenEmpire ProjectileHitFlags.All, false ); + // 复制重要的属性 CopyProjectileProperties(originalProjectile, newProjectile); + // 使用延迟销毁而不是立即销毁 ReflectedProjectileManager.MarkForDelayedDestroy(originalProjectile); - Log.Message($"反射抛射体: 由 {Wearer?.LabelShort} 从 {spawnCell} 向 {targetCell} 发射"); + + Log.Message($"反射抛射体: 由 {Holder?.LabelShort} 从 {spawnCell} 向 {targetCell} 发射"); return true; } catch (System.Exception ex) @@ -266,15 +451,15 @@ namespace WulaFallenEmpire /// private Vector3 GetReflectSpawnPosition(Vector3 collisionPoint) { - if (Wearer == null) + if (Holder == null) return collisionPoint; // 计算从护盾中心到碰撞点的方向 - Vector3 directionFromCenter = (collisionPoint - Wearer.DrawPos).normalized; + Vector3 directionFromCenter = (collisionPoint - GetHolderCenter()).normalized; // 在护盾边界上生成(稍微向内一点避免立即再次碰撞) float spawnDistance = Props.radius * 0.9f; - Vector3 spawnPosition = Wearer.DrawPos + directionFromCenter * spawnDistance; + Vector3 spawnPosition = GetHolderCenter() + directionFromCenter * spawnDistance; return spawnPosition; } @@ -310,26 +495,26 @@ namespace WulaFallenEmpire public override void PostPreApplyDamage(ref DamageInfo dinfo, out bool absorbed) { absorbed = false; - if (!Active || Wearer == null) return; + if (!Active || Holder == null) return; if (dinfo.Def.isRanged) return; if (dinfo.Instigator != null) { - float distance = Wearer.Position.DistanceTo(dinfo.Instigator.Position); + float distance = Holder.Position.DistanceTo(dinfo.Instigator.Position); if (distance > Props.radius) return; } if (currentHitPoints <= 0) return; - Props.absorbEffecter?.Spawn(Wearer.Position, Wearer.Map).Cleanup(); + Props.absorbEffecter?.Spawn(Holder.Position, Holder.Map).Cleanup(); ApplyCosts(); absorbed = true; } private void Break() { - Props.breakEffecter?.Spawn(Wearer.Position, Wearer.Map).Cleanup(); + Props.breakEffecter?.Spawn(Holder.Position, Holder.Map).Cleanup(); ticksToReset = Props.rechargeDelay; currentHitPoints = 0; AreaShieldManager.NotifyShieldStateChanged(this); @@ -337,85 +522,50 @@ namespace WulaFallenEmpire private void Reset() { - if (Wearer != null && Wearer.Spawned) + if (Holder != null && Holder.Spawned) { - Props.reactivateEffecter?.Spawn(Wearer.Position, Wearer.Map).Cleanup(); + Props.reactivateEffecter?.Spawn(Holder.Position, Holder.Map).Cleanup(); } currentHitPoints = HitPointsMax; AreaShieldManager.NotifyShieldStateChanged(this); } - // 护盾绘制方法 - 只有在立定时才绘制 - public override void CompDrawWornExtras() - { - base.CompDrawWornExtras(); - - // 修改:移动时不绘制护盾 - if (!Active || Wearer?.Map == null || !ShouldDisplay || IsWearerMoving) - return; - - Vector3 drawPos = Wearer.Drawer?.DrawPos ?? Wearer.Position.ToVector3Shifted(); - drawPos.y = AltitudeLayer.MoteOverhead.AltitudeFor(); - - float alpha = GetCurrentAlpha(); - if (alpha > 0f) - { - Color color = Props.color; - color.a *= alpha; - MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); - Matrix4x4 matrix = default; - - float scale = Props.radius * 2f * 1.1601562f; - matrix.SetTRS(drawPos, Quaternion.identity, new Vector3(scale, 1f, scale)); - Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldMat, 0, null, 0, MatPropertyBlock); - } - - // 添加拦截锥形效果 - float coneAlpha = GetCurrentConeAlpha(); - if (coneAlpha > 0f) - { - Color color = Props.color; - color.a *= coneAlpha; - MatPropertyBlock.SetColor(ShaderPropertyIDs.Color, color); - Matrix4x4 matrix = default; - float scale = Props.radius * 2f; - matrix.SetTRS(drawPos, Quaternion.Euler(0f, lastInterceptAngle - 90f, 0f), new Vector3(scale, 1f, scale)); - Graphics.DrawMesh(MeshPool.plane10, matrix, ForceFieldConeMat, 0, null, 0, MatPropertyBlock); - } - } - - // 显示条件 + // 显示条件 - 修改为固定物品始终显示,装备有条件显示 protected bool ShouldDisplay { get { - if (Wearer == null || !Wearer.Spawned || Wearer.Dead || Wearer.Downed || !Active) + if (Holder == null || !Holder.Spawned || Holder.Destroyed || !Active) return false; - - if (Wearer.Drafted || Wearer.InAggroMentalState || - (Wearer.Faction != null && Wearer.Faction.HostileTo(Faction.OfPlayer) && !Wearer.IsPrisoner)) + + // 对于装备:只在特定条件下显示 + if (IsEquipment && Holder is Pawn pawn) + { + if (pawn.Dead || pawn.Downed) + return false; + + // 装备护盾只在以下情况显示: + // 1. 穿戴者被选中 + // 2. 穿戴者处于战斗状态(征召状态或敌对) + // 3. 穿戴者处于攻击性精神状态 + if (Find.Selector.IsSelected(pawn)) + return true; + + if (pawn.Drafted || pawn.InAggroMentalState) + return true; + + if (pawn.Faction != null && pawn.Faction.HostileTo(Faction.OfPlayer) && !pawn.IsPrisoner) + return true; + } + // 对于固定物品:始终显示(只要护盾激活) + else if (IsStandalone) + { return true; - - if (Find.Selector.IsSelected(Wearer)) - return true; - + } + return false; } } - - private float GetCurrentAlpha() - { - float idleAlpha = Mathf.Lerp(0.3f, 0.6f, (Mathf.Sin((float)Gen.HashCombineInt(parent.thingIDNumber, 35990913) + Time.realtimeSinceStartup * 2f) + 1f) / 2f); - float interceptAlpha = Mathf.Clamp01(1f - (float)(Find.TickManager.TicksGame - lastInterceptTicks) / 40f); - return Mathf.Max(idleAlpha, interceptAlpha); - } - - private float GetCurrentConeAlpha() - { - if (!drawInterceptCone) return 0f; - return Mathf.Clamp01(1f - (float)(Find.TickManager.TicksGame - lastInterceptTicks) / 40f) * 0.82f; - } - private void EnsureInitialized() { if (initialized) return; @@ -433,7 +583,18 @@ namespace WulaFallenEmpire { EnsureInitialized(); - if (Wearer != null && Find.Selector.SingleSelectedThing == Wearer) + if (IsEquipment && Wearer != null && Find.Selector.SingleSelectedThing == Wearer) + { + yield return new Gizmo_AreaShieldStatus { shield = this }; + } + } + + public override IEnumerable CompGetGizmosExtra() + { + EnsureInitialized(); + + // 固定物品也显示护盾状态 + if (IsStandalone && Find.Selector.SingleSelectedThing == parent) { yield return new Gizmo_AreaShieldStatus { shield = this }; } diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompPlaySoundOnSpawn.cs b/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompPlaySoundOnSpawn.cs new file mode 100644 index 00000000..85f641e9 --- /dev/null +++ b/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompPlaySoundOnSpawn.cs @@ -0,0 +1,187 @@ +using RimWorld; +using Verse; +using Verse.Sound; +using System.Collections.Generic; + +namespace WulaFallenEmpire +{ + public class CompPlaySoundOnSpawn : ThingComp + { + private CompProperties_PlaySoundOnSpawn Props => (CompProperties_PlaySoundOnSpawn)props; + + private bool soundPlayed = false; + private int delayTicksRemaining = 0; + + public override void Initialize(CompProperties props) + { + base.Initialize(props); + + // 计算延迟的 ticks + if (Props.delaySeconds > 0) + { + delayTicksRemaining = (int)(Props.delaySeconds * 60f); + } + } + + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + + // 如果是重新加载存档,不播放声音 + if (respawningAfterLoad) + return; + + // 检查播放条件 + if (!ShouldPlaySound()) + return; + + // 如果有延迟,设置延迟计数器 + if (Props.delaySeconds > 0) + { + delayTicksRemaining = (int)(Props.delaySeconds * 60f); + } + else + { + // 立即播放声音 + PlaySound(); + } + } + + public override void CompTick() + { + base.CompTick(); + + // 处理延迟播放 + if (delayTicksRemaining > 0 && !soundPlayed) + { + delayTicksRemaining--; + if (delayTicksRemaining <= 0) + { + PlaySound(); + } + } + } + + private bool ShouldPlaySound() + { + if (soundPlayed) + return false; + + if (Props.sound == null) + return false; + + // 检查派系条件 + if (parent.Faction != null) + { + if (Props.onlyIfPlayerFaction && parent.Faction != Faction.OfPlayer) + return false; + + if (Props.onlyIfHostileFaction && parent.Faction.RelationKindWith(Faction.OfPlayer) != FactionRelationKind.Hostile) + return false; + + if (Props.onlyIfNeutralFaction && parent.Faction.RelationKindWith(Faction.OfPlayer) != FactionRelationKind.Neutral) + return false; + } + else + { + // 如果没有派系,检查是否要求特定派系 + if (Props.onlyIfPlayerFaction || Props.onlyIfHostileFaction || Props.onlyIfNeutralFaction) + return false; + } + + return true; + } + + private void PlaySound() + { + if (soundPlayed || Props.sound == null) + return; + + try + { + SoundInfo soundInfo; + + if (Props.playOnCamera) + { + // 在摄像机位置播放 + soundInfo = SoundInfo.OnCamera(); + } + else if (Props.playAtThingPosition) + { + // 在物体位置播放 + soundInfo = SoundInfo.InMap(new TargetInfo(parent.Position, parent.Map)); + } + else + { + // 默认在物体位置播放 + soundInfo = SoundInfo.InMap(new TargetInfo(parent.Position, parent.Map)); + } + + // 应用音量和音调设置 + if (Props.volume != 1f) + soundInfo.volumeFactor = Props.volume; + + if (Props.pitch != 1f) + soundInfo.pitchFactor = Props.pitch; + + // 播放声音 + Props.sound.PlayOneShot(soundInfo); + soundPlayed = true; + + // 调试日志 + if (Prefs.DevMode) + { + Log.Message($"Played spawn sound: {Props.sound.defName} for {parent.Label} at {parent.Position}"); + } + } + catch (System.Exception ex) + { + Log.Error($"Error playing spawn sound for {parent.Label}: {ex}"); + } + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref soundPlayed, "soundPlayed", false); + Scribe_Values.Look(ref delayTicksRemaining, "delayTicksRemaining", 0); + } + + // 调试工具 + public override IEnumerable CompGetGizmosExtra() + { + if (DebugSettings.ShowDevGizmos) + { + yield return new Command_Action + { + defaultLabel = "Dev: Test Spawn Sound", + defaultDesc = $"Play sound: {Props.sound?.defName ?? "None"}", + action = () => + { + if (Props.sound != null) + { + PlaySound(); + } + else + { + Log.Warning("No sound defined for CompPlaySoundOnSpawn"); + } + } + }; + + yield return new Command_Action + { + defaultLabel = $"Dev: Sound Status - Played: {soundPlayed}, Delay: {delayTicksRemaining}", + action = () => {} + }; + } + } + + // 重置状态(用于重新播放) + public void Reset() + { + soundPlayed = false; + delayTicksRemaining = Props.delaySeconds > 0 ? (int)(Props.delaySeconds * 60f) : 0; + } + } +} diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompProperties_PlaySoundOnSpawn.cs b/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompProperties_PlaySoundOnSpawn.cs new file mode 100644 index 00000000..90760f61 --- /dev/null +++ b/Source/WulaFallenEmpire/ThingComp/WULA_PlaySoundOnSpawn/CompProperties_PlaySoundOnSpawn.cs @@ -0,0 +1,31 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_PlaySoundOnSpawn : CompProperties + { + public SoundDef sound; + + // 可选:延迟播放声音(秒) + public float delaySeconds = 0f; + + // 可选:只在特定条件下播放 + public bool onlyIfPlayerFaction = false; + public bool onlyIfHostileFaction = false; + public bool onlyIfNeutralFaction = false; + + // 可选:音量控制 + public float volume = 1f; + public float pitch = 1f; + + // 可选:播放位置 + public bool playOnCamera = false; // 在摄像机位置播放 + public bool playAtThingPosition = true; // 在物体位置播放 + + public CompProperties_PlaySoundOnSpawn() + { + compClass = typeof(CompPlaySoundOnSpawn); + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 994afeb9..3a98a251 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -117,13 +117,15 @@ - + + + @@ -266,6 +268,8 @@ + + diff --git a/美术与文本源文件/Wula/Building/WULA_Support_Shield_Building.sai2 b/美术与文本源文件/Wula/Building/WULA_Support_Shield_Building.sai2 new file mode 100644 index 00000000..b3ec89a6 Binary files /dev/null and b/美术与文本源文件/Wula/Building/WULA_Support_Shield_Building.sai2 differ diff --git a/美术与文本源文件/Wula/UI/Abilities/WULA_CallBattleShip.sai2 b/美术与文本源文件/Wula/UI/Abilities/WULA_CallBattleShip.sai2 index 48a81bda..5cb4a50c 100644 Binary files a/美术与文本源文件/Wula/UI/Abilities/WULA_CallBattleShip.sai2 and b/美术与文本源文件/Wula/UI/Abilities/WULA_CallBattleShip.sai2 differ