diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index 3e60e2b2..e5ad8c5a 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/HediffDefs/WULA_Misc_Hediffs.xml b/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
index b825b08b..01fecea4 100644
--- a/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
+++ b/1.6/1.6/Defs/HediffDefs/WULA_Misc_Hediffs.xml
@@ -202,6 +202,32 @@
+
+ WULA_MechShutdown
+ HediffWithComps
+
+ This mech has stopped due to insufficient fuel, need to assign a colonist to refuel it to restore its operational capability.
+ This mech has stopped due to insufficient fuel.
+
+ 0.01
+ 1
+ true
+ true
+ true
+ true
+
+
+
+
+
+ Moving
+ 0.1
+
+
+
+
+
+
WULA_MechCarrierSwitchHediff
diff --git a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
index 7d85f771..79489a62 100644
--- a/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
+++ b/1.6/1.6/Defs/JobDefs/WULA_JobDefs.xml
@@ -86,7 +86,7 @@
false -->
- WULA_Refuel
+ WULA_RefuelMech
refuel Mechs
WulaFallenEmpire.WorkGiver_RefuelMech
Hauling
diff --git a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
index d85a59d1..6f5f3ee5 100644
--- a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
+++ b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml
@@ -179,6 +179,7 @@
PlayerColony
false
true
+ false
Wula/Things/Wula_Mech_Mobile_Factory/Flying/Wula_Mech_Mobile_Factory_Flying_
1
diff --git a/1.6/1.6/Defs/StatDefs/WULA_Stats.xml b/1.6/1.6/Defs/StatDefs/WULA_Stats.xml
index 59021daa..e7d6ff9b 100644
--- a/1.6/1.6/Defs/StatDefs/WULA_Stats.xml
+++ b/1.6/1.6/Defs/StatDefs/WULA_Stats.xml
@@ -133,4 +133,17 @@
true
WulaFallenEmpire.StatWorker_Maintenance
+
+
+
+ WULA_MechArmor
+ 复合装甲层
+ 乌拉帝国在大型战争机械和少部分护甲上使用的特殊防御装甲,当 护甲穿透乘数 * 攻击 的最终值小于此值时,该攻击将被完全抵消而不造成任何伤害。
+ Apparel
+ FloatTwo
+ 0
+ 0
+ 0
+ 5000
+
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
index 59bf4d02..42a240e4 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Machine_Weapon.xml
@@ -477,9 +477,17 @@
200
12
-
+
Wula_AI_Heavy_Panzer_Weapon
+
+
+
+
+ Wula_AI_Heavy_Panzer
+
+
+
Bullet_Wula_AI_Heavy_Panzer_Main_Weapon
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 85cb6430..610a2796 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
@@ -1,6 +1,5 @@
-
Wula_Human
human
@@ -225,7 +224,6 @@
-
0
@@ -785,7 +783,6 @@
-
BulletImpact_Metal
@@ -877,7 +874,6 @@
-
5
@@ -1099,695 +1095,6 @@
-
- Wula_AI_Heavy_Panzer
- HAp-6"战车"
- 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。
- Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Heavy_Panzer_Icon
-
-
-
- Wula_AI_Heavy_Panzer_Main_Weapon
-
- true
- true
-
-
- false
-
-
-
- 1
- 2
- 2
- 0
-
- 9999
- 0
-
- 1
- 1
- 2
-
-
- 300
- 18
- 2
-
-
- WULA_AI_Heavy_Panzer_Body
- 20
-
-
- MechanoidFullyFormed
- 0
- Pawn_Wula_AI_Heavy_Panzer_Call
-
-
- 10
-
- 1
- Heavy
-
-
-
-
- 碾压
-
- Blunt
-
- 360
- 8
- Torso
- true
-
-
-
-
- 0
- Wula_AI_Heavy_Panzer_Turret_Weapon
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (7, 7)
- 20
- Any
-
-
- -90
-
-
- -90
-
-
- -90
-
-
- 90
-
-
-
-
-
-
- 36000
- 5.2
- 5.4
- 0.02
- 4.0
- false
-
-
-
-
-
- Drafted
-
-
- WULA_Hover_FlyNorth
- WULA_Hover_FlyEast
- WULA_Hover_FlySouth
-
-
- 1.5
- 30
- Crush
- 3
- false
- false
- false
- true
- false
- false
- false
- 碾压伤害
- HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
- Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
-
-
-
-
- Wula_AI_Rocket_Panzer
- HRp-3"喷火战车"
- 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢,但是未像其姊妹型号那样装备护盾。
- Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Rocket_Panzer_Icon
-
-
-
- Wula_AI_Heavy_Panzer_Main_Weapon
-
- true
- true
-
-
- false
-
-
-
- 1
- 2
- 2
- 0
-
- 9999
- 0
-
- 1
- 1
- 2
-
-
- 300
- 18
- 2
-
-
- WULA_AI_Heavy_Panzer_Body
- 20
-
-
- MechanoidFullyFormed
- 0
- Pawn_Wula_AI_Heavy_Panzer_Call
-
-
- 10
-
- 1
- Heavy
-
-
-
-
- 碾压
-
- Blunt
-
- 360
- 8
- Torso
- true
-
-
-
-
- 0
- Wula_AI_Rocket_Panzer_Turret_Weapon
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (7, 7)
- 20
- Any
-
-
- -90
-
-
- -90
-
-
- -90
-
-
- 90
-
-
-
-
-
-
-
-
-
- Drafted
-
-
- WULA_Hover_FlyNorth
- WULA_Hover_FlyEast
- WULA_Hover_FlySouth
-
-
- 1.5
- 30
- Crush
- 3
- false
- false
- false
- true
- false
- false
- false
- 碾压伤害
- HRp-3"喷火战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
- Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
-
-
-
-
- Wula_Mech_Mobile_Shield
- MSm-8"放射盾"
- 乌拉帝国的中型战争机械,常被用于镇压异族聚居地的暴动。它形状非常奇怪,根本分不出头在哪,但是不要因此小瞧这个机械体——其强大的立场盾能护佑一片区域并反射大量炮火,机体放射出来的辐射则会点燃进入反射盾范围内的敌人。在相关许可开放后,它甚至可以支持机械乌拉使用其内置的相位场进行区域传送,使其获得无与伦比的机动性。
-
-
- true
- true
-
-
- false
-
-
-
- 1
- 3
-
- 0.5
- 0.5
- 2
-
-
- WULA_Mech_Mobile_Shield_Body
- 50
-
-
- MechanoidFullyFormed
- 0
- Pawn_Wula_Mech_Mobile_Factory_Call
-
-
- 5
- Heavy
-
-
-
- 碾压
-
- Blunt
-
- 360
- 8
- Torso
- true
-
-
-
-
-
- 15
- 300
- 2400
- 30
-
-
- Interceptor_BlockedProjectile
- Interceptor_BlockedProjectile
- Shield_Break
- BulletShieldGenerator_Reactivate
-
- (0.9, 0.2, 0.2, 0.5)
-
-
- true
- false
- true
-
-
- true
- 0.85
- 30
- 0
- Interceptor_BlockedProjectile
-
-
- 15
- 30
- Flame
- 8
- false
- false
- false
- true
- false
- false
- false
- 热辐射
- MSm-8"放射盾"可以打开外壳,蒸发胆敢进入反射立场内的敌军——这同时会使得它伤害附近所有的散落物品。
- Wula/UI/Commands/Wula_Psi_Titan_AreaDamage
-
-
-
- 15
- 60
-
-
- WulaSpecies
-
- true
-
- Skip_Entry
- Skip_Exit
- Psycast_Skip_Entry
-
- true
- WULA_Mech_Mobile_Shield_Teleporter_Technology
-
-
-
-
- Wula_Mech_Mobile_Factory
- MFm-2"陆行舰"
- 乌拉帝国的大型战争机械,简直就是一座移动堡垒——它不仅装甲厚实、火炮林立,还能在战场上生产大量的辅助战争机械以形成坚实的弹性阵线,生来就是为了粉碎坚固的要塞和顽强的抵抗。
-
-
-
- WULA_RW_Unlimit_Penetrating_Beam_Cannon
-
- true
- true
-
-
- false
-
-
-
- 1
- 1
- 5
-
- 9999
- 0
-
- 1.75
- 1.75
- 2
-
-
- WULA_Mech_Mobile_Factory_Body
- 50
-
-
- MechanoidFullyFormed
- 0
- Pawn_Wula_Mech_Mobile_Factory_Call
-
-
- 25
-
- 1
- Heavy
-
-
-
-
- 碾压
-
- Blunt
-
- 360
- 8
- Torso
- true
-
-
-
-
- 0
- Wula_CR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (-1, 0, -1.45)
- true
- -5
-
-
- 90
- -5
- (3.25, 0, -1)
-
-
- -90
- (1.5, 0, -1.45)
-
-
- 90
- (-3.25, 0, -1)
-
-
-
-
-
-
- 1
- Wula_CR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (1, 0, -1.45)
- -5
-
-
- -90
- (3.25, 0, -1)
-
-
- -90
- (-1.6, 0, -1.45)
-
-
- 90
- (-3.25, 0, -1)
- -5
-
-
-
-
-
-
- 2
- Wula_MR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (-1.3, 0, -0.45)
- true
- -5
-
-
- 90
- -5
- (2.4, 0, -0.35)
-
-
- -90
- (2.3, 0, -0.45)
-
-
- 90
- (-2.4, 0, -0.35)
-
-
-
-
-
-
- 3
- Wula_MR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (1.3, 0, -0.45)
- true
- -5
-
-
- -90
- (2.4, 0, -0.35)
-
-
- -90
- (-2.3, 0, -0.45)
-
-
- 90
- -5
- (-2.4, 0, -0.35)
-
-
-
-
-
-
- 4
- Wula_LR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (1.25, 0, 0.45)
- true
- -5
-
-
- 90
- -5
- (1.6, 0, 0.25)
-
-
- -90
- (-2.15, 0, 0.65)
-
-
- 90
- (-1.6, 0, 0.25)
-
-
-
-
-
-
- 5
- Wula_LR_Mobile_Factory_Turret
-
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
- -90
- (-1.25, 0, 0.45)
- true
- -5
-
-
- -90
- (1.6, 0, 0.25)
-
-
- -90
- (2.05, 0, 0.65)
-
-
- 90
- -5
- (-1.6, 0, 0.25)
-
-
-
-
-
-
-
- 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
-
-
-
-
-
- Drafted
-
-
- WULA_Hover_FlyNorth
- WULA_Hover_FlyEast
- WULA_Hover_FlySouth
-
-
- 3.5
- 30
- Crush
- 4
- false
- false
- false
- true
- false
- false
- false
- 碾压伤害
- MFm-2"陆行舰"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
- Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
-
-
-
WULA_Mech_Flyer
CRm-51"兵蚁"
@@ -2004,7 +1311,6 @@
-
WULA_Fxxk_Goose
神人大鹅
diff --git a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
index a935b9a5..7af5ee83 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/WULA_Mechunit_Race.xml
@@ -56,7 +56,6 @@
0.1
-
WulaFallenEmpire.ITab_MechSkills
ITab_Pawn_Health
@@ -66,25 +65,11 @@
-
- Wula_AI_Heavy_Panzer
+
+ Wula_AI_Heavy_Panzer
HAp-6"战车"
-
- Wula/Things/Wula_AI_Heavy_Panzer/Wula_AI_Heavy_Panzer_Icon
-
-
-
- Wula_AI_Heavy_Panzer_Main_Weapon
-
- true
- true
-
-
- false
-
-
+ 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。
- 1
2
2
0
@@ -101,21 +86,18 @@
18
2
+
+ 300
+ 18
+ 2
+
WULA_AI_Heavy_Panzer_Body
20
-
-
- MechanoidFullyFormed
- 0
- Pawn_Wula_AI_Heavy_Panzer_Call
-
-
+ Wula_Battle_Mech_With_1_Pilot
10
1
- Heavy
-
@@ -167,11 +149,10 @@
4.0
false
-
- Drafted
+ DraftedAndMove
WULA_Hover_FlyNorth
@@ -194,46 +175,17 @@
HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
-
-
-
- Wula_Basic_Panzer
- DHM70-Rampart
- 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,使用破坏力巨大的自动炮和车体臼炮打击敌方,是乌拉帝国前锋部队的中流砥柱。
-
- 3.25
- 17500
- 0.35
- 1.25
- 1.25
- 1.5
-
-
- 2
-
-
- DD_Race_DHM69_Scythe_Body
- DD_Battle_Mech_With_3_Pilot
- 10
- 5
-
-
- 500
- 300
- 12
-
-
-
- 3
+
+ 1
MechPilot
0.1
- DivineDiurganate/UI/Commands/DD_Enter_Mech
- DivineDiurganate/UI/Commands/DD_Exit_Mech
+ WulaFallenEmpire/UI/Commands/DD_Enter_Mech
+ WulaFallenEmpire/UI/Commands/DD_Exit_Mech
-
+
Chemfuel
70
35
@@ -248,7 +200,7 @@
true
-
+
true
1
@@ -257,10 +209,10 @@
ConstructMetal
-
- DD_DHM70_Rampart_Mech_Weapon
+
+ Wula_AI_Heavy_Panzer_Main_Weapon
-
+
true
false
@@ -271,18 +223,18 @@
- DD_Ratkin_Pilot
+ Wula_PIA_Light_Unit
1
false
-
+
0
1
-
+
-
+
-
- 0.1
+
+ 0.1
120~180
true
-
11.5
Flame
5
@@ -321,72 +272,22 @@
true
1
-
-
Explosion_Bomb
-
true
true
- 0
+ 0
-
- 0
- DD_DHM69_Scythe_MG_Turret
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
-
-
- 1
- DD_DHM69_Scythe_MG_Turret
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
-
-
- 2
- DD_DHM69_Scythe_MG_Turret
-
-
- PawnRenderNode_TurretGun
- PawnRenderNodeWorker_TurretGun
- Body
- (2, 2)
- 20
- Any
-
-
-
-
-
-
+
1
false
-
-
DD_DHM70_Rampart_Mech_Prototype
@@ -396,59 +297,940 @@
false
-
+ -->
+
+
+
+
+
+ Wula_AI_Rocket_Panzer
+ HRp-3"喷火战车"
+ 乌拉帝国的中型战争机械,以悬浮的方式穿梭于战场之上,拥有车体臼炮和两具可以发射大量燃烧火箭弹的转轮导弹巢,但是未像其姊妹型号那样装备护盾。
+
+ 2
+ 2
+ 0
+
+ 9999
+ 0
+
+ 1
+ 1
+ 2
+
+
+ 300
+ 18
+ 2
+
+
+ 300
+ 18
+ 2
+
+
+ WULA_AI_Heavy_Panzer_Body
+ 20
+ Wula_Battle_Mech_With_1_Pilot
+ 10
+
+ 1
+
+
+
+ 碾压
+
+ Blunt
+
+ 360
+ 8
+ Torso
+ true
+
+
+
+
+ 0
+ Wula_AI_Rocket_Panzer_Turret_Weapon
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (7, 7)
+ 20
+ Any
+
+
+ -90
+
+
+ -90
+
+
+ -90
+
+
+ 90
+
+
+
+
+
+
+
+
+ DraftedAndMove
+
+
+ WULA_Hover_FlyNorth
+ WULA_Hover_FlyEast
+ WULA_Hover_FlySouth
+
+
+ 1.5
+ 30
+ Crush
+ 3
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ 碾压伤害
+ HAp-6"战车"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
+ Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
+
+
+
+ 1
+ MechPilot
+
+ 0.1
+
+ WulaFallenEmpire/UI/Commands/DD_Enter_Mech
+ WulaFallenEmpire/UI/Commands/DD_Exit_Mech
+
+
+ Chemfuel
+ 70
+ 35
+
+ 1
+ 240
+
+ (0.6, 0.5, 0.4)
+
+ true
+ 1
+
+ true
+
+
+ true
+ 1
+
+ 10
+
+
+ ConstructMetal
+
+
+ Wula_AI_Heavy_Panzer_Main_Weapon
+
+
+ true
+ false
+
+ 1.0
+ true
+ false
+ 3
+
+
+
+ Wula_PIA_Light_Unit
+ 1
+ false
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+ 0.1
+ 120~180
+ true
+
+ 11.5
+ Flame
+ 5
+ 2
+ 0.25
+ true
+ true
+ true
+ 1
+
+ Explosion_Bomb
+
+ true
+ true
+ 0
+
+
+
+
+
+
+ Wula_Mech_Mobile_Shield
+ MSm-8"放射盾"
+ 乌拉帝国的中型战争机械,常被用于镇压异族聚居地的暴动。它形状非常奇怪,根本分不出头在哪,但是不要因此小瞧这个机械体——其强大的立场盾能护佑一片区域并反射大量炮火,机体放射出来的辐射则会点燃进入反射盾范围内的敌人。
+
+ 3
+
+ 0.5
+ 0.5
+ 2
+
+
+ 300
+ 18
+ 2
+ 50
+
+
+ 300
+ 18
+ 2
+ 50
+
+
+ WULA_Mech_Mobile_Shield_Body
+ 20
+ Wula_Battle_Mech_With_1_Pilot
+ 5
+
+
+
+ 碾压
+
+ Blunt
+
+ 360
+ 8
+ Torso
+ true
+
+
+
+
+ 15
+ 300
+ 2400
+ 30
+
+
+ Interceptor_BlockedProjectile
+ Interceptor_BlockedProjectile
+ Shield_Break
+ BulletShieldGenerator_Reactivate
+
+ (0.9, 0.2, 0.2, 0.5)
+
+
+ true
+ false
+ true
+
+
+ true
+ 0.85
+ 30
+ 0
+ Interceptor_BlockedProjectile
+
+
+ 15
+ 30
+ Flame
+ 8
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ 热辐射
+ MSm-8"放射盾"可以打开外壳,蒸发胆敢进入反射立场内的敌军——这同时会使得它伤害附近所有的散落物品。
+ Wula/UI/Commands/Wula_Psi_Titan_AreaDamage
+
+
+
+
+ 1
+ MechPilot
+
+ 0.1
+
+ WulaFallenEmpire/UI/Commands/DD_Enter_Mech
+ WulaFallenEmpire/UI/Commands/DD_Exit_Mech
+
+
+ Chemfuel
+ 70
+ 35
+
+ 1
+ 240
+
+ (0.6, 0.5, 0.4)
+
+ true
+ 1
+
+ true
+
+
+ true
+ 1
+
+ 10
+
+
+ ConstructMetal
+
+
+ Wula_AI_Heavy_Panzer_Main_Weapon
+
+
+ true
+ false
+
+ 1.0
+ true
+ false
+ 3
+
+
+
+ Wula_PIA_Light_Unit
+ 1
+ false
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+ 0.1
+ 120~180
+ true
+
+ 11.5
+ Flame
+ 5
+ 2
+ 0.25
+ true
+ true
+ true
+ 1
+
+ Explosion_Bomb
+
+ true
+ true
+ 0
+
+
+
+
+
+
+ Wula_Mech_Mobile_Factory
+ MFm-2"陆行舰"
+ 乌拉帝国的大型战争机械,简直就是一座移动堡垒——它不仅装甲厚实、火炮林立,还能在战场上生产大量的辅助战争机械以形成坚实的弹性阵线,生来就是为了粉碎坚固的要塞和顽强的抵抗。
+
+ 1
+ 5
+
+ 9999
+ 0
+
+ 1.75
+ 1.75
+ 2
+
+
+ 300
+ 18
+ 2
+
+
+ 300
+ 18
+ 2
+
+
+ WULA_Mech_Mobile_Factory_Body
+ 50
+ Wula_Battle_Mech_With_1_Pilot
+ 10
+
+ 1
+
+
+
+ 碾压
+
+ Blunt
+
+ 360
+ 8
+ Torso
+ true
+
+
+
+
+ 0
+ Wula_CR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (-1, 0, -1.45)
+ true
+ -5
+
+
+ 90
+ -5
+ (3.25, 0, -1)
+
+
+ -90
+ (1.5, 0, -1.45)
+
+
+ 90
+ (-3.25, 0, -1)
+
+
+
+
+
+
+ 1
+ Wula_CR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (1, 0, -1.45)
+ -5
+
+
+ -90
+ (3.25, 0, -1)
+
+
+ -90
+ (-1.6, 0, -1.45)
+
+
+ 90
+ (-3.25, 0, -1)
+ -5
+
+
+
+
+
+
+ 2
+ Wula_MR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (-1.3, 0, -0.45)
+ true
+ -5
+
+
+ 90
+ -5
+ (2.4, 0, -0.35)
+
+
+ -90
+ (2.3, 0, -0.45)
+
+
+ 90
+ (-2.4, 0, -0.35)
+
+
+
+
+
+
+ 3
+ Wula_MR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (1.3, 0, -0.45)
+ true
+ -5
+
+
+ -90
+ (2.4, 0, -0.35)
+
+
+ -90
+ (-2.3, 0, -0.45)
+
+
+ 90
+ -5
+ (-2.4, 0, -0.35)
+
+
+
+
+
+
+ 4
+ Wula_LR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (1.25, 0, 0.45)
+ true
+ -5
+
+
+ 90
+ -5
+ (1.6, 0, 0.25)
+
+
+ -90
+ (-2.15, 0, 0.65)
+
+
+ 90
+ (-1.6, 0, 0.25)
+
+
+
+
+
+
+ 5
+ Wula_LR_Mobile_Factory_Turret
+
+
+
+ PawnRenderNode_TurretGun
+ PawnRenderNodeWorker_TurretGun
+ Body
+ (2, 2)
+ 20
+ Any
+
+
+ -90
+ (-1.25, 0, 0.45)
+ true
+ -5
+
+
+ -90
+ (1.6, 0, 0.25)
+
+
+ -90
+ (2.05, 0, 0.65)
+
+
+ 90
+ -5
+ (-1.6, 0, 0.25)
+
+
+
+
+
+
+ 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
+
+
+
+
+ DraftedAndMove
+
+
+ WULA_Hover_FlyNorth
+ WULA_Hover_FlyEast
+ WULA_Hover_FlySouth
+
+
+ 3.5
+ 30
+ Crush
+ 4
+ false
+ false
+ false
+ true
+ false
+ false
+ false
+ 碾压伤害
+ MFm-2"陆行舰"可以将舰身稍微下沉一些并创造低压区,以碾压靠近的敌军——这同时会使得它伤害附近所有的散落物品。
+ Wula/UI/Commands/Wula_Mech_Mobile_Factory_AreaDamage
+
+
+
+ 1
+ MechPilot
+
+ 0.1
+
+ WulaFallenEmpire/UI/Commands/DD_Enter_Mech
+ WulaFallenEmpire/UI/Commands/DD_Exit_Mech
+
+
+ Chemfuel
+ 70
+ 35
+
+ 1
+ 240
+
+ (0.6, 0.5, 0.4)
+
+ true
+ 1
+
+ true
+
+
+ true
+ 1
+
+ 10
+
+
+ ConstructMetal
+
+
+ Wula_AI_Heavy_Panzer_Main_Weapon
+
+
+ true
+ false
+
+ 1.0
+ true
+ false
+ 3
+
+
+
+ Wula_PIA_Light_Unit
+ 1
+ false
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+ 0.1
+ 120~180
+ true
+
+ 11.5
+ Flame
+ 5
+ 2
+ 0.25
+ true
+ true
+ true
+ 1
+
+ Explosion_Bomb
+
+ true
+ true
+ 0
+
+
+
-
- DD_DHM70_Rampart_Mech
- DHM70-Rampart
- DD_DHM70_Rampart_Mech
- PlayerColony
- false
- false
- false
- 800
-
- DD_DHM70_Rampart_Mech_Weapon
-
- 99999~99999
-
-
-
- DivineDiurganate/Things/DD_DHM70_Rampart/Naked_Thin
- 6.5
-
- (2 ,2, 0.8)
- (0,0,-0.15)
-
-
-
-
-
-
- DD_DHM70_Rampart_Mech_Prototype
- DHM70-Rampart Prototype
- DD_DHM70_Rampart_Mech
- PlayerColony
- false
- false
- false
- 900
-
- DD_DHM70_Rampart_Mech_Weapon
-
- 99999~99999
-
-
-
- DivineDiurganate/Things/DD_DHM70_Rampart/Prototype
- 6.5
-
- (2 ,2, 0.8)
- (0,0,-0.15)
-
-
-
-
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ThinkTreeDefs/WULA_ThinkTrees.xml b/1.6/1.6/Defs/ThinkTreeDefs/WULA_ThinkTrees.xml
index 16ec116b..bde0a03f 100644
--- a/1.6/1.6/Defs/ThinkTreeDefs/WULA_ThinkTrees.xml
+++ b/1.6/1.6/Defs/ThinkTreeDefs/WULA_ThinkTrees.xml
@@ -560,4 +560,99 @@
+
+
+ Wula_Battle_Mech_With_1_Pilot
+
+
+
+
+ Despawned
+
+
+
+
+
+
+
+
+
+
+
+ Downed
+
+
+
+
+ 1
+
+
+
+
+
+
+
+ BerserkMechanoid
+
+
+
+
+
+ Deadly
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DraftedOrder
+
+
+
+
+
+
+
+
+
+
+ LordDuty
+
+
+
+
+
+
+ Idle
+
+
+ None
+
+
+
+
+
+
+
+
+ Idle
+
+
+ Deadly
+
+
+
+
+
+
+
+
+
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/Hediff_Mechlink_PostAdd_Patch.cs b/Source/WulaFallenEmpire/HarmonyPatches/Hediff_Mechlink_PostAdd_Patch.cs
index ac2986de..3a6149bc 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/Hediff_Mechlink_PostAdd_Patch.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/Hediff_Mechlink_PostAdd_Patch.cs
@@ -5,7 +5,7 @@ using Verse;
namespace ArachnaeSwarm
{
[HarmonyPatch(typeof(Hediff_Mechlink), "PostAdd")]
- public static class Hediff_Mechlink_PostAdd_Patch
+ public static class Hediff_Mechlink_PostAWULA_Patch
{
public static bool Prefix(Hediff_Mechlink __instance, DamageInfo? dinfo)
{
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_ColonistBarMech.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_ColonistBarMech.cs
index cdcec392..9f448009 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_ColonistBarMech.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_ColonistBarMech.cs
@@ -131,7 +131,7 @@ namespace WulaFallenEmpire
}
catch (System.Exception ex)
{
- Log.Error($"[DD] Error in fixed ColonistBar patch: {ex}");
+ Log.Error($"[WULA] Error in fixed ColonistBar patch: {ex}");
// 出错时不改变原列表
}
}
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_MechSpecificWeapon.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_MechSpecificWeapon.cs
index a2b4b048..aff65f78 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_MechSpecificWeapon.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_MechSpecificWeapon.cs
@@ -34,7 +34,7 @@ namespace WulaFallenEmpire
else
{
// 此机甲不在允许列表中
- cantReason = "DD_Equipment_For_Other_Mech".Translate();
+ cantReason = "WULA_Equipment_For_Other_Mech".Translate();
__result = false;
return false;
}
@@ -42,7 +42,7 @@ namespace WulaFallenEmpire
else
{
// 非机甲尝试装备专用武器,禁止
- cantReason = "DD_Human_Cannot_Equip_Mech_Weapon".Translate();
+ cantReason = "WULA_Human_Cannot_Equip_Mech_Weapon".Translate();
__result = false;
return false;
}
@@ -54,7 +54,7 @@ namespace WulaFallenEmpire
if (pawn is Wulamechunit)
{
// 机甲不能装备普通武器
- cantReason = "DD_Equipment_Not_Allow_For_Mech".Translate();
+ cantReason = "WULA_Equipment_Not_Allow_For_Mech".Translate();
__result = false;
return false;
}
@@ -66,7 +66,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] CanEquip patch error: {ex}");
+ Log.Error($"[WULA] CanEquip patch error: {ex}");
return true;
}
}
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_RomanceFix.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_RomanceFix.cs
index 2d42f528..aeb8e82c 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_RomanceFix.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_RomanceFix.cs
@@ -80,14 +80,14 @@ namespace WulaFallenEmpire
// 如果任一pawn是机甲单位,返回拒绝
if (initiator is Wulamechunit || target is Wulamechunit)
{
- __result = new AcceptanceReport("DD_MechCannotRomance".Translate());
+ __result = new AcceptanceReport("WULA_MechCannotRomance".Translate());
return false; // 跳过原始方法
}
// 如果任一pawn没有story组件,返回拒绝
if (initiator?.story == null || target?.story == null)
{
- __result = new AcceptanceReport("DD_NoStoryComponent".Translate());
+ __result = new AcceptanceReport("WULA_NoStoryComponent".Translate());
return false;
}
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_TakeDamage.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_TakeDamage.cs
index b761647c..62201f3f 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_TakeDamage.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_TakeDamage.cs
@@ -17,7 +17,7 @@ namespace WulaFallenEmpire.HarmonyPatches
public static class Thing_TakeDamage_Patch
{
// 缓存装甲值StatDef
- private static readonly StatDef ArmorStatDef = StatDef.Named("DD_MechArmor");
+ private static readonly StatDef ArmorStatDef = StatDef.Named("WULA_MechArmor");
// 阻挡效果的MoteDef
private static readonly ThingDef BlockMoteDef = DefDatabase.GetNamedSilentFail("Mote_Spark");
@@ -102,7 +102,7 @@ namespace WulaFallenEmpire.HarmonyPatches
// 显示文字效果
Vector3 textPos = target.DrawPos + new Vector3(0, 0, 1f);
- MoteMaker.ThrowText(textPos, target.Map, "DD_BlockByMechArmor".Translate(), Color.yellow, 2.5f);
+ MoteMaker.ThrowText(textPos, target.Map, "WULA_BlockByMechArmor".Translate(), Color.yellow, 2.5f);
// 显示粒子效果
if (BlockMoteDef != null)
diff --git a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_mechunit.cs b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_mechunit.cs
index 238de388..ef4e4bef 100644
--- a/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_mechunit.cs
+++ b/Source/WulaFallenEmpire/HarmonyPatches/WULA_MechUnit/Patch_mechunit.cs
@@ -277,7 +277,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] Harmony patch error in TryMeleeAttack: {ex}");
+ Log.Error($"[WULA] Harmony patch error in TryMeleeAttack: {ex}");
return true; // ʱִԭʼ
}
}
diff --git a/Source/WulaFallenEmpire/HediffComp/WULA_SyncedWithMech/HediffCompProperties_SyncedWithMech.cs b/Source/WulaFallenEmpire/HediffComp/WULA_SyncedWithMech/HediffCompProperties_SyncedWithMech.cs
index 3b9afd4b..516cf358 100644
--- a/Source/WulaFallenEmpire/HediffComp/WULA_SyncedWithMech/HediffCompProperties_SyncedWithMech.cs
+++ b/Source/WulaFallenEmpire/HediffComp/WULA_SyncedWithMech/HediffCompProperties_SyncedWithMech.cs
@@ -42,7 +42,7 @@ namespace WulaFallenEmpire
}
else if (Prefs.DevMode)
{
- Log.Warning($"[DD] OnPilotEnteredMech: 参数不是Wulamechunit类型: {mech?.GetType().Name}");
+ Log.Warning($"[WULA] OnPilotEnteredMech: 参数不是Wulamechunit类型: {mech?.GetType().Name}");
}
}
@@ -203,7 +203,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 在机甲{mech.LabelShort}上添加Hediff时出错: {ex}");
+ Log.Error($"[WULA] 在机甲{mech.LabelShort}上添加Hediff时出错: {ex}");
}
}
@@ -220,7 +220,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 从机甲{mech.LabelShort}移除Hediff时出错: {ex}");
+ Log.Error($"[WULA] 从机甲{mech.LabelShort}移除Hediff时出错: {ex}");
}
}
@@ -242,7 +242,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 触发同步效果时出错: {ex}");
+ Log.Error($"[WULA] 触发同步效果时出错: {ex}");
}
}
diff --git a/Source/WulaFallenEmpire/ITab/ITab_MechSkills.cs b/Source/WulaFallenEmpire/ITab/ITab_MechSkills.cs
index e495e336..4008fd4a 100644
--- a/Source/WulaFallenEmpire/ITab/ITab_MechSkills.cs
+++ b/Source/WulaFallenEmpire/ITab/ITab_MechSkills.cs
@@ -25,7 +25,7 @@ namespace WulaFallenEmpire
public ITab_MechSkills()
{
this.size = new Vector2(520f, 600f);
- this.labelKey = "DD_MechSkills".Translate();
+ this.labelKey = "WULA_MechSkills".Translate();
}
protected override void FillTab()
@@ -36,7 +36,7 @@ namespace WulaFallenEmpire
if (pawn.TryGetComp() == null)
{
- DrawError("DD_NoMechSkillComps".Translate());
+ DrawError("WULA_NoMechSkillComps".Translate());
return;
}
@@ -226,7 +226,7 @@ namespace WulaFallenEmpire
);
string status = GetStatus(pawn);
- string type = "DD_Mech".Translate();
+ string type = "WULA_Mech".Translate();
Widgets.Label(statusRect, $"{type} | {status}");
GUI.color = Color.white;
@@ -248,7 +248,7 @@ namespace WulaFallenEmpire
);
Text.Font = GameFont.Medium;
- Widgets.Label(titleRect, "DD_PilotTitle".Translate());
+ Widgets.Label(titleRect, "WULA_PilotTitle".Translate());
Text.Font = GameFont.Small;
// 内容
@@ -268,12 +268,12 @@ namespace WulaFallenEmpire
if (pilot != null) pilotNames.Add(pilot.LabelShort);
}
var pilotNamelist = string.Join(", ", pilotNames);
- Widgets.Label(contentRect, $"DD_PilotInfo".Translate(pilotNamelist));
+ Widgets.Label(contentRect, $"WULA_PilotInfo".Translate(pilotNamelist));
}
else
{
GUI.color = Color.gray;
- Widgets.Label(contentRect, "DD_NoPilotShort".Translate());
+ Widgets.Label(contentRect, "WULA_NoPilotShort".Translate());
GUI.color = Color.white;
}
}
@@ -307,7 +307,7 @@ namespace WulaFallenEmpire
if (pawn.skills == null || pawn.skills.skills.Count == 0)
{
GUI.color = Color.gray;
- Widgets.Label(skillsArea.ContractedBy(padding * 2), "DD_MechNoSkill".Translate());
+ Widgets.Label(skillsArea.ContractedBy(padding * 2), "WULA_MechNoSkill".Translate());
GUI.color = Color.white;
return;
}
@@ -412,9 +412,9 @@ namespace WulaFallenEmpire
var pilotComp = pawn.TryGetComp();
if (pilotComp == null || !pilotComp.HasPilots)
- return "DD_NoPilot".Translate();
+ return "WULA_NoPilot".Translate();
- return "DD_Operational".Translate();
+ return "WULA_Operational".Translate();
}
private void DrawError(string message)
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalBreakWorker_BrokenPersonality.cs b/Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalBreakWorker_BrokenPersonality.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalBreakWorker_BrokenPersonality.cs
rename to Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalBreakWorker_BrokenPersonality.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalStateDefExtension_BrokenPersonality.cs b/Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalStateDefExtension_BrokenPersonality.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalStateDefExtension_BrokenPersonality.cs
rename to Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalStateDefExtension_BrokenPersonality.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalState_BrokenPersonality.cs b/Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalState_BrokenPersonality.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_BrokenPersonality/MentalState_BrokenPersonality.cs
rename to Source/WulaFallenEmpire/MentalState/BrokenPersonality/MentalState_BrokenPersonality.cs
diff --git a/Source/WulaFallenEmpire/MentalState/MentalState_MechNoPilot.cs b/Source/WulaFallenEmpire/MentalState/MentalState_MechNoPilot.cs
new file mode 100644
index 00000000..56eb3aed
--- /dev/null
+++ b/Source/WulaFallenEmpire/MentalState/MentalState_MechNoPilot.cs
@@ -0,0 +1,62 @@
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class MentalState_MechNoPilot : MentalState
+ {
+ public override void PostStart(string reason)
+ {
+ base.PostStart(reason);
+
+ // 停止所有工作和移动
+ pawn.jobs?.StopAll();
+ pawn.pather?.StopDead();
+
+ // 取消征召
+ if (pawn.drafter != null && pawn.Drafted)
+ {
+ pawn.drafter.Drafted = false;
+ }
+
+ // 清除当前敌人目标
+ pawn.mindState.enemyTarget = null;
+ }
+
+ public override void PostEnd()
+ {
+ base.PostEnd();
+ }
+
+ public override void MentalStateTick(int delta)
+ {
+ // 使用父类的tick逻辑,但不允许自动恢复
+ if (pawn.IsHashIntervalTick(30, delta))
+ {
+ age += 30;
+
+ // 只有在有驾驶员时才允许恢复
+ // 检查会由 CompMechPilotHolder 处理
+ // 这里不实现自动恢复逻辑
+ }
+ }
+
+ // 重写以禁用敌对行为
+ public override bool ForceHostileTo(Thing t)
+ {
+ return false;
+ }
+
+ public override bool ForceHostileTo(Faction f)
+ {
+ return false;
+ }
+
+ // 重写以禁用社交活动
+ public override RandomSocialMode SocialModeMax()
+ {
+ return RandomSocialMode.Off;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn/Mechunit.cs b/Source/WulaFallenEmpire/Pawn/Mechunit.cs
index 75e2c988..68aae6c4 100644
--- a/Source/WulaFallenEmpire/Pawn/Mechunit.cs
+++ b/Source/WulaFallenEmpire/Pawn/Mechunit.cs
@@ -63,7 +63,7 @@ namespace WulaFallenEmpire
var pilotComp = this.TryGetComp();
if (pilotComp != null && !pilotComp.HasPilots)
{
- Messages.Message("DD_CannotDraftWithoutPilot".Translate(this.LabelShort),
+ Messages.Message("WULA_CannotDraftWithoutPilot".Translate(this.LabelShort),
this, MessageTypeDefOf.RejectInput);
return;
}
@@ -101,7 +101,7 @@ namespace WulaFallenEmpire
var pilotComp = this.TryGetComp();
if (pilotComp != null && !pilotComp.HasPilots)
{
- command_Toggle.Disable("DD_NoPilot".Translate());
+ command_Toggle.Disable("WULA_NoPilot".Translate());
}
command_Toggle.tutorTag = ((!base.Drafted) ? "Draft" : "Undraft");
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/CompAutoMechCarrier.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/CompAutoMechCarrier.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/CompAutoMechCarrier.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/CompAutoMechCarrier.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/CompProperties_AutoMechCarrier.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/CompProperties_AutoMechCarrier.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/CompProperties_AutoMechCarrier.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/CompProperties_AutoMechCarrier.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/PawnProductionEntry.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/PawnProductionEntry.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutoMechCarrier/PawnProductionEntry.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutoMechCarrier/PawnProductionEntry.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/CompAutonomousMech.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/CompAutonomousMech.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/CompAutonomousMech.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/DroneGizmo.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/DroneGizmo.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/DroneGizmo.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/DroneGizmo.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_DroneSelfShutdown.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/JobGiver_DroneSelfShutdown.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/JobGiver_DroneSelfShutdown.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/JobGiver_DroneSelfShutdown.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/PawnColumnWorker_DroneEnergy.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/PawnColumnWorker_DroneEnergy.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/PawnColumnWorker_DroneEnergy.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/PawnColumnWorker_DroneEnergy.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/PawnColumnWorker_DroneWorkMode.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/PawnColumnWorker_DroneWorkMode.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/PawnColumnWorker_DroneWorkMode.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/PawnColumnWorker_DroneWorkMode.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalAutonomousWorkMode.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalAutonomousWorkMode.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalAutonomousWorkMode.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalAutonomousWorkMode.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalLowEnergy_Drone.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalLowEnergy_Drone.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalLowEnergy_Drone.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalLowEnergy_Drone.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalNeedRecharge.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalWorkMode_Drone.cs b/Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalWorkMode_Drone.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_AutonomousMech/ThinkNode_ConditionalWorkMode_Drone.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/AutonomousMech/ThinkNode_ConditionalWorkMode_Drone.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Cat_Invisible/CompFighterInvisible.cs b/Source/WulaFallenEmpire/Pawn_Comps/Cat_Invisible/CompFighterInvisible.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_Cat_Invisible/CompFighterInvisible.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Cat_Invisible/CompFighterInvisible.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Cat_Invisible/CompProperties_FighterInvisible.cs b/Source/WulaFallenEmpire/Pawn_Comps/Cat_Invisible/CompProperties_FighterInvisible.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_Cat_Invisible/CompProperties_FighterInvisible.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Cat_Invisible/CompProperties_FighterInvisible.cs
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/DefaultPilotEntry/CompMechDefaultPilot.cs b/Source/WulaFallenEmpire/Pawn_Comps/DefaultPilotEntry/CompMechDefaultPilot.cs
index f45717e3..2a0c12ff 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/DefaultPilotEntry/CompMechDefaultPilot.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/DefaultPilotEntry/CompMechDefaultPilot.cs
@@ -109,7 +109,7 @@ namespace WulaFallenEmpire
var pilotKind = Props.SelectRandomPilotKind();
if (pilotKind == null)
{
- Log.Warning($"[DD] No valid pilot kind found");
+ Log.Warning($"[WULA] No valid pilot kind found");
return false;
}
@@ -151,7 +151,7 @@ namespace WulaFallenEmpire
}
else
{
- Log.Warning($"[DD] Cannot add pilot {pilot.LabelShortCap} to mech");
+ Log.Warning($"[WULA] Cannot add pilot {pilot.LabelShortCap} to mech");
// 清理生成的pawn
pilot.Destroy();
return false;
@@ -159,7 +159,7 @@ namespace WulaFallenEmpire
}
catch (System.Exception ex)
{
- Log.Error($"[DD] Error generating default pilot: {ex}");
+ Log.Error($"[WULA] Error generating default pilot: {ex}");
return false;
}
}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_CompHediffGiver/CompHediffGiver.cs b/Source/WulaFallenEmpire/Pawn_Comps/HediffGiver/CompHediffGiver.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_CompHediffGiver/CompHediffGiver.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/HediffGiver/CompHediffGiver.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_CompHediffGiver/CompProperties_HediffGiver.cs b/Source/WulaFallenEmpire/Pawn_Comps/HediffGiver/CompProperties_HediffGiver.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_CompHediffGiver/CompProperties_HediffGiver.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/HediffGiver/CompProperties_HediffGiver.cs
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs b/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs
new file mode 100644
index 00000000..91ab5cce
--- /dev/null
+++ b/Source/WulaFallenEmpire/Pawn_Comps/HighSpeedCollision/CompHighSpeedCollision.cs
@@ -0,0 +1,855 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+using Verse.Sound;
+
+namespace WulaFallenEmpire
+{
+ ///
+ /// 高速移动撞击组件
+ ///
+ public class CompHighSpeedCollision : ThingComp
+ {
+ // === 运行时状态 ===
+ private enum SpeedStage
+ {
+ Stage0, // 0阶段:不移动
+ Stage1, // 1阶段:低速碰撞
+ Stage2 // 2阶段:高速击飞
+ }
+
+ private SpeedStage currentStage = SpeedStage.Stage0;
+ private int stageTransitionCooldown = 0;
+
+ // 用于计算速度的帧历史
+ private Queue speedHistory = new Queue();
+ private IntVec3 lastPosition = IntVec3.Invalid;
+ private int lastPositionTick = -1;
+
+ // 已处理的敌人记录(避免同一帧重复处理)
+ private HashSet processedPawnsThisTick = new HashSet();
+
+ // === 缓存 ===
+ private CellRect collisionAreaCache = default;
+ private int lastAreaRecalculationTick = -1;
+
+ public CompProperties_HighSpeedCollision Props => (CompProperties_HighSpeedCollision)props;
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ // 初始化速度历史
+ speedHistory.Clear();
+ for (int i = 0; i < Props.speedHistoryFrameCount; i++)
+ {
+ speedHistory.Enqueue(0f);
+ }
+
+ lastPosition = parent.Position;
+ lastPositionTick = Find.TickManager.TicksGame;
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ if (!parent.Spawned || parent.Destroyed)
+ return;
+
+ Pawn pawn = parent as Pawn;
+ if (pawn == null || pawn.Dead || pawn.Downed)
+ return;
+
+ // 检查是否死亡或不能移动
+ if (!CanMove(pawn))
+ {
+ ResetToStage0();
+ return;
+ }
+
+ // 每帧更新
+ ProcessFrame(pawn);
+ }
+
+ ///
+ /// 处理每帧逻辑
+ ///
+ private void ProcessFrame(Pawn pawn)
+ {
+ int currentTick = Find.TickManager.TicksGame;
+
+ // 1. 计算当前速度
+ float currentSpeed = CalculateCurrentSpeed(pawn, currentTick);
+
+ // 2. 更新速度历史
+ UpdateSpeedHistory(currentSpeed);
+
+ // 3. 计算平均速度
+ float averageSpeed = GetAverageSpeed();
+
+ // 4. 确定阶段
+ DetermineSpeedStage(averageSpeed);
+
+ // 5. 根据阶段应用效果
+ ApplyStageEffects(pawn);
+
+ // 6. 清理每帧记录
+ processedPawnsThisTick.Clear();
+
+ // 7. 更新冷却
+ if (stageTransitionCooldown > 0)
+ stageTransitionCooldown--;
+
+ // 8. 调试绘制
+ if (Props.enableDebugVisuals && DebugSettings.godMode)
+ DrawDebugVisuals(pawn);
+ }
+
+ ///
+ /// 计算当前速度(每秒格数)
+ ///
+ private float CalculateCurrentSpeed(Pawn pawn, int currentTick)
+ {
+ // 如果没有上次位置记录,无法计算速度
+ if (lastPositionTick < 0 || lastPosition == IntVec3.Invalid)
+ {
+ lastPosition = pawn.Position;
+ lastPositionTick = currentTick;
+ return 0f;
+ }
+
+ // 计算时间差(秒)
+ float timeDelta = (currentTick - lastPositionTick) / 60f;
+ if (timeDelta <= 0f)
+ return 0f;
+
+ // 计算距离(格数)
+ float distance = pawn.Position.DistanceTo(lastPosition);
+
+ // 计算速度(格/秒)
+ float speed = distance / timeDelta;
+
+ // 更新记录
+ lastPosition = pawn.Position;
+ lastPositionTick = currentTick;
+
+ return speed;
+ }
+
+ ///
+ /// 更新速度历史
+ ///
+ private void UpdateSpeedHistory(float currentSpeed)
+ {
+ speedHistory.Enqueue(currentSpeed);
+ while (speedHistory.Count > Props.speedHistoryFrameCount)
+ {
+ speedHistory.Dequeue();
+ }
+ }
+
+ ///
+ /// 获取平均速度
+ ///
+ private float GetAverageSpeed()
+ {
+ if (speedHistory.Count == 0)
+ return 0f;
+
+ float sum = 0f;
+ foreach (float speed in speedHistory)
+ {
+ sum += speed;
+ }
+
+ return sum / speedHistory.Count;
+ }
+
+ ///
+ /// 确定速度阶段
+ ///
+ private void DetermineSpeedStage(float averageSpeed)
+ {
+ // 如果有冷却,保持当前阶段
+ if (stageTransitionCooldown > 0)
+ return;
+
+ SpeedStage newStage;
+
+ if (averageSpeed <= Props.minSpeedForStage1)
+ {
+ newStage = SpeedStage.Stage0;
+ }
+ else if (averageSpeed >= Props.minSpeedForStage2)
+ {
+ newStage = SpeedStage.Stage2;
+ }
+ else
+ {
+ newStage = SpeedStage.Stage1;
+ }
+
+ // 阶段变化时设置冷却
+ if (newStage != currentStage)
+ {
+ currentStage = newStage;
+ stageTransitionCooldown = Props.stageTransitionCooldownTicks;
+
+ if (Props.enableDebugLogging)
+ {
+ Log.Message($"[HighSpeedCollision] {parent.Label} transitioned to Stage {(int)currentStage} " +
+ $"at speed {averageSpeed:F2} cells/sec");
+ }
+ }
+ }
+
+ ///
+ /// 应用阶段效果
+ ///
+ private void ApplyStageEffects(Pawn pawn)
+ {
+ if (currentStage == SpeedStage.Stage0)
+ return;
+
+ // 获取碰撞区域内的所有敌人
+ List enemiesInArea = GetEnemiesInCollisionArea(pawn);
+
+ foreach (Pawn enemy in enemiesInArea)
+ {
+ if (enemy == null || enemy.Destroyed || enemy.Dead || processedPawnsThisTick.Contains(enemy))
+ continue;
+
+ switch (currentStage)
+ {
+ case SpeedStage.Stage1:
+ ApplyStage1Effects(pawn, enemy);
+ break;
+ case SpeedStage.Stage2:
+ ApplyStage2Effects(pawn, enemy);
+ break;
+ }
+
+ processedPawnsThisTick.Add(enemy);
+ }
+ }
+
+ ///
+ /// 应用阶段1效果(伤害+hediff)
+ ///
+ private void ApplyStage1Effects(Pawn attacker, Pawn target)
+ {
+ // 检查目标是否已有hediff
+ bool alreadyHasHediff = target.health.hediffSet.HasHediff(Props.stage1Hediff);
+
+ // 如果已有hediff,不造成伤害
+ if (alreadyHasHediff && Props.stage1HediffPreventsDamage)
+ return;
+
+ // 造成伤害
+ if (Props.stage1DamageAmount > 0f)
+ {
+ ApplyDamage(attacker, target, Props.stage1DamageAmount, Props.stage1DamageDef);
+ }
+
+ // 应用hediff
+ if (Props.stage1Hediff != null)
+ {
+ Hediff hediff = HediffMaker.MakeHediff(Props.stage1Hediff, target);
+ if (Props.stage1HediffDurationTicks > 0)
+ {
+ hediff.Severity = 1f;
+ hediff.TryGetComp()?.CompPostMake();
+ }
+ target.health.AddHediff(hediff);
+ }
+
+ // 播放效果
+ PlayStage1Effects(attacker, target);
+
+ if (Props.enableDebugLogging)
+ {
+ Log.Message($"[HighSpeedCollision] Stage1: {attacker.Label} -> {target.Label}, " +
+ $"Damage: {Props.stage1DamageAmount}, Hediff: {Props.stage1Hediff?.defName}");
+ }
+ }
+
+ ///
+ /// 应用阶段2效果(伤害+击飞)
+ ///
+ private void ApplyStage2Effects(Pawn attacker, Pawn target)
+ {
+ // 造成伤害
+ if (Props.stage2DamageAmount > 0f)
+ {
+ ApplyDamage(attacker, target, Props.stage2DamageAmount, Props.stage2DamageDef);
+ }
+
+ // 执行击飞
+ PerformKnockback(attacker, target);
+
+ // 播放效果
+ PlayStage2Effects(attacker, target);
+
+ if (Props.enableDebugLogging)
+ {
+ Log.Message($"[HighSpeedCollision] Stage2: {attacker.Label} -> {target.Label}, " +
+ $"Damage: {Props.stage2DamageAmount}, Knockback");
+ }
+ }
+
+ ///
+ /// 执行击飞(参考CompAbilityEffect_FanShapedStunKnockback)
+ ///
+ private void PerformKnockback(Pawn attacker, Pawn target)
+ {
+ if (target == null || target.Destroyed || target.Dead || attacker.Map == null)
+ return;
+
+ // 计算击飞方向(从攻击者指向目标)
+ IntVec3 knockbackDirection = CalculateKnockbackDirection(attacker, target.Position);
+
+ // 寻找击飞位置
+ IntVec3 knockbackDestination = FindKnockbackDestination(attacker, target, knockbackDirection);
+
+ // 如果找到有效位置,执行击飞
+ if (knockbackDestination.IsValid && knockbackDestination != target.Position)
+ {
+ CreateKnockbackFlyer(attacker, target, knockbackDestination);
+ }
+ }
+
+ ///
+ /// 计算击飞方向
+ ///
+ private IntVec3 CalculateKnockbackDirection(Pawn attacker, IntVec3 targetPosition)
+ {
+ IntVec3 direction = targetPosition - attacker.Position;
+
+ // 标准化方向
+ if (direction.x != 0 || direction.z != 0)
+ {
+ if (Mathf.Abs(direction.x) > Mathf.Abs(direction.z))
+ {
+ return new IntVec3(Mathf.Sign(direction.x) > 0 ? 1 : -1, 0, 0);
+ }
+ else
+ {
+ return new IntVec3(0, 0, Mathf.Sign(direction.z) > 0 ? 1 : -1);
+ }
+ }
+
+ // 如果攻击者和目标在同一位置,使用随机方向
+ return new IntVec3(Rand.Value > 0.5f ? 1 : -1, 0, 0);
+ }
+
+ ///
+ /// 寻找击飞位置
+ ///
+ private IntVec3 FindKnockbackDestination(Pawn attacker, Pawn target, IntVec3 direction)
+ {
+ Map map = attacker.Map;
+ IntVec3 currentPos = target.Position;
+
+ // 从最大距离开始向回找
+ for (int distance = Props.stage2KnockbackDistance; distance >= 1; distance--)
+ {
+ IntVec3 testPos = currentPos + (direction * distance);
+
+ if (!IsValidKnockbackDestination(testPos, map, target, attacker))
+ continue;
+
+ return testPos;
+ }
+
+ return currentPos;
+ }
+
+ ///
+ /// 检查击飞位置是否有效
+ ///
+ private bool IsValidKnockbackDestination(IntVec3 destination, Map map, Pawn victim, Pawn attacker)
+ {
+ if (!destination.IsValid || !destination.InBounds(map))
+ return false;
+
+ if (!destination.Standable(map))
+ return false;
+
+ // 检查是否有其他pawn
+ Pawn existingPawn = destination.GetFirstPawn(map);
+ if (existingPawn != null && existingPawn != victim)
+ return false;
+
+ // 检查视线
+ if (Props.requireLineOfSightForKnockback && !GenSight.LineOfSight(victim.Position, destination, map))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// 创建击飞飞行器
+ ///
+ private void CreateKnockbackFlyer(Pawn attacker, Pawn target, IntVec3 destination)
+ {
+ try
+ {
+ Map map = attacker.Map;
+
+ // 使用自定义飞行器或默认飞行器
+ ThingDef flyerDef = Props.knockbackFlyerDef ?? ThingDefOf.PawnFlyer;
+
+ // 创建飞行器
+ PawnFlyer flyer = PawnFlyer.MakeFlyer(
+ flyerDef,
+ target,
+ destination,
+ Props.flightEffecterDef,
+ Props.landingSound,
+ false,
+ null,
+ null,
+ new LocalTargetInfo(destination)
+ );
+
+ if (flyer != null)
+ {
+ GenSpawn.Spawn(flyer, destination, map);
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"[HighSpeedCollision] Exception creating PawnFlyer: {ex}");
+ }
+ }
+
+ ///
+ /// 应用伤害
+ ///
+ private void ApplyDamage(Pawn attacker, Pawn target, float amount, DamageDef damageDef)
+ {
+ if (amount <= 0f || damageDef == null)
+ return;
+
+ DamageInfo damageInfo = new DamageInfo(
+ damageDef,
+ amount,
+ Props.armorPenetration,
+ -1f,
+ attacker,
+ null
+ );
+
+ target.TakeDamage(damageInfo);
+ }
+
+ ///
+ /// 播放阶段1效果
+ ///
+ private void PlayStage1Effects(Pawn attacker, Pawn target)
+ {
+ if (Props.stage1Effecter != null && attacker.Map != null)
+ {
+ Effecter effect = Props.stage1Effecter.Spawn();
+ effect.Trigger(new TargetInfo(attacker.Position, attacker.Map),
+ new TargetInfo(target.Position, attacker.Map));
+ effect.Cleanup();
+ }
+
+ if (Props.stage1Sound != null && attacker.Map != null)
+ {
+ Props.stage1Sound.PlayOneShot(new TargetInfo(target.Position, attacker.Map));
+ }
+ }
+
+ ///
+ /// 播放阶段2效果
+ ///
+ private void PlayStage2Effects(Pawn attacker, Pawn target)
+ {
+ if (Props.stage2Effecter != null && attacker.Map != null)
+ {
+ Effecter effect = Props.stage2Effecter.Spawn();
+ effect.Trigger(new TargetInfo(attacker.Position, attacker.Map),
+ new TargetInfo(target.Position, attacker.Map));
+ effect.Cleanup();
+ }
+
+ if (Props.stage2Sound != null && attacker.Map != null)
+ {
+ Props.stage2Sound.PlayOneShot(new TargetInfo(target.Position, attacker.Map));
+ }
+ }
+
+ ///
+ /// 获取碰撞区域内的所有敌人
+ ///
+ private List GetEnemiesInCollisionArea(Pawn pawn)
+ {
+ List enemies = new List();
+
+ // 获取碰撞区域
+ CellRect collisionArea = GetCollisionArea(pawn);
+
+ // 检查区域内的每个单元格
+ foreach (IntVec3 cell in collisionArea)
+ {
+ if (!cell.InBounds(pawn.Map))
+ continue;
+
+ // 获取单元格内的所有pawn
+ List things = cell.GetThingList(pawn.Map);
+ foreach (Thing thing in things)
+ {
+ if (thing is Pawn otherPawn && otherPawn != pawn)
+ {
+ // 检查是否为敌人
+ if (IsValidTarget(pawn, otherPawn))
+ {
+ enemies.Add(otherPawn);
+ }
+ }
+ }
+ }
+
+ return enemies;
+ }
+
+ ///
+ /// 获取碰撞区域
+ ///
+ private CellRect GetCollisionArea(Pawn pawn)
+ {
+ int currentTick = Find.TickManager.TicksGame;
+
+ // 每10帧重新计算一次区域,或当位置变化时
+ if (currentTick - lastAreaRecalculationTick > 10 ||
+ pawn.Position != collisionAreaCache.CenterCell)
+ {
+ int radius = Props.collisionAreaRadius;
+ IntVec3 center = pawn.Position;
+
+ collisionAreaCache = new CellRect(
+ center.x - radius,
+ center.z - radius,
+ radius * 2 + 1,
+ radius * 2 + 1
+ );
+
+ collisionAreaCache.ClipInsideMap(pawn.Map);
+ lastAreaRecalculationTick = currentTick;
+ }
+
+ return collisionAreaCache;
+ }
+
+ ///
+ /// 检查是否是有效目标
+ ///
+ private bool IsValidTarget(Pawn attacker, Pawn target)
+ {
+ if (target == null || target.Destroyed || target.Dead)
+ return false;
+
+ // 检查是否为敌人
+ if (Props.onlyAffectEnemies && !target.HostileTo(attacker))
+ return false;
+
+ // 检查是否排除友方
+ if (Props.excludeAlliedPawns && target.Faction == attacker.Faction)
+ return false;
+
+ // 检查是否排除中立
+ if (Props.excludeNeutralPawns && !target.HostileTo(attacker))
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// 检查Pawn是否可以移动
+ ///
+ private bool CanMove(Pawn pawn)
+ {
+ if (pawn.Downed || pawn.Dead || pawn.InMentalState)
+ return false;
+
+ if (pawn.stances?.stunner?.Stunned ?? false)
+ return false;
+
+ return true;
+ }
+
+ ///
+ /// 重置到阶段0
+ ///
+ private void ResetToStage0()
+ {
+ currentStage = SpeedStage.Stage0;
+
+ // 清空速度历史
+ speedHistory.Clear();
+ for (int i = 0; i < Props.speedHistoryFrameCount; i++)
+ {
+ speedHistory.Enqueue(0f);
+ }
+ }
+
+ ///
+ /// 绘制调试视觉效果
+ ///
+ private void DrawDebugVisuals(Pawn pawn)
+ {
+ if (!pawn.Spawned)
+ return;
+
+ // 绘制碰撞区域
+ CellRect area = GetCollisionArea(pawn);
+ GenDraw.DrawFieldEdges(area.Cells.ToList(), GetStageColor(currentStage));
+
+ // 绘制速度指示器
+ float averageSpeed = GetAverageSpeed();
+ string speedText = $"Speed: {averageSpeed:F1} cells/sec\nStage: {(int)currentStage}";
+
+ Vector3 drawPos = pawn.DrawPos + new Vector3(0, 0, 1f);
+ GenMapUI.DrawText(drawPos, speedText, GetStageColor(currentStage));
+ }
+
+ ///
+ /// 获取阶段颜色
+ ///
+ private Color GetStageColor(SpeedStage stage)
+ {
+ switch (stage)
+ {
+ case SpeedStage.Stage0: return Color.gray;
+ case SpeedStage.Stage1: return Color.yellow;
+ case SpeedStage.Stage2: return Color.red;
+ default: return Color.white;
+ }
+ }
+
+ ///
+ /// 获取调试信息
+ ///
+ public string GetDebugInfo()
+ {
+ float averageSpeed = GetAverageSpeed();
+
+ return $"HighSpeedCollision Debug Info:\n" +
+ $"Current Stage: {(int)currentStage}\n" +
+ $"Average Speed: {averageSpeed:F2} cells/sec\n" +
+ $"Stage 1 Threshold: {Props.minSpeedForStage1:F2}\n" +
+ $"Stage 2 Threshold: {Props.minSpeedForStage2:F2}\n" +
+ $"Speed History: {speedHistory.Count} frames\n" +
+ $"Stage Cooldown: {stageTransitionCooldown} ticks";
+ }
+
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+
+ Scribe_Values.Look(ref currentStage, "currentStage", SpeedStage.Stage0);
+ Scribe_Values.Look(ref stageTransitionCooldown, "stageTransitionCooldown", 0);
+ Scribe_Values.Look(ref lastPosition, "lastPosition", IntVec3.Invalid);
+ Scribe_Values.Look(ref lastPositionTick, "lastPositionTick", -1);
+
+ // 保存速度历史
+ if (Scribe.mode == LoadSaveMode.Saving)
+ {
+ List speedList = speedHistory.ToList();
+ Scribe_Collections.Look(ref speedList, "speedHistory", LookMode.Value);
+ }
+ else if (Scribe.mode == LoadSaveMode.LoadingVars)
+ {
+ List speedList = null;
+ Scribe_Collections.Look(ref speedList, "speedHistory", LookMode.Value);
+
+ speedHistory.Clear();
+ if (speedList != null)
+ {
+ foreach (float speed in speedList)
+ {
+ speedHistory.Enqueue(speed);
+ }
+ }
+
+ // 确保有足够的历史数据
+ while (speedHistory.Count < Props.speedHistoryFrameCount)
+ {
+ speedHistory.Enqueue(0f);
+ }
+ }
+ }
+ }
+
+ ///
+ /// 高速移动撞击组件属性
+ ///
+ public class CompProperties_HighSpeedCollision : CompProperties
+ {
+ // === 速度阈值配置 ===
+
+ ///
+ /// 进入阶段1所需的最小速度(格/秒)
+ ///
+ public float minSpeedForStage1 = 3f;
+
+ ///
+ /// 进入阶段2所需的最小速度(格/秒)
+ ///
+ public float minSpeedForStage2 = 6f;
+
+ ///
+ /// 速度历史帧数(用于计算平均速度)
+ ///
+ public int speedHistoryFrameCount = 10;
+
+ ///
+ /// 阶段转换冷却时间(tick)
+ ///
+ public int stageTransitionCooldownTicks = 5;
+
+ // === 碰撞区域配置 ===
+
+ ///
+ /// 碰撞区域半径(以pawn为中心的正方形)
+ ///
+ public int collisionAreaRadius = 1;
+
+ // === 目标过滤 ===
+
+ ///
+ /// 只影响敌人
+ ///
+ public bool onlyAffectEnemies = true;
+
+ ///
+ /// 排除友方单位
+ ///
+ public bool excludeAlliedPawns = true;
+
+ ///
+ /// 排除中立单位
+ ///
+ public bool excludeNeutralPawns = false;
+
+ // === 阶段1效果配置 ===
+
+ ///
+ /// 阶段1伤害类型
+ ///
+ public DamageDef stage1DamageDef = DamageDefOf.Blunt;
+
+ ///
+ /// 阶段1伤害量
+ ///
+ public float stage1DamageAmount = 5f;
+
+ ///
+ /// 阶段1护甲穿透
+ ///
+ public float armorPenetration = 0f;
+
+ ///
+ /// 阶段1应用的hediff
+ ///
+ public HediffDef stage1Hediff;
+
+ ///
+ /// 阶段1hediff持续时间(tick)
+ ///
+ public int stage1HediffDurationTicks = 60;
+
+ ///
+ /// 拥有hediff的目标是否免疫伤害
+ ///
+ public bool stage1HediffPreventsDamage = true;
+
+ ///
+ /// 阶段1效果器
+ ///
+ public EffecterDef stage1Effecter;
+
+ ///
+ /// 阶段1音效
+ ///
+ public SoundDef stage1Sound;
+
+ // === 阶段2效果配置 ===
+
+ ///
+ /// 阶段2伤害类型
+ ///
+ public DamageDef stage2DamageDef = DamageDefOf.Blunt;
+
+ ///
+ /// 阶段2伤害量
+ ///
+ public float stage2DamageAmount = 10f;
+
+ ///
+ /// 阶段2击退距离
+ ///
+ public int stage2KnockbackDistance = 3;
+
+ ///
+ /// 击退是否需要视线
+ ///
+ public bool requireLineOfSightForKnockback = true;
+
+ ///
+ /// 阶段2效果器
+ ///
+ public EffecterDef stage2Effecter;
+
+ ///
+ /// 阶段2音效
+ ///
+ public SoundDef stage2Sound;
+
+ // === 击飞配置 ===
+
+ ///
+ /// 击退飞行器定义
+ ///
+ public ThingDef knockbackFlyerDef;
+
+ ///
+ /// 飞行效果器
+ ///
+ public EffecterDef flightEffecterDef;
+
+ ///
+ /// 落地音效
+ ///
+ public SoundDef landingSound;
+
+ // === 调试配置 ===
+
+ ///
+ /// 启用调试日志
+ ///
+ public bool enableDebugLogging = false;
+
+ ///
+ /// 启用调试视觉效果
+ ///
+ public bool enableDebugVisuals = false;
+
+ ///
+ /// 绘制速度历史图
+ ///
+ public bool debugDrawSpeedHistory = false;
+
+ public CompProperties_HighSpeedCollision()
+ {
+ compClass = typeof(CompHighSpeedCollision);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechArmor/CompMechArmor.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechArmor/CompMechArmor.cs
deleted file mode 100644
index de554798..00000000
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechArmor/CompMechArmor.cs
+++ /dev/null
@@ -1,199 +0,0 @@
-// File: CompMechArmor.cs
-using RimWorld;
-using System.Collections.Generic;
-using UnityEngine;
-using Verse;
-using Verse.Sound;
-using static RimWorld.MechClusterSketch;
-
-namespace WulaFallenEmpire
-{
- ///
- /// 机甲装甲组件:提供基于装甲值的伤害减免系统
- ///
- public class CompMechArmor : ThingComp
- {
- public CompProperties_MechArmor Props =>
- (CompProperties_MechArmor)props;
-
- private static StatDef DD_MechArmorDef = null;
-
- // 当前装甲值(从Stat获取)
- public float CurrentArmor
- {
- get
- {
- if (DD_MechArmorDef == null)
- {
- DD_MechArmorDef = StatDef.Named("DD_MechArmor");
- if (DD_MechArmorDef == null)
- {
- Log.Warning("[DD] DD_MechArmor stat definition not found!");
- return 0f;
- }
- }
- return parent.GetStatValue(DD_MechArmorDef);
- }
- }
-
- // 调试信息
- private int blockedHits = 0;
- private int totalHits = 0;
-
- ///
- /// 检查伤害是否被装甲抵消
- ///
- /// 伤害信息
- /// true=伤害被抵消,false=伤害有效
- public bool TryBlockDamage(ref DamageInfo dinfo)
- {
- totalHits++;
-
- // 获取穿甲率(如果没有则为0)
- float armorPenetration = dinfo.ArmorPenetrationInt;
-
- // 计算穿甲伤害
- float armorPiercingDamage = dinfo.Amount * armorPenetration;
-
- // 获取当前装甲值
- float currentArmor = CurrentArmor;
-
- // 检查是否应该被装甲抵消
- bool shouldBlock = armorPiercingDamage < currentArmor;
-
- if (shouldBlock)
- {
- blockedHits++;
-
- // 可选:触发视觉效果
- if (Props.showBlockEffect && parent.Spawned)
- {
- ShowBlockEffect(dinfo);
- }
-
- // 可选:播放音效
- if (Props.soundOnBlock != null && parent.Spawned)
- {
- Props.soundOnBlock.PlayOneShot(parent);
- }
- }
-
- // 调试日志
- if (Props.debugLogging && parent.Spawned)
- {
- Log.Message($"[DD Armor] {parent.LabelShort}: " +
- $"Damage={dinfo.Amount}, " +
- $"Penetration={armorPenetration:P0}, " +
- $"PierceDamage={armorPiercingDamage:F1}, " +
- $"Armor={currentArmor:F1}, " +
- $"Blocked={shouldBlock}");
- }
-
- return shouldBlock;
- }
-
- ///
- /// 显示阻挡效果
- ///
- private void ShowBlockEffect(DamageInfo dinfo)
- {
- MoteMaker.ThrowText(parent.DrawPos, parent.Map, "DD_BlockByMechArmor".Translate(), Color.white, 3.5f);
- // 创建火花或特效
- if (Props.blockEffectMote != null)
- {
- MoteMaker.MakeStaticMote(
- parent.DrawPos + new Vector3(0, 0, 0.5f),
- parent.Map,
- Props.blockEffectMote,
- 1.0f
- );
- }
- }
-
- ///
- /// 获取装甲信息(用于调试)
- ///
- public string GetArmorInfo()
- {
- return $"{parent.LabelShort}的装甲系统 \n" +
- $"当前装甲值: {CurrentArmor:F1}\n" +
- $"阻挡规则: 穿甲伤害 < 装甲值\n" +
- $"统计: 已阻挡 {blockedHits}/{totalHits} 次攻击\n" +
- $"阻挡率: {(totalHits > 0 ? (float)blockedHits / totalHits * 100 : 0):F1}%";
- }
-
- ///
- /// 获取调试按钮
- ///
- public override IEnumerable CompGetGizmosExtra()
- {
- foreach (var gizmo in base.CompGetGizmosExtra())
- {
- yield return gizmo;
- }
-
- // 在开发模式下显示装甲信息
- if (DebugSettings.ShowDevGizmos)
- {
- yield return new Command_Action
- {
- defaultLabel = "DEBUG: 装甲信息",
- defaultDesc = GetArmorInfo(),
- //icon = TexCommand.Shield,
- action = () =>
- {
- Find.WindowStack.Add(new Dialog_MessageBox(
- GetArmorInfo(),
- "关闭",
- null,
- null,
- null,
- "机甲装甲信息"
- ));
- }
- };
-
- yield return new Command_Action
- {
- defaultLabel = "DEBUG: 重置统计",
- defaultDesc = "重置阻挡统计计数器",
- //icon = TexCommand.Clear,
- action = () =>
- {
- blockedHits = 0;
- totalHits = 0;
- Messages.Message("装甲统计已重置", MessageTypeDefOf.TaskCompletion);
- }
- };
- }
- }
-
- public override void PostExposeData()
- {
- base.PostExposeData();
- Scribe_Values.Look(ref blockedHits, "blockedHits", 0);
- Scribe_Values.Look(ref totalHits, "totalHits", 0);
- }
- }
-
- ///
- /// 机甲装甲组件属性
- ///
- public class CompProperties_MechArmor : CompProperties
- {
- // 视觉效果
- public bool showBlockEffect = true;
- public ThingDef blockEffectMote; // 阻挡时显示的特效
-
- // 音效
- public SoundDef soundOnBlock;
-
- // 调试
- public bool debugLogging = false;
-
- public CompProperties_MechArmor()
- {
- compClass = typeof(CompMechArmor);
- }
- }
-}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/CompMechFuel.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/CompMechFuel.cs
index 57e96611..1c4c7219 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/CompMechFuel.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/CompMechFuel.cs
@@ -26,7 +26,7 @@ namespace WulaFallenEmpire
public ThingDef FuelType => Props.fuelType;
// 停机状态 Hediff
- private HediffDef ShutdownHediffDef => HediffDef.Named("DD_MechShutdown");
+ private HediffDef ShutdownHediffDef => HediffDef.Named("WULA_MechShutdown");
public override void PostSpawnSetup(bool respawningAfterLoad)
{
@@ -162,7 +162,7 @@ namespace WulaFallenEmpire
}
// 播放关机效果
- MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Shutdown".Translate(), Color.gray, 3.5f);
+ MoteMaker.ThrowText(mech.DrawPos, mech.Map, "WULA_Shutdown".Translate(), Color.gray, 3.5f);
}
}
@@ -186,7 +186,7 @@ namespace WulaFallenEmpire
}
}
- MoteMaker.ThrowText(mech.DrawPos, mech.Map, "DD_Startup".Translate(), Color.green, 3.5f);
+ MoteMaker.ThrowText(mech.DrawPos, mech.Map, "WULA_Startup".Translate(), Color.green, 3.5f);
}
}
@@ -236,7 +236,7 @@ namespace WulaFallenEmpire
// 发送调试消息
if (DebugSettings.godMode)
{
- Messages.Message($"DD_Debug_FuelSet".Translate(
+ Messages.Message($"WULA_Debug_FuelSet".Translate(
parent.LabelShort,
fuel.ToString("F1"),
Props.fuelCapacity.ToString("F1"),
@@ -267,7 +267,7 @@ namespace WulaFallenEmpire
if (bestColonist == null)
{
- Messages.Message("DD_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
+ Messages.Message("WULA_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
return;
}
@@ -275,7 +275,7 @@ namespace WulaFallenEmpire
Thing fuel = FindFuelForRefuel(bestColonist);
if (fuel == null)
{
- Messages.Message("DD_NoFuelAvailable".Translate(FuelType), parent, MessageTypeDefOf.RejectInput);
+ Messages.Message("WULA_NoFuelAvailable".Translate(FuelType), parent, MessageTypeDefOf.RejectInput);
return;
}
@@ -287,7 +287,7 @@ namespace WulaFallenEmpire
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
// 显示消息
- Messages.Message("DD_OrderedRefuel".Translate(bestColonist.LabelShort, parent.LabelShort),
+ Messages.Message("WULA_OrderedRefuel".Translate(bestColonist.LabelShort, parent.LabelShort),
parent, MessageTypeDefOf.PositiveEvent);
}
@@ -370,16 +370,16 @@ namespace WulaFallenEmpire
{
Command_Action refuelNow = new Command_Action
{
- defaultLabel = "DD_RefuelNow".Translate(),
- defaultDesc = "DD_RefuelNowDesc".Translate(),
- icon = ContentFinder.Get("WulaFallenEmpire/UI/Commands/DD_Refuel_Mech"),
+ defaultLabel = "WULA_RefuelNow".Translate(),
+ defaultDesc = "WULA_RefuelNowDesc".Translate(),
+ icon = ContentFinder.Get("WulaFallenEmpire/UI/Commands/WULA_Refuel_Mech"),
action = () => RefuelNow()
};
// 检查是否可以立刻加注
if (!CanRefuelNow())
{
- refuelNow.Disable("DD_CannotRefuelNow".Translate());
+ refuelNow.Disable("WULA_CannotRefuelNow".Translate());
}
yield return refuelNow;
@@ -391,8 +391,8 @@ namespace WulaFallenEmpire
// 设置燃料为空
Command_Action setEmpty = new Command_Action
{
- defaultLabel = "DD_Debug_SetEmpty".Translate(),
- defaultDesc = "DD_Debug_SetEmptyDesc".Translate(),
+ defaultLabel = "WULA_Debug_SetEmpty".Translate(),
+ defaultDesc = "WULA_Debug_SetEmptyDesc".Translate(),
icon = ContentFinder.Get("UI/Commands/SetEmpty", false) ?? BaseContent.BadTex,
action = () => SetFuel(0f)
};
@@ -401,8 +401,8 @@ namespace WulaFallenEmpire
// 设置燃料为50%
Command_Action setHalf = new Command_Action
{
- defaultLabel = "DD_Debug_SetHalf".Translate(),
- defaultDesc = "DD_Debug_SetHalfDesc".Translate(),
+ defaultLabel = "WULA_Debug_SetHalf".Translate(),
+ defaultDesc = "WULA_Debug_SetHalfDesc".Translate(),
icon = ContentFinder.Get("UI/Commands/SetHalf", false) ?? BaseContent.BadTex,
action = () => SetFuel(Props.fuelCapacity * 0.5f)
};
@@ -411,8 +411,8 @@ namespace WulaFallenEmpire
// 设置燃料为满
Command_Action setFull = new Command_Action
{
- defaultLabel = "DD_Debug_SetFull".Translate(),
- defaultDesc = "DD_Debug_SetFullDesc".Translate(),
+ defaultLabel = "WULA_Debug_SetFull".Translate(),
+ defaultDesc = "WULA_Debug_SetFullDesc".Translate(),
icon = ContentFinder.Get("UI/Commands/SetFull", false) ?? BaseContent.BadTex,
action = () => SetFuel(Props.fuelCapacity)
};
@@ -433,7 +433,7 @@ namespace WulaFallenEmpire
{
string baseString = base.CompInspectStringExtra();
- string fuelString = "DD_Fuel".Translate(FuelType) + ": " +
+ string fuelString = "WULA_Fuel".Translate(FuelType) + ": " +
fuel.ToString("F1") + " / " + Props.fuelCapacity.ToString("F1") +
" (" + (FuelPercent * 100f).ToString("F0") + "%)";
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/Gizmo_MechFuelStatus.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/Gizmo_MechFuelStatus.cs
index 2ea975fa..28dc7eab 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/Gizmo_MechFuelStatus.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechFuel/Gizmo_MechFuelStatus.cs
@@ -49,8 +49,8 @@ namespace WulaFallenEmpire
// 在 God Mode 下显示"调试模式"标题
string title = DebugSettings.godMode ?
- "DD_MechFuel".Translate().Resolve() + " [DEBUG]" :
- "DD_MechFuel".Translate().Resolve();
+ "WULA_MechFuel".Translate().Resolve() + " [DEBUG]" :
+ "WULA_MechFuel".Translate().Resolve();
Widgets.Label(titleRect, title);
@@ -88,13 +88,13 @@ namespace WulaFallenEmpire
Text.Font = GameFont.Tiny;
Text.Anchor = TextAnchor.UpperCenter;
GUI.color = Color.red;
- Widgets.Label(statusRect, "DD_Shutdown".Translate());
+ Widgets.Label(statusRect, "WULA_Shutdown".Translate());
GUI.color = Color.white;
Text.Anchor = TextAnchor.UpperLeft;
}
// 工具提示
- string tip = "DD_MechFuelTip".Translate(
+ string tip = "WULA_MechFuelTip".Translate(
fuelComp.FuelPercent.ToStringPercent(),
fuelComp.Props.dailyFuelConsumption,
fuelComp.Props.fuelType.label
@@ -102,20 +102,20 @@ namespace WulaFallenEmpire
if (fuelComp.IsShutdown)
{
- tip += "\n\n" + "DD_ShutdownTip".Translate();
+ tip += "\n\n" + "WULA_ShutdownTip".Translate();
}
else if (fuelComp.NeedsRefueling)
{
- tip += "\n\n" + "DD_NeedsRefueling".Translate();
+ tip += "\n\n" + "WULA_NeedsRefueling".Translate();
}
// 在 God Mode 下添加调试信息到工具提示
if (DebugSettings.godMode)
{
- tip += "\n\n" + "DD_Debug_Tip".Translate().Colorize(Color.gray) +
- "\n" + "DD_Debug_Status".Translate(
- fuelComp.IsShutdown ? "DD_Shutdown".Translate() : "DD_Running".Translate(),
- fuelComp.HasPilot() ? "DD_HasPilot".Translate() : "DD_NoPilot".Translate()
+ tip += "\n\n" + "WULA_Debug_Tip".Translate().Colorize(Color.gray) +
+ "\n" + "WULA_Debug_Status".Translate(
+ fuelComp.IsShutdown ? "WULA_Shutdown".Translate() : "WULA_Running".Translate(),
+ fuelComp.HasPilot() ? "WULA_HasPilot".Translate() : "WULA_NoPilot".Translate()
);
}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompMechMovementSound.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompMechMovementSound.cs
index adaf0f04..5870af53 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompMechMovementSound.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompMechMovementSound.cs
@@ -244,7 +244,7 @@ namespace WulaFallenEmpire
}
else
{
- Log.Warning($"[DD] Failed to create sustainer for {Props.movementSound.defName}");
+ Log.Warning($"[WULA] Failed to create sustainer for {Props.movementSound.defName}");
isPlaying = false;
}
}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompProperties_MechMovementSound.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompProperties_MechMovementSound.cs
index be894f41..b0b9f9f5 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompProperties_MechMovementSound.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechMovementSound/CompProperties_MechMovementSound.cs
@@ -59,7 +59,7 @@ namespace WulaFallenEmpire
// 如果需要驾驶员,检查是否配置了驾驶员容器
if (requirePilot && parentDef.GetCompProperties() == null)
{
- Log.Warning($"[DD] requirePilot is true but no CompProperties_MechPilotHolder found for {parentDef.defName}");
+ Log.Warning($"[WULA] requirePilot is true but no CompProperties_MechPilotHolder found for {parentDef.defName}");
}
}
}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs
index 62ad3c17..238eb8e9 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechPilotHolder/CompMechPilotHolder.cs
@@ -16,8 +16,8 @@ namespace WulaFallenEmpire
public string pilotWorkTag = "MechPilot";
// 新增:驾驶员图标配置
- public string summonPilotIcon = "WulaFallenEmpire/UI/Commands/DD_Enter_Mech";
- public string ejectPilotIcon = "WulaFallenEmpire/UI/Commands/DD_Exit_Mech";
+ public string summonPilotIcon = "WulaFallenEmpire/UI/Commands/WULA_Enter_Mech";
+ public string ejectPilotIcon = "WulaFallenEmpire/UI/Commands/WULA_Exit_Mech";
public float ejectPilotHealthPercentThreshold = 0.1f; // 默认30%血量
public bool allowEntryBelowThreshold = false; // 血量低于阈值时是否允许进入
@@ -204,7 +204,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 同步Hediff时出错: {ex}");
+ Log.Error($"[WULA] 同步Hediff时出错: {ex}");
}
}
@@ -231,7 +231,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 取消同步Hediff时出错: {ex}");
+ Log.Error($"[WULA] 取消同步Hediff时出错: {ex}");
}
}
@@ -273,7 +273,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 自动添加Hediff时出错: {ex}");
+ Log.Error($"[WULA] 自动添加Hediff时出错: {ex}");
}
}
@@ -333,7 +333,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] CompTick error: {ex}");
+ Log.Error($"[WULA] CompTick error: {ex}");
}
}
@@ -384,7 +384,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 检查Hediff同步状态时出错: {ex}");
+ Log.Error($"[WULA] 检查Hediff同步状态时出错: {ex}");
}
}
@@ -395,7 +395,7 @@ namespace WulaFallenEmpire
if (!(parent is Wulamechunit))
{
- Log.Warning($"[DD] CompMechPilotHolder attached to non-mech: {parent}");
+ Log.Warning($"[WULA] CompMechPilotHolder attached to non-mech: {parent}");
}
// 确保加载后恢复状态
@@ -567,7 +567,7 @@ namespace WulaFallenEmpire
// 发送消息
if (parent.Faction == Faction.OfPlayer)
{
- Messages.Message("DD_PilotsEjectedDueToLowHealth".Translate(parent.LabelShort,
+ Messages.Message("WULA_PilotsEjectedDueToLowHealth".Translate(parent.LabelShort,
(Props.ejectPilotHealthPercentThreshold * 100).ToString("F0")),
parent, MessageTypeDefOf.NegativeEvent);
}
@@ -605,8 +605,8 @@ namespace WulaFallenEmpire
{
Command_Action summonCommand = new Command_Action
{
- defaultLabel = "DD_SummonPilot".Translate(),
- defaultDesc = "DD_SummonPilotDesc".Translate(),
+ defaultLabel = "WULA_SummonPilot".Translate(),
+ defaultDesc = "WULA_SummonPilotDesc".Translate(),
icon = Props.GetSummonPilotIcon(),
action = () =>
{
@@ -618,7 +618,7 @@ namespace WulaFallenEmpire
// 如果血量低于阈值且不允许进入,禁用按钮
if (!Props.allowEntryBelowThreshold && IsBelowHealthThreshold)
{
- summonCommand.Disable("DD_MechTooDamagedForEntry".Translate());
+ summonCommand.Disable("WULA_MechTooDamagedForEntry".Translate());
}
yield return summonCommand;
@@ -629,8 +629,8 @@ namespace WulaFallenEmpire
{
yield return new Command_Action
{
- defaultLabel = "DD_EjectAllPilots".Translate(),
- defaultDesc = "DD_EjectAllPilotsDesc".Translate(),
+ defaultLabel = "WULA_EjectAllPilots".Translate(),
+ defaultDesc = "WULA_EjectAllPilotsDesc".Translate(),
icon = Props.GetEjectPilotIcon(),
action = () =>
{
@@ -723,14 +723,14 @@ namespace WulaFallenEmpire
}
else
{
- Log.Error($"[DD] 无法弹出驾驶员: {pawn.LabelShort}");
+ Log.Error($"[WULA] 无法弹出驾驶员: {pawn.LabelShort}");
}
}
}
}
catch (Exception ex)
{
- Log.Error($"[DD] 弹出驾驶员时发生错误: {ex}");
+ Log.Error($"[WULA] 弹出驾驶员时发生错误: {ex}");
}
finally
{
@@ -778,7 +778,7 @@ namespace WulaFallenEmpire
Map map = parent.Map;
if (map == null)
{
- Log.Error($"[DD] 尝试在没有地图的情况下生成驾驶员: {pawn.LabelShort}");
+ Log.Error($"[WULA] 尝试在没有地图的情况下生成驾驶员: {pawn.LabelShort}");
return false;
}
@@ -810,7 +810,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] 生成驾驶员时发生错误: {ex}");
+ Log.Error($"[WULA] 生成驾驶员时发生错误: {ex}");
return false;
}
}
@@ -841,7 +841,7 @@ namespace WulaFallenEmpire
{
if (pilot.Faction == Faction.OfPlayer)
{
- Messages.Message("DD_PilotEnteredMech".Translate(pilot.LabelShort, parent.LabelShort),
+ Messages.Message("WULA_PilotEnteredMech".Translate(pilot.LabelShort, parent.LabelShort),
parent, MessageTypeDefOf.PositiveEvent);
}
}
@@ -850,7 +850,7 @@ namespace WulaFallenEmpire
{
if (pilot.Faction == Faction.OfPlayer)
{
- Messages.Message("DD_PilotExitedMech".Translate(pilot.LabelShort, parent.LabelShort),
+ Messages.Message("WULA_PilotExitedMech".Translate(pilot.LabelShort, parent.LabelShort),
parent, MessageTypeDefOf.NeutralEvent);
}
}
@@ -899,7 +899,7 @@ namespace WulaFallenEmpire
// 为能够行动的殖民者创建选项
if (ableColonists.Count == 0 && disabledColonists.Count == 0)
{
- options.Add(new FloatMenuOption("DD_NoAvailablePilots".Translate(), null));
+ options.Add(new FloatMenuOption("WULA_NoAvailablePilots".Translate(), null));
}
else
{
@@ -930,7 +930,7 @@ namespace WulaFallenEmpire
// 无法行动的殖民者:需要搬运
foreach (var colonist in disabledColonists)
{
- string colonistLabel = colonist.LabelShortCap + " " + "DD_DisabledColonistRequiresCarry".Translate();
+ string colonistLabel = colonist.LabelShortCap + " " + "WULA_DisabledColonistRequiresCarry".Translate();
Action action = () => OrderCarryDisabledColonistToMech(colonist);
FloatMenuOption option = new FloatMenuOption(
@@ -977,7 +977,7 @@ namespace WulaFallenEmpire
if (carrier == null)
{
- Messages.Message("DD_NoAvailableCarrier".Translate(disabledColonist.LabelShortCap),
+ Messages.Message("WULA_NoAvailableCarrier".Translate(disabledColonist.LabelShortCap),
parent, MessageTypeDefOf.RejectInput);
return;
}
@@ -986,7 +986,7 @@ namespace WulaFallenEmpire
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_CarryToMech, disabledColonist, mech);
carrier.jobs.TryTakeOrderedJob(job, JobTag.Misc);
- Messages.Message("DD_CarrierAssigned".Translate(carrier.LabelShortCap, disabledColonist.LabelShortCap),
+ Messages.Message("WULA_CarrierAssigned".Translate(carrier.LabelShortCap, disabledColonist.LabelShortCap),
parent, MessageTypeDefOf.PositiveEvent);
}
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MechRepairable/CompMechRepairable.cs b/Source/WulaFallenEmpire/Pawn_Comps/MechRepairable/CompMechRepairable.cs
index 6f68edf5..08f1df22 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MechRepairable/CompMechRepairable.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MechRepairable/CompMechRepairable.cs
@@ -84,16 +84,16 @@ namespace WulaFallenEmpire
{
Command_Action repairCommand = new Command_Action
{
- defaultLabel = "DD_ForceRepair".Translate(),
- defaultDesc = "DD_ForceRepairDesc".Translate(),
- icon = ContentFinder.Get("WulaFallenEmpire/UI/Commands/DD_Repair_Mech"),
+ defaultLabel = "WULA_ForceRepair".Translate(),
+ defaultDesc = "WULA_ForceRepairDesc".Translate(),
+ icon = ContentFinder.Get("WulaFallenEmpire/UI/Commands/WULA_Repair_Mech"),
action = () => ForceRepairNow()
};
// 检查是否可以立即维修
if (!CanRepairNow())
{
- repairCommand.Disable("DD_CannotRepairNow".Translate());
+ repairCommand.Disable("WULA_CannotRepairNow".Translate());
}
yield return repairCommand;
@@ -105,8 +105,8 @@ namespace WulaFallenEmpire
// 模拟受伤按钮
Command_Action damageCommand = new Command_Action
{
- defaultLabel = "DD_Debug_Damage".Translate(),
- defaultDesc = "DD_Debug_DamageDesc".Translate(),
+ defaultLabel = "WULA_Debug_Damage".Translate(),
+ defaultDesc = "WULA_Debug_DamageDesc".Translate(),
icon = ContentFinder.Get("UI/Commands/Damage", false) ?? BaseContent.BadTex,
action = () => DebugDamage()
};
@@ -115,8 +115,8 @@ namespace WulaFallenEmpire
// 完全修复按钮
Command_Action fullRepairCommand = new Command_Action
{
- defaultLabel = "DD_Debug_FullRepair".Translate(),
- defaultDesc = "DD_Debug_FullRepairDesc".Translate(),
+ defaultLabel = "WULA_Debug_FullRepair".Translate(),
+ defaultDesc = "WULA_Debug_FullRepairDesc".Translate(),
icon = ContentFinder.Get("UI/Commands/Repair", false) ?? BaseContent.BadTex,
action = () => DebugFullRepair()
};
@@ -125,8 +125,8 @@ namespace WulaFallenEmpire
// 显示维修统计
Command_Action statsCommand = new Command_Action
{
- defaultLabel = "DD_Debug_RepairStats".Translate(),
- defaultDesc = "DD_Debug_RepairStatsDesc".Translate(totalRepairedHP.ToString("F1")),
+ defaultLabel = "WULA_Debug_RepairStats".Translate(),
+ defaultDesc = "WULA_Debug_RepairStatsDesc".Translate(totalRepairedHP.ToString("F1")),
icon = ContentFinder.Get("UI/Commands/Stats", false) ?? BaseContent.BadTex,
action = () => DebugShowStats()
};
@@ -145,7 +145,7 @@ namespace WulaFallenEmpire
if (bestColonist == null)
{
- Messages.Message("DD_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
+ Messages.Message("WULA_NoColonistAvailable".Translate(), parent, MessageTypeDefOf.RejectInput);
return;
}
@@ -156,7 +156,7 @@ namespace WulaFallenEmpire
bestColonist.jobs.StartJob(job, JobCondition.InterruptForced, null, resumeCurJobAfterwards: true);
// 显示消息
- Messages.Message("DD_OrderedRepair".Translate(bestColonist.LabelShort, parent.LabelShort),
+ Messages.Message("WULA_OrderedRepair".Translate(bestColonist.LabelShort, parent.LabelShort),
parent, MessageTypeDefOf.PositiveEvent);
}
@@ -221,7 +221,7 @@ namespace WulaFallenEmpire
DamageInfo dinfo = new DamageInfo(DamageDefOf.Cut, damage, 1f, -1f, null, part);
mech.TakeDamage(dinfo);
- Messages.Message($"DD_Debug_Damaged".Translate(parent.LabelShort, damage.ToString("F1")),
+ Messages.Message($"WULA_Debug_Damaged".Translate(parent.LabelShort, damage.ToString("F1")),
parent, MessageTypeDefOf.NeutralEvent);
}
@@ -246,14 +246,14 @@ namespace WulaFallenEmpire
}
}
- Messages.Message($"DD_Debug_FullyRepaired".Translate(parent.LabelShort),
+ Messages.Message($"WULA_Debug_FullyRepaired".Translate(parent.LabelShort),
parent, MessageTypeDefOf.PositiveEvent);
}
// 调试功能:显示维修统计
private void DebugShowStats()
{
- Messages.Message($"DD_Debug_RepairStatsInfo".Translate(
+ Messages.Message($"WULA_Debug_RepairStatsInfo".Translate(
parent.LabelShort,
totalRepairedHP.ToString("F1"),
Props.repairAmountPerCycle.ToString("F1"),
@@ -277,7 +277,7 @@ namespace WulaFallenEmpire
string repairString = "";
if (NeedsRepair)
{
- repairString = "DD_NeedsRepair".Translate().Colorize(Color.yellow);
+ repairString = "WULA_NeedsRepair".Translate().Colorize(Color.yellow);
}
if (!baseString.NullOrEmpty())
diff --git a/Source/WulaFallenEmpire/Pawn_Comps/MoteEmitterNorthward/CompMoteEmitterNorthward.cs b/Source/WulaFallenEmpire/Pawn_Comps/MoteEmitterNorthward/CompMoteEmitterNorthward.cs
index 1c9cc887..8c76b946 100644
--- a/Source/WulaFallenEmpire/Pawn_Comps/MoteEmitterNorthward/CompMoteEmitterNorthward.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/MoteEmitterNorthward/CompMoteEmitterNorthward.cs
@@ -55,7 +55,7 @@ namespace WulaFallenEmpire
// 如果需要驾驶员但组件不存在,发出警告
if (Props.requirePilot && pilotHolder == null)
{
- Log.Warning($"[DD] CompMoteEmitterNorthward on {parent} requires pilot but no CompMechPilotHolder found");
+ Log.Warning($"[WULA] CompMoteEmitterNorthward on {parent} requires pilot but no CompMechPilotHolder found");
}
// 初始化位置
@@ -154,7 +154,7 @@ namespace WulaFallenEmpire
catch (NullReferenceException ex)
{
// 发生异常时重置状态
- Log.Warning($"[DD] Error updating movement state for {parent}: {ex.Message}");
+ Log.Warning($"[WULA] Error updating movement state for {parent}: {ex.Message}");
isMoving = false;
}
}
@@ -284,7 +284,7 @@ namespace WulaFallenEmpire
}
catch (Exception ex)
{
- Log.Error($"[DD] Error emitting mote: {ex}");
+ Log.Error($"[WULA] Error emitting mote: {ex}");
}
}
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_PawnRenderExtra/Comp_PawnRenderExtra.cs b/Source/WulaFallenEmpire/Pawn_Comps/PawnRenderExtra/Comp_PawnRenderExtra.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_PawnRenderExtra/Comp_PawnRenderExtra.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/PawnRenderExtra/Comp_PawnRenderExtra.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Flight/CompPawnFlight.cs b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_Flight/CompPawnFlight.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompPawnFlight.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Flight/CompProperties_PawnFlight.cs b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompProperties_PawnFlight.cs
similarity index 77%
rename from Source/WulaFallenEmpire/Pawn/WULA_Flight/CompProperties_PawnFlight.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompProperties_PawnFlight.cs
index ae079fbb..62618e9e 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Flight/CompProperties_PawnFlight.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/CompProperties_PawnFlight.cs
@@ -1,13 +1,13 @@
using Verse;
using RimWorld;
-using System.Collections.Generic;
namespace WulaFallenEmpire
{
public enum FlightCondition
{
Drafted,
- MechAlwaysExceptSpecialJobs // 新增:机械族在非特殊工作状态下始终飞行
+ DraftedAndMove,
+ Always
}
public class CompProperties_PawnFlight : CompProperties
@@ -15,13 +15,6 @@ namespace WulaFallenEmpire
// --- Custom Flight Logic ---
public FlightCondition flightCondition = FlightCondition.Drafted;
- // --- 新增:机械族特殊工作检查 ---
- public List mechForbiddenJobs = new List
- {
- JobDefOf.MechCharge, // 充电工作
- JobDefOf.SelfShutdown // 关机工作
- };
-
// --- Vanilla PawnKindDef Flight Parameters ---
[NoTranslate]
public string flyingAnimationFramePathPrefix;
@@ -40,6 +33,8 @@ namespace WulaFallenEmpire
public bool flyingAnimationInheritColors;
// --- Vanilla PawnKindLifeStage Flight Parameters ---
+ // Note: These are normally defined per lifestage, we define them once here for simplicity.
+ // The harmony patch will need to inject these into the correct lifestage at runtime.
public AnimationDef flyingAnimationEast;
public AnimationDef flyingAnimationNorth;
public AnimationDef flyingAnimationSouth;
@@ -47,9 +42,10 @@ namespace WulaFallenEmpire
public AnimationDef flyingAnimationNorthFemale;
public AnimationDef flyingAnimationSouthFemale;
+
public CompProperties_PawnFlight()
{
compClass = typeof(CompPawnFlight);
}
}
-}
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Flight/PawnRenderNodeWorker_AttachmentBody_NoFlight.cs b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/PawnRenderNodeWorker_AttachmentBody_NoFlight.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Pawn/WULA_Flight/PawnRenderNodeWorker_AttachmentBody_NoFlight.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/PawnRenderNodeWorker_AttachmentBody_NoFlight.cs
diff --git a/Source/WulaFallenEmpire/Pawn/WULA_Flight/Pawn_FlightTrackerPatches.cs b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/Pawn_FlightTrackerPatches.cs
similarity index 84%
rename from Source/WulaFallenEmpire/Pawn/WULA_Flight/Pawn_FlightTrackerPatches.cs
rename to Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/Pawn_FlightTrackerPatches.cs
index 000a9bb3..cfb5324b 100644
--- a/Source/WulaFallenEmpire/Pawn/WULA_Flight/Pawn_FlightTrackerPatches.cs
+++ b/Source/WulaFallenEmpire/Pawn_Comps/Pawn_Flight/Pawn_FlightTrackerPatches.cs
@@ -62,8 +62,20 @@ namespace WulaFallenEmpire
return true;
}
+ bool shouldBeFlying = false;
var compProps = flightComp.Props;
- bool shouldBeFlying = (compProps.flightCondition == FlightCondition.Drafted && ___pawn.Drafted);
+ if (compProps.flightCondition == FlightCondition.Always)
+ {
+ shouldBeFlying = true;
+ }
+ else if (compProps.flightCondition == FlightCondition.DraftedAndMove && ___pawn.Drafted || ___pawn.pather.MovingNow)
+ {
+ shouldBeFlying = true;
+ }
+ else if (compProps.flightCondition == FlightCondition.Drafted && ___pawn.Drafted)
+ {
+ shouldBeFlying = true;
+ }
if (shouldBeFlying)
{
diff --git a/Source/WulaFallenEmpire/Utils/DefInjectedExportUtility.cs b/Source/WulaFallenEmpire/Utils/DefInjectedExportUtility.cs
index 77160374..7e281f1a 100644
--- a/Source/WulaFallenEmpire/Utils/DefInjectedExportUtility.cs
+++ b/Source/WulaFallenEmpire/Utils/DefInjectedExportUtility.cs
@@ -33,7 +33,7 @@ namespace WulaFallenEmpire.Utils
string outRoot = Path.Combine(
GenFilePaths.SaveDataFolderPath,
"WulaFallenEmpire_DefInjectedExport",
- DateTime.Now.ToString("yyyyMMdd_HHmmss"));
+ DateTime.Now.ToString("yyyyMMWULA_HHmmss"));
string outDefInjected = Path.Combine(outRoot, "English", "DefInjected");
Directory.CreateDirectory(outDefInjected);
diff --git a/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs b/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs
new file mode 100644
index 00000000..ec8039bd
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/EnterMech/FloatMenuOptionProvider_EnterMech.cs
@@ -0,0 +1,213 @@
+// File: FloatMenuOptionProvider_EnterMech.cs
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class FloatMenuOptionProvider_EnterMech : FloatMenuOptionProvider
+ {
+
+ // 检查Thing是否为机甲
+ private bool IsMech(Thing thing)
+ {
+ return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
+ }
+
+ protected override bool Drafted => true; // 征召状态下不能进入机甲
+ protected override bool Undrafted => true; // 非征召状态下可以进入
+ protected override bool Multiselect => true; // 不支持多选
+
+ // 检查是否适用于当前上下文
+ protected override bool AppliesInt(FloatMenuContext context)
+ {
+ // 必须有选中的殖民者
+ if (context.FirstSelectedPawn == null)
+ return false;
+
+ // 检查点击的单元格中是否有机甲
+ var clickedThings = context.ClickedThings;
+ if (clickedThings == null || clickedThings.Count == 0)
+ return false;
+
+ // 查找第一个机甲
+ Thing mech = null;
+ foreach (var thing in clickedThings)
+ {
+ if (IsMech(thing))
+ {
+ mech = thing;
+ break;
+ }
+ }
+
+ if (mech == null)
+ return false;
+
+ // 检查机甲是否有驾驶员组件
+ var comp = mech.TryGetComp();
+ if (comp == null)
+ return false;
+
+ // 检查殖民者是否已经在机甲内
+ // 由于CompMechPilotHolder没有ContainsPilot方法,我们需要通过其他方式检查
+ if (IsPawnInMech(context.FirstSelectedPawn, mech))
+ return false;
+
+ return true;
+ }
+
+ // 检查殖民者是否已经在机甲内(替代ContainsPilot)
+ private bool IsPawnInMech(Pawn pawn, Thing mech)
+ {
+ var comp = mech.TryGetComp();
+ if (comp == null)
+ return false;
+
+ // 尝试通过内部容器检查
+ var holder = comp as IThingHolder;
+ if (holder != null)
+ {
+ var things = holder.GetDirectlyHeldThings();
+ if (things != null && things.Contains(pawn))
+ return true;
+ }
+
+ // 或者尝试通过其他属性检查
+ // 这里假设CompMechPilotHolder有HasPilots属性
+ if (comp.HasPilots)
+ {
+ // 如果有必要,可以通过反射或其他方式检查具体驾驶员
+ // 暂时返回false,假设不在机甲内
+ return false;
+ }
+
+ return false;
+ }
+
+ // 获取单个选项
+ protected override FloatMenuOption GetSingleOptionFor(Thing clickedThing, FloatMenuContext context)
+ {
+ if (clickedThing == null || context.FirstSelectedPawn == null)
+ return null;
+
+ // 如果不是机甲,返回null
+ if (!IsMech(clickedThing))
+ return null;
+
+ // 获取机甲和组件
+ var mech = clickedThing as Wulamechunit;
+ var comp = mech?.TryGetComp();
+
+ if (mech == null || comp == null)
+ return null;
+
+ // 检查殖民者是否已经在机甲内
+ if (IsPawnInMech(context.FirstSelectedPawn, mech))
+ return null;
+
+ // 检查各种条件,生成相应的菜单选项
+ return CreateEnterMechOption(mech, context.FirstSelectedPawn, comp);
+ }
+
+ // 创建进入机甲的菜单选项
+ private FloatMenuOption CreateEnterMechOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp)
+ {
+ string label = "WULA_EnterMech".Translate(mech.LabelShort);
+ string disabledReason = "";
+
+ // 检查条件是否允许进入
+ bool canEnter = CanEnterMech(mech, pawn, comp, ref disabledReason);
+
+ // 如果条件允许,创建可点击的选项
+ if (canEnter)
+ {
+ return new FloatMenuOption(label, () =>
+ {
+ // 创建进入机甲的工作
+ Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, mech);
+ pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+
+ // 播放音效(如果有的话)
+ FleckMaker.Static(mech.DrawPos, mech.MapHeld, FleckDefOf.FeedbackEquip);
+ }, MenuOptionPriority.High);
+ }
+ else
+ {
+ // 创建禁用的选项,显示原因
+ return new FloatMenuOption(
+ "WULA_EnterMech".Translate(mech.LabelShort) + ": " + disabledReason,
+ null,
+ MenuOptionPriority.DisabledOption);
+ }
+ }
+
+ // 检查殖民者是否可以进入机甲
+ private bool CanEnterMech(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason)
+ {
+ // 检查机甲是否已满
+ if (comp.IsFull)
+ {
+ disabledReason = "WULA_MechFull".Translate();
+ return false;
+ }
+
+ // 检查殖民者是否可以成为驾驶员
+ if (!comp.CanAddPilot(pawn))
+ {
+ disabledReason = "WULA_CannotBecomePilot".Translate();
+ return false;
+ }
+
+ // 检查距离
+ if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Deadly))
+ {
+ disabledReason = "NoPath".Translate();
+ return false;
+ }
+
+ // 检查殖民者状态
+ if (pawn.Downed)
+ {
+ disabledReason = "Downed".Translate();
+ return false;
+ }
+
+ if (pawn.Dead)
+ {
+ disabledReason = "Dead".Translate();
+ return false;
+ }
+
+ // 检查是否为囚犯
+ if (pawn.IsPrisoner)
+ {
+ disabledReason = "Prisoner".Translate();
+ return false;
+ }
+
+ // 检查是否为奴隶
+ if (pawn.IsSlave)
+ {
+ disabledReason = "Slave".Translate();
+ return false;
+ }
+
+ // 检查机甲状态
+ if (mech.Downed)
+ {
+ disabledReason = "Downed".Translate();
+ return false;
+ }
+
+ if (mech.Dead)
+ {
+ disabledReason = "Dead".Translate();
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/EnterMech/JobDriver_EnterMech.cs b/Source/WulaFallenEmpire/Work/EnterMech/JobDriver_EnterMech.cs
new file mode 100644
index 00000000..40b9616e
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/EnterMech/JobDriver_EnterMech.cs
@@ -0,0 +1,76 @@
+// File: JobDriver_EnterMech.cs (不再保留机甲)
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+namespace WulaFallenEmpire
+{
+ public class JobDriver_EnterMech : JobDriver
+ {
+ private const TargetIndex MechIndex = TargetIndex.A;
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ Pawn pawn = this.pawn;
+ LocalTargetInfo target = this.job.GetTarget(MechIndex);
+
+ // 不再保留机甲,这样多个殖民者可以同时被命令进入同一个机甲
+ // 只需要检查殖民者是否可以到达机甲
+ if (!pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ // 0. 初始检查
+ AddFailCondition(() =>
+ {
+ var mech = TargetThingA as Wulamechunit;
+ if (mech == null || mech.Destroyed)
+ {
+ return true;
+ }
+
+ var comp = mech.GetComp();
+ if (comp == null || comp.IsFull || !comp.CanAddPilot(pawn))
+ {
+ return true;
+ }
+
+ if (pawn.Downed || pawn.Dead)
+ return true;
+
+ return false;
+ });
+
+ // 1. 走到机甲旁边
+ yield return Toils_Goto.GotoThing(MechIndex, PathEndMode.Touch);
+
+ // 2. 检查是否仍然可以进入
+ yield return Toils_General.Wait(10).WithProgressBarToilDelay(MechIndex);
+
+ // 3. 进入机甲
+ Toil enterToil = new Toil();
+ enterToil.initAction = () =>
+ {
+ var mech = TargetThingA as Wulamechunit;
+ if (mech == null)
+ return;
+
+ var comp = mech.GetComp();
+ if (comp != null && comp.CanAddPilot(pawn))
+ {
+ comp.AddPilot(pawn);
+ Messages.Message("WULA_PilotEnteredMech".Translate(pawn.LabelShort, mech.LabelShort),
+ MessageTypeDefOf.PositiveEvent, false);
+ }
+ };
+ enterToil.defaultCompleteMode = ToilCompleteMode.Instant;
+ yield return enterToil;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs b/Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
new file mode 100644
index 00000000..6e9ed9d5
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/EnterMech/WorkGiver_EnterMech.cs
@@ -0,0 +1,188 @@
+// File: WorkGiver_EnterMech.cs
+using RimWorld;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Verse;
+using Verse.AI;
+namespace WulaFallenEmpire
+{
+ public class WorkGiver_EnterMech : WorkGiver_Scanner
+ {
+ // 缓存机甲定义列表
+ private static List cachedMechDefs = null;
+
+ public override PathEndMode PathEndMode => PathEndMode.Touch;
+
+ // 获取所有机甲定义的列表
+ private List GetAllMechDefs()
+ {
+ if (cachedMechDefs == null)
+ {
+ cachedMechDefs = new List();
+
+ // 搜索所有ThingDef,找出继承自Wulamechunit的类
+ foreach (var def in DefDatabase.AllDefs)
+ {
+ try
+ {
+ if (def.thingClass == typeof(Wulamechunit) ||
+ def.thingClass?.IsSubclassOf(typeof(Wulamechunit)) == true)
+ {
+ cachedMechDefs.Add(def);
+ }
+ }
+ catch (Exception ex)
+ {
+ // 忽略错误,继续搜索
+ Log.Warning($"[WULA] Error checking ThingDef {def.defName}: {ex.Message}");
+ }
+ }
+ }
+
+ return cachedMechDefs;
+ }
+
+ // 检查Thing是否为机甲
+ private bool IsMech(Thing thing)
+ {
+ return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
+ }
+
+ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ try
+ {
+ // 检查基本条件
+ if (t == null || pawn == null)
+ return false;
+
+ // 必须是Wulamechunit或其子类
+ if (!IsMech(t))
+ return false;
+
+ // 检查距离
+ if (!pawn.CanReach(t, PathEndMode, Danger.Deadly))
+ return false;
+
+ // 检查机甲是否有驾驶员槽位组件
+ var comp = t.TryGetComp();
+ if (comp == null)
+ return false;
+
+ // 检查是否已满
+ if (comp.IsFull)
+ return false;
+
+ // 检查殖民者是否可以成为驾驶员
+ if (!comp.CanAddPilot(pawn))
+ return false;
+
+ // 检查殖民者状态
+ if (pawn.Downed || pawn.Dead)
+ return false;
+
+ // 检查殖民者是否正在执行任务
+ if (pawn.CurJob != null && pawn.CurJob.def != JobDefOf.Wait)
+ return false;
+
+ // 检查是否被征召
+ if (pawn.Drafted)
+ return false;
+
+ // 检查是否为囚犯
+ if (pawn.IsPrisoner)
+ return false;
+
+ // 检查是否为奴隶
+ if (pawn.IsSlave)
+ return false;
+
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"[WULA] Error in HasJobOnThing: {ex}");
+ return false;
+ }
+ }
+
+ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ try
+ {
+ if (IsMech(t))
+ {
+ // 创建进入机甲的工作
+ return JobMaker.MakeJob(Wula_JobDefOf.WULA_EnterMech, t);
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"[WULA] Error creating job: {ex}");
+ }
+
+ return null;
+ }
+
+ public override IEnumerable PotentialWorkThingsGlobal(Pawn pawn)
+ {
+ try
+ {
+ // 只搜索玩家拥有的机甲
+ List potentialMechs = new List();
+
+ // 获取地图中的所有机甲
+ if (pawn.Map != null)
+ {
+ // 使用缓存的机甲定义列表
+ var mechDefs = GetAllMechDefs();
+
+ foreach (var def in mechDefs)
+ {
+ try
+ {
+ var allMechs = pawn.Map.listerThings.ThingsOfDef(def);
+ foreach (var mech in allMechs)
+ {
+ if (mech.Faction == Faction.OfPlayer &&
+ mech.TryGetComp() != null)
+ {
+ potentialMechs.Add(mech);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Warning($"[WULA] Error getting mechs for def {def.defName}: {ex.Message}");
+ }
+ }
+ }
+
+ return potentialMechs;
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"[WULA] Error in PotentialWorkThingsGlobal: {ex}");
+ return Enumerable.Empty();
+ }
+ }
+
+ public override bool ShouldSkip(Pawn pawn, bool forced = false)
+ {
+ try
+ {
+ // 简化版本:只检查殖民者状态
+ if (pawn.Downed || pawn.Dead || pawn.Drafted || pawn.IsPrisoner || pawn.IsSlave)
+ return true;
+
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Log.Error($"[WULA] Error in ShouldSkip: {ex}");
+ return true;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Work/ForceEjectPilot/FloatMenuOptionProvider_ForceEjectPilot.cs b/Source/WulaFallenEmpire/Work/ForceEjectPilot/FloatMenuOptionProvider_ForceEjectPilot.cs
new file mode 100644
index 00000000..81e7f1b5
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/ForceEjectPilot/FloatMenuOptionProvider_ForceEjectPilot.cs
@@ -0,0 +1,182 @@
+// File: FloatMenuOptionProvider_ForceEjectPilot.cs
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class FloatMenuOptionProvider_ForceEjectPilot : FloatMenuOptionProvider
+ {
+ // 征召状态下不能执行此工作
+ protected override bool Drafted => true;
+
+ // 非征召状态下可以执行
+ protected override bool Undrafted => true;
+
+ // 不支持多选
+ protected override bool Multiselect => false;
+
+ // 需要操纵能力
+ protected override bool RequiresManipulation => true;
+
+ // 检查Thing是否为机甲
+ private bool IsMech(Pawn thing)
+ {
+ return thing is Wulamechunit || thing?.GetType()?.IsSubclassOf(typeof(Wulamechunit)) == true;
+ }
+
+ // 检查是否适用于当前上下文
+ protected override bool AppliesInt(FloatMenuContext context)
+ {
+ // 必须有选中的殖民者
+ if (context.FirstSelectedPawn == null)
+ return false;
+
+ // 检查点击的单元格中是否有机甲
+ var ClickedPawns = context.ClickedPawns;
+ if (ClickedPawns == null || ClickedPawns.Count == 0)
+ return false;
+
+ // 查找第一个机甲
+ Pawn mech = null;
+ foreach (var thing in ClickedPawns)
+ {
+ if (IsMech(thing))
+ {
+ mech = thing;
+ break;
+ }
+ }
+
+ if (mech == null)
+ return false;
+
+ // 检查机甲是否有驾驶员组件
+ var comp = mech.TryGetComp();
+ if (comp == null)
+ return false;
+
+ // 检查机甲是否属于非玩家派系,且Downed但未死亡,并且有驾驶员
+ if (mech.Faction == Faction.OfPlayer || !mech.Downed || mech.Dead || !comp.HasPilots)
+ return false;
+
+ return true;
+ }
+
+ // 获取单个选项
+ protected override FloatMenuOption GetSingleOptionFor(Pawn clickedPawn, FloatMenuContext context)
+ {
+ if (clickedPawn == null || context.FirstSelectedPawn == null)
+ return null;
+
+ // 如果不是机甲,返回null
+ if (!IsMech(clickedPawn))
+ return null;
+
+ // 获取机甲和组件
+ var mech = clickedPawn as Wulamechunit;
+ var comp = mech?.TryGetComp();
+
+ if (mech == null || comp == null)
+ return null;
+
+ // 检查机甲是否属于非玩家派系,且Downed但未死亡,并且有驾驶员
+ if (mech.Faction == Faction.OfPlayer || !mech.Downed || mech.Dead || !comp.HasPilots)
+ return null;
+
+ // 检查殖民者是否能够执行此工作
+ return CreateForceEjectOption(mech, context.FirstSelectedPawn, comp);
+ }
+
+ // 创建强制拉出驾驶员的菜单选项
+ private FloatMenuOption CreateForceEjectOption(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp)
+ {
+ string label = "WULA_ForceEjectPilot".Translate(mech.LabelShort);
+ string disabledReason = "";
+
+ // 检查条件是否允许执行强制拉出
+ bool canForceEject = CanForceEject(mech, pawn, comp, ref disabledReason);
+
+ if (canForceEject)
+ {
+ return new FloatMenuOption(label, () =>
+ {
+ // 创建强制拉出驾驶员的工作
+ Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_ForceEjectPilot, mech);
+ pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
+ }, MenuOptionPriority.High);
+ }
+ else
+ {
+ // 创建禁用的选项,显示原因
+ return new FloatMenuOption(
+ "WULA_ForceEjectPilot".Translate(mech.LabelShort) + ": " + disabledReason,
+ null,
+ MenuOptionPriority.DisabledOption);
+ }
+ }
+
+ // 检查殖民者是否可以执行强制拉出
+ private bool CanForceEject(Wulamechunit mech, Pawn pawn, CompMechPilotHolder comp, ref string disabledReason)
+ {
+ // 检查殖民者是否能够到达机甲
+ if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Some))
+ {
+ disabledReason = "NoPath".Translate();
+ return false;
+ }
+
+ // 检查殖民者状态
+ if (pawn.Downed)
+ {
+ disabledReason = "Downed".Translate();
+ return false;
+ }
+
+ if (pawn.Dead)
+ {
+ disabledReason = "Dead".Translate();
+ return false;
+ }
+
+ // 检查是否为囚犯
+ if (pawn.IsPrisoner)
+ {
+ disabledReason = "Prisoner".Translate();
+ return false;
+ }
+
+ // 检查是否为奴隶
+ if (pawn.IsSlave)
+ {
+ disabledReason = "Slave".Translate();
+ return false;
+ }
+
+ // 检查机甲是否已经被玩家派系控制
+ if (mech.Faction == Faction.OfPlayer)
+ {
+ disabledReason = "WULA_AlreadyPlayerMech".Translate();
+ return false;
+ }
+
+ // 检查机甲是否Downed且未死亡
+ if (!mech.Downed || mech.Dead)
+ {
+ disabledReason = "WULA_MechNotDowned".Translate();
+ return false;
+ }
+
+ // 检查是否有驾驶员
+ if (!comp.HasPilots)
+ {
+ disabledReason = "WULA_NoPilot".Translate();
+ return false;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/ForceEjectPilot/JobDriver_ForceEjectPilot.cs b/Source/WulaFallenEmpire/Work/ForceEjectPilot/JobDriver_ForceEjectPilot.cs
new file mode 100644
index 00000000..a7963936
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/ForceEjectPilot/JobDriver_ForceEjectPilot.cs
@@ -0,0 +1,177 @@
+// Jobs/JobDriver_ForceEjectPilot.cs
+using RimWorld;
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using System.Linq;
+
+namespace WulaFallenEmpire
+{
+ public class JobDriver_ForceEjectPilot : JobDriver
+ {
+ private const int WorkDurationTicks = 600; // 10秒(60帧/秒)
+
+ // 目标机甲
+ private Pawn TargetMech => job.targetA.Thing as Pawn;
+
+ // 工作进度属性
+ private float WorkProgress
+ {
+ get
+ {
+ if (TargetMech == null) return 0f;
+ return (float)ticksLeftThisToil / WorkDurationTicks;
+ }
+ }
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ // 为殖民者预留机甲的位置
+ return pawn.Reserve(TargetMech, job, 1, -1, null, errorOnFailed);
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ // 目标验证
+ this.FailOnDespawnedNullOrForbidden(TargetIndex.A);
+ this.FailOn(() => !CanForceEject(TargetMech));
+
+ // Toil 1:移动到机甲位置
+ yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch)
+ .FailOnDespawnedOrNull(TargetIndex.A);
+
+ // Toil 2:执行强制拉出工作
+ var workToil = new Toil();
+ workToil.initAction = () =>
+ {
+ pawn.rotationTracker.FaceCell(TargetMech.Position);
+ pawn.jobs.posture = PawnPosture.Standing;
+ };
+ workToil.tickAction = () =>
+ {
+ // 每帧工作进度
+ pawn.skills?.Learn(SkillDefOf.Melee, 0.1f);
+
+ // 显示工作条
+ if (pawn.IsColonistPlayerControlled)
+ {
+ TargetMech.Map.overlayDrawer.DrawOverlay(TargetMech, OverlayTypes.QuestionMark);
+ }
+ };
+ workToil.defaultCompleteMode = ToilCompleteMode.Delay;
+ workToil.WithEffect(EffecterDefOf.MechRepairing, TargetIndex.A);
+ workToil.defaultDuration = WorkDurationTicks;
+ workToil.WithProgressBar(TargetIndex.A, () => 1f - WorkProgress);
+ workToil.handlingFacing = true;
+ workToil.activeSkill = () => SkillDefOf.Construction;
+ yield return workToil;
+
+ // Toil 3:完成工作
+ yield return new Toil
+ {
+ initAction = () =>
+ {
+ CompleteForceEject();
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+ }
+
+ // 检查是否可以强制拉出
+ private bool CanForceEject(Pawn mech)
+ {
+ if (mech == null || mech.Dead)
+ return false;
+
+ // 必须是机甲
+ if (!(mech is Wulamechunit))
+ return false;
+
+ // 必须是玩家派系的目标
+ if (mech.Faction == Faction.OfPlayer)
+ return false;
+
+ // 必须失去行动能力但未死亡
+ if (!mech.Downed)
+ return false;
+
+ // 必须有驾驶员
+ var pilotComp = mech.TryGetComp();
+ if (pilotComp == null || !pilotComp.HasPilots)
+ return false;
+
+ // 殖民者必须能够接触机甲
+ if (!pawn.CanReach(mech, PathEndMode.Touch, Danger.Some))
+ return false;
+
+ // 殖民者不能是囚犯或已失去行动能力
+ if (pawn.Downed || pawn.Dead || pawn.IsPrisoner)
+ return false;
+
+ return true;
+ }
+
+ // 完成强制拉出
+ private void CompleteForceEject()
+ {
+ var mech = TargetMech;
+ if (mech == null) return;
+
+ var pilotComp = mech.TryGetComp();
+ if (pilotComp == null) return;
+
+ try
+ {
+ // 1. 弹出所有驾驶员
+ var ejectedPilots = pilotComp.GetPilots().ToList();
+ pilotComp.RemoveAllPilots();
+
+ // 2. 转换派系为玩家
+ mech.SetFaction(Faction.OfPlayer);
+
+ // 4. 发送消息
+ SendCompletionMessages(mech, ejectedPilots);
+ }
+ catch (System.Exception ex)
+ {
+ Log.Error($"[WULA] Error in ForceEjectPilot: {ex}");
+ }
+ }
+
+ // 发送完成消息
+ private void SendCompletionMessages(Pawn mech, List ejectedPilots)
+ {
+ string message;
+
+ if (ejectedPilots.Count > 0)
+ {
+ message = "WULA_ForceEjectComplete_WithPilots".Translate(
+ pawn.LabelShortCap,
+ mech.LabelShortCap,
+ ejectedPilots.Count
+ );
+ }
+ else
+ {
+ message = "WULA_ForceEjectComplete".Translate(
+ pawn.LabelShortCap,
+ mech.LabelShortCap
+ );
+ }
+
+ Messages.Message(message, MessageTypeDefOf.PositiveEvent);
+
+ // 如果弹出的是敌对派系驾驶员,添加额外消息
+ foreach (var pilot in ejectedPilots)
+ {
+ if (pilot.Faction != null && pilot.Faction.HostileTo(Faction.OfPlayer))
+ {
+ Messages.Message("WULA_HostilePilotEjected".Translate(
+ pilot.LabelShortCap,
+ pilot.Faction.Name
+ ), MessageTypeDefOf.NeutralEvent);
+ }
+ }
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Job/JobDriver_InspectBuilding.cs b/Source/WulaFallenEmpire/Work/InspectBuilding/JobDriver_InspectBuilding.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Job/JobDriver_InspectBuilding.cs
rename to Source/WulaFallenEmpire/Work/InspectBuilding/JobDriver_InspectBuilding.cs
diff --git a/Source/WulaFallenEmpire/Job/JobGiver_InspectBuilding.cs b/Source/WulaFallenEmpire/Work/InspectBuilding/JobGiver_InspectBuilding.cs
similarity index 100%
rename from Source/WulaFallenEmpire/Job/JobGiver_InspectBuilding.cs
rename to Source/WulaFallenEmpire/Work/InspectBuilding/JobGiver_InspectBuilding.cs
diff --git a/Source/WulaFallenEmpire/Work/JobDriver_CarryToMech.cs b/Source/WulaFallenEmpire/Work/JobDriver_CarryToMech.cs
new file mode 100644
index 00000000..95c0b351
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/JobDriver_CarryToMech.cs
@@ -0,0 +1,82 @@
+// File: JobDriver_CarryToMech.cs (修复count问题)
+using System.Collections.Generic;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class JobDriver_CarryToMech : JobDriver
+ {
+ private const TargetIndex TakeeIndex = TargetIndex.A;
+ private const TargetIndex MechIndex = TargetIndex.B;
+
+ protected Pawn Takee => (Pawn)job.GetTarget(TakeeIndex).Thing;
+ protected Wulamechunit Mech => (Wulamechunit)job.GetTarget(MechIndex).Thing;
+ protected CompMechPilotHolder MechComp => Mech?.TryGetComp();
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ // 确保job.count是有效的(至少为1)
+ if (job.count <= 0)
+ {
+ job.count = 1;
+ }
+
+ // 保留目标和机甲,明确指定数量为1
+ return pawn.Reserve(Takee, job, 1, -1, null, errorOnFailed)
+ && pawn.Reserve(Mech, job, 1, -1, null, errorOnFailed);
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ // 确保job.count是有效的
+ if (job.count <= 0)
+ {
+ job.count = 1;
+ }
+
+ // 标准失败条件
+ this.FailOnDestroyedOrNull(TakeeIndex);
+ this.FailOnDestroyedOrNull(MechIndex);
+ this.FailOn(() => MechComp == null);
+ this.FailOn(() => !Takee.Downed); // 确保被搬运者是Downed状态
+
+ // 1. 前往要被搬运的殖民者
+ yield return Toils_Goto.GotoThing(TakeeIndex, PathEndMode.ClosestTouch)
+ .FailOnDespawnedNullOrForbidden(TakeeIndex)
+ .FailOnDespawnedNullOrForbidden(MechIndex)
+ .FailOnSomeonePhysicallyInteracting(TakeeIndex);
+
+ // 2. 开始搬运殖民者 - 使用原版的StartCarryThing方法
+ yield return Toils_Haul.StartCarryThing(TakeeIndex, false, true, false);
+
+ // 3. 携带殖民者前往机甲
+ yield return Toils_Goto.GotoThing(MechIndex, PathEndMode.Touch);
+
+ // 4. 将殖民者放入机甲
+ yield return new Toil
+ {
+ initAction = () =>
+ {
+ if (MechComp != null && Takee != null && MechComp.CanAddPilot(Takee))
+ {
+ // 放下殖民者
+ if (pawn.carryTracker.CarriedThing == Takee)
+ {
+ pawn.carryTracker.TryDropCarriedThing(pawn.Position, ThingPlaceMode.Near, out Thing droppedThing);
+ }
+
+ // 将殖民者添加到机甲
+ MechComp.AddPilot(Takee);
+ }
+ else
+ {
+ Log.Warning($"[WULA] 无法将殖民者添加到机甲");
+ }
+ },
+ defaultCompleteMode = ToilCompleteMode.Instant
+ };
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/JobGiver_NoPilot.cs b/Source/WulaFallenEmpire/Work/JobGiver_NoPilot.cs
new file mode 100644
index 00000000..5a41a600
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/JobGiver_NoPilot.cs
@@ -0,0 +1,18 @@
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class JobGiver_NoPilot : ThinkNode_JobGiver
+ {
+ private const int WaitTime = 100;
+
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ Job job = JobMaker.MakeJob(JobDefOf.Wait);
+ job.expiryInterval = 100;
+ return job;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs b/Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
new file mode 100644
index 00000000..db020b66
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
@@ -0,0 +1,176 @@
+// JobDriver_RefuelMech.cs
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using Verse;
+using Verse.AI;
+using UnityEngine;
+
+namespace WulaFallenEmpire
+{
+ public class JobDriver_RefuelMech : JobDriver
+ {
+ private const TargetIndex MechInd = TargetIndex.A;
+ private const TargetIndex FuelInd = TargetIndex.B;
+ private const int RefuelingDuration = 240; // 基础加注时间
+
+ protected Pawn Mech => job.GetTarget(MechInd).Thing as Pawn;
+ protected CompMechFuel FuelComp => Mech?.TryGetComp();
+ protected Thing Fuel => job.GetTarget(FuelInd).Thing;
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ Pawn pawn = this.pawn;
+ Job job = this.job;
+ LocalTargetInfo target = job.GetTarget(MechInd);
+
+ if (!pawn.Reserve(target, job, 1, -1, null, errorOnFailed))
+ {
+ return false;
+ }
+
+ if (!pawn.Reserve(job.GetTarget(FuelInd), job, 1, -1, null, errorOnFailed))
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ // 检查目标是否有效
+ this.FailOnDespawnedNullOrForbidden(MechInd);
+ this.FailOn(() => FuelComp == null);
+
+ // 添加结束条件:燃料已满
+ AddEndCondition(() => {
+ if (FuelComp.IsFull)
+ return JobCondition.Succeeded;
+ return JobCondition.Ongoing;
+ });
+
+ // 如果不是玩家强制命令,检查是否应该自动加注
+ AddFailCondition(() => {
+ if (job.playerForced)
+ return false;
+
+ // 获取驾驶员组件
+ var pilotComp = Mech.TryGetComp();
+ bool hasPilot = pilotComp != null && pilotComp.HasPilots;
+
+ // 如果有驾驶员且不是玩家强制命令,不自动加注
+ if (hasPilot && !job.playerForced)
+ return true;
+
+ // 检查燃料组件是否允许自动加注
+ if (!FuelComp.Props.allowAutoRefuel && !job.playerForced)
+ return true;
+
+ return false;
+ });
+
+ // 第一步:计算需要多少燃料
+ yield return Toils_General.DoAtomic(delegate
+ {
+ if (FuelComp != null)
+ {
+ job.count = FuelComp.GetFuelCountToFullyRefuel();
+ }
+ });
+
+ // 第二步:预留燃料
+ Toil reserveFuel = Toils_Reserve.Reserve(FuelInd);
+ yield return reserveFuel;
+
+ // 第三步:前往燃料位置
+ yield return Toils_Goto.GotoThing(FuelInd, PathEndMode.ClosestTouch)
+ .FailOnDespawnedNullOrForbidden(FuelInd)
+ .FailOnSomeonePhysicallyInteracting(FuelInd);
+
+ // 第四步:拿起燃料
+ yield return Toils_Haul.StartCarryThing(FuelInd, putRemainderInQueue: false, subtractNumTakenFromJobCount: true)
+ .FailOnDestroyedNullOrForbidden(FuelInd);
+
+ // 第五步:检查是否有机会拿更多燃料
+ yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserveFuel, FuelInd, TargetIndex.None, takeFromValidStorage: true);
+
+ // 第六步:前往机甲位置
+ yield return Toils_Goto.GotoThing(MechInd, PathEndMode.Touch);
+
+ // 第七步:等待加注(有进度条)
+ Toil refuelToil = Toils_General.Wait(RefuelingDuration)
+ .FailOnDestroyedNullOrForbidden(FuelInd)
+ .FailOnDestroyedNullOrForbidden(MechInd)
+ .FailOnCannotTouch(MechInd, PathEndMode.Touch)
+ .WithProgressBarToilDelay(MechInd);
+
+ // 调整加注时间基于燃料组件的速度因子
+ refuelToil.defaultDuration = Mathf.RoundToInt(RefuelingDuration / FuelComp.Props.refuelSpeedFactor);
+
+ yield return refuelToil;
+
+ // 第八步:完成加注 - 模仿 RimWorld 原版实现
+ yield return FinalizeRefueling(MechInd, FuelInd);
+ }
+
+ // 模仿 RimWorld.Toils_Refuel.FinalizeRefueling 的实现
+ private static Toil FinalizeRefueling(TargetIndex refuelableInd, TargetIndex fuelInd)
+ {
+ Toil toil = ToilMaker.MakeToil("FinalizeRefueling");
+ toil.initAction = delegate
+ {
+ Pawn actor = toil.actor;
+ Job curJob = actor.CurJob;
+ Thing refuelable = curJob.GetTarget(refuelableInd).Thing;
+ CompMechFuel fuelComp = refuelable.TryGetComp();
+
+ if (fuelComp != null)
+ {
+ // 获取所有燃料物品
+ List fuelThings;
+ if (actor.CurJob.placedThings.NullOrEmpty())
+ {
+ // 如果没有 placedThings,则使用燃料目标
+ Thing fuel = curJob.GetTarget(fuelInd).Thing;
+ if (fuel != null)
+ {
+ fuelThings = new List { fuel };
+ }
+ else
+ {
+ fuelThings = null;
+ }
+ }
+ else
+ {
+ // 使用 placedThings 中的所有燃料物品
+ fuelThings = actor.CurJob.placedThings.Select((ThingCountClass p) => p.thing).ToList();
+ }
+
+ if (fuelThings != null)
+ {
+ // 计算总燃料量并销毁燃料物品
+ float totalFuel = 0f;
+ foreach (Thing fuelThing in fuelThings)
+ {
+ if (fuelThing != null && fuelThing.def == fuelComp.FuelType)
+ {
+ totalFuel += fuelThing.stackCount;
+ fuelThing.Destroy(DestroyMode.Vanish);
+ }
+ }
+
+ // 添加燃料到机甲
+ if (totalFuel > 0)
+ {
+ fuelComp.Refuel(totalFuel);
+ }
+ }
+ }
+ };
+ toil.defaultCompleteMode = ToilCompleteMode.Instant;
+ return toil;
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs b/Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
new file mode 100644
index 00000000..3544ab46
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
@@ -0,0 +1,123 @@
+// WorkGiver_RefuelMech.cs
+using System.Collections.Generic;
+using System.Linq;
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class WorkGiver_RefuelMech : WorkGiver_Scanner
+ {
+ public override PathEndMode PathEndMode => PathEndMode.Touch;
+
+ public override IEnumerable PotentialWorkThingsGlobal(Pawn pawn)
+ {
+ // 返回所有需要燃料的机甲
+ // 修复:使用 LINQ 的 Where 方法而不是 FindAll
+ var mechs = pawn.Map.mapPawns.AllPawnsSpawned.Where(p =>
+ p.TryGetComp() != null);
+
+ foreach (Pawn mech in mechs)
+ {
+ yield return mech;
+ }
+ }
+
+ public override bool ShouldSkip(Pawn pawn, bool forced = false)
+ {
+ // 如果没有需要燃料的机甲,跳过
+ return !PotentialWorkThingsGlobal(pawn).Any();
+ }
+
+ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ if (!(t is Pawn mech))
+ return false;
+
+ var fuelComp = mech.TryGetComp();
+ if (fuelComp == null)
+ return false;
+
+ // 检查机甲是否已加满燃料
+ if (fuelComp.IsFull)
+ return false;
+
+ // 检查是否有可用的燃料
+ if (FindFuel(pawn, fuelComp) == null)
+ return false;
+
+ // 检查是否能接触到机甲
+ if (!pawn.CanReserveAndReach(t, PathEndMode.Touch, Danger.Some))
+ return false;
+
+ // 检查机甲状态
+ var pilotComp = mech.TryGetComp();
+ bool hasPilot = pilotComp != null && pilotComp.HasPilots;
+
+ // 如果有驾驶员且不是强制命令,不自动加注
+ if (hasPilot && !forced)
+ return false;
+
+ // 检查燃料组件是否允许自动加注
+ if (!fuelComp.Props.allowAutoRefuel && !forced)
+ return false;
+
+ // 检查是否达到自动加注阈值
+ if (!forced && !fuelComp.NeedsRefueling)
+ return false;
+
+ return true;
+ }
+
+ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ var fuelComp = t.TryGetComp();
+ if (fuelComp == null)
+ return null;
+
+ // 寻找燃料
+ Thing fuel = FindFuel(pawn, fuelComp);
+ if (fuel == null)
+ return null;
+
+ // 创建加注工作
+ Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_RefuelMech, t, fuel);
+ job.count = fuelComp.GetFuelCountToFullyRefuel();
+ return job;
+ }
+
+ // 修改方法:返回 Thing 而不是 bool
+ private Thing FindFuel(Pawn pawn, CompMechFuel fuelComp)
+ {
+ if (fuelComp.FuelType == null)
+ return null;
+
+ // 在库存中寻找燃料
+ Thing fuel = FindFuelInInventory(pawn, fuelComp.FuelType);
+ if (fuel != null)
+ return fuel;
+
+ // 在地图上寻找燃料
+ fuel = GenClosest.ClosestThingReachable(
+ pawn.Position,
+ pawn.Map,
+ ThingRequest.ForDef(fuelComp.FuelType),
+ PathEndMode.ClosestTouch,
+ TraverseParms.For(pawn),
+ 9999f,
+ validator: thing => !thing.IsForbidden(pawn) && pawn.CanReserve(thing)
+ );
+
+ return fuel;
+ }
+
+ private Thing FindFuelInInventory(Pawn pawn, ThingDef fuelType)
+ {
+ if (pawn.inventory == null)
+ return null;
+
+ return pawn.inventory.innerContainer.FirstOrDefault(t => t.def == fuelType);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/RepairMech/JobDriver_RepairMech.cs b/Source/WulaFallenEmpire/Work/RepairMech/JobDriver_RepairMech.cs
new file mode 100644
index 00000000..e08f9028
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/RepairMech/JobDriver_RepairMech.cs
@@ -0,0 +1,416 @@
+// JobDriver_RepairMech.cs
+using RimWorld;
+using System.Collections.Generic;
+using UnityEngine;
+using Verse;
+using Verse.AI;
+using System.Linq;
+
+namespace WulaFallenEmpire
+{
+ public class JobDriver_RepairMech : JobDriver
+ {
+ private const TargetIndex MechInd = TargetIndex.A;
+
+ protected int ticksToNextRepair;
+
+ protected Pawn Mech => (Pawn)job.GetTarget(TargetIndex.A).Thing;
+
+ protected virtual bool Remote => false;
+
+ protected CompMechRepairable RepairableComp => Mech?.TryGetComp();
+
+ // 使用配置的修复周期ticks数,并根据MechRepairSpeed调整
+ protected int TicksPerRepairCycle
+ {
+ get
+ {
+ if (RepairableComp == null)
+ return 120;
+
+ int baseTicks = RepairableComp.Props.ticksPerRepairCycle;
+ return Mathf.RoundToInt(baseTicks / pawn.GetStatValue(StatDefOf.MechRepairSpeed));
+ }
+ }
+
+ // 每次修复的HP量
+ protected float RepairAmountPerCycle
+ {
+ get
+ {
+ if (RepairableComp == null)
+ return 1f;
+
+ return RepairableComp.Props.repairAmountPerCycle;
+ }
+ }
+
+ // 新增:缺失部位修复配置
+ protected float MissingPartRepairCostMultiplier => 2f;
+ protected HediffDef MissingPartReplacementInjury => HediffDefOf.Misc;
+
+ public override bool TryMakePreToilReservations(bool errorOnFailed)
+ {
+ return pawn.Reserve(Mech, job, 1, -1, null, errorOnFailed);
+ }
+
+ protected override IEnumerable MakeNewToils()
+ {
+ this.FailOnDestroyedOrNull(TargetIndex.A);
+ this.FailOnForbidden(TargetIndex.A);
+ this.FailOn(() => !MechRepairable() || !MechNeedsRepair());
+
+ if (!Remote)
+ {
+ yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);
+ }
+
+ Toil repairToil = (Remote ? Toils_General.Wait(int.MaxValue) : Toils_General.WaitWith(TargetIndex.A, int.MaxValue, useProgressBar: true, maintainPosture: true, maintainSleep: true));
+
+ // 添加维修特效
+ if (RepairableComp?.Props.repairEffect != null)
+ {
+ repairToil.WithEffect(RepairableComp.Props.repairEffect, TargetIndex.A);
+ }
+ else
+ {
+ repairToil.WithEffect(EffecterDefOf.MechRepairing, TargetIndex.A);
+ }
+
+ // 添加维修音效
+ if (RepairableComp?.Props.repairSound != null)
+ {
+ repairToil.PlaySustainerOrSound(RepairableComp.Props.repairSound);
+ }
+ else
+ {
+ repairToil.PlaySustainerOrSound(Remote ? SoundDefOf.RepairMech_Remote : SoundDefOf.RepairMech_Touch);
+ }
+
+ repairToil.AddPreInitAction(delegate
+ {
+ ticksToNextRepair = TicksPerRepairCycle;
+ });
+
+ repairToil.handlingFacing = true;
+
+ repairToil.tickIntervalAction = delegate(int delta)
+ {
+ ticksToNextRepair -= delta;
+ if (ticksToNextRepair <= 0)
+ {
+ RepairTick(delta);
+ ticksToNextRepair = TicksPerRepairCycle;
+ }
+ pawn.rotationTracker.FaceTarget(Mech);
+ if (pawn.skills != null)
+ {
+ pawn.skills.Learn(SkillDefOf.Crafting, 0.05f * (float)delta);
+ }
+ };
+
+ repairToil.AddFinishAction(delegate
+ {
+ // 维修完成后,如果机甲被征召,恢复其工作
+ if (Mech.jobs?.curJob != null && job.playerForced)
+ {
+ Mech.jobs.EndCurrentJob(JobCondition.InterruptForced);
+ }
+ });
+
+ repairToil.AddEndCondition(() => MechNeedsRepair() ? JobCondition.Ongoing : JobCondition.Succeeded);
+
+ if (!Remote)
+ {
+ repairToil.activeSkill = () => SkillDefOf.Crafting;
+ }
+
+ yield return repairToil;
+ }
+
+ private bool MechRepairable()
+ {
+ return RepairableComp != null;
+ }
+
+ private bool MechNeedsRepair()
+ {
+ return RepairableComp?.NeedsRepair ?? false;
+ }
+
+ private void RepairTick(int delta)
+ {
+ if (Mech == null || Mech.health == null || Mech.Dead)
+ return;
+
+ // 计算本次修复的总HP量
+ float totalRepairAmount = RepairAmountPerCycle;
+ float originalRepairAmount = totalRepairAmount;
+
+ // 第一阶段:先修复现有伤口(非缺失部位)
+ totalRepairAmount = RepairExistingInjuries(totalRepairAmount);
+
+ // 第二阶段:如果还有修复量,并且机甲血量足够安全,再处理缺失部位
+ if (totalRepairAmount > 0f && IsSafeToRepairMissingParts())
+ {
+ // 直接尝试转换缺失部位,不消耗修复量
+ TryConvertMissingParts();
+ }
+
+ // 记录修复统计(只统计实际修复的伤口)
+ if (RepairableComp != null && totalRepairAmount < originalRepairAmount)
+ {
+ RepairableComp.RecordRepair(originalRepairAmount - totalRepairAmount);
+ }
+ }
+
+ // 修复现有伤口(非缺失部位)
+ private float RepairExistingInjuries(float totalRepairAmount)
+ {
+ float remainingAmount = totalRepairAmount;
+
+ // 获取所有非缺失部位的伤口
+ var existingInjuries = Mech.health.hediffSet.hediffs
+ .Where(h =>
+ (h is Hediff_Injury && h.Severity > 0f) ||
+ (h.def.tendable && h.Severity > 0f && !(h is Hediff_MissingPart))
+ )
+ .OrderByDescending(h => h.Severity) // 优先修复最严重的伤口
+ .ToList();
+
+ foreach (var injury in existingInjuries)
+ {
+ if (remainingAmount <= 0f)
+ break;
+
+ if (injury is Hediff_Injury injuryHediff)
+ {
+ // 修复伤害
+ float healAmount = Mathf.Min(remainingAmount, injuryHediff.Severity);
+ injuryHediff.Severity -= healAmount;
+ remainingAmount -= healAmount;
+
+ if (injuryHediff.Severity <= 0f)
+ {
+ Mech.health.RemoveHediff(injuryHediff);
+ }
+ }
+ else if (injury.def.tendable)
+ {
+ // 其他可治疗的hediff
+ float healAmount = Mathf.Min(remainingAmount, injury.Severity);
+ injury.Severity -= healAmount;
+ remainingAmount -= healAmount;
+
+ if (injury.Severity <= 0f)
+ {
+ Mech.health.RemoveHediff(injury);
+ }
+ }
+ }
+
+ return remainingAmount;
+ }
+
+ // 检查是否安全可以修复缺失部位
+ private bool IsSafeToRepairMissingParts()
+ {
+ // 获取机甲当前血量百分比
+ float currentHealthPercent = Mech.health.summaryHealth.SummaryHealthPercent;
+
+ // 如果血量低于30%,不安全修复缺失部位
+ if (currentHealthPercent < 0.3f)
+ return false;
+
+ // 如果有严重伤口(严重性大于5),先修复它们
+ bool hasCriticalInjuries = Mech.health.hediffSet.hediffs
+ .Any(h => h is Hediff_Injury && h.Severity > 5f);
+
+ if (hasCriticalInjuries)
+ return false;
+
+ // 检查缺失部位转换是否会致命
+ if (WouldMissingPartConversionBeFatal())
+ return false;
+
+ return true;
+ }
+
+ // 检查缺失部位转换是否会致命
+ private bool WouldMissingPartConversionBeFatal()
+ {
+ // 获取所有缺失部位
+ var missingParts = Mech.health.hediffSet.GetMissingPartsCommonAncestors();
+ if (!missingParts.Any())
+ return false;
+
+ // 计算转换后可能增加的总伤害量
+ float potentialAddedDamage = 0f;
+
+ foreach (var missingPart in missingParts)
+ {
+ float partMaxHealth = missingPart.Part.def.GetMaxHealth(Mech);
+ float injurySeverity = partMaxHealth - 1;
+ if (partMaxHealth <= 1)
+ injurySeverity = 0.5f;
+
+ potentialAddedDamage += injurySeverity;
+ }
+
+ // 获取当前总伤害量
+ float currentTotalInjurySeverity = Mech.health.hediffSet.hediffs
+ .Where(h => h is Hediff_Injury)
+ .Sum(h => h.Severity);
+
+ // 计算转换后的总伤害量
+ float projectedTotalInjurySeverity = currentTotalInjurySeverity + potentialAddedDamage;
+
+ // 获取致命伤害阈值
+ float lethalDamageThreshold = Mech.health.LethalDamageThreshold;
+
+ // 如果转换后的总伤害量超过或接近致命阈值,不安全
+ return projectedTotalInjurySeverity >= lethalDamageThreshold * 0.8f;
+ }
+
+ // 尝试转换缺失部位
+ private void TryConvertMissingParts()
+ {
+ // 获取所有缺失部位
+ var missingParts = Mech.health.hediffSet.GetMissingPartsCommonAncestors();
+ if (!missingParts.Any())
+ return;
+
+ // 选择最小的缺失部件进行转换(成本较低)
+ Hediff_MissingPart partToRepair = null;
+ float minHealth = float.MaxValue;
+
+ foreach (var missingPart in missingParts)
+ {
+ float partHealth = missingPart.Part.def.GetMaxHealth(Mech);
+ if (partHealth < minHealth)
+ {
+ minHealth = partHealth;
+ partToRepair = missingPart;
+ }
+ }
+
+ if (partToRepair != null)
+ {
+ // 直接转换缺失部位
+ if (ConvertMissingPartToInjury(partToRepair))
+ {
+ }
+ }
+ }
+
+ // 将缺失部件转换为伤害hediff
+ private bool ConvertMissingPartToInjury(Hediff_MissingPart missingPart)
+ {
+ try
+ {
+ float partMaxHealth = missingPart.Part.def.GetMaxHealth(Mech);
+
+ // 关键修复:确保转换后的损伤不会导致部位再次缺失
+ // 设置损伤严重性为最大健康值-1,这样部位健康值至少为1
+ float injurySeverity = partMaxHealth - 1;
+
+ // 如果最大健康值为1,则设置为0.5,确保部位健康值大于0
+ if (partMaxHealth <= 1)
+ {
+ injurySeverity = 0.5f;
+ }
+
+ // 移除缺失部件hediff
+ Mech.health.RemoveHediff(missingPart);
+
+ // 添加指定的伤害hediff
+ HediffDef injuryDef = MissingPartReplacementInjury;
+ if (injuryDef == null)
+ {
+ Log.Error($"[WULA] 找不到指定的hediff定义: {MissingPartReplacementInjury?.defName ?? "null"}");
+ return false;
+ }
+
+ // 创建损伤
+ Hediff injury = HediffMaker.MakeHediff(injuryDef, Mech, missingPart.Part);
+ injury.Severity = injurySeverity;
+
+ Mech.health.AddHediff(injury);
+
+ return true;
+ }
+ catch (System.Exception ex)
+ {
+ Log.Error($"[WULA] 转换缺失部件 {missingPart.Part.def.defName} 时出错: {ex}");
+ return false;
+ }
+ }
+
+ // 获取所有可修复的hediff
+ private List GetAllRepairableHediffs()
+ {
+ var repairableHediffs = new List();
+
+ if (Mech.health?.hediffSet == null)
+ return repairableHediffs;
+
+ // 获取所有hediff
+ foreach (var hediff in Mech.health.hediffSet.hediffs)
+ {
+ if (CanRepairHediff(hediff))
+ {
+ repairableHediffs.Add(hediff);
+ }
+ }
+
+ return repairableHediffs;
+ }
+
+ // 检查hediff是否可修复
+ private bool CanRepairHediff(Hediff hediff)
+ {
+ // 缺失部位可以修复
+ if (hediff is Hediff_MissingPart)
+ return true;
+
+ // 伤害可以修复
+ if (hediff is Hediff_Injury)
+ return true;
+
+ // 可治疗的hediff可以修复
+ if (hediff.def.tendable && hediff.Severity > 0f)
+ return true;
+
+ // 跳过疾病
+ if (IsDisease(hediff))
+ return false;
+
+ return false;
+ }
+
+ // 检查是否是疾病
+ private bool IsDisease(Hediff hediff)
+ {
+ // 常见的疾病类型
+ string[] diseaseKeywords = {
+ "Disease", "Flu", "Plague", "Infection", "Malaria",
+ "SleepingSickness", "FibrousMechanites", "SensoryMechanites",
+ "WoundInfection", "FoodPoisoning", "GutWorms", "MuscleParasites"
+ };
+
+ foreach (string keyword in diseaseKeywords)
+ {
+ if (hediff.def.defName.Contains(keyword))
+ return true;
+ }
+
+ return false;
+ }
+
+ public override void ExposeData()
+ {
+ base.ExposeData();
+ Scribe_Values.Look(ref ticksToNextRepair, "ticksToNextRepair", 0);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/RepairMech/WorkGiver_RepairMech.cs b/Source/WulaFallenEmpire/Work/RepairMech/WorkGiver_RepairMech.cs
new file mode 100644
index 00000000..c2004b7e
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/RepairMech/WorkGiver_RepairMech.cs
@@ -0,0 +1,73 @@
+// WorkGiver_RepairMech.cs
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class WorkGiver_RepairMech : WorkGiver_Scanner
+ {
+ public override PathEndMode PathEndMode => PathEndMode.Touch;
+
+ public override Danger MaxPathDanger(Pawn pawn)
+ {
+ return Danger.Deadly;
+ }
+
+ public override IEnumerable PotentialWorkThingsGlobal(Pawn pawn)
+ {
+ if (pawn.Faction != Faction.OfPlayer || pawn.Map == null)
+ return Enumerable.Empty();
+
+ // 获取所有需要维修的玩家机甲
+ return pawn.Map.mapPawns.AllPawnsSpawned
+ .Where(p =>
+ p.Faction == Faction.OfPlayer &&
+ p.health != null &&
+ !p.Dead &&
+ p.TryGetComp()?.CanAutoRepair == true
+ )
+ .Cast();
+ }
+
+ public override bool ShouldSkip(Pawn pawn, bool forced = false)
+ {
+ if (pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Crafting))
+ return true;
+
+ return false;
+ }
+
+ public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ if (!(t is Pawn mech) || mech.Dead)
+ return false;
+
+ var repairableComp = t.TryGetComp();
+ if (repairableComp == null || !repairableComp.CanAutoRepair)
+ return false;
+
+ if (!repairableComp.NeedsRepair)
+ return false;
+
+ if (pawn.Faction != Faction.OfPlayer)
+ return false;
+
+ if (!pawn.CanReserveAndReach(t, PathEndMode.Touch, Danger.Some, 1, -1, null, forced))
+ return false;
+
+ // 检查工作标签
+ if (pawn.story != null && pawn.WorkTagIsDisabled(WorkTags.Crafting))
+ return false;
+
+ return true;
+ }
+
+ public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
+ {
+ return JobMaker.MakeJob(Wula_JobDefOf.WULA_RepairMech, t);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Work/ThinkNode_ConditionalMechHasPilot.cs b/Source/WulaFallenEmpire/Work/ThinkNode_ConditionalMechHasPilot.cs
new file mode 100644
index 00000000..cec11484
--- /dev/null
+++ b/Source/WulaFallenEmpire/Work/ThinkNode_ConditionalMechHasPilot.cs
@@ -0,0 +1,39 @@
+// ThinkNode_ConditionalMechHasPilot.cs (修复版)
+using RimWorld;
+using Verse;
+using Verse.AI;
+
+namespace WulaFallenEmpire
+{
+ public class ThinkNode_ConditionalMechHasPilot : ThinkNode_Conditional
+ {
+ // 可选的:可以在XML中设置的参数
+ public int minPilotCount = 1; // 最少需要的驾驶员数量
+
+ protected override bool Satisfied(Pawn pawn)
+ {
+ if (pawn.Faction != Faction.OfPlayer)
+ return false; // 仅适用于玩家派系的机甲
+ var pilotComp = pawn.TryGetComp();
+ if (pilotComp == null)
+ return false; // 如果没有驾驶员组件,条件满足(允许执行)
+
+ int currentPilotCount = pilotComp.CurrentPilotCount;
+
+ // 检查是否满足最小驾驶员数量要求
+ bool hasEnoughPilots = currentPilotCount >= minPilotCount;
+
+ // 这意味着机甲可以正常工作
+ bool conditionSatisfied = hasEnoughPilots;
+
+ return !conditionSatisfied;
+ }
+
+ public override ThinkNode DeepCopy(bool resolve = true)
+ {
+ ThinkNode_ConditionalMechHasPilot thinkNode_ConditionalMechHasPilot = (ThinkNode_ConditionalMechHasPilot)base.DeepCopy(resolve);
+ thinkNode_ConditionalMechHasPilot.minPilotCount = minPilotCount;
+ return thinkNode_ConditionalMechHasPilot;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/WulaFallenEmpire/WulaDefOf.cs b/Source/WulaFallenEmpire/WulaDefOf.cs
index e1245472..627e86af 100644
--- a/Source/WulaFallenEmpire/WulaDefOf.cs
+++ b/Source/WulaFallenEmpire/WulaDefOf.cs
@@ -27,7 +27,6 @@ namespace WulaFallenEmpire
public static JobDef WULA_Launch_Proj;
public static JobDef WULA_EnterMech;
public static JobDef WULA_RefuelMech;
- public static JobDef WULA_Refuel;
public static JobDef WULA_RepairMech;
public static JobDef WULA_ForceEjectPilot;
public static JobDef WULA_CarryToMech;
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index 54bfbef4..90c889b3 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -95,7 +95,23 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -333,29 +349,27 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -371,10 +385,10 @@
-
-
-
-
+
+
+
+
@@ -388,7 +402,6 @@
-