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
+
+
+
+
+
+
+
+ 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
+ DLa-1"页岩"
+ 乌拉帝国的基础突击步枪,仍然使用可靠的导气式结构驱动自动射击构件,是一种便宜但好用的武器,通常派发给殖民地作自卫武器之用。
+ 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