diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll
index de917666..167dc660 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/BackstoryDefs/Solid/Solid_Adult_WULA.xml b/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Adult_WULA.xml
index 5e9da4c8..645a8741 100644
--- a/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Adult_WULA.xml
+++ b/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Adult_WULA.xml
@@ -1,7 +1,6 @@
-
WULA_Adult_Backstory01
Adulthood
@@ -361,7 +360,6 @@
-
WULA_Adult_Backstory100
Adulthood
@@ -573,7 +571,6 @@
-
WULA_Adult_Backstory200
Adulthood
@@ -804,7 +801,6 @@
-
WULA_Adult_Backstory300
Adulthood
@@ -1044,22 +1040,6 @@
-
-
- WULA_Adult_Backstory998
- Adulthood
- 养尊处优
- 养尊处优
- 在边缘世界的人们几乎无法想象[PAWN_nameDef]在乌拉帝国的生活,就像农民想象皇帝用金锄头耕地一样让人发笑。
-
- Wula_Backstory_Categories_For_RealWula
-
- Thin
- Thin
- Thin
- AllWork
-
-
WULA_Adult_Backstory999
diff --git a/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Child_WULA.xml b/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Child_WULA.xml
index c90d3af6..fcd03658 100644
--- a/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Child_WULA.xml
+++ b/1.6/1.6/Defs/BackstoryDefs/Solid/Solid_Child_WULA.xml
@@ -113,6 +113,8 @@
2
+ 0.5
+ 0.75
@@ -151,7 +153,7 @@
0.8
- 0.5
+ 0.75
0.75
2
1.2
@@ -195,6 +197,7 @@
+ 0.15
3
1
@@ -207,7 +210,7 @@
Childhood
产地:玛瑞克
玛瑞克
- [PAWN_nameDef] 是产自玛瑞克星区的合成人。玛瑞克星区是一个相较于其他星区都要庞大的农业型星区。这里有多个天文位置得天独厚的行星适合进行农业生产,使其得以源源不断地向乌拉帝国输送大量的食材。\n\n这个星域生产的合成人通常内置了家政和农业系统,使得她们非常善于处理一些杂事。此外她们经久耐用的射击使其在自然条件下的磨损速度比其他星区的合成人要慢很多。
+ [PAWN_nameDef] 是产自玛瑞克星区的合成人。玛瑞克星区是一个相较于其他星区都要庞大的农业型星区。这里有多个天文位置得天独厚的行星适合进行农业生产,使其得以源源不断地向乌拉帝国输送大量的食材。\n\n这个星域生产的合成人通常内置了家政和农业系统,使得她们非常善于处理一些杂事。此外她们经久耐用的设计使其在自然条件下的磨损速度比其他星区的合成人要慢很多。
4
4
@@ -226,7 +229,7 @@
WULA_Child_Backstory06_Hediff
产地:玛瑞克
- 这个星域生产的合成人通常内置了家政和农业系统,使得她们非常善于处理一些杂事。此外她们经久耐用的射击使其在自然条件下的磨损速度比其他星区的合成人要慢很多。
+ 这个星域生产的合成人通常内置了家政和农业系统,使得她们非常善于处理一些杂事。此外她们经久耐用的设计使其在自然条件下的磨损速度比其他星区的合成人要慢很多。
HediffWithComps
false
false
diff --git a/1.6/1.6/Defs/HediffDefs/Hediffs_BodyParts_WULA.xml b/1.6/1.6/Defs/HediffDefs/Hediffs_BodyParts_WULA.xml
index 1910c299..a074935c 100644
--- a/1.6/1.6/Defs/HediffDefs/Hediffs_BodyParts_WULA.xml
+++ b/1.6/1.6/Defs/HediffDefs/Hediffs_BodyParts_WULA.xml
@@ -61,7 +61,7 @@
2
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
WULA_Cube_Productor_Energy
@@ -723,7 +723,7 @@
2
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
WULA_Cube_Productor_Energy
diff --git a/1.6/1.6/Defs/RecipeDefs/Recipes_WULA.xml b/1.6/1.6/Defs/RecipeDefs/Recipes_WULA.xml
index f5ba65d0..37a8440b 100644
--- a/1.6/1.6/Defs/RecipeDefs/Recipes_WULA.xml
+++ b/1.6/1.6/Defs/RecipeDefs/Recipes_WULA.xml
@@ -44,7 +44,7 @@
100
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -91,7 +91,7 @@
100
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -140,7 +140,7 @@
100
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -180,7 +180,7 @@
100
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -220,7 +220,7 @@
100
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -339,28 +339,10 @@
-
+
WULA_Build_Wula_Synth
建造URa-00"机械乌拉"
- 建造一台URa-00"机械乌拉"合成人,是乌拉帝国合成人殖民地的主体种族,作为机械体的同时拥有复杂拟真的模拟情感。\n\n以此方法建造的合成人被称为新生代合成人,它们在出厂时只会设置人格,不会拥有任何技能等级,需要通过乌拉帝国数据库下载相关技能!
-
-
-
-
- Steel
-
-
- 5
-
-
-
-
- ComponentIndustrial
-
-
- 6
-
-
+ 建造一台URa-00"机械乌拉"合成人,是乌拉帝国合成人殖民地的主体种族,作为机械体的同时拥有复杂拟真的模拟情感。
1
@@ -369,8 +351,44 @@
WULA_Synth_Productor_Technology
+
+ WULA_Build_Mech_Cat
+ 建造CAt-11"猫猫"
+ 建造一台CAt-11"猫猫"辅助机器人,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作。
+
+ 1
+
+
+ Mech_WULA_Cat
+
+ WULA_Bunker_Drop_Technology
+
+
+ WULA_Build_Mech_Cat_Constructor
+ 建造CAt-86"土木猫猫"
+ 建造一台CAt-86"土木猫猫"辅助机器人,允许执行挖矿和建造的工作,并且拥有一把可以砸碎敌人膝盖的锤子。
+
+ 1
+
+
+ Mech_WULA_Cat_Constructor
+
+ WULA_Bunker_Drop_Technology
+
+
+ WULA_Build_Mech_Cat_Assault
+ 建造CAt-46"突击猫猫"
+ 建造一台CAt-46"突击猫猫"辅助机器人,可以执行搬运、狩猎和割除任务,配备与DLa-1"页岩"性能相近的DLa-4"云母"突击步枪。
+
+ 1
+
+
+ Mech_WULA_Cat_Assault
+
+ WULA_Bunker_Drop_Technology
+
-
+
WULA_Build_AI_Heavy_Panzer
建造SMp-38"萨克森"
建造一台SMp-38"萨克森"智能战车。
@@ -416,7 +434,7 @@
WULA_AI_Machine_Panzer_Technology
-
+
WULA_Build_AI_Heavy_Panzer_Gunnery
建造SMp-38A"斯佩萨特"
建造一台SMp-38A"斯佩萨特"智能战车。
@@ -463,7 +481,7 @@
WULA_AI_Machine_Panzer_Technology
-
+
WULA_Build_Alpha_Wolf
建造SNm-6"狼蛛"
建造一台SNm-6"狼蛛"智能机甲。
@@ -509,7 +527,7 @@
WULA_Alpha_Wolf_Technology
-
+
WULA_Build_Alpha_Mantodea
建造SNm-82"螳螂"
建造一台SNm-82"螳螂"智能机甲。
@@ -555,96 +573,4 @@
WULA_Alpha_Wolf_Technology
-
-
-
- WULA_Build_Mech_Cat
- 建造CAt-11"猫猫"
- 建造一台CAt-11"猫猫"辅助机器人,可以执行包括搬运、烹饪、种植收割、清理、急救和灭火一类的简单工作。
-
-
-
-
- Steel
-
-
- 50
-
-
-
-
- ComponentIndustrial
-
-
- 4
-
-
-
- 1
-
-
- Mech_WULA_Cat
-
- WULA_Machine_Productor_Technology
-
-
- WULA_Build_Mech_Cat_Constructor
- 建造CAt-86"土木猫猫"
- 建造一台CAt-86"土木猫猫"辅助机器人,允许执行挖矿和建造的工作,并且拥有一把可以砸碎敌人膝盖的锤子。
-
-
-
-
- Steel
-
-
- 50
-
-
-
-
- ComponentIndustrial
-
-
- 4
-
-
-
- 1
-
-
- Mech_WULA_Cat_Constructor
-
- WULA_Machine_Productor_Technology
-
-
- WULA_Build_Mech_Cat_Assault
- 建造CAt-46"突击猫猫"
- 建造一台CAt-46"突击猫猫"辅助机器人,可以执行搬运、狩猎和割除任务,配备与DLa-1"页岩"性能相近的DLa-4"云母"突击步枪。
-
-
-
-
- Steel
-
-
- 50
-
-
-
-
- ComponentIndustrial
-
-
- 4
-
-
-
- 1
-
-
- Mech_WULA_Cat_Assault
-
- WULA_Machine_Productor_1_Technology
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml b/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml
index 436e78d2..5061a279 100644
--- a/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml
+++ b/1.6/1.6/Defs/ResearchProjectDefs/WULA_ResearchProjects_Remake.xml
@@ -6,79 +6,245 @@
-
+
WULA_Colony_License_LV1_Technology
乌拉帝国殖民地许可:等级1
- 乌拉帝国的第一阶殖民地许可,代表此殖民地正式被乌拉帝国承认为其下辖殖民地之一,允许建立与乌拉帝国舰队进行通讯的设施。(只有机械乌拉才能呼叫舰队)
- 35000
+ 乌拉帝国的第一阶殖民地许可,代表此殖民地正式被乌拉帝国承认为其下辖殖民地之一。许可不会为殖民地带来什么好处,但是提升许可是继续研究乌拉帝国科技的重要条件。
+ 10000
0.00
3.20
Electricity
+
+ WULA_Colony_License_LV2_Technology
+ 乌拉帝国殖民地许可:等级2
+ 乌拉帝国的第二阶殖民地许可,代表此殖民地已经被乌拉帝国赋予更多特权,许可不会为殖民地带来什么好处,但是提升许可是继续研究乌拉帝国科技的重要条件。
+ 15000
+ 4.00
+ 3.20
+
+ WULA_Colony_License_LV1_Technology
+
+
+
+ WULA_Colony_License_LV3_Technology
+ 乌拉帝国殖民地许可:等级3
+ 乌拉帝国的第一阶殖民地许可,代表此殖民地已经被乌拉帝国赋予更多特权,许可不会为殖民地带来什么好处,但是提升许可是继续研究乌拉帝国科技的重要条件。
+ 20000
+ 8.00
+ 3.20
+
+ WULA_Colony_License_LV2_Technology
+
+
+
+
+
+ WULA_Light_Fighter_Drone_Technology
+ 蜂群无人机许可
+ 允许殖民地自行组装和放飞蜂群无人机,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n蜂群无人机是一种轻型的智能无人机,通过乌拉帝国的大气层内电离网络输电运作,可以以较高的频率对敌方进行编队掠袭和投掷小型炸弹。\n\n和其他的航空器不同,蜂群无人机不依赖于机库,因此不需要携带机库的战舰到场即可呼叫支援。
+ 600
+ 1.00
+ 4.40
+
+ WULA_Colony_License_LV1_Technology
+
+
+
+ WULA_Striker_Technology
+ 攻击机调配许可
+ 允许殖民地建立信标增加攻击机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的攻击机是强大的对地支援火力,挂载了大量导弹和强大的机炮,对敌方目标实施精准收割。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。
+ 600
+ 5.00
+ 4.40
+
+ WULA_Light_Fighter_Drone_Technology
+ WULA_Colony_License_LV2_Technology
+
+
+
+ WULA_Bomber_Technology
+ 轰炸机调配许可
+ 允许殖民地建立信标增加轰炸机配额,并使得机械乌拉可以调频天线以申请航空器空中打击。\n\n乌拉帝国的轰炸机是可以进入大气层的最大的飞行载具,除了可以使用机炮监视航路外,还能投下大量炸弹夷平帝国之敌。\n\n空中打击依赖于战舰的<color=#BD952F><i>机库</i></color>,只有携带此类设施的战舰出现在地图中时,才能呼叫航空器支援。
+ 600
+ 6.00
+ 4.40
+
+ WULA_Striker_Technology
+
+
+
+ WULA_Aircraft_Carrier_Technology
+ 9.00
+ 4.40
+ 航空母舰调配许可
+ 允许殖民地建立信标增加航空母舰配额,并使得机械乌拉可以调频天线以申请舰队空中支援。\n\n乌拉帝国的轻型航空母舰没有什么武装,但是能够装载大量的战机以支援地面战斗。\n\n此战舰携带以下设施:\n<color=#BD952F><i>机库</i></color>
+ 600
+
+ WULA_Bomber_Technology
+ WULA_Colony_License_LV3_Technology
+
+
+
+
+
+ WULA_WeaponArmor_Productor_Technology
+ 1.00
+ 0.90
+ 作业通讯台空投许可
+ 允许殖民地申请空投作业通讯台和建造物资输送舱,可以向乌拉帝国舰队输送资源、提交生产订单和获取舰队生产的产品。
+ 600
+
+ WULA_Colony_License_LV1_Technology
+
+
+
+ WULA_Synth_Maintain_Technology
+ 1.00
+ 2.70
+ 维护空投许可
+ 允许殖民地申请空投合成人维护舱和合成人充电站,以实现对机械乌拉的充电和周期性维护。
+ 600
+
+ WULA_Colony_License_LV1_Technology
+
+
WULA_Structure_Technology
- 结构构件空投许可
- 允许殖民地申请空投乌拉帝国堡垒结构,包括坚固耐用的墙和通过速度较高的自动门。
- 600
1.00
- 4.70
-
- WULA_Colony_License_LV1_Technology
-
-
-
- WULA_Synth_Clothes_Technology
- 1.00
- 2.60
- 基础衣物加工许可
- 许殖民地申请加工基础衣物
- 400
-
- ComplexClothing
- WULA_Colony_License_LV1_Technology
-
-
-
- WULA_Synth_Weapon_Technology
- 1.00
- 0.20
- 基础武装加工许可
- 开发能够武装乌拉帝国合成人的老式气动武器,以抵御针对殖民地的外部袭击。
+ 1.50
+ 结构空投许可
+ 允许殖民地申请空投乌拉帝国堡垒结构。以快速构建殖民地外墙和门。
600
- Machining
WULA_Colony_License_LV1_Technology
+
WULA_Bunker_Drop_Technology
1.00
- 0.20
+ 2.10
地堡空投许可
- 开发能够武装乌拉帝国合成人的老式气动武器,以抵御针对殖民地的外部袭击。
+ 允许殖民地申请空投乌拉猫猫地堡和机械族充电站,地堡是内含三只乌拉猫猫机械体的集防御和生产为一身的建筑。
600
- Machining
+ BasicMechtech
WULA_Colony_License_LV1_Technology
+
WULA_Synth_Productor_Technology
合成人空投许可
- 获取构建乌拉帝国合成人的相关知识,以增加殖民地人口。
+ 允许殖民地申请机械乌拉的订单,为殖民地生产新的机械乌拉。
1000
2.00
- 5.50
+ 2.10
- WULA_Machine_Productor_Technology
+ WULA_Bunker_Drop_Technology
+ WULA_WeaponArmor_Productor_Technology
+
+
+
+ WULA_Shutdown_Technology
+ 3.00
+ 3.90
+ 系统休眠套件
+ 获取关闭乌拉帝国合成人各系统的必须知识。
+ 800
+
+ WULA_Synth_Productor_Technology
+
+
+
+
+
+ WULA_Synth_Weapon_1_Base_Technology
+ 基础武装加工许可
+ 允许从作业通讯台提交生产基础武器的订单,一些资源花费不是很多但是可以护殖民地周全的步枪和近战武器。
+ 1600
+ 2.00
+ 0.90
+
+ Fabrication
+ WULA_WeaponArmor_Productor_Technology
+
+
+
+ WULA_Synth_Weapon_1_Missile_Technology
+ 导弹武装加工许可
+ 允许从作业通讯台提交生产发射追踪巡飞弹的乌拉帝国武备的订单,以对抗普通武器难以消灭的重甲敌军。
+ 1600
+ 3.00
+ 0.20
+
+ WULA_Synth_Weapon_1_Base_Technology
+
+
+
+ WULA_Synth_Weapon_2_Laser_Technology
+ 镭射武装加工许可
+ 允许从作业通讯台提交生产基础能量武器的乌拉帝国武备的订单,这些武器需要较长的瞄准时间,但是瞄准之后可以连续开火。
+ 2400
+ 5.00
+ 0.80
+
+
+
+ WULA_Synth_Weapon_1_Base_Technology
+ WULA_Colony_License_LV2_Technology
+
+
+
+ WULA_Synth_Weapon_2_Bullet_Technology
+ 磁轨武装加工许可
+ 允许从作业通讯台提交生产高级实弹武器的乌拉帝国武备的订单,这些武器的破坏力较强,但是其优劣射程区间都相当明显。
+ 2400
+ 5.00
+ 0.20
+
+
+
+ WULA_Synth_Weapon_1_Base_Technology
+ WULA_Colony_License_LV2_Technology
+
+
+
+ WULA_Synth_Weapon_3_Explosive_Technology
+ 爆炸武装加工许可
+ 允许从作业通讯台提交生产爆炸武器的乌拉帝国武备的订单,这些武器能够造成区域性爆炸,拥有相当凶狠的火力。
+ 2400
+ 9.00
+ 0.20
+
+ WULA_Synth_Weapon_1_Missile_Technology
+
+
+ WULA_Synth_Weapon_2_Bullet_Technology
+ WULA_Colony_License_LV3_Technology
+
+
+
+ WULA_Synth_Weapon_3_Laser_Technology
+ 9.00
+ 0.80
+ 熔炉武装套件
+ 允许从作业通讯台提交生产高级能量武器的乌拉帝国武备的订单,只要为其提供安稳的输出环境,它们就能展现其恐怖的攻坚能力。
+ 600
+
+
+
+ WULA_Synth_Weapon_2_Laser_Technology
+ WULA_Colony_License_LV3_Technology
-
+
WULA_Synth_Clothes_2_Technology
4.50
@@ -160,71 +325,8 @@
PoweredArmor
WULA_Synth_Armor_Technology
-
-
-
- WULA_Synth_Weapon_2_Melee_Technology
- 短兵武装套件
- 开发能够武装乌拉帝国合成人的近距离武器,可以在短距离上消灭敌人。
- 1600
- 4.50
- 1.00
-
- Fabrication
- WULA_Adv_WorkTable_Technology
- WULA_Synth_Weapon_Technology
-
-
-
- WULA_Synth_Weapon_2_Missile_Technology
- 导弹武装套件
- 开发能够发射追踪巡飞弹的乌拉帝国武备,以对抗难以消灭的重甲敌军。
- 1600
- 3.00
- 1.00
-
- WULA_Synth_Weapon_Technology
-
-
-
- WULA_Synth_Weapon_2_Stun_Technology
- 镇暴武装套件
- 开发能够武装乌拉帝国合成人的镇暴类装备,以盾牌和失能武器构成,旨在抑制对手的行动。
- 2400
- 5.50
- 1.00
-
- ReconArmor
- Bionics
- WULA_Synth_Weapon_2_Melee_Technology
-
-
-
- WULA_Synth_Weapon_2_Plasma_Technology
- 3.00
- 0.20
- 等离子武装套件
- 开发能够供乌拉帝国合成人的使用的等离子武器,以便进一步对抗强大的外部威胁。
- 600
-
- WULA_Synth_Weapon_Technology
-
-
-
-
-
- WULA_Synth_Weapon_2_Laser_Technology
- 3.00
- 1.80
- 镭射武装套件
- 开发能够供乌拉帝国合成人的使用的镭射武器,以便进一步对抗强大的外部威胁。
- 600
-
- WULA_Synth_Weapon_Technology
-
-
-
-
+ -->
+
-
- WULA_Synth_Weapon_2_Ranged_Technology
- 4.50
- 1.80
- 远射武装套件
- 开发能够武装乌拉帝国合成人的远距离武器,旨在构建密集火力网消灭敌人。
- 2400
-
- ChargedShot
- WULA_Adv_WorkTable_Technology
- WULA_Synth_Weapon_2_Laser_Technology
-
-
-
- WULA_Synth_Weapon_3_Bomb_Technology
- 4.50
- 0.20
- 轰炸武装套件
- 开发能够武装乌拉帝国合成人的大范围杀伤性武器,用于对抗最难应付的敌人。
- 3200
-
- BeamWeapons
- WULA_Adv_WorkTable_Technology
- WULA_Synth_Weapon_2_Plasma_Technology
- WULA_Synth_Weapon_2_Missile_Technology
-
-
-
- WULA_Synth_Weapon_4_DM_Base_Technology
- 9.00
- 0.20
- 暗物质远射套件
- 开发供乌拉帝国合成人使用的暗物质驱动远程武器——乌拉帝国科技极致伟力的具象化。
- 4000
-
- WULA_Synth_Weapon_2_Ranged_Technology
- WULA_Synth_Weapon_3_Bomb_Technology
- WULA_Dark_Matter_Technology
-
-
-
-
+
WULA_Machine_Productor_Technology
机械体构建套件
@@ -298,7 +358,7 @@
1.00
5.50
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -362,7 +422,6 @@
WULA_Mech_WULA_Cat_DM_Technology
-
WULA_Repair_All_Technology
2.00
@@ -371,18 +430,7 @@
获取构建修理包并使用其修复乌拉帝国合成人的必须知识。
600
- WULA_Base_Technology
-
-
-
- WULA_Shutdown_Technology
- 3.00
- 3.90
- 系统休眠套件
- 获取关闭乌拉帝国合成人各系统的必须知识。
- 800
-
- WULA_Repair_All_Technology
+ WULA_Colony_License_LV1_Technology
@@ -393,7 +441,7 @@
2.00
4.70
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
@@ -442,5 +490,5 @@
WULA_Synth_Addons_Technology
WULA_Dark_Matter_Technology
-
+ -->
\ No newline at end of file
diff --git a/1.6/1.6/Defs/Scenarios/Scenarios_WULA.xml b/1.6/1.6/Defs/Scenarios/Scenarios_WULA.xml
index 36cac001..51b26fb6 100644
--- a/1.6/1.6/Defs/Scenarios/Scenarios_WULA.xml
+++ b/1.6/1.6/Defs/Scenarios/Scenarios_WULA.xml
@@ -114,7 +114,7 @@
StartingResearch
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
StartingResearch
diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml
index be0dc8af..7d9c0c8c 100644
--- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml
+++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Drop_Buildings.xml
@@ -41,6 +41,9 @@
0
1
+
+ WULA_Structure_Technology
+
0
15
@@ -211,6 +214,9 @@
Structure
RealtimeOnly
WULA_Buildings
+
+ WULA_Structure_Technology
+
true
true
@@ -386,7 +392,7 @@
3
Misc6
-
+
WULA_Structure_Technology
1138
@@ -425,7 +431,9 @@
false
false
false
-
+
+ WULA_Bunker_Drop_Technology
+
1
1
@@ -669,6 +677,9 @@
(3,3)
0
1
+
+ WULA_Synth_Maintain_Technology
+
150
10
@@ -823,7 +834,7 @@
WULA_WeaponArmor_Productor_Cleanzone
- 乌拉帝国作业通讯台(装备)
+ 乌拉帝国作业通讯台
清理出一块场地并准备好资源,使得乌拉帝国母舰可以向此处投放建筑。建造好的信标可以收起或移至他处,但是必须要有母舰或者后勤舰在上空才能投送建筑。\n\n乌拉帝国作业通讯台是用于联络乌拉帝国母舰和后勤舰并下达武器、装备订单的特殊通讯台。这些武器装备的生产不需要殖民地参与,只需要使用乌拉帝国物资交换舱将材料发送给帝国舰队,然后根据材料数量下单即可。
Wula/Building/WULA_WeaponArmor_Productor
MinifiedThing
@@ -961,7 +972,7 @@
false
Item
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
WulaFallenEmpire.ITab_GlobalBills
@@ -1011,7 +1022,9 @@
0
false
false
-
+
+ WULA_Bunker_Drop_Technology
+
1
1
@@ -1178,7 +1191,9 @@
0
false
false
-
+
+ WULA_Synth_Maintain_Technology
+
1
1
@@ -1278,7 +1293,7 @@
2010
0.5
- WULA_Base_Technology
+ WULA_Colony_License_LV1_Technology
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Apperals/WULA_Apparel.xml b/1.6/1.6/Defs/ThingDefs_Misc/Apperals/WULA_Apparel.xml
index 02d9afe8..fc6e3a1a 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/Apperals/WULA_Apparel.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/Apperals/WULA_Apparel.xml
@@ -1018,127 +1018,6 @@
-
- Apparel_WULA_Manpack_Loitering_Munition
- MPl_8"蛭石"
- 派发给乌拉帝国突击队的一次性巡飞弹发射器,装有温压炸药,能对大量软目标造成范围性的伤害——而且不需要占用编制,允许突击队携带其他武器。
-
- Wula/Apparel/WULA_Manpack_Loitering_Munition
- Graphic_Single
-
- Spacer
-
- RewardStandardLowFreq
-
-
- 1000
- 1
- 1
- 150
-
-
-
- WULA_Cube_Productor_Energy
-
- WULA_Synth_Weapon_2_Missile_Technology
- UnfinishedWeapon
-
-
- 30
- 1
-
- Normal
-
- ApparelUtility
-
-
- false
- 4
- false
- false
- true
- 0
-
- Waist
-
-
- Belt
-
- Wula/Apparel/WULA_Manpack_Loitering_Munition
-
- true
-
-
-
-
- (0,0)
-
-
- (-0.1,0)
-
-
- (0.1,0)
-
-
-
- false
- false
- false
-
-
- 1
- true
- Misc4
- 蛭石巡飞弹
- false
-
-
-
-
- Verb_LaunchProjectileStaticPsychic
- true
-
- Bullet_WULA_Manpack_Loitering_Munition
- 1
- 25
- 1
- RocketswarmLauncher_Fire
- GunTail_Heavy
- 12
-
-
-
-
- Bullet_WULA_Manpack_Loitering_Munition
- 蛭石巡飞弹
-
- Wula/Projectile/WULA_Loitering_Munition
- Graphic_Single
-
- WulaFallenEmpire.Projectile_ExplosiveTrackingBullet
-
- 25
- Bomb
- 60
- 0.25
- 10
-
-
-
- 4.5
- Bomb
-
-
- 0.75
- 0
-
- 60
- 120
-
- 1
-
-
-
Shield
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml
index 24dc25aa..eb10e648 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/WULA_Flyover_Item.xml
@@ -18,7 +18,7 @@
(0, 0)
0
FlyOver/Flying
- FlyOver/Landing
+
@@ -81,7 +81,7 @@
(0, 0)
0
FlyOver/Flying
- FlyOver/Landing
+
diff --git a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml
index 5fa604b1..c5770965 100644
--- a/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml
+++ b/1.6/1.6/Defs/ThingDefs_Misc/Weapons/WULA_FE_Remake_Weapon.xml
@@ -19,13 +19,11 @@
20000
5
- 60
-
- Metallic
-
+ 0
+
- 5
- 6
+ 80
+ 2
@@ -63,7 +61,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_2_Stun_Technology
+ WULA_Synth_Weapon_1_Base_Technology
7
@@ -90,13 +88,12 @@
Interact_WULA_MW_ChainSword
Spacer
- 60
-
- Metallic
-
+ 0
+
- 5
- 3
+ 90
+ 25
+ 6
20000
@@ -177,16 +174,16 @@
0.8
Spacer
- 50
+ 0
+
20000
20
-
- Metallic
-
+ 40
+ 80
20
4
@@ -317,7 +314,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_Technology
+ WULA_Synth_Weapon_1_Base_Technology
UnfinishedWeapon
@@ -445,7 +442,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_Technology
+ WULA_Synth_Weapon_2_Bullet_Technology
UnfinishedWeapon
@@ -525,7 +522,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_Technology
+ WULA_Synth_Weapon_2_Bullet_Technology
UnfinishedWeapon
@@ -612,7 +609,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_3_Bomb_Technology
+ WULA_Synth_Weapon_3_Explosive_Technology
UnfinishedWeapon
@@ -682,7 +679,7 @@
Bullet
- 15
+ 12
90
1.2
0.4
@@ -752,7 +749,7 @@
WULA_RW_Beam_Base_AR
SLb-3"星岚"
- 乌拉帝国殖民地的制式装备之一,在预热后通过高能电容能量的瞬间释放产生短光束,烧穿敌军。作为手持武器,其功率不算太高,因此虽然有强大的贯穿能力却没办法造成太大的伤害。
+ 乌拉帝国殖民地的制式装备之一,在预热后通过高能电容能量的瞬间释放产生短光束,烧穿多个敌军。作为手持武器,其功率不算太高,因此虽然有强大的贯穿能力却没办法造成太大的伤害。
Normal
Spacer
@@ -829,8 +826,8 @@
WulaFallenEmpire.Projectile_WulaLineAttack
- -1
- 0
+ 4
+ 0.25
true
@@ -854,7 +851,7 @@
WULA_RW_Penetrating_Beam_Rifle
- MLr-15 "三叉戟"
+ MLr-15 "三叉戟"(分光)
乌拉帝国的多用途穿透型光束武器,可以在散射和集束模式下切换以应对不同的情况。当分光棱镜打开时,其所发射的光束将分裂为多道,伤害和射程有所降低但是获得了更大的散射面积。
Spacer
@@ -880,13 +877,7 @@
6
20
-
-
- WULA_WeaponArmor_Productor
-
- WULA_Synth_Weapon_2_Laser_Technology
- UnfinishedWeapon
-
+
WulaFallenEmpire.Verb_ShootShotgun
@@ -918,9 +909,36 @@
+
+ Bullet_WULA_RW_Penetrating_Beam
+ 穿透光束
+ WulaFallenEmpire.Projectile_WulaPenetratingBeam
+
+
+ 2
+ 0.5
+ true
+ Mote_WULA_RW_Penetrating_Beam
+ 0.5
+
+
+ 3
+
+
+
+ Things/Projectile/ChargeLanceShot
+ Graphic_Single
+
+
+ BeamBypassShields
+ 6
+ 0.8
+ 1
+
+
WULA_RW_Penetrating_Beam_Rifle_Ranged
- SLb-15 "三叉戟"(集中)
+ SLb-15 "三叉戟"
乌拉帝国的多用途穿透型光束武器,可以在散射和集束模式下切换以应对不同的情况。当分光棱镜关闭时,其所发射的光束将集中在一个目标上,获得更大的对单目标的输出能力。
Spacer
@@ -945,7 +963,13 @@
120
6
-
+
+
+ WULA_WeaponArmor_Productor
+
+ WULA_Synth_Weapon_2_Laser_Technology
+ UnfinishedWeapon
+
Verb_Shoot
@@ -981,41 +1005,14 @@
0
-
- Bullet_WULA_RW_Penetrating_Beam
- 穿透光束
- WulaFallenEmpire.Projectile_WulaPenetratingBeam
-
-
- -1
- 0
- true
- Mote_WULA_RW_Penetrating_Beam
- 0.5
-
-
- 3
-
-
-
- Things/Projectile/ChargeLanceShot
- Graphic_Single
-
-
- BeamBypassShields
- 6
- 0.8
- 1
-
-
Bullet_WULA_RW_Penetrating_Beam_Ranged
穿透光束
WulaFallenEmpire.Projectile_WulaPenetratingBeam
- -1
- 0
+ 2
+ 0.5
true
Mote_WULA_RW_Penetrating_Beam
0.5
@@ -1087,7 +1084,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_2_Ranged_Technology
+ WULA_Synth_Weapon_3_Laser_Technology
UnfinishedWeapon
@@ -1192,7 +1189,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_3_Bomb_Technology
+ WULA_Synth_Weapon_3_Laser_Technology
UnfinishedWeapon
@@ -1552,6 +1549,127 @@
+
+ Apparel_WULA_Manpack_Loitering_Munition
+ MPl_8"蛭石"
+ 派发给乌拉帝国突击队的一次性巡飞弹发射器,装有温压炸药,能对大量软目标造成范围性的伤害——而且不需要占用编制,允许突击队携带其他武器。
+
+ Wula/Apparel/WULA_Manpack_Loitering_Munition
+ Graphic_Single
+
+ Spacer
+
+ RewardStandardLowFreq
+
+
+ 1000
+ 1
+ 1
+ 150
+
+
+
+ WULA_Cube_Productor_Energy
+
+ WULA_Synth_Weapon_1_Missile_Technology
+ UnfinishedWeapon
+
+
+ 30
+ 1
+
+ Normal
+
+ ApparelUtility
+
+
+ false
+ 4
+ false
+ false
+ true
+ 0
+
+ Waist
+
+
+ Belt
+
+ Wula/Apparel/WULA_Manpack_Loitering_Munition
+
+ true
+
+
+
+
+ (0,0)
+
+
+ (-0.1,0)
+
+
+ (0.1,0)
+
+
+
+ false
+ false
+ false
+
+
+ 1
+ true
+ Misc4
+ 蛭石巡飞弹
+ false
+
+
+
+
+ Verb_LaunchProjectileStaticPsychic
+ true
+
+ Bullet_WULA_Manpack_Loitering_Munition
+ 1
+ 25
+ 1
+ RocketswarmLauncher_Fire
+ GunTail_Heavy
+ 12
+
+
+
+
+ Bullet_WULA_Manpack_Loitering_Munition
+ 蛭石巡飞弹
+
+ Wula/Projectile/WULA_Loitering_Munition
+ Graphic_Single
+
+ WulaFallenEmpire.Projectile_ExplosiveTrackingBullet
+
+ 25
+ Bomb
+ 60
+ 0.25
+ 10
+
+
+
+ 4.5
+ Bomb
+
+
+ 0.75
+ 0
+
+ 60
+ 120
+
+ 1
+
+
+
WULA_RW_Base_Loitering_Munition
WLl-35"沸石"
@@ -1569,7 +1687,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_2_Missile_Technology
+ WULA_Synth_Weapon_1_Missile_Technology
UnfinishedWeapon
@@ -1659,7 +1777,7 @@
WULA_RW_Base_Loitering_Munition_Ability
启动引导系统
- 启动WLl-35"沸石"的自引导系统,使得其在短时间内可以连续发射飞弹而不需要漫长的引导。
+ 启动WLl-35"沸石"的自引导系统,使得其下一发飞弹不需要漫长的引导。
Wula/UI/Abilities/WULA_RW_Base_Loitering_Munition_Ability
True
False
@@ -1667,7 +1785,7 @@
false
3600
- 6
+ 1
Verb_CastAbility
@@ -1735,7 +1853,7 @@
WULA_WeaponArmor_Productor
- WULA_Synth_Weapon_3_Bomb_Technology
+ WULA_Synth_Weapon_3_Explosive_Technology
UnfinishedWeapon
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 4a34365b..4148e92f 100644
--- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
+++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml
@@ -497,22 +497,6 @@
true
- WULA_Official_Uniform
- WULA_Sailor_Dress
- WULA_Body_Suit
- WULA_Knight_PowerArmor
- WULA_Maid_Uniform
- WULA_Maid_Uniform_Headband
- WULA_Nurse_Uniform
- WULA_Nurse_Uniform_Headband
- WULA_Qipao
- WULA_Bodystocking
- WULA_Bodystocking_White
- WULA_Body_Suit
- WULA_Assault_Troop_PowerArmor
- WULA_Assault_Troop_Helmet
- WULA_Knight_Helmet
- WULA_Heavy_Infantry_PowerArmor
Apparel_AdvancedHelmet
diff --git a/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompAbilityOrbitalBombardment.cs b/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompAbilityOrbitalBombardment.cs
new file mode 100644
index 00000000..6c3e1fff
--- /dev/null
+++ b/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompAbilityOrbitalBombardment.cs
@@ -0,0 +1,749 @@
+// CompAbilityEffect_OrbitalBombardment.cs
+using RimWorld;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class CompAbilityEffect_OrbitalBombardment : CompAbilityEffect
+ {
+ public new CompProperties_AbilityOrbitalBombardment Props => (CompProperties_AbilityOrbitalBombardment)props;
+
+ public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
+ {
+ base.Apply(target, dest);
+
+ if (parent.pawn == null || parent.pawn.Map == null)
+ return;
+
+ try
+ {
+ Log.Message($"OrbitalBombardment skill activated by {parent.pawn.Label} at position {parent.pawn.Position}");
+ Log.Message($"Target cell: {target.Cell}, Dest: {dest.Cell}");
+
+ // 计算起始和结束位置
+ IntVec3 startPos, endPos;
+
+ if (Props.approachType == ApproachType.Perpendicular)
+ {
+ CalculatePerpendicularPath(target, out startPos, out endPos);
+ }
+ else
+ {
+ startPos = CalculateStartPosition(target);
+ endPos = CalculateEndPosition(target, startPos);
+ }
+
+ // 确保位置安全
+ startPos = GetSafeMapPosition(startPos, parent.pawn.Map);
+ endPos = GetSafeMapPosition(endPos, parent.pawn.Map);
+
+ Log.Message($"Final positions - Start: {startPos}, End: {endPos}");
+
+ // 验证位置是否有效
+ if (!startPos.InBounds(parent.pawn.Map))
+ {
+ Log.Warning($"Start position {startPos} is out of bounds, adjusting to map center");
+ startPos = parent.pawn.Map.Center;
+ }
+
+ if (!endPos.InBounds(parent.pawn.Map))
+ {
+ Log.Warning($"End position {endPos} is out of bounds, adjusting to map center");
+ endPos = parent.pawn.Map.Center;
+ }
+
+ // 确保起点和终点不同
+ if (startPos == endPos)
+ {
+ Log.Warning($"OrbitalBombardment start and end positions are the same: {startPos}. Adjusting end position.");
+ IntVec3 randomOffset = new IntVec3(Rand.Range(-10, 11), 0, Rand.Range(-10, 11));
+ endPos += randomOffset;
+ endPos = GetSafeMapPosition(endPos, parent.pawn.Map);
+ }
+
+ // 创建轨道炮击飞越
+ CreateOrbitalBombardmentFlyOver(startPos, endPos, target.Cell);
+ }
+ catch (System.Exception ex)
+ {
+ Log.Error($"Error spawning orbital bombardment: {ex}");
+ }
+ }
+
+ public override void DrawEffectPreview(LocalTargetInfo target)
+ {
+ base.DrawEffectPreview(target);
+
+ if (parent.pawn != null && parent.pawn.Map != null)
+ {
+ Map map = parent.pawn.Map;
+
+ try
+ {
+ // 计算飞行路径
+ IntVec3 startPos, endPos;
+ if (Props.approachType == ApproachType.Perpendicular)
+ {
+ CalculatePerpendicularPath(target, out startPos, out endPos);
+ }
+ else
+ {
+ startPos = CalculateStartPosition(target);
+ endPos = CalculateEndPosition(target, startPos);
+ }
+
+ // 确保位置在地图范围内
+ startPos = GetSafeMapPosition(startPos, map);
+ endPos = GetSafeMapPosition(endPos, map);
+
+ // 检查预览稳定性
+ if (!IsPreviewStable(startPos, endPos, map))
+ {
+ return;
+ }
+
+ // 绘制炮击区域预览
+ DrawBombardmentAreaPreview(startPos, endPos, target.Cell);
+ }
+ catch (System.Exception)
+ {
+ // 忽略预览绘制中的错误
+ }
+ }
+ }
+
+ // 绘制炮击区域预览
+ private void DrawBombardmentAreaPreview(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
+ {
+ Map map = parent.pawn.Map;
+
+ // 计算飞行方向
+ Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
+ if (flightDirection == Vector3.zero)
+ {
+ flightDirection = Vector3.forward;
+ }
+
+ // 计算炮击影响区域的单元格
+ List bombardmentImpactCells = CalculateBombardmentImpactCells(targetCell, flightDirection);
+
+ // 绘制炮击影响区域的预览单元格
+ foreach (IntVec3 cell in bombardmentImpactCells)
+ {
+ if (cell.InBounds(map))
+ {
+ GenDraw.DrawFieldEdges(new List { cell }, Props.bombardmentPreviewColor, 0.5f);
+ }
+ }
+
+ // 绘制飞行路径线
+ GenDraw.DrawLineBetween(startPos.ToVector3Shifted(), endPos.ToVector3Shifted(), SimpleColor.Yellow, 0.2f);
+
+ // 绘制炮击范围边界
+ DrawBombardmentBoundaries(targetCell, flightDirection);
+ }
+
+ // 计算炮击影响区域的单元格
+ private List CalculateBombardmentImpactCells(IntVec3 targetCell, Vector3 flightDirection)
+ {
+ List cells = new List();
+ Map map = parent.pawn.Map;
+
+ // 计算垂直于飞行方向的方向
+ Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
+
+ // 以目标单元格为中心计算炮击区域
+ Vector3 targetCenter = targetCell.ToVector3();
+
+ // 计算炮击区域的起始和结束位置(基于炮击长度,以目标为中心)
+ float bombardmentHalfLength = Props.bombardmentLength * 0.5f;
+ Vector3 bombardmentStart = targetCenter - flightDirection * bombardmentHalfLength;
+ Vector3 bombardmentEnd = targetCenter + flightDirection * bombardmentHalfLength;
+
+ // 使用整数步进
+ int steps = Mathf.Max(1, Mathf.CeilToInt(Props.bombardmentLength));
+ for (int i = 0; i <= steps; i++)
+ {
+ float progress = (float)i / steps;
+ Vector3 centerPoint = Vector3.Lerp(bombardmentStart, bombardmentEnd, progress);
+
+ // 在垂直方向扩展炮击宽度
+ for (int w = -Props.bombardmentWidth; w <= Props.bombardmentWidth; w++)
+ {
+ Vector3 offset = perpendicular * w;
+ Vector3 cellPos = centerPoint + offset;
+
+ // 使用精确的单元格转换
+ IntVec3 cell = new IntVec3(
+ Mathf.RoundToInt(cellPos.x),
+ Mathf.RoundToInt(cellPos.y),
+ Mathf.RoundToInt(cellPos.z)
+ );
+
+ if (cell.InBounds(map) && !cells.Contains(cell))
+ {
+ cells.Add(cell);
+ }
+ }
+ }
+
+ Log.Message($"Bombardment Area: Calculated {cells.Count} impact cells centered at {targetCell}");
+ return cells;
+ }
+
+ // 绘制炮击范围边界
+ private void DrawBombardmentBoundaries(IntVec3 targetCell, Vector3 flightDirection)
+ {
+ Map map = parent.pawn.Map;
+ Vector3 perpendicular = new Vector3(-flightDirection.z, 0f, flightDirection.x).normalized;
+
+ // 以目标单元格为中心
+ Vector3 targetCenter = targetCell.ToVector3();
+
+ // 计算炮击区域的起始和结束位置
+ float bombardmentHalfLength = Props.bombardmentLength * 0.5f;
+ Vector3 bombardmentStart = targetCenter - flightDirection * bombardmentHalfLength;
+ Vector3 bombardmentEnd = targetCenter + flightDirection * bombardmentHalfLength;
+
+ // 计算炮击区域的四个角
+ Vector3 startLeft = bombardmentStart + perpendicular * Props.bombardmentWidth;
+ Vector3 startRight = bombardmentStart - perpendicular * Props.bombardmentWidth;
+ Vector3 endLeft = bombardmentEnd + perpendicular * Props.bombardmentWidth;
+ Vector3 endRight = bombardmentEnd - perpendicular * Props.bombardmentWidth;
+
+ // 转换为 IntVec3 并确保在地图范围内
+ IntVec3 startLeftCell = GetSafeMapPosition(new IntVec3((int)startLeft.x, (int)startLeft.y, (int)startLeft.z), map);
+ IntVec3 startRightCell = GetSafeMapPosition(new IntVec3((int)startRight.x, (int)startRight.y, (int)startRight.z), map);
+ IntVec3 endLeftCell = GetSafeMapPosition(new IntVec3((int)endLeft.x, (int)endLeft.y, (int)endLeft.z), map);
+ IntVec3 endRightCell = GetSafeMapPosition(new IntVec3((int)endRight.x, (int)endRight.y, (int)endRight.z), map);
+
+ // 绘制边界线
+ if (startLeftCell.InBounds(map) && endLeftCell.InBounds(map))
+ GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), endLeftCell.ToVector3Shifted(), SimpleColor.Yellow, 0.2f);
+
+ if (startRightCell.InBounds(map) && endRightCell.InBounds(map))
+ GenDraw.DrawLineBetween(startRightCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Yellow, 0.2f);
+
+ if (startLeftCell.InBounds(map) && startRightCell.InBounds(map))
+ GenDraw.DrawLineBetween(startLeftCell.ToVector3Shifted(), startRightCell.ToVector3Shifted(), SimpleColor.Yellow, 0.2f);
+
+ if (endLeftCell.InBounds(map) && endRightCell.InBounds(map))
+ GenDraw.DrawLineBetween(endLeftCell.ToVector3Shifted(), endRightCell.ToVector3Shifted(), SimpleColor.Yellow, 0.2f);
+ }
+
+ // 预处理炮击目标单元格
+ private List PreprocessBombardmentTargets(List potentialTargets, float fireChance)
+ {
+ List confirmedTargets = new List();
+ List missedCells = new List();
+
+ foreach (IntVec3 cell in potentialTargets)
+ {
+ if (Rand.Value <= fireChance)
+ {
+ confirmedTargets.Add(cell);
+ }
+ else
+ {
+ missedCells.Add(cell);
+ }
+ }
+
+ // 应用最小和最大炮击数限制
+ if (Props.maxBombardmentCount > -1 && confirmedTargets.Count > Props.maxBombardmentCount)
+ {
+ confirmedTargets = confirmedTargets.InRandomOrder().Take(Props.maxBombardmentCount).ToList();
+ }
+
+ if (Props.minBombardmentCount > -1 && confirmedTargets.Count < Props.minBombardmentCount)
+ {
+ int needed = Props.minBombardmentCount - confirmedTargets.Count;
+ if (needed > 0 && missedCells.Count > 0)
+ {
+ confirmedTargets.AddRange(missedCells.InRandomOrder().Take(Mathf.Min(needed, missedCells.Count)));
+ }
+ }
+
+ Log.Message($"Bombardment Preprocess: {confirmedTargets.Count}/{potentialTargets.Count} cells confirmed after min/max adjustment.");
+ return confirmedTargets;
+ }
+
+ // 创建轨道炮击飞越
+ private void CreateOrbitalBombardmentFlyOver(IntVec3 startPos, IntVec3 endPos, IntVec3 targetCell)
+ {
+ ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase.GetNamedSilentFail("ARA_HiveCorvette");
+ if (flyOverDef == null)
+ {
+ Log.Warning("No fly over def specified for orbital bombardment fly over");
+ return;
+ }
+
+ FlyOver flyOver = FlyOver.MakeFlyOver(
+ flyOverDef,
+ startPos,
+ endPos,
+ parent.pawn.Map,
+ Props.flightSpeed,
+ Props.altitude,
+ casterPawn: parent.pawn
+ );
+
+ // 设置基本属性
+ flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
+ flyOver.playFlyOverSound = Props.playFlyOverSound;
+
+ // 获取轨道炮击组件并设置预处理后的目标单元格
+ CompOrbitalBombardment bombardmentComp = flyOver.GetComp();
+ if (bombardmentComp != null)
+ {
+ // 计算炮击区域的所有单元格,以目标单元格为中心
+ Vector3 flightDirection = (endPos.ToVector3() - startPos.ToVector3()).normalized;
+ List potentialTargetCells = CalculateBombardmentImpactCells(targetCell, flightDirection);
+
+ if (potentialTargetCells.Count > 0)
+ {
+ // 预处理:根据概率筛选实际会被炮击的单元格
+ List confirmedTargetCells = PreprocessBombardmentTargets(
+ potentialTargetCells,
+ Props.bombardmentFireChance
+ );
+
+ if (confirmedTargetCells.Count > 0)
+ {
+ bombardmentComp.SetConfirmedTargets(confirmedTargetCells);
+ }
+ else
+ {
+ Log.Warning("No confirmed target cells after preprocessing!");
+ }
+ }
+ else
+ {
+ Log.Error("No potential target cells calculated for orbital bombardment!");
+ }
+ }
+ else
+ {
+ Log.Error("FlyOver def does not have CompOrbitalBombardment component!");
+ }
+ }
+
+ // 以下方法与 CompAbilityEffect_SpawnFlyOver 中的相同,需要复制过来
+ private IntVec3 GetSafeMapPosition(IntVec3 pos, Map map)
+ {
+ if (map == null) return pos;
+
+ pos.x = Mathf.Clamp(pos.x, 0, map.Size.x - 1);
+ pos.z = Mathf.Clamp(pos.z, 0, map.Size.z - 1);
+
+ return pos;
+ }
+
+ private bool IsPreviewStable(IntVec3 startPos, IntVec3 endPos, Map map)
+ {
+ if (map == null) return false;
+
+ if (!startPos.IsValid || !endPos.IsValid) return false;
+
+ if (!startPos.InBounds(map) || !endPos.InBounds(map)) return false;
+
+ float distance = Vector3.Distance(startPos.ToVector3(), endPos.ToVector3());
+ if (distance < 5f) return false;
+
+ return true;
+ }
+
+ private void CalculatePerpendicularPath(LocalTargetInfo target, out IntVec3 startPos, out IntVec3 endPos)
+ {
+ Map map = parent.pawn.Map;
+ IntVec3 casterPos = parent.pawn.Position;
+ IntVec3 targetPos = target.Cell;
+
+ Log.Message($"Calculating perpendicular path: Caster={casterPos}, Target={targetPos}");
+
+ Vector3 directionToTarget = (targetPos.ToVector3() - casterPos.ToVector3()).normalized;
+
+ if (directionToTarget == Vector3.zero)
+ {
+ directionToTarget = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
+ Log.Message($"Using random direction: {directionToTarget}");
+ }
+
+ Vector3 perpendicularDirection = new Vector3(-directionToTarget.z, 0, directionToTarget.x).normalized;
+
+ Log.Message($"Perpendicular direction: {perpendicularDirection}");
+
+ IntVec3 edge1 = FindMapEdgeInDirection(map, targetPos, perpendicularDirection);
+ IntVec3 edge2 = FindMapEdgeInDirection(map, targetPos, -perpendicularDirection);
+
+ if (Rand.Value < 0.5f)
+ {
+ startPos = edge1;
+ endPos = edge2;
+ }
+ else
+ {
+ startPos = edge2;
+ endPos = edge1;
+ }
+
+ Log.Message($"Perpendicular path: {startPos} -> {targetPos} -> {endPos}");
+ }
+
+ private IntVec3 FindMapEdgeInDirection(Map map, IntVec3 fromPos, Vector3 direction)
+ {
+ if (direction == Vector3.zero)
+ {
+ direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
+ }
+
+ IntVec3 mapCenter = map.Center;
+ IntVec3 mapSize = new IntVec3(map.Size.x, 0, map.Size.z);
+
+ Vector3 fromVec = fromPos.ToVector3();
+ Vector3 dirNormalized = direction.normalized;
+
+ float tMin = float.MaxValue;
+ IntVec3? bestEdgePos = null;
+
+ for (int i = 0; i < 4; i++)
+ {
+ float t = 0f;
+ IntVec3 edgePos = IntVec3.Invalid;
+
+ switch (i)
+ {
+ case 0: // 左边界 (x = 0)
+ if (Mathf.Abs(dirNormalized.x) > 0.001f)
+ {
+ t = (0 - fromVec.x) / dirNormalized.x;
+ if (t > 0)
+ {
+ float z = fromVec.z + dirNormalized.z * t;
+ if (z >= 0 && z < map.Size.z)
+ {
+ edgePos = new IntVec3(0, 0, Mathf.RoundToInt(z));
+ }
+ }
+ }
+ break;
+
+ case 1: // 右边界 (x = map.Size.x - 1)
+ if (Mathf.Abs(dirNormalized.x) > 0.001f)
+ {
+ t = (map.Size.x - 1 - fromVec.x) / dirNormalized.x;
+ if (t > 0)
+ {
+ float z = fromVec.z + dirNormalized.z * t;
+ if (z >= 0 && z < map.Size.z)
+ {
+ edgePos = new IntVec3(map.Size.x - 1, 0, Mathf.RoundToInt(z));
+ }
+ }
+ }
+ break;
+
+ case 2: // 下边界 (z = 0)
+ if (Mathf.Abs(dirNormalized.z) > 0.001f)
+ {
+ t = (0 - fromVec.z) / dirNormalized.z;
+ if (t > 0)
+ {
+ float x = fromVec.x + dirNormalized.x * t;
+ if (x >= 0 && x < map.Size.x)
+ {
+ edgePos = new IntVec3(Mathf.RoundToInt(x), 0, 0);
+ }
+ }
+ }
+ break;
+
+ case 3: // 上边界 (z = map.Size.z - 1)
+ if (Mathf.Abs(dirNormalized.z) > 0.001f)
+ {
+ t = (map.Size.z - 1 - fromVec.z) / dirNormalized.z;
+ if (t > 0)
+ {
+ float x = fromVec.x + dirNormalized.x * t;
+ if (x >= 0 && x < map.Size.x)
+ {
+ edgePos = new IntVec3(Mathf.RoundToInt(x), 0, map.Size.z - 1);
+ }
+ }
+ }
+ break;
+ }
+
+ if (edgePos.IsValid && edgePos.InBounds(map) && t > 0 && t < tMin)
+ {
+ tMin = t;
+ bestEdgePos = edgePos;
+ }
+ }
+
+ if (bestEdgePos.HasValue)
+ {
+ return bestEdgePos.Value;
+ }
+
+ Log.Warning($"Could not find map edge in direction {direction}, using random edge");
+ return GetRandomMapEdgePosition(map);
+ }
+
+ private IntVec3 GetRandomMapEdgePosition(Map map)
+ {
+ int edge = Rand.Range(0, 4);
+ int x, z;
+
+ switch (edge)
+ {
+ case 0: // 上边
+ x = Rand.Range(0, map.Size.x);
+ z = 0;
+ break;
+ case 1: // 右边
+ x = map.Size.x - 1;
+ z = Rand.Range(0, map.Size.z);
+ break;
+ case 2: // 下边
+ x = Rand.Range(0, map.Size.x);
+ z = map.Size.z - 1;
+ break;
+ case 3: // 左边
+ default:
+ x = 0;
+ z = Rand.Range(0, map.Size.z);
+ break;
+ }
+
+ IntVec3 edgePos = new IntVec3(x, 0, z);
+ Log.Message($"Random map edge position: {edgePos}");
+ return edgePos;
+ }
+
+ private IntVec3 CalculateStartPosition(LocalTargetInfo target)
+ {
+ Map map = parent.pawn.Map;
+
+ switch (Props.startPosition)
+ {
+ case StartPosition.Caster:
+ return parent.pawn.Position;
+
+ case StartPosition.MapEdge:
+ return GetMapEdgePosition(map, GetDirectionFromCasterToTarget(target));
+
+ case StartPosition.CustomOffset:
+ return GetSafeMapPosition(parent.pawn.Position + Props.customStartOffset, map);
+
+ case StartPosition.RandomMapEdge:
+ return GetRandomMapEdgePosition(map);
+
+ default:
+ return parent.pawn.Position;
+ }
+ }
+
+ private IntVec3 CalculateEndPosition(LocalTargetInfo target, IntVec3 startPos)
+ {
+ Map map = parent.pawn.Map;
+ IntVec3 endPos;
+
+ switch (Props.endPosition)
+ {
+ case EndPosition.TargetCell:
+ endPos = target.Cell;
+ break;
+
+ case EndPosition.OppositeMapEdge:
+ endPos = GetOppositeMapEdgeThroughCenter(map, startPos);
+ break;
+
+ case EndPosition.CustomOffset:
+ endPos = GetSafeMapPosition(target.Cell + Props.customEndOffset, map);
+ break;
+
+ case EndPosition.FixedDistance:
+ endPos = GetFixedDistancePosition(startPos, target.Cell);
+ break;
+
+ case EndPosition.RandomMapEdge:
+ endPos = GetRandomMapEdgePosition(map);
+ Log.Message($"Random map edge selected as end position: {endPos}");
+ break;
+
+ default:
+ endPos = target.Cell;
+ break;
+ }
+
+ return GetSafeMapPosition(endPos, map);
+ }
+
+ private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos)
+ {
+ IntVec3 center = map.Center;
+ Vector3 toCenter = (center.ToVector3() - startPos.ToVector3()).normalized;
+
+ if (toCenter == Vector3.zero)
+ {
+ toCenter = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
+ Log.Message($"Using random direction to center: {toCenter}");
+ }
+
+ Vector3 fromCenter = toCenter;
+ IntVec3 oppositeEdge = GetMapEdgePositionFromCenter(map, fromCenter);
+
+ Log.Message($"Found opposite edge through center: {oppositeEdge}");
+ return oppositeEdge;
+ }
+
+ private IntVec3 GetMapEdgePositionFromCenter(Map map, Vector3 direction)
+ {
+ IntVec3 center = map.Center;
+ float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
+
+ for (int i = 1; i <= maxDist; i++)
+ {
+ IntVec3 testPos = center + new IntVec3(
+ Mathf.RoundToInt(direction.x * i),
+ 0,
+ Mathf.RoundToInt(direction.z * i));
+
+ if (!testPos.InBounds(map))
+ {
+ IntVec3 edgePos = FindClosestValidPosition(testPos, map);
+ Log.Message($"Found map edge from center: {edgePos} (direction: {direction}, distance: {i})");
+ return edgePos;
+ }
+ }
+
+ Log.Warning("Could not find map edge from center, using random edge");
+ return GetRandomMapEdgePosition(map);
+ }
+
+ private IntVec3 GetMapEdgePosition(Map map, Vector3 direction)
+ {
+ if (direction == Vector3.zero)
+ {
+ direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
+ Log.Message($"Using random direction: {direction}");
+ }
+
+ IntVec3 center = map.Center;
+ float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
+
+ for (int i = 1; i <= maxDist; i++)
+ {
+ IntVec3 testPos = center + new IntVec3(
+ Mathf.RoundToInt(direction.x * i),
+ 0,
+ Mathf.RoundToInt(direction.z * i));
+
+ if (!testPos.InBounds(map))
+ {
+ IntVec3 edgePos = FindClosestValidPosition(testPos, map);
+ Log.Message($"Found map edge position: {edgePos} (direction: {direction}, distance: {i})");
+ return edgePos;
+ }
+ }
+
+ Log.Warning("Could not find map edge in direction, using random edge");
+ return GetRandomMapEdgePosition(map);
+ }
+
+ private IntVec3 FindClosestValidPosition(IntVec3 invalidPos, Map map)
+ {
+ for (int radius = 1; radius <= 5; radius++)
+ {
+ foreach (IntVec3 pos in GenRadial.RadialPatternInRadius(radius))
+ {
+ IntVec3 testPos = invalidPos + pos;
+ if (testPos.InBounds(map))
+ {
+ return testPos;
+ }
+ }
+ }
+
+ return map.Center;
+ }
+
+ private IntVec3 GetFixedDistancePosition(IntVec3 startPos, IntVec3 targetPos)
+ {
+ Vector3 direction = (targetPos.ToVector3() - startPos.ToVector3()).normalized;
+ IntVec3 endPos = startPos + new IntVec3(
+ (int)(direction.x * Props.flyOverDistance),
+ 0,
+ (int)(direction.z * Props.flyOverDistance));
+
+ Log.Message($"Fixed distance position: {endPos} (from {startPos}, distance: {Props.flyOverDistance})");
+ return endPos;
+ }
+
+ private Vector3 GetDirectionFromCasterToTarget(LocalTargetInfo target)
+ {
+ Vector3 direction = (target.Cell.ToVector3() - parent.pawn.Position.ToVector3()).normalized;
+
+ if (direction == Vector3.zero)
+ {
+ direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
+ Log.Message($"Using random direction: {direction}");
+ }
+
+ return direction;
+ }
+
+ public override string ExtraLabelMouseAttachment(LocalTargetInfo target)
+ {
+ return $"炮击区域: {Props.bombardmentWidth * 2 + 1}格宽度 × {Props.bombardmentLength}格长度";
+ }
+
+ public override bool Valid(LocalTargetInfo target, bool throwMessages = false)
+ {
+ return base.Valid(target, throwMessages) &&
+ parent.pawn != null &&
+ parent.pawn.Map != null &&
+ target.Cell.IsValid &&
+ target.Cell.InBounds(parent.pawn.Map);
+ }
+ }
+
+ public class CompProperties_AbilityOrbitalBombardment : CompProperties_AbilityEffect
+ {
+ public ThingDef flyOverDef; // 飞越物体的 ThingDef
+ public ApproachType approachType = ApproachType.Standard; // 进场类型
+ public float flightSpeed = 1f; // 飞行速度
+ public float altitude = 20f; // 飞行高度
+ public bool dropContentsOnImpact = false; // 是否在终点投放内容物
+ public bool playFlyOverSound = true; // 是否播放飞越音效
+
+ // 起始位置选项
+ public StartPosition startPosition = StartPosition.Caster;
+ public IntVec3 customStartOffset = IntVec3.Zero;
+
+ // 终点位置选项
+ public EndPosition endPosition = EndPosition.TargetCell;
+ public IntVec3 customEndOffset = IntVec3.Zero;
+ public int flyOverDistance = 30; // 飞越距离
+
+ // 炮击配置
+ public int bombardmentWidth = 3; // 炮击宽度
+ public int bombardmentLength = 15; // 炮击长度
+ public float bombardmentFireChance = 0.6f; // 炮击发射概率
+ public int minBombardmentCount = -1; // 最小炮击数
+ public int maxBombardmentCount = -1; // 最大炮击数
+
+ // 炮击可视化
+ public bool showBombardmentPreview = true; // 是否显示炮击预览
+ public Color bombardmentPreviewColor = new Color(1f, 1f, 0.3f, 0.3f); // 黄色预览
+
+ public CompProperties_AbilityOrbitalBombardment()
+ {
+ this.compClass = typeof(CompAbilityEffect_OrbitalBombardment);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompOrbitalBombardment.cs b/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompOrbitalBombardment.cs
new file mode 100644
index 00000000..fc29400a
--- /dev/null
+++ b/Source/WulaFallenEmpire/Flyover/WULA_OrbitalBombardment/CompOrbitalBombardment.cs
@@ -0,0 +1,450 @@
+// CompOrbitalBombardment.cs
+using System.Collections.Generic;
+using RimWorld;
+using UnityEngine;
+using Verse;
+
+namespace WulaFallenEmpire
+{
+ public class CompOrbitalBombardment : ThingComp
+ {
+ public CompProperties_OrbitalBombardment Props => (CompProperties_OrbitalBombardment)props;
+
+ // 炮击状态
+ private List confirmedTargetCells = new List();
+ private HashSet firedCells = new HashSet();
+
+ // 横向偏移状态(左右)
+ private float currentLateralOffsetAngle = 0f;
+ private int shotsFired = 0;
+
+ // 纵向偏移状态(前后)
+ private float currentLongitudinalOffset = 0f;
+ private bool isForwardPhase = true;
+
+ // 炮击间隔控制
+ private int nextBombardmentTick = 0;
+ private int currentBurstCount = 0;
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ // 初始化偏移
+ if (!respawningAfterLoad)
+ {
+ currentLateralOffsetAngle = Props.lateralInitialOffsetAngle;
+ currentLongitudinalOffset = Props.longitudinalInitialOffset;
+ nextBombardmentTick = Find.TickManager.TicksGame + Props.initialDelayTicks;
+ }
+
+ Log.Message($"OrbitalBombardment: Initialized with {confirmedTargetCells.Count} targets, " +
+ $"Lateral Offset: {currentLateralOffsetAngle:F1}°, " +
+ $"Longitudinal Offset: {currentLongitudinalOffset:F1}");
+ }
+
+ public override void CompTick()
+ {
+ base.CompTick();
+
+ if (confirmedTargetCells.Count == 0 || Find.TickManager.TicksGame < nextBombardmentTick)
+ {
+ return;
+ }
+
+ CheckAndBombardTargets();
+
+ // 定期状态输出
+ if (Find.TickManager.TicksGame % 120 == 0 && confirmedTargetCells.Count > 0)
+ {
+ Log.Message($"OrbitalBombardment: {firedCells.Count}/{confirmedTargetCells.Count + firedCells.Count} targets bombarded, " +
+ $"Lateral: {currentLateralOffsetAngle:F1}°, Longitudinal: {currentLongitudinalOffset:F1}");
+ }
+ }
+
+ private void CheckAndBombardTargets()
+ {
+ Vector3 currentPos = parent.DrawPos;
+
+ for (int i = confirmedTargetCells.Count - 1; i >= 0; i--)
+ {
+ IntVec3 targetCell = confirmedTargetCells[i];
+
+ if (firedCells.Contains(targetCell))
+ {
+ confirmedTargetCells.RemoveAt(i);
+ continue;
+ }
+
+ float horizontalDistance = GetHorizontalDistance(currentPos, targetCell);
+ if (horizontalDistance <= Props.range)
+ {
+ if (LaunchSkyfallerAt(targetCell))
+ {
+ firedCells.Add(targetCell);
+ confirmedTargetCells.RemoveAt(i);
+
+ // 更新所有偏移参数
+ UpdateOffsets();
+
+ // 设置下一次炮击时间
+ UpdateNextBombardmentTick();
+
+ if (firedCells.Count == 1)
+ {
+ Log.Message($"First orbital bombardment at {targetCell}, " +
+ $"Lateral offset: {currentLateralOffsetAngle:F1}°, " +
+ $"Longitudinal offset: {currentLongitudinalOffset:F1}");
+ }
+
+ // 检查是否需要暂停(连发模式)
+ if (Props.burstMode && currentBurstCount >= Props.burstSize)
+ {
+ currentBurstCount = 0;
+ nextBombardmentTick = Find.TickManager.TicksGame + Props.burstCooldownTicks;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // 新增:更新所有偏移参数
+ private void UpdateOffsets()
+ {
+ shotsFired++;
+ currentBurstCount++;
+
+ // 更新横向偏移
+ UpdateLateralOffset();
+
+ // 更新纵向偏移
+ UpdateLongitudinalOffset();
+ }
+
+ // 横向偏移逻辑(左右)
+ private void UpdateLateralOffset()
+ {
+ switch (Props.lateralOffsetMode)
+ {
+ case OffsetMode.Alternating:
+ currentLateralOffsetAngle = (shotsFired % 2 == 0) ? Props.lateralOffsetDistance : -Props.lateralOffsetDistance;
+ break;
+
+ case OffsetMode.Progressive:
+ currentLateralOffsetAngle += Props.lateralAngleIncrement;
+ if (Mathf.Abs(currentLateralOffsetAngle) > Props.lateralMaxOffsetAngle)
+ {
+ currentLateralOffsetAngle = Props.lateralInitialOffsetAngle;
+ }
+ break;
+
+ case OffsetMode.Random:
+ currentLateralOffsetAngle = Random.Range(-Props.lateralMaxOffsetAngle, Props.lateralMaxOffsetAngle);
+ break;
+
+ case OffsetMode.Fixed:
+ default:
+ break;
+ }
+
+ if (Props.lateralMaxOffsetAngle > 0)
+ {
+ currentLateralOffsetAngle = Mathf.Clamp(currentLateralOffsetAngle, -Props.lateralMaxOffsetAngle, Props.lateralMaxOffsetAngle);
+ }
+ }
+
+ // 纵向偏移逻辑(前后)
+ private void UpdateLongitudinalOffset()
+ {
+ switch (Props.longitudinalOffsetMode)
+ {
+ case LongitudinalOffsetMode.Alternating:
+ currentLongitudinalOffset = (shotsFired % 2 == 0) ? Props.longitudinalAlternationAmplitude : -Props.longitudinalAlternationAmplitude;
+ break;
+
+ case LongitudinalOffsetMode.Progressive:
+ if (isForwardPhase)
+ {
+ currentLongitudinalOffset += Props.longitudinalProgressionStep;
+ if (currentLongitudinalOffset >= Props.longitudinalMaxOffset)
+ {
+ isForwardPhase = false;
+ }
+ }
+ else
+ {
+ currentLongitudinalOffset -= Props.longitudinalProgressionStep;
+ if (currentLongitudinalOffset <= Props.longitudinalMinOffset)
+ {
+ isForwardPhase = true;
+ }
+ }
+ break;
+
+ case LongitudinalOffsetMode.Random:
+ currentLongitudinalOffset = Random.Range(Props.longitudinalMinOffset, Props.longitudinalMaxOffset);
+ break;
+
+ case LongitudinalOffsetMode.Sinusoidal:
+ float time = shotsFired * Props.longitudinalOscillationSpeed;
+ currentLongitudinalOffset = Mathf.Sin(time) * Props.longitudinalOscillationAmplitude;
+ break;
+
+ case LongitudinalOffsetMode.Fixed:
+ default:
+ break;
+ }
+
+ currentLongitudinalOffset = Mathf.Clamp(currentLongitudinalOffset, Props.longitudinalMinOffset, Props.longitudinalMaxOffset);
+ }
+
+ // 更新下一次炮击时间
+ private void UpdateNextBombardmentTick()
+ {
+ if (Props.burstMode && currentBurstCount < Props.burstSize)
+ {
+ // 连发模式中的连续射击
+ nextBombardmentTick = Find.TickManager.TicksGame + Props.burstIntervalTicks;
+ }
+ else
+ {
+ // 单发模式或连发模式结束
+ nextBombardmentTick = Find.TickManager.TicksGame + Props.cooldownTicks;
+ }
+ }
+
+ // 计算包含横向和纵向偏移的目标位置
+ private IntVec3 CalculateOffsetTargetPosition(IntVec3 baseTarget)
+ {
+ Vector3 basePos = baseTarget.ToVector3();
+ Vector3 finalPos = basePos;
+
+ // 应用横向偏移(左右)
+ if (Mathf.Abs(currentLateralOffsetAngle) > 0.01f)
+ {
+ Vector3 flyDirection = GetFlyOverDirection();
+ Vector3 perpendicular = Vector3.Cross(flyDirection, Vector3.up).normalized;
+ float lateralOffsetDistance = Props.lateralOffsetDistance;
+ Vector3 lateralOffset = perpendicular * lateralOffsetDistance * Mathf.Sin(currentLateralOffsetAngle * Mathf.Deg2Rad);
+ finalPos += lateralOffset;
+ }
+
+ // 应用纵向偏移(前后)
+ if (Mathf.Abs(currentLongitudinalOffset) > 0.01f)
+ {
+ Vector3 flyDirection = GetFlyOverDirection();
+ Vector3 longitudinalOffset = flyDirection * currentLongitudinalOffset;
+ finalPos += longitudinalOffset;
+ }
+
+ return finalPos.ToIntVec3();
+ }
+
+ private Vector3 GetFlyOverDirection()
+ {
+ FlyOver flyOver = parent as FlyOver;
+ if (flyOver != null)
+ {
+ return flyOver.MovementDirection;
+ }
+ return Vector3.forward;
+ }
+
+ private float GetHorizontalDistance(Vector3 fromPos, IntVec3 toCell)
+ {
+ Vector2 fromPos2D = new Vector2(fromPos.x, fromPos.z);
+ Vector2 toPos2D = new Vector2(toCell.x, toCell.z);
+ return Vector2.Distance(fromPos2D, toPos2D);
+ }
+
+ private bool LaunchSkyfallerAt(IntVec3 targetCell)
+ {
+ if (Props.skyfallerDef == null)
+ {
+ Log.Error("No skyfaller defined for orbital bombardment");
+ return false;
+ }
+
+ try
+ {
+ // 计算偏移后的目标位置
+ IntVec3 offsetTarget = CalculateOffsetTargetPosition(targetCell);
+
+ // 确保目标位置在地图范围内
+ if (!offsetTarget.InBounds(parent.Map))
+ {
+ Log.Warning($"OrbitalBombardment: Offset target position {offsetTarget} is out of bounds, using original target {targetCell}");
+ offsetTarget = targetCell;
+ }
+
+ // 创建 Skyfaller
+ Skyfaller skyfaller = SkyfallerMaker.SpawnSkyfaller(
+ Props.skyfallerDef,
+ offsetTarget,
+ parent.Map
+ );
+
+ if (skyfaller != null)
+ {
+ // 设置发射者信息(如果需要)
+ Thing launcher = GetLauncher();
+ if (launcher != null)
+ {
+ // 这里可以设置 Skyfaller 的发射者信息
+ // 具体取决于 Skyfaller 的实现
+ }
+
+ // 播放炮击特效
+ if (Props.spawnBombardmentEffect)
+ {
+ CreateBombardmentEffect(offsetTarget);
+ }
+
+ Log.Message($"OrbitalBombardment: Launched {Props.skyfallerDef.defName} at {offsetTarget}");
+ return true;
+ }
+ }
+ catch (System.Exception ex)
+ {
+ Log.Error($"Error launching orbital bombardment skyfaller: {ex}");
+ }
+
+ return false;
+ }
+
+ // 炮击特效
+ private void CreateBombardmentEffect(IntVec3 targetPos)
+ {
+ if (Props.bombardmentEffectDef != null)
+ {
+ MoteMaker.MakeStaticMote(
+ targetPos.ToVector3Shifted(),
+ parent.Map,
+ Props.bombardmentEffectDef,
+ Props.bombardmentEffectScale
+ );
+ }
+ }
+
+ private Thing GetLauncher()
+ {
+ FlyOver flyOver = parent as FlyOver;
+ // 如果需要,可以返回发射者信息
+ return parent;
+ }
+
+ public void SetConfirmedTargets(List targets)
+ {
+ confirmedTargetCells.Clear();
+ firedCells.Clear();
+ shotsFired = 0;
+ currentBurstCount = 0;
+ currentLateralOffsetAngle = Props.lateralInitialOffsetAngle;
+ currentLongitudinalOffset = Props.longitudinalInitialOffset;
+ isForwardPhase = true;
+
+ confirmedTargetCells.AddRange(targets);
+
+ // 设置首次炮击时间
+ nextBombardmentTick = Find.TickManager.TicksGame + Props.initialDelayTicks;
+
+ Log.Message($"OrbitalBombardment: Set {confirmedTargetCells.Count} targets, " +
+ $"Lateral Mode: {Props.lateralOffsetMode}, " +
+ $"Longitudinal Mode: {Props.longitudinalOffsetMode}, " +
+ $"Initial Delay: {Props.initialDelayTicks} ticks");
+
+ if (confirmedTargetCells.Count > 0)
+ {
+ Log.Message($"First target: {confirmedTargetCells[0]}, Last target: {confirmedTargetCells[confirmedTargetCells.Count - 1]}");
+ }
+ }
+
+ public override void PostExposeData()
+ {
+ base.PostExposeData();
+
+ Scribe_Collections.Look(ref confirmedTargetCells, "confirmedTargetCells", LookMode.Value);
+ Scribe_Collections.Look(ref firedCells, "firedCells", LookMode.Value);
+ Scribe_Values.Look(ref currentLateralOffsetAngle, "currentLateralOffsetAngle", Props.lateralInitialOffsetAngle);
+ Scribe_Values.Look(ref currentLongitudinalOffset, "currentLongitudinalOffset", Props.longitudinalInitialOffset);
+ Scribe_Values.Look(ref shotsFired, "shotsFired", 0);
+ Scribe_Values.Look(ref isForwardPhase, "isForwardPhase", true);
+ Scribe_Values.Look(ref nextBombardmentTick, "nextBombardmentTick", 0);
+ Scribe_Values.Look(ref currentBurstCount, "currentBurstCount", 0);
+ }
+
+ // 调试方法
+ public void DebugBombardmentStatus()
+ {
+ Log.Message($"OrbitalBombardment Status:");
+ Log.Message($" Lateral - Angle: {currentLateralOffsetAngle:F1}°, Mode: {Props.lateralOffsetMode}");
+ Log.Message($" Longitudinal - Offset: {currentLongitudinalOffset:F1}, Mode: {Props.longitudinalOffsetMode}");
+ Log.Message($" Shots Fired: {shotsFired}, Forward Phase: {isForwardPhase}");
+ Log.Message($" Next Bombardment: {nextBombardmentTick}, Current Burst: {currentBurstCount}/{Props.burstSize}");
+ Log.Message($" Targets: {confirmedTargetCells.Count} remaining, {firedCells.Count} completed");
+ }
+
+ // 获取剩余目标数量
+ public int GetRemainingTargets()
+ {
+ return confirmedTargetCells.Count;
+ }
+
+ // 获取总进度
+ public float GetCompletionProgress()
+ {
+ int totalTargets = confirmedTargetCells.Count + firedCells.Count;
+ if (totalTargets == 0) return 1f;
+ return (float)firedCells.Count / totalTargets;
+ }
+ }
+
+ public class CompProperties_OrbitalBombardment : CompProperties
+ {
+ public ThingDef skyfallerDef; // Skyfaller 定义
+ public float range = 25f; // 炮击范围
+
+ // 炮击时序控制
+ public int initialDelayTicks = 60; // 初始延迟(游戏刻)
+ public int cooldownTicks = 30; // 冷却时间(游戏刻)
+ public bool burstMode = false; // 是否使用连发模式
+ public int burstSize = 3; // 连发数量
+ public int burstIntervalTicks = 10; // 连发间隔(游戏刻)
+ public int burstCooldownTicks = 60; // 连发后冷却(游戏刻)
+
+ // 横向偏移配置(左右)
+ public float lateralOffsetDistance = 2f;
+ public float lateralInitialOffsetAngle = 0f;
+ public float lateralMaxOffsetAngle = 45f;
+ public float lateralAngleIncrement = 5f;
+ public OffsetMode lateralOffsetMode = OffsetMode.Alternating;
+
+ // 纵向偏移配置(前后)
+ public float longitudinalInitialOffset = 0f;
+ public float longitudinalMinOffset = -2f;
+ public float longitudinalMaxOffset = 2f;
+ public LongitudinalOffsetMode longitudinalOffsetMode = LongitudinalOffsetMode.Alternating;
+
+ // 正弦波模式参数
+ public float longitudinalOscillationSpeed = 0.5f;
+ public float longitudinalOscillationAmplitude = 1f;
+
+ // 交替模式参数
+ public float longitudinalAlternationAmplitude = 1f;
+
+ // 渐进模式参数
+ public float longitudinalProgressionStep = 0.1f;
+
+ // 视觉效果和音效
+ public bool spawnBombardmentEffect = true;
+ public ThingDef bombardmentEffectDef;
+ public float bombardmentEffectScale = 1f;
+ public SoundDef bombardmentSound;
+
+ public CompProperties_OrbitalBombardment()
+ {
+ compClass = typeof(CompOrbitalBombardment);
+ }
+ }
+}
diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
index b24441de..dade2b9b 100644
--- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
+++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj
@@ -100,6 +100,8 @@
+
+