diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index dea759aa..80e4abd4 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/PrefabDefs/WULA_Prefabs.xml b/1.6/1.6/Defs/PrefabDefs/WULA_Prefabs.xml index e1e4b596..fe345ab2 100644 --- a/1.6/1.6/Defs/PrefabDefs/WULA_Prefabs.xml +++ b/1.6/1.6/Defs/PrefabDefs/WULA_Prefabs.xml @@ -148,4 +148,640 @@ + + + WULA_Bunker_Drop_Zone_Prefeb + (5,5) + + + (2, 0, 2) + + + +
  • (0,0,1,0)
  • +
  • (3,0,4,0)
  • +
  • (0,1,0,1)
  • +
  • (4,1,4,1)
  • +
  • (0,3,0,4)
  • +
  • (4,3,4,4)
  • +
  • (1,4,1,4)
  • +
  • (3,4,3,4)
  • +
    + Cloth +
    +
    +
    + + WULA_Turret_Group_Drop_Zone_Prefeb + (15,15) + + + +
  • (3, 0, 3)
  • +
  • (11, 0, 3)
  • +
  • (3, 0, 11)
  • +
  • (11, 0, 11)
  • +
    +
    + + (7, 0, 7) + + + +
  • (7, 0, 1)
  • +
  • (1, 0, 7)
  • +
  • (13, 0, 7)
  • +
  • (7, 0, 13)
  • +
    +
    + + +
  • (7,3,7,3)
  • +
  • (3,7,3,7)
  • +
  • (11,7,11,7)
  • +
  • (7,11,7,11)
  • +
    +
    + + +
  • (5,5,9,5)
  • +
  • (5,6,5,9)
  • +
  • (9,6,9,9)
  • +
  • (6,9,8,9)
  • +
    +
    + + +
  • (1,1,5,1)
  • +
  • (9,1,13,1)
  • +
  • (1,2,1,5)
  • +
  • (5,2,5,2)
  • +
  • (9,2,9,2)
  • +
  • (13,2,13,5)
  • +
  • (2,5,2,5)
  • +
  • (12,5,12,5)
  • +
  • (1,9,2,9)
  • +
  • (12,9,13,9)
  • +
  • (1,10,1,13)
  • +
  • (13,10,13,13)
  • +
  • (5,12,5,13)
  • +
  • (9,12,9,13)
  • +
  • (2,13,4,13)
  • +
  • (10,13,12,13)
  • +
    + Cloth +
    +
    +
    + + WULA_Fortress_Drop_Zone_Prefeb + (25,25) + + + +
  • (7,6,7,6)
  • +
  • (9,6,9,6)
  • +
  • (15,6,15,6)
  • +
  • (17,6,17,6)
  • +
  • (12,8,12,8)
  • +
  • (12,16,12,16)
  • +
  • (7,18,7,18)
  • +
  • (9,18,9,18)
  • +
  • (15,18,15,18)
  • +
  • (17,18,17,18)
  • +
    + Clockwise +
    + + +
  • (6,7,6,7)
  • +
  • (18,7,18,7)
  • +
  • (6,9,6,9)
  • +
  • (18,9,18,9)
  • +
  • (8,12,8,12)
  • +
  • (16,12,16,12)
  • +
  • (6,15,6,15)
  • +
  • (18,15,18,15)
  • +
  • (6,17,6,17)
  • +
  • (18,17,18,17)
  • +
    +
    + + +
  • (10,6,10,6)
  • +
  • (14,6,14,6)
  • +
    +
    + + +
  • (6,10,6,10)
  • +
  • (6,14,6,14)
  • +
    + Clockwise +
    + + +
  • (18,10,18,10)
  • +
  • (18,14,18,14)
  • +
    + Counterclockwise +
    + + +
  • (10,18,10,18)
  • +
  • (14,18,14,18)
  • +
    + Opposite +
    + + +
  • (5, 0, 1)
  • +
  • (19, 0, 1)
  • +
  • (1, 0, 5)
  • +
  • (23, 0, 5)
  • +
  • (1, 0, 19)
  • +
  • (23, 0, 19)
  • +
  • (19, 0, 23)
  • +
    +
    + + (5, 0, 23) + 476 + + + +
  • (5, 0, 5)
  • +
  • (19, 0, 5)
  • +
  • (5, 0, 19)
  • +
  • (19, 0, 19)
  • +
    +
    + + +
  • (9, 0, 3)
  • +
  • (15, 0, 3)
  • +
  • (3, 0, 9)
  • +
  • (21, 0, 9)
  • +
  • (3, 0, 15)
  • +
  • (21, 0, 15)
  • +
  • (9, 0, 21)
  • +
  • (15, 0, 21)
  • +
    +
    + + +
  • (10,5,10,5)
  • +
  • (14,5,14,5)
  • +
  • (5,10,5,10)
  • +
  • (19,10,19,10)
  • +
  • (5,14,5,14)
  • +
  • (19,14,19,14)
  • +
  • (10,19,10,19)
  • +
  • (14,19,14,19)
  • +
    +
    + + +
  • (3,3,7,3)
  • +
  • (17,3,21,3)
  • +
  • (3,4,3,7)
  • +
  • (7,4,7,5)
  • +
  • (17,4,17,5)
  • +
  • (21,4,21,7)
  • +
  • (8,5,9,5)
  • +
  • (15,5,16,5)
  • +
  • (4,7,5,7)
  • +
  • (7,7,7,7)
  • +
  • (9,7,15,7)
  • +
  • (17,7,17,7)
  • +
  • (19,7,20,7)
  • +
  • (5,8,5,9)
  • +
  • (19,8,19,9)
  • +
  • (7,9,7,15)
  • +
  • (9,9,15,9)
  • +
  • (17,9,17,15)
  • +
  • (9,10,9,15)
  • +
  • (15,10,15,15)
  • +
  • (5,15,5,17)
  • +
  • (10,15,14,15)
  • +
  • (19,15,19,17)
  • +
  • (3,17,4,17)
  • +
  • (7,17,7,17)
  • +
  • (9,17,15,17)
  • +
  • (17,17,17,17)
  • +
  • (20,17,21,17)
  • +
  • (3,18,3,21)
  • +
  • (21,18,21,21)
  • +
  • (7,19,9,19)
  • +
  • (15,19,17,19)
  • +
  • (7,20,7,21)
  • +
  • (17,20,17,21)
  • +
  • (4,21,6,21)
  • +
  • (18,21,20,21)
  • +
    +
    + + (12, 0, 12) + + + +
  • (7,1,11,1)
  • +
  • (13,1,17,1)
  • +
  • (7,2,7,2)
  • +
  • (11,2,11,2)
  • +
  • (13,2,13,2)
  • +
  • (17,2,17,2)
  • +
  • (1,7,2,7)
  • +
  • (22,7,23,7)
  • +
  • (1,8,1,11)
  • +
  • (23,8,23,11)
  • +
  • (2,11,2,11)
  • +
  • (22,11,22,11)
  • +
  • (1,13,2,13)
  • +
  • (22,13,23,13)
  • +
  • (1,14,1,17)
  • +
  • (23,14,23,17)
  • +
  • (2,17,2,17)
  • +
  • (22,17,22,17)
  • +
  • (7,22,7,23)
  • +
  • (11,22,11,23)
  • +
  • (13,22,13,23)
  • +
  • (17,22,17,23)
  • +
  • (8,23,10,23)
  • +
  • (14,23,16,23)
  • +
    + Cloth +
    +
    + + + +
  • (3,3,7,7)
  • +
  • (17,3,21,7)
  • +
  • (8,5,9,19)
  • +
  • (15,5,16,19)
  • +
  • (10,7,14,17)
  • +
  • (5,8,7,9)
  • +
  • (17,8,19,9)
  • +
  • (7,10,7,21)
  • +
  • (17,10,17,21)
  • +
  • (5,15,6,21)
  • +
  • (18,15,19,21)
  • +
  • (3,17,4,21)
  • +
  • (20,17,21,21)
  • +
    +
    +
    +
    + + + WULA_Huge_Fortress_Drop_Zone_Prefeb + (44,44) + + + +
  • (14, 0, 12)
  • +
  • (15, 0, 12)
  • +
  • (16, 0, 12)
  • +
  • (14, 0, 32)
  • +
  • (15, 0, 32)
  • +
  • (16, 0, 32)
  • +
  • (27, 0, 32)
  • +
  • (28, 0, 32)
  • +
  • (29, 0, 32)
  • +
    + Opposite +
    + + +
  • (27, 0, 11)
  • +
  • (28, 0, 11)
  • +
  • (29, 0, 11)
  • +
    +
    + + +
  • (12, 0, 14)
  • +
  • (12, 0, 15)
  • +
  • (12, 0, 16)
  • +
    + Counterclockwise +
    + + +
  • (31, 0, 14)
  • +
  • (31, 0, 15)
  • +
  • (31, 0, 16)
  • +
  • (11, 0, 27)
  • +
  • (31, 0, 27)
  • +
  • (11, 0, 28)
  • +
  • (31, 0, 28)
  • +
  • (11, 0, 29)
  • +
  • (31, 0, 29)
  • +
    + Clockwise +
    + + +
  • (16, 0, 8)
  • +
  • (27, 0, 8)
  • +
  • (8, 0, 16)
  • +
  • (35, 0, 16)
  • +
  • (8, 0, 27)
  • +
  • (35, 0, 27)
  • +
  • (16, 0, 35)
  • +
  • (27, 0, 35)
  • +
    +
    + + +
  • (12,11,12,11)
  • +
  • (31,11,31,11)
  • +
  • (20,12,20,12)
  • +
  • (23,12,23,12)
  • +
  • (15,14,15,14)
  • +
  • (28,14,28,14)
  • +
  • (13,17,13,17)
  • +
  • (30,17,30,17)
  • +
  • (21,19,22,19)
  • +
  • (21,24,22,24)
  • +
  • (13,26,13,26)
  • +
  • (30,26,30,26)
  • +
  • (15,29,15,29)
  • +
  • (28,29,28,29)
  • +
  • (20,31,20,31)
  • +
  • (23,31,23,31)
  • +
  • (12,32,12,32)
  • +
  • (31,32,31,32)
  • +
    +
    + + +
  • (11,12,11,12)
  • +
  • (32,12,32,12)
  • +
  • (17,13,17,13)
  • +
  • (26,13,26,13)
  • +
  • (14,15,14,15)
  • +
  • (29,15,29,15)
  • +
  • (12,20,12,20)
  • +
  • (31,20,31,20)
  • +
  • (19,21,19,22)
  • +
  • (24,21,24,22)
  • +
  • (12,23,12,23)
  • +
  • (31,23,31,23)
  • +
  • (14,28,14,28)
  • +
  • (29,28,29,28)
  • +
  • (17,30,17,30)
  • +
  • (26,30,26,30)
  • +
  • (11,31,11,31)
  • +
  • (32,31,32,31)
  • +
    + Clockwise +
    + + +
  • (2, 0, 2)
  • +
  • (41, 0, 2)
  • +
  • (19, 0, 5)
  • +
  • (24, 0, 5)
  • +
  • (38, 0, 19)
  • +
  • (5, 0, 20)
  • +
  • (5, 0, 24)
  • +
  • (38, 0, 24)
  • +
  • (19, 0, 38)
  • +
  • (24, 0, 38)
  • +
  • (2, 0, 41)
  • +
  • (41, 0, 41)
  • +
    +
    + + +
  • (8, 0, 8)
  • +
  • (12, 0, 8)
  • +
  • (31, 0, 8)
  • +
  • (35, 0, 8)
  • +
  • (8, 0, 12)
  • +
  • (35, 0, 12)
  • +
  • (8, 0, 31)
  • +
  • (35, 0, 31)
  • +
  • (8, 0, 35)
  • +
  • (12, 0, 35)
  • +
  • (31, 0, 35)
  • +
  • (35, 0, 35)
  • +
    +
    + + +
  • (5,5,5,5)
  • +
  • (38,5,38,5)
  • +
  • (18,9,18,9)
  • +
  • (25,9,25,9)
  • +
  • (10,10,10,10)
  • +
  • (33,10,33,10)
  • +
  • (13,13,13,13)
  • +
  • (30,13,30,13)
  • +
  • (9,18,9,18)
  • +
  • (34,18,34,18)
  • +
  • (9,25,9,25)
  • +
  • (34,25,34,25)
  • +
  • (13,30,13,30)
  • +
  • (30,30,30,30)
  • +
  • (10,33,10,33)
  • +
  • (33,33,33,33)
  • +
  • (18,34,18,34)
  • +
  • (25,34,25,34)
  • +
  • (5,38,5,38)
  • +
  • (38,38,38,38)
  • +
    +
    + + +
  • (8, 0, 3)
  • +
  • (12, 0, 3)
  • +
  • (31, 0, 3)
  • +
  • (35, 0, 3)
  • +
  • (3, 0, 8)
  • +
  • (40, 0, 8)
  • +
  • (3, 0, 12)
  • +
  • (40, 0, 12)
  • +
  • (3, 0, 31)
  • +
  • (40, 0, 31)
  • +
  • (3, 0, 35)
  • +
  • (40, 0, 35)
  • +
  • (8, 0, 40)
  • +
  • (12, 0, 40)
  • +
  • (31, 0, 40)
  • +
  • (35, 0, 40)
  • +
    +
    + + +
  • (6,6,14,6)
  • +
  • (29,6,37,6)
  • +
  • (6,7,6,14)
  • +
  • (14,7,14,10)
  • +
  • (29,7,29,10)
  • +
  • (37,7,37,14)
  • +
  • (13,10,13,11)
  • +
  • (15,10,17,10)
  • +
  • (26,10,28,10)
  • +
  • (30,10,30,11)
  • +
  • (11,11,11,11)
  • +
  • (17,11,17,12)
  • +
  • (26,11,26,12)
  • +
  • (32,11,32,11)
  • +
  • (18,12,19,12)
  • +
  • (21,12,22,12)
  • +
  • (24,12,25,12)
  • +
  • (10,13,11,13)
  • +
  • (32,13,33,13)
  • +
  • (7,14,10,14)
  • +
  • (14,14,14,14)
  • +
  • (16,14,20,14)
  • +
  • (23,14,27,14)
  • +
  • (29,14,29,14)
  • +
  • (33,14,36,14)
  • +
  • (10,15,10,17)
  • +
  • (20,15,20,20)
  • +
  • (23,15,23,20)
  • +
  • (33,15,33,17)
  • +
  • (14,16,14,20)
  • +
  • (29,16,29,20)
  • +
  • (11,17,12,17)
  • +
  • (31,17,32,17)
  • +
  • (12,18,12,19)
  • +
  • (31,18,31,19)
  • +
  • (15,20,19,20)
  • +
  • (24,20,28,20)
  • +
  • (12,21,12,22)
  • +
  • (31,21,31,22)
  • +
  • (14,23,20,23)
  • +
  • (23,23,29,23)
  • +
  • (12,24,12,26)
  • +
  • (14,24,14,27)
  • +
  • (20,24,20,29)
  • +
  • (23,24,23,29)
  • +
  • (29,24,29,27)
  • +
  • (31,24,31,26)
  • +
  • (10,26,11,26)
  • +
  • (32,26,33,26)
  • +
  • (10,27,10,30)
  • +
  • (33,27,33,30)
  • +
  • (6,29,9,29)
  • +
  • (14,29,14,29)
  • +
  • (16,29,19,29)
  • +
  • (24,29,27,29)
  • +
  • (29,29,29,29)
  • +
  • (34,29,37,29)
  • +
  • (6,30,6,37)
  • +
  • (11,30,11,30)
  • +
  • (32,30,32,30)
  • +
  • (37,30,37,37)
  • +
  • (17,31,19,31)
  • +
  • (21,31,22,31)
  • +
  • (24,31,26,31)
  • +
  • (11,32,11,32)
  • +
  • (13,32,13,33)
  • +
  • (17,32,17,33)
  • +
  • (26,32,26,33)
  • +
  • (30,32,30,33)
  • +
  • (32,32,32,32)
  • +
  • (14,33,16,33)
  • +
  • (27,33,29,33)
  • +
  • (14,34,14,37)
  • +
  • (29,34,29,37)
  • +
  • (7,37,13,37)
  • +
  • (30,37,36,37)
  • +
    +
    + + +
  • (17, 0, 17)
  • +
  • (26, 0, 17)
  • +
  • (17, 0, 26)
  • +
  • (26, 0, 26)
  • +
    +
    + + +
  • (0,0,3,0)
  • +
  • (40,0,43,0)
  • +
  • (0,1,0,3)
  • +
  • (6,1,14,1)
  • +
  • (29,1,37,1)
  • +
  • (43,1,43,3)
  • +
  • (6,2,6,3)
  • +
  • (14,2,14,3)
  • +
  • (29,2,29,3)
  • +
  • (37,2,37,3)
  • +
  • (17,3,20,3)
  • +
  • (23,3,26,3)
  • +
  • (17,4,17,6)
  • +
  • (26,4,26,6)
  • +
  • (1,6,3,6)
  • +
  • (15,6,16,6)
  • +
  • (27,6,28,6)
  • +
  • (40,6,42,6)
  • +
  • (1,7,1,14)
  • +
  • (42,7,42,14)
  • +
  • (2,14,3,14)
  • +
  • (40,14,41,14)
  • +
  • (6,15,6,18)
  • +
  • (37,15,37,17)
  • +
  • (38,17,40,17)
  • +
  • (3,18,5,18)
  • +
  • (40,18,40,20)
  • +
  • (3,19,3,21)
  • +
  • (3,23,3,26)
  • +
  • (40,23,40,26)
  • +
  • (4,26,6,26)
  • +
  • (37,26,39,26)
  • +
  • (6,27,6,28)
  • +
  • (37,27,37,28)
  • +
  • (1,29,3,29)
  • +
  • (40,29,42,29)
  • +
  • (1,30,1,37)
  • +
  • (42,30,42,37)
  • +
  • (2,37,3,37)
  • +
  • (15,37,17,37)
  • +
  • (26,37,28,37)
  • +
  • (40,37,41,37)
  • +
  • (17,38,17,40)
  • +
  • (26,38,26,40)
  • +
  • (0,40,0,43)
  • +
  • (6,40,6,42)
  • +
  • (14,40,14,42)
  • +
  • (18,40,20,40)
  • +
  • (23,40,25,40)
  • +
  • (29,40,29,42)
  • +
  • (37,40,37,42)
  • +
  • (43,40,43,43)
  • +
  • (7,42,13,42)
  • +
  • (30,42,36,42)
  • +
  • (1,43,3,43)
  • +
  • (40,43,42,43)
  • +
    + Cloth +
    +
    + + + +
  • (6,6,14,14)
  • +
  • (29,6,37,14)
  • +
  • (15,10,17,33)
  • +
  • (26,10,28,33)
  • +
  • (18,12,25,31)
  • +
  • (10,15,14,17)
  • +
  • (29,15,33,17)
  • +
  • (12,18,14,37)
  • +
  • (29,18,31,37)
  • +
  • (10,26,11,37)
  • +
  • (32,26,33,37)
  • +
  • (6,29,9,37)
  • +
  • (34,29,37,37)
  • +
    +
    +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Hostile_Fortress_Drop_Quest.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Hostile_Fortress_Drop_Quest.xml new file mode 100644 index 00000000..c6bb05f1 --- /dev/null +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Hostile_Fortress_Drop_Quest.xml @@ -0,0 +1,294 @@ + + + + WULA_GiveQuest_Hostile_PIA_Attack_Quest + GiveQuest + + +
  • Map_PlayerHome
  • +
    + WULA_Hostile_PIA_Attack_Quest + IncidentWorker_GiveQuest + 0 +
    + + WULA_Hostile_PIA_Attack_Quest + 0 + true + false + 1 + true + false + + + +
  • questName->WULA_Hostile_PIA_Attack_Quest_questName
  • +
    +
    + + +
  • QuestHospitalityCommon
  • +
    + +
  • questDescription->WULA_Hostile_PIA_Attack_Quest_questDescription
  • +
    +
    + + + + + +
  • + + +
  • + + +
  • + +
  • + + +
  • questName->要塞空投
  • + + + +
  • + + +
  • questDescription->乌拉帝国 行星封锁机关对殖民地发起了报复打击,她们往殖民地空投了整装的要塞!
  • + + + +
  • + + NegativeEvent + 乌拉帝国 行星封锁机关对殖民地发起了报复打击,她们往殖民地空投了整装的要塞! +
  • +
  • + WULA_Bunker_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $points + 1000 + + + +
  • + WULA_Bunker_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 4 + false + false +
  • +
    + + +
  • + $points + 2999 + + + +
  • + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 2 + false + false +
  • + + + +
  • + $points + 5999 + + + + +
  • + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $prefabSpawnSuccessCount + $prefabSpawnRequestedCount + + + +
  • + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 3 + false + false +
  • + + + + + + +
  • + $points + 7999 + + + + +
  • + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $prefabSpawnSuccessCount + $prefabSpawnRequestedCount + + + +
  • + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 3 + false + false +
  • + + + + + + +
  • + $points + 9999 + + + + +
  • + WULA_Huge_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $prefabSpawnSuccessCount + $prefabSpawnRequestedCount + + + +
  • + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 2 + false + false +
  • + + + + + + +
  • + $points + 12999 + + + + +
  • + WULA_Bunker_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 4 + false + false +
  • +
  • + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $prefabSpawnSuccessCount + $prefabSpawnRequestedCount + + + +
  • + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 3 + false + false +
  • + + + + + + +
  • + $points + 15999 + + + + +
  • + WULA_Bunker_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 4 + false + false +
  • +
  • + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 1 + false + false +
  • +
  • + $prefabSpawnSuccessCount + $prefabSpawnRequestedCount + + + +
  • + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + Wula_PIA_Legion_Faction + 3 + false + false +
  • + + + + + + + + + + +
  • + + + + \ No newline at end of file diff --git a/1.6/1.6/Defs/QuestScriptDefs/WULA_Recycle_PIA_Legion_File.xml b/1.6/1.6/Defs/QuestScriptDefs/WULA_Recycle_PIA_Legion_File.xml index 2fb9d4f5..2cbcf9c0 100644 --- a/1.6/1.6/Defs/QuestScriptDefs/WULA_Recycle_PIA_Legion_File.xml +++ b/1.6/1.6/Defs/QuestScriptDefs/WULA_Recycle_PIA_Legion_File.xml @@ -1108,12 +1108,12 @@ Wula/Item/WULA_Safe_Box_For_Mission Graphic_Single - 30 + 1 0 0 0 - 24 + 8650000 0.3 450 @@ -1125,6 +1125,7 @@ true 14 200 + 0 None Last true 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 b8b06981..d7b78491 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 @@ -1,7 +1,7 @@ - + WulaWall_Cleanzone 清理出一块场地并准备好资源,使得乌拉帝国可以向此处投放建筑,建造好的信标可以收起或移至他处。\n\n乌拉帝国用于建造堡垒的外壁相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 @@ -72,7 +72,7 @@
  • - + WulaWall_Incoming (1,1) @@ -106,7 +106,7 @@ - + WulaWall 乌拉帝国堡垒外壁,相当厚实,能够抵御大量伤害,并且拥有气密性,可以用在飞船外壳上。 @@ -177,7 +177,7 @@ - + WulaDoor_Cleanzone 清理出一块场地并准备好资源,使得乌拉帝国可以向此处投放建筑,建造好的信标可以收起或移至他处。\n\n乌拉帝国堡垒的大门不仅能够抵御大量爆炸和震荡伤害,还拥有无需通电即可运转的伺服系统来增加大门通过速度。 @@ -254,7 +254,7 @@ - + WulaDoor_Incoming (1,1) @@ -288,7 +288,7 @@ - + WulaDoor 乌拉帝国堡垒的大门,不仅能够抵御大量爆炸和震荡伤害,还拥有无需通电即可运转的伺服系统来增加大门通过速度。 @@ -970,7 +970,7 @@ 1 -
  • WULA_WeaponArmor_Productor_Technology
  • +
  • WULA_Colony_License_LV1_Technology
  • ITab_ContentsTransporter
  • @@ -1860,6 +1860,7 @@ false false BuildingDestroyed_Metal_Medium + false 50 @@ -2078,7 +2079,7 @@
  • CompPowerPlant - -1500 + -2000 true ChemfuelFiredGenerator_Ambience
  • diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml index fd2ffafc..0340ef34 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Misc_Buildings.xml @@ -669,7 +669,6 @@ WULA_Sky_Lock 天锁 - Building WulaFallenEmpire.Building_ExtraGraphics true MetaOverlays diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml index 9d5ca9dc..41fb4f67 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Prefab_Beacons.xml @@ -105,4 +105,432 @@
    + + + WULA_Huge_Fortress_Drop_Zone_Beacon_Cleanzone + + 一个用于呼叫建筑的信标,用于快速建造一个大型要塞。 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Normal + MinifiedThing + + Wula/Building/WULA_Dropping_Building_Cleanzone_Plus + Graphic_Multi + (44,44) + + false + + + +
  • BuildingsMisc
  • +
    + false + false + false + false + false + false + BuildingOnTop + PassThroughOnly + 0 + false + false + + 0 + false + Light + + 1 + 0 + 1 + 0 + + (44,44) + 0 + 1 + + + 0 + + 4 + + + BuildingDestroyed_Metal_Small + false + false + + +
  • + WULA_Huge_Fortress_Drop_Zone_Prefeb + true + WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming + true + 1 + true + false +
  • +
    +
    + + + WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming + + WulaFallenEmpire.Skyfaller_PrefabSpawner + (44,44) + + Wula/Building/WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming + Graphic_Single + CutoutFlying + (44,44) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (44, 44) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + 2.5 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    +
    + +
  • + Smoke_Joint +
  • +
  • + AncientsHostile +
  • +
    +
    + + + WULA_Bunker_Drop_Zone_Beacon_Cleanzone + + 一个用于呼叫建筑的信标,用于快速建造一个碉堡防御设施。 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Normal + MinifiedThing + + Wula/Building/WULA_Dropping_Building_Cleanzone + Graphic_Multi + (5,5) + + false + + + +
  • BuildingsMisc
  • +
    + false + false + false + false + false + false + BuildingOnTop + PassThroughOnly + 0 + false + false + + 0 + false + Light + + 1 + 0 + 1 + 0 + + (5,5) + 0 + 1 + + + 0 + + 4 + + + BuildingDestroyed_Metal_Small + false + false + + +
  • + WULA_Bunker_Drop_Zone_Prefeb + true + WULA_Bunker_Drop_Zone_Prefeb_Incoming + true + 1 + true + false +
  • +
    +
    + + + WULA_Bunker_Drop_Zone_Prefeb_Incoming + + WulaFallenEmpire.Skyfaller_PrefabSpawner + (5,5) + + Wula/Building/WULA_Bunker_Drop_Zone_Prefeb_Incoming + Graphic_Single + CutoutFlying + (5,5) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (5, 5) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + 2.5 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    +
    + +
  • + Smoke_Joint +
  • +
  • + AncientsHostile +
  • +
    +
    + + + WULA_Turret_Group_Drop_Zone_Beacon_Cleanzone + + 一个用于呼叫建筑的信标,用于快速建造一个炮塔群。 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Normal + MinifiedThing + + Wula/Building/WULA_Dropping_Building_Cleanzone_Plus + Graphic_Multi + (15,15) + + false + + + +
  • BuildingsMisc
  • +
    + false + false + false + false + false + false + BuildingOnTop + PassThroughOnly + 0 + false + false + + 0 + false + Light + + 1 + 0 + 1 + 0 + + (15,15) + 0 + 1 + + + 0 + + 4 + + + BuildingDestroyed_Metal_Small + false + false + + +
  • + WULA_Turret_Group_Drop_Zone_Prefeb + true + WULA_Turret_Group_Drop_Zone_Prefeb_Incoming + true + 1 + true + false +
  • +
    +
    + + + WULA_Turret_Group_Drop_Zone_Prefeb_Incoming + + WulaFallenEmpire.Skyfaller_PrefabSpawner + (15,15) + + Wula/Building/WULA_Turret_Group_Drop_Zone_Prefeb_Incoming + Graphic_Single + CutoutFlying + (15,15) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (15, 15) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + 2.5 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    +
    + +
  • + Smoke_Joint +
  • +
  • + AncientsHostile +
  • +
    +
    + + + WULA_Fortress_Drop_Zone_Beacon_Cleanzone + + 一个用于呼叫建筑的信标,用于快速建造一个要塞。 + Wula/Building/Linked/WULA_Fortress_Wall_MenuIcon + Normal + MinifiedThing + + Wula/Building/WULA_Dropping_Building_Cleanzone_Plus + Graphic_Multi + (25,25) + + false + + + +
  • BuildingsMisc
  • +
    + false + false + false + false + false + false + BuildingOnTop + PassThroughOnly + 0 + false + false + + 0 + false + Light + + 1 + 0 + 1 + 0 + + (25,25) + 0 + 1 + + + 0 + + 4 + + + BuildingDestroyed_Metal_Small + false + false + + +
  • + WULA_Fortress_Drop_Zone_Prefeb + true + WULA_Fortress_Drop_Zone_Prefeb_Incoming + true + 1 + true + false +
  • +
    +
    + + + WULA_Fortress_Drop_Zone_Prefeb_Incoming + + WulaFallenEmpire.Skyfaller_PrefabSpawner + (25,25) + + Wula/Building/WULA_Fortress_Drop_Zone_Prefeb_Incoming + Graphic_Single + CutoutFlying + (25,25) + + + Accelerate + Things/Skyfaller/SkyfallerShadowDropPod + (25, 25) + DropPod_Fall + 100 + Explosion_Vaporize + 0.05 + 1 + 1 + 2.5 + + +
  • (0,0)
  • +
  • (1, 1)
  • +
    +
    +
    + +
  • + Smoke_Joint +
  • +
  • + AncientsHostile +
  • +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml index 43bd2eb1..602158d2 100644 --- a/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml +++ b/1.6/1.6/Defs/ThingDefs_Buildings/WULA_Turret_Buildings.xml @@ -47,7 +47,7 @@ (3,3) 0 - 1 + 0 300 3 @@ -145,7 +145,6 @@ false false - 0 Light 500 @@ -155,11 +154,15 @@ (3,3) - 200 + 60 BuildingDestroyed_Metal_Small 3.5 + false + true + WULA_Cat_Bunker_TurretGun + false
  • @@ -301,7 +304,7 @@ (3,3) 0 - 1 + 0 100 6 @@ -409,7 +412,6 @@ 100 6 - false Normal PassThroughOnly 40 @@ -429,22 +431,34 @@ 3 (-0.04, 0) 5.0 + false
  • PlaceWorker_TurretTop
  • PlaceWorker_ShowTurretRadius
  • + +
  • + EMP + 50 + 2 + true +
  • +
  • + +
  • Stun
  • +
  • EMP
  • + + +
  • EMP
  • +
    +
  • MechanoidsWakeUp
  • -
  • - -
  • EMP
  • - -
  • MechTurretBig_Call
  • @@ -455,7 +469,7 @@
  • CompPowerTrader - 300 + 300
  • 6 @@ -579,7 +593,7 @@ (3,3) 0 - 1 + 0 Light 100 @@ -689,7 +703,6 @@ 100 6 - false Normal PassThroughOnly 40 @@ -708,22 +721,34 @@ 0.01 (-0.04, 0) 5.0 + false
  • PlaceWorker_TurretTop
  • PlaceWorker_ShowTurretRadius
  • + +
  • + EMP + 50 + 2 + true +
  • +
  • + +
  • Stun
  • +
  • EMP
  • + + +
  • EMP
  • +
    +
  • MechanoidsWakeUp
  • -
  • - -
  • EMP
  • - -
  • MechTurretBig_Call
  • @@ -734,7 +759,7 @@
  • CompPowerTrader - 500 + 300
  • 6 @@ -870,7 +895,7 @@ (3,3) 0 - 1 + 0 100 6 @@ -969,7 +994,6 @@ 150 12 - false Normal Impassable true @@ -982,12 +1006,20 @@ 4 (-0.04, 0) 5.0 + false
  • PlaceWorker_TurretTop
  • PlaceWorker_ShowTurretRadius
  • + +
  • + EMP + 500 + 2 + true +
  • @@ -995,8 +1027,12 @@
  • +
  • Stun
  • EMP
  • + +
  • EMP
  • +
  • MechTurretBig_Call @@ -1008,7 +1044,7 @@
  • CompPowerTrader - 200 + 300
  • 6 @@ -1115,7 +1151,6 @@ true 0.20 14 - false BulletImpact_Metal Wula/Building/Flag/WULA_Flag_Building_B_north true diff --git a/1.6/1.6/Defs/ThingDefs_Plants/WULA_Plants.xml b/1.6/1.6/Defs/ThingDefs_Plants/WULA_Plants.xml index 697192fc..1bd871b0 100644 --- a/1.6/1.6/Defs/ThingDefs_Plants/WULA_Plants.xml +++ b/1.6/1.6/Defs/ThingDefs_Plants/WULA_Plants.xml @@ -16,6 +16,9 @@ true 10 + + NeverForNutrition + Wula/Plant/WULA_Plant_Eggplant_Immature 0.5 diff --git a/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml b/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml index 0dab8537..82075289 100644 --- a/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml +++ b/1.6/1.6/Patches/WULA_BaseStoryteller_Patch.xml @@ -26,8 +26,6 @@
  • WULA_Colony_License_LV1_Technology - WULA_GiveQuest_Base_Tex - WULA_Base_Tex_Quest 0 @@ -37,7 +35,11 @@ false false + false Wula_PIA_Legion_Faction + + WULA_GiveQuest_Base_Tex + WULA_GiveQuest_Hostile_PIA_Attack_Quest
  • diff --git a/About/About.xml b/About/About.xml index de95f7ba..be0dec17 100644 --- a/About/About.xml +++ b/About/About.xml @@ -25,6 +25,11 @@ Humanoid Alien Races 2.0 https://steamcommunity.com/sharedfiles/filedetails/?id=839005762 +
  • + HaiLuan.CustomQuestFramework + Custom Quest Framework + https://steamcommunity.com/sharedfiles/filedetails/?id=2978572782 +
  • @@ -32,5 +37,6 @@
  • Ludeon.RimWorld
  • Ludeon.RimWorld.Biotech
  • erdelf.HumanoidAlienRaces
  • +
  • HaiLuan.CustomQuestFramework
  • \ No newline at end of file diff --git a/Content/Textures/Wula/Building/WULA_Bunker_Drop_Zone_Prefeb_Incoming.png b/Content/Textures/Wula/Building/WULA_Bunker_Drop_Zone_Prefeb_Incoming.png new file mode 100644 index 00000000..443dbcb0 Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_Bunker_Drop_Zone_Prefeb_Incoming.png differ diff --git a/Content/Textures/Wula/Building/WULA_Fortress_Drop_Zone_Prefeb_Incoming.png b/Content/Textures/Wula/Building/WULA_Fortress_Drop_Zone_Prefeb_Incoming.png new file mode 100644 index 00000000..6f8a620b Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_Fortress_Drop_Zone_Prefeb_Incoming.png differ diff --git a/Content/Textures/Wula/Building/WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming.png b/Content/Textures/Wula/Building/WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming.png new file mode 100644 index 00000000..b0d26a7d Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_Huge_Fortress_Drop_Zone_Prefeb_Incoming.png differ diff --git a/Content/Textures/Wula/Building/WULA_Turret_Group_Drop_Zone_Prefeb_Incoming.png b/Content/Textures/Wula/Building/WULA_Turret_Group_Drop_Zone_Prefeb_Incoming.png new file mode 100644 index 00000000..156bcb3f Binary files /dev/null and b/Content/Textures/Wula/Building/WULA_Turret_Group_Drop_Zone_Prefeb_Incoming.png differ diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs index 9af5f7c2..f4e662eb 100644 --- a/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_MechanoidRecycler/Building_MechanoidRecycler.cs @@ -359,8 +359,6 @@ namespace WulaFallenEmpire return Mathf.Max(0, remainingTicks / 2500f); } - // 开发模式方法:立即结束冷却 - [DebugAction("机械族回收器", "立即结束冷却", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Playing)] public static void DevEndCooldown() { Building_MechanoidRecycler selectedRecycler = Find.Selector.SingleSelectedThing as Building_MechanoidRecycler; diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompPrefabSkyfallerCaller.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompPrefabSkyfallerCaller.cs index 12ae42b1..e65a7a34 100644 --- a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompPrefabSkyfallerCaller.cs +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompPrefabSkyfallerCaller.cs @@ -2,6 +2,7 @@ using RimWorld; using System.Collections.Generic; using System.Linq; using Verse; +using UnityEngine; namespace WulaFallenEmpire { @@ -75,31 +76,96 @@ namespace WulaFallenEmpire ConsumeMaterials(); - Thing thing = ThingMaker.MakeThing(Props.skyfallerDef); - if (thing is Skyfaller_PrefabSpawner skyfaller) - { - skyfaller.prefabDefName = PropsPrefab.prefabDefName; - GenSpawn.Spawn(skyfaller, parent.Position, parent.Map); - } - else - { - Log.Error($"[PrefabSkyfallerCaller] Failed to create Skyfaller_PrefabSpawner. Created thing is of type {thing.GetType().FullName}. Def: {Props.skyfallerDef.defName}, ThingClass: {Props.skyfallerDef.thingClass.FullName}"); - // Fallback: spawn as normal skyfaller if possible, or just abort - if (thing is Skyfaller normalSkyfaller) - { - GenSpawn.Spawn(normalSkyfaller, parent.Position, parent.Map); - } - } - - if (PropsPrefab.destroyBuilding && !parent.Destroyed) - { - parent.Destroy(DestroyMode.Vanish); - } + SpawnPrefabSkyfaller(); } else { base.ExecuteSkyfallerCall(); } } + + // 新增:重写自动呼叫方法 + protected override void ExecuteAutoSkyfallerCall() + { + if (!string.IsNullOrEmpty(PropsPrefab.prefabDefName)) + { + Log.Message($"[PrefabSkyfallerCaller] Executing auto skyfaller call for prefab at {parent.Position}"); + + // 非玩家派系自动呼叫不需要资源检查 + HandleRoofDestruction(); + + SpawnPrefabSkyfaller(); + + ResetCall(); + autoCallScheduled = false; + } + else + { + base.ExecuteAutoSkyfallerCall(); + } + } + + // 新增:统一的 Prefab Skyfaller 生成方法 + private void SpawnPrefabSkyfaller() + { + Thing thing = ThingMaker.MakeThing(Props.skyfallerDef); + if (thing is Skyfaller_PrefabSpawner skyfaller) + { + skyfaller.prefabDefName = PropsPrefab.prefabDefName; + Log.Message($"[PrefabSkyfallerCaller] Setting prefabDefName to: {PropsPrefab.prefabDefName}"); + GenSpawn.Spawn(skyfaller, parent.Position, parent.Map); + } + else + { + Log.Error($"[PrefabSkyfallerCaller] Failed to create Skyfaller_PrefabSpawner. Created thing is of type {thing.GetType().FullName}. Def: {Props.skyfallerDef.defName}, ThingClass: {Props.skyfallerDef.thingClass.FullName}"); + // Fallback: spawn as normal skyfaller if possible, or just abort + if (thing is Skyfaller normalSkyfaller) + { + GenSpawn.Spawn(normalSkyfaller, parent.Position, parent.Map); + } + } + + if (PropsPrefab.destroyBuilding && !parent.Destroyed) + { + parent.Destroy(DestroyMode.Vanish); + } + } + + // 新增:重写屋顶处理方法以确保日志输出 + private void HandleRoofDestruction() + { + if (parent?.Map == null) return; + + IntVec3 targetPos = parent.Position; + RoofDef roof = targetPos.GetRoof(parent.Map); + + if (roof != null && !roof.isThickRoof && Props.allowThinRoof) + { + Log.Message($"[PrefabSkyfallerCaller] Destroying thin roof at {targetPos}"); + parent.Map.roofGrid.SetRoof(targetPos, null); + + // 生成屋顶破坏效果 + FleckMaker.ThrowDustPuffThick(targetPos.ToVector3Shifted(), parent.Map, 2f, new Color(1f, 1f, 1f, 2f)); + } + } + + // 新增:调试信息 + public override string CompInspectStringExtra() + { + var baseString = base.CompInspectStringExtra(); + + if (!string.IsNullOrEmpty(PropsPrefab.prefabDefName)) + { + var sb = new System.Text.StringBuilder(); + if (!string.IsNullOrEmpty(baseString)) + { + sb.AppendLine(baseString); + } + sb.Append($"Prefab: {PropsPrefab.prefabDefName}"); + return sb.ToString(); + } + + return baseString; + } } -} \ No newline at end of file +} diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompProperties_SkyfallerCaller.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompProperties_SkyfallerCaller.cs index 04d985e5..d320be2b 100644 --- a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompProperties_SkyfallerCaller.cs +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompProperties_SkyfallerCaller.cs @@ -10,7 +10,7 @@ namespace WulaFallenEmpire public int delayTicks = 0; public bool canAutoCall = true; // 默认启用自动召唤 - public int autoCallDelayTicks = 600; // 默认10秒 + public int autoCallDelayTicks = 1; // 默认10秒 // 新增:是否需要 FlyOver 作为前提条件 public bool requireFlyOver = false; // 默认不需要 FlyOver diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompSkyfallerCaller.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompSkyfallerCaller.cs index d94ef747..d0dac7b0 100644 --- a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompSkyfallerCaller.cs +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/CompSkyfallerCaller.cs @@ -41,10 +41,17 @@ namespace WulaFallenEmpire private bool used = false; private int callTick = -1; private bool calling = false; - private bool usedGlobalStorage = false; // 新增:标记是否使用了全局储存器 + private bool usedGlobalStorage = false; + public bool autoCallScheduled = false; // 新增:标记是否已安排自动呼叫 public bool CanCall => !used && !calling; + // 新增:检查建筑是否属于非玩家派系 + public bool IsNonPlayerFaction => parent.Faction != null && parent.Faction != Faction.OfPlayer; + + // 新增:检查是否应该自动呼叫 + private bool ShouldAutoCall => IsNonPlayerFaction && Props.canAutoCall && !autoCallScheduled && !used; + // 固定的显示标签 public string RequiredFlyOverLabel => "建筑空投飞行器"; @@ -127,6 +134,22 @@ namespace WulaFallenEmpire public bool CanCallSkyfaller => CanCall && HasRequiredFlyOver && CheckRoofConditions; + // 新增:在建筑生成时检查是否需要自动呼叫 + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + + if (!respawningAfterLoad && ShouldAutoCall) + { + // 安排自动呼叫 + autoCallScheduled = true; + callTick = Find.TickManager.TicksGame + Props.autoCallDelayTicks; + calling = true; + + Log.Message($"[SkyfallerCaller] Scheduled auto-call for non-player building {parent.Label} at tick {callTick}"); + } + } + public override void PostExposeData() { base.PostExposeData(); @@ -134,23 +157,95 @@ namespace WulaFallenEmpire Scribe_Values.Look(ref callTick, "callTick", -1); Scribe_Values.Look(ref calling, "calling", false); Scribe_Values.Look(ref usedGlobalStorage, "usedGlobalStorage", false); + Scribe_Values.Look(ref autoCallScheduled, "autoCallScheduled", false); } public override void CompTick() { base.CompTick(); + + // 处理自动呼叫 if (calling && callTick >= 0 && Find.TickManager.TicksGame >= callTick) { - ExecuteSkyfallerCall(); + if (autoCallScheduled) + { + // 执行自动呼叫 + ExecuteAutoSkyfallerCall(); + } + else + { + // 执行手动呼叫 + ExecuteSkyfallerCall(); + } + } + } + + // 新增:自动呼叫方法(非玩家派系专用) + protected virtual void ExecuteAutoSkyfallerCall() + { + try + { + Log.Message($"[SkyfallerCaller] Executing auto skyfaller call for non-player building at {parent.Position}"); + + if (Props.skyfallerDef == null) + { + Log.Error("[SkyfallerCaller] Skyfaller def is null!"); + ResetCall(); + return; + } + + // 非玩家派系自动呼叫不需要资源检查 + // 直接处理屋顶 + HandleRoofDestruction(); + + // 创建Skyfaller + Skyfaller skyfaller = SkyfallerMaker.MakeSkyfaller(Props.skyfallerDef); + if (skyfaller == null) + { + Log.Error("[SkyfallerCaller] Failed to create skyfaller!"); + ResetCall(); + return; + } + + IntVec3 spawnPos = parent.Position; + Log.Message($"[SkyfallerCaller] Spawning auto skyfaller at {spawnPos}"); + + GenSpawn.Spawn(skyfaller, spawnPos, parent.Map); + + if (Props.destroyBuilding) + { + Log.Message($"[SkyfallerCaller] Destroying non-player building {parent.Label}"); + parent.Destroy(DestroyMode.Vanish); + } + + // 重置状态 + ResetCall(); + autoCallScheduled = false; + + // 显示自动呼叫消息 + Messages.Message("WULA_AutoSkyfallerCalled".Translate(parent.Faction.Name), + MessageTypeDefOf.NeutralEvent); + } + catch (System.Exception ex) + { + Log.Error($"[SkyfallerCaller] Error in ExecuteAutoSkyfallerCall: {ex}"); + ResetCall(); } } public void CallSkyfaller(bool isAutoCall = false) { + // 新增:非玩家派系不能手动呼叫 + if (IsNonPlayerFaction && !isAutoCall) + { + Messages.Message("WULA_NonPlayerCannotCall".Translate(), parent, MessageTypeDefOf.RejectInput); + return; + } + if (!CanCallSkyfaller) { // 显示相应的错误消息 - if (!HasRequiredFlyOver && Props.requireFlyOver) // 只在需要 FlyOver 时才显示此消息 + if (!HasRequiredFlyOver && Props.requireFlyOver) { Messages.Message("WULA_NoBuildingDropperFlyOver".Translate(), parent, MessageTypeDefOf.RejectInput); } @@ -195,6 +290,7 @@ namespace WulaFallenEmpire used = false; callTick = -1; usedGlobalStorage = false; + autoCallScheduled = false; } protected virtual void ExecuteSkyfallerCall() @@ -599,6 +695,7 @@ namespace WulaFallenEmpire used = false; callTick = -1; usedGlobalStorage = false; + autoCallScheduled = false; Messages.Message("WULA_SkyfallerCallCancelled".Translate(), parent, MessageTypeDefOf.NeutralEvent); } @@ -607,6 +704,10 @@ namespace WulaFallenEmpire foreach (var gizmo in base.CompGetGizmosExtra()) yield return gizmo; + // 新增:非玩家派系不显示呼叫按钮 + if (IsNonPlayerFaction) + yield break; + if (calling) { Command_Action cancelCommand = new Command_Action @@ -679,6 +780,12 @@ namespace WulaFallenEmpire private string GetDisabledReason() { + // 新增:非玩家派系不能手动呼叫 + if (IsNonPlayerFaction) + { + return "WULA_NonPlayerCannotCall".Translate(); + } + // 只在需要 FlyOver 时检查并显示相关原因 if (Props.requireFlyOver && !HasRequiredFlyOver) { @@ -719,7 +826,12 @@ namespace WulaFallenEmpire var sb = new System.Text.StringBuilder(); - if (calling) + // 新增:显示自动呼叫状态 + if (autoCallScheduled && calling) + { + int ticksLeft = callTick - Find.TickManager.TicksGame; + } + else if (calling) { int ticksLeft = callTick - Find.TickManager.TicksGame; if (ticksLeft > 0) @@ -732,7 +844,15 @@ namespace WulaFallenEmpire } else if (!used) { - sb.Append("WULA_ReadyToCallSkyfaller".Translate()); + // 新增:显示非玩家派系自动呼叫信息 + if (IsNonPlayerFaction && Props.canAutoCall) + { + sb.Append("WULA_AutoSkyfallerReady".Translate()); + } + else + { + sb.Append("WULA_ReadyToCallSkyfaller".Translate()); + } if (Props.requireFlyOver && !HasRequiredFlyOver) { diff --git a/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/DebugActions_PrefabSkyfallerCaller.cs b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/DebugActions_PrefabSkyfallerCaller.cs new file mode 100644 index 00000000..6d7fed40 --- /dev/null +++ b/Source/WulaFallenEmpire/BuildingComp/WULA_SkyfallerCaller/DebugActions_PrefabSkyfallerCaller.cs @@ -0,0 +1,428 @@ +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using UnityEngine; +using Verse; +using LudeonTK; + +namespace WulaFallenEmpire +{ + public class DebugActions_PrefabSkyfallerCaller + { + [DebugAction("Wula Fallen Empire", "Spawn Prefab Skyfaller Caller (Single)", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Playing)] + public static void SpawnPrefabSkyfallerCallerSingle() + { + var eligibleDefs = DefDatabase.AllDefs + .Where(def => def.comps != null && def.comps.Any(comp => comp is CompProperties_PrefabSkyfallerCaller)) + .ToList(); + + if (!eligibleDefs.Any()) + { + Log.Warning("[Debug] No ThingDefs found with CompProperties_PrefabSkyfallerCaller"); + return; + } + + var options = new List(); + foreach (var thingDef in eligibleDefs) + { + options.Add(new DebugMenuOption(thingDef.defName, DebugMenuOptionMode.Tool, () => + { + ShowFactionSelectionMenu(thingDef, false); + })); + } + + Find.WindowStack.Add(new Dialog_DebugOptionListLister(options)); + } + + [DebugAction("Wula Fallen Empire", "Spawn Prefab Skyfaller Caller (x10)", actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Playing)] + public static void SpawnPrefabSkyfallerCallerMultiple() + { + var eligibleDefs = DefDatabase.AllDefs + .Where(def => def.comps != null && def.comps.Any(comp => comp is CompProperties_PrefabSkyfallerCaller)) + .ToList(); + + if (!eligibleDefs.Any()) + { + Log.Warning("[Debug] No ThingDefs found with CompProperties_PrefabSkyfallerCaller"); + return; + } + + var options = new List(); + foreach (var thingDef in eligibleDefs) + { + options.Add(new DebugMenuOption(thingDef.defName, DebugMenuOptionMode.Tool, () => + { + ShowFactionSelectionMenu(thingDef, true); + })); + } + + Find.WindowStack.Add(new Dialog_DebugOptionListLister(options)); + } + + private static void ShowFactionSelectionMenu(ThingDef thingDef, bool spawnMultiple) + { + var allFactions = Find.FactionManager.AllFactions.ToList(); + var options = new List(); + + options.Add(new DebugMenuOption("No Faction", DebugMenuOptionMode.Tool, () => + { + SpawnThingAtValidLocation(thingDef, null, spawnMultiple); + })); + + foreach (var faction in allFactions) + { + options.Add(new DebugMenuOption(faction.Name, DebugMenuOptionMode.Tool, () => + { + SpawnThingAtValidLocation(thingDef, faction, spawnMultiple); + })); + } + + Find.WindowStack.Add(new Dialog_DebugOptionListLister(options)); + } + + private static void SpawnThingAtValidLocation(ThingDef thingDef, Faction faction, bool spawnMultiple) + { + var currentMap = Find.CurrentMap; + if (currentMap == null) + { + Log.Warning("[Debug] No current map found"); + return; + } + + int spawnCount = spawnMultiple ? 10 : 1; + int successCount = 0; + int attempts = 0; + const int maxAttempts = 50; + + var compProps = thingDef.comps.OfType().FirstOrDefault(); + if (compProps == null) + { + Log.Warning($"[Debug] Could not find CompProperties_PrefabSkyfallerCaller for {thingDef.defName}"); + return; + } + + Log.Message($"[Debug] Looking for spawn positions for {thingDef.defName} (Size: {thingDef.Size})"); + + for (int i = 0; i < spawnCount && attempts < maxAttempts; i++) + { + attempts++; + IntVec3 spawnPos = FindSpawnPositionForSkyfaller(currentMap, thingDef, compProps); + + if (spawnPos.IsValid) + { + Thing thing = ThingMaker.MakeThing(thingDef); + + if (faction != null) + { + thing.SetFaction(faction); + } + + GenSpawn.Spawn(thing, spawnPos, currentMap); + + successCount++; + Log.Message($"[Debug] Successfully spawned {thingDef.defName} at {spawnPos} for faction {faction?.Name ?? "None"}"); + } + else + { + Log.Warning($"[Debug] Failed to find valid spawn position for {thingDef.defName} (attempt {attempts})"); + } + } + + if (successCount > 0) + { + Messages.Message($"[Debug] Successfully spawned {successCount} {thingDef.defName}", MessageTypeDefOf.PositiveEvent); + } + else + { + Messages.Message($"[Debug] Failed to spawn any {thingDef.defName} after {attempts} attempts", MessageTypeDefOf.NegativeEvent); + } + } + + private static IntVec3 FindSpawnPositionForSkyfaller(Map map, ThingDef thingDef, CompProperties_SkyfallerCaller compProps) + { + // 基于Skyfaller实际行为的查找逻辑 + var potentialCells = new List(); + + // 策略1:首先尝试玩家基地附近的开放区域 + Log.Message($"[Debug] Searching near base area..."); + var baseCells = GetOpenAreaCellsNearBase(map, thingDef.Size); + foreach (var cell in baseCells) + { + if (IsValidForSkyfallerDrop(map, cell, thingDef, compProps)) + { + potentialCells.Add(cell); + } + if (potentialCells.Count > 20) break; // 找到足够位置就停止 + } + + if (potentialCells.Count > 0) + { + Log.Message($"[Debug] Found {potentialCells.Count} positions near base"); + return potentialCells.RandomElement(); + } + + // 策略2:搜索整个地图的开阔区域 + Log.Message($"[Debug] Searching open areas..."); + var openAreas = FindOpenAreas(map, thingDef.Size, 1000); + foreach (var cell in openAreas) + { + if (IsValidForSkyfallerDrop(map, cell, thingDef, compProps)) + { + potentialCells.Add(cell); + } + if (potentialCells.Count > 10) break; + } + + if (potentialCells.Count > 0) + { + Log.Message($"[Debug] Found {potentialCells.Count} positions in open areas"); + return potentialCells.RandomElement(); + } + + // 策略3:使用随机采样 + Log.Message($"[Debug] Trying random sampling..."); + for (int i = 0; i < 500; i++) + { + IntVec3 randomCell = new IntVec3( + Rand.Range(thingDef.Size.x, map.Size.x - thingDef.Size.x), + 0, + Rand.Range(thingDef.Size.z, map.Size.z - thingDef.Size.z) + ); + + if (randomCell.InBounds(map) && IsValidForSkyfallerDrop(map, randomCell, thingDef, compProps)) + { + potentialCells.Add(randomCell); + } + if (potentialCells.Count > 5) break; + } + + if (potentialCells.Count > 0) + { + Log.Message($"[Debug] Found {potentialCells.Count} positions via random sampling"); + return potentialCells.RandomElement(); + } + + Log.Warning($"[Debug] No valid positions found for {thingDef.defName}"); + return IntVec3.Invalid; + } + + /// + /// 基于Skyfaller实际行为的有效性检查 + /// + private static bool IsValidForSkyfallerDrop(Map map, IntVec3 cell, ThingDef thingDef, CompProperties_SkyfallerCaller compProps) + { + // 1. 检查边界 + if (!cell.InBounds(map)) + return false; + + // 2. 检查整个建筑区域 + CellRect occupiedRect = GenAdj.OccupiedRect(cell, Rot4.North, thingDef.Size); + + foreach (IntVec3 occupiedCell in occupiedRect) + { + if (!occupiedCell.InBounds(map)) + return false; + + // 3. 检查厚岩顶 - 绝对不允许 + RoofDef roof = occupiedCell.GetRoof(map); + if (roof != null && roof.isThickRoof) + { + if (!compProps.allowThickRoof) + return false; + } + + // 4. 检查水体 - 不允许 + TerrainDef terrain = occupiedCell.GetTerrain(map); + if (terrain != null && terrain.IsWater) + return false; + + // 5. 检查建筑 - 不允许(但自然物体如树、石头是允许的) + var things = map.thingGrid.ThingsListAtFast(occupiedCell); + foreach (var thing in things) + { + // 允许自然物体(树、石头等),它们会被空投清除 + if (thing.def.category == ThingCategory.Plant || + thing.def.category == ThingCategory.Item || + thing.def.category == ThingCategory.Filth) + { + continue; // 这些是可以被清除的 + } + + // 不允许建筑、蓝图、框架等 + if (thing.def.category == ThingCategory.Building || + thing.def.IsBlueprint || + thing.def.IsFrame) + { + return false; + } + + // 不允许其他不可清除的物体 + if (thing.def.passability == Traversability.Impassable && + thing.def.category != ThingCategory.Plant) // 植物是可清除的 + { + return false; + } + } + + // 6. 检查薄岩顶和普通屋顶的条件 + if (roof != null && !roof.isThickRoof) + { + if (!compProps.allowThinRoof) + return false; + } + } + + return true; + } + + /// + /// 获取基地附近的开阔区域 + /// + private static IEnumerable GetOpenAreaCellsNearBase(Map map, IntVec2 size) + { + var homeArea = map.areaManager.Home; + IntVec3 searchCenter; + + if (homeArea != null && homeArea.ActiveCells.Any()) + { + searchCenter = homeArea.ActiveCells.First(); + } + else + { + searchCenter = new IntVec3(map.Size.x / 2, 0, map.Size.z / 2); + } + + // 在基地周围搜索开阔区域 + int searchRadius = 50; + var searchArea = CellRect.CenteredOn(searchCenter, searchRadius); + + // 返回该区域内所有可能的中心点 + foreach (var cell in searchArea.Cells) + { + if (!cell.InBounds(map)) continue; + + // 检查这个位置周围是否有足够的开阔空间 + if (IsAreaMostlyOpen(map, cell, size, 0.8f)) // 80%的区域需要是开阔的 + { + yield return cell; + } + } + } + + /// + /// 查找地图上的开阔区域 + /// + private static IEnumerable FindOpenAreas(Map map, IntVec2 size, int maxCellsToCheck) + { + int cellsChecked = 0; + + // 优先检查地图上已知的开阔区域 + var allCells = map.AllCells.Where(c => c.InBounds(map)).ToList(); + + foreach (var cell in allCells) + { + if (cellsChecked >= maxCellsToCheck) yield break; + cellsChecked++; + + // 快速检查:如果这个单元格本身就不适合,跳过 + if (!cell.InBounds(map) || cell.GetTerrain(map).IsWater) + continue; + + // 检查整个区域是否开阔 + if (IsAreaMostlyOpen(map, cell, size, 0.7f)) // 70%的区域需要是开阔的 + { + yield return cell; + } + } + } + + /// + /// 检查区域是否大部分是开阔的(没有建筑,允许自然物体) + /// + private static bool IsAreaMostlyOpen(Map map, IntVec3 center, IntVec2 size, float openThreshold) + { + CellRect area = GenAdj.OccupiedRect(center, Rot4.North, size); + int totalCells = area.Area; + int openCells = 0; + + foreach (IntVec3 cell in area) + { + if (!cell.InBounds(map)) + { + continue; // 边界外的单元格不计入 + } + + // 检查是否有不可清除的建筑 + bool hasBlockingBuilding = false; + var things = map.thingGrid.ThingsListAtFast(cell); + foreach (var thing in things) + { + if (thing.def.category == ThingCategory.Building || + thing.def.IsBlueprint || + thing.def.IsFrame || + (thing.def.passability == Traversability.Impassable && + thing.def.category != ThingCategory.Plant)) + { + hasBlockingBuilding = true; + break; + } + } + + // 检查水体 + bool isWater = cell.GetTerrain(map).IsWater; + + if (!hasBlockingBuilding && !isWater) + { + openCells++; + } + } + + float openRatio = (float)openCells / totalCells; + return openRatio >= openThreshold; + } + + /// + /// 强制清除区域(作为最后手段) + /// + private static bool TryForceClearAreaForSkyfaller(Map map, IntVec3 center, IntVec2 size) + { + try + { + CellRect clearRect = GenAdj.OccupiedRect(center, Rot4.North, size); + int clearedCount = 0; + + foreach (IntVec3 cell in clearRect) + { + if (!cell.InBounds(map)) continue; + + // 清除植物和物品 + var thingsToRemove = map.thingGrid.ThingsAt(cell) + .Where(thing => thing.def.category == ThingCategory.Plant || + thing.def.category == ThingCategory.Item || + thing.def.category == ThingCategory.Filth) + .ToList(); + + foreach (var thing in thingsToRemove) + { + thing.Destroy(); + clearedCount++; + } + + // 确保不是水体 + if (cell.GetTerrain(map).IsWater) + { + map.terrainGrid.SetTerrain(cell, TerrainDefOf.Soil); + } + } + + Log.Message($"[Debug] Force cleared {clearedCount} objects for skyfaller drop"); + return clearedCount > 0; + } + catch (System.Exception ex) + { + Log.Error($"[Debug] Error force clearing area: {ex}"); + return false; + } + } + } +} diff --git a/Source/WulaFallenEmpire/QuestNodes/QuestNode_SpawnPrefabSkyfallerCaller.cs b/Source/WulaFallenEmpire/QuestNodes/QuestNode_SpawnPrefabSkyfallerCaller.cs new file mode 100644 index 00000000..77e696a4 --- /dev/null +++ b/Source/WulaFallenEmpire/QuestNodes/QuestNode_SpawnPrefabSkyfallerCaller.cs @@ -0,0 +1,382 @@ +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using RimWorld.Planet; +using UnityEngine; +using Verse; +using RimWorld.QuestGen; + +namespace WulaFallenEmpire +{ + public class QuestNode_SpawnPrefabSkyfallerCaller : QuestNode + { + [NoTranslate] + public SlateRef inSignal; + public SlateRef thingDef; + public SlateRef faction; + public SlateRef spawnCount = 1; + public SlateRef map; + public SlateRef sendMessageOnSuccess = true; + public SlateRef sendMessageOnFailure = true; + + protected override bool TestRunInt(Slate slate) + { + // 在测试运行中只检查基本条件 + if (thingDef.GetValue(slate) == null) + { + Log.Warning("[QuestNode] ThingDef is null in TestRun"); + return false; + } + + var mapValue = map.GetValue(slate) ?? Find.CurrentMap; + if (mapValue == null) + { + Log.Warning("[QuestNode] Map is null in TestRun"); + return false; + } + + var compProps = thingDef.GetValue(slate).comps?.OfType().FirstOrDefault(); + if (compProps == null) + { + Log.Warning($"[QuestNode] ThingDef {thingDef.GetValue(slate).defName} does not have CompProperties_PrefabSkyfallerCaller"); + return false; + } + + return true; + } + + protected override void RunInt() + { + Slate slate = QuestGen.slate; + + // 获取参数值 + ThingDef targetThingDef = thingDef.GetValue(slate); + Faction targetFaction = faction.GetValue(slate); + int targetSpawnCount = spawnCount.GetValue(slate); + Map targetMap = map.GetValue(slate) ?? Find.CurrentMap; + bool doSendMessageOnSuccess = sendMessageOnSuccess.GetValue(slate); + bool doSendMessageOnFailure = sendMessageOnFailure.GetValue(slate); + + if (targetThingDef == null) + { + Log.Error("[QuestNode] ThingDef is null in RunInt"); + return; + } + + if (targetMap == null) + { + Log.Error("[QuestNode] Map is null in RunInt"); + return; + } + + // 获取组件属性 + var compProps = targetThingDef.comps?.OfType().FirstOrDefault(); + if (compProps == null) + { + Log.Error($"[QuestNode] ThingDef {targetThingDef.defName} does not have CompProperties_PrefabSkyfallerCaller"); + return; + } + + Log.Message($"[QuestNode] Attempting to spawn {targetSpawnCount} {targetThingDef.defName} on map {targetMap}"); + + // 执行生成 + int successCount = SpawnThingsAtValidLocations(targetThingDef, targetFaction, targetSpawnCount, targetMap); + + // 发送结果消息 + if (successCount > 0) + { + if (doSendMessageOnSuccess) + { + Messages.Message($"[Quest] Successfully spawned {successCount} {targetThingDef.label}", MessageTypeDefOf.PositiveEvent); + } + Log.Message($"[QuestNode] Successfully spawned {successCount}/{targetSpawnCount} {targetThingDef.defName}"); + } + else + { + if (doSendMessageOnFailure) + { + Messages.Message($"[Quest] Failed to spawn any {targetThingDef.label}", MessageTypeDefOf.NegativeEvent); + } + Log.Warning($"[QuestNode] Failed to spawn any {targetThingDef.defName}"); + } + + // 将结果存储到Slate中,供后续节点使用 + QuestGen.slate.Set("prefabSpawnSuccessCount", successCount); + QuestGen.slate.Set("prefabSpawnRequestedCount", targetSpawnCount); + } + + /// + /// 在有效位置生成多个建筑 + /// + private int SpawnThingsAtValidLocations(ThingDef thingDef, Faction faction, int spawnCount, Map targetMap) + { + int successCount = 0; + int attempts = 0; + const int maxAttempts = 100; // 最大尝试次数 + + var compProps = thingDef.comps.OfType().FirstOrDefault(); + if (compProps == null) + { + Log.Error($"[QuestNode] Could not find CompProperties_PrefabSkyfallerCaller for {thingDef.defName}"); + return 0; + } + + for (int i = 0; i < spawnCount && attempts < maxAttempts; i++) + { + attempts++; + IntVec3 spawnPos = FindSpawnPositionForSkyfaller(targetMap, thingDef, compProps); + + if (spawnPos.IsValid) + { + Thing thing = ThingMaker.MakeThing(thingDef); + + if (faction != null) + { + thing.SetFaction(faction); + } + + GenSpawn.Spawn(thing, spawnPos, targetMap); + successCount++; + + Log.Message($"[QuestNode] Successfully spawned {thingDef.defName} at {spawnPos} for faction {faction?.Name ?? "None"}"); + } + else + { + Log.Warning($"[QuestNode] Failed to find valid spawn position for {thingDef.defName} (attempt {attempts})"); + } + } + + return successCount; + } + + /// + /// 查找适合Skyfaller空投的位置 + /// + private IntVec3 FindSpawnPositionForSkyfaller(Map map, ThingDef thingDef, CompProperties_SkyfallerCaller compProps) + { + var potentialCells = new List(); + + // 策略1:首先尝试玩家基地附近的开放区域 + var baseCells = GetOpenAreaCellsNearBase(map, thingDef.Size); + foreach (var cell in baseCells) + { + if (IsValidForSkyfallerDrop(map, cell, thingDef, compProps)) + { + potentialCells.Add(cell); + } + if (potentialCells.Count > 20) break; + } + + if (potentialCells.Count > 0) + { + return potentialCells.RandomElement(); + } + + // 策略2:搜索整个地图的开阔区域 + var openAreas = FindOpenAreas(map, thingDef.Size, 500); + foreach (var cell in openAreas) + { + if (IsValidForSkyfallerDrop(map, cell, thingDef, compProps)) + { + potentialCells.Add(cell); + } + if (potentialCells.Count > 10) break; + } + + if (potentialCells.Count > 0) + { + return potentialCells.RandomElement(); + } + + // 策略3:使用随机采样 + for (int i = 0; i < 300; i++) + { + IntVec3 randomCell = new IntVec3( + Rand.Range(thingDef.Size.x, map.Size.x - thingDef.Size.x), + 0, + Rand.Range(thingDef.Size.z, map.Size.z - thingDef.Size.z) + ); + + if (randomCell.InBounds(map) && IsValidForSkyfallerDrop(map, randomCell, thingDef, compProps)) + { + potentialCells.Add(randomCell); + } + if (potentialCells.Count > 5) break; + } + + if (potentialCells.Count > 0) + { + return potentialCells.RandomElement(); + } + + Log.Warning($"[QuestNode] No valid positions found for {thingDef.defName} after exhaustive search"); + return IntVec3.Invalid; + } + + /// + /// 基于Skyfaller实际行为的有效性检查 + /// + private bool IsValidForSkyfallerDrop(Map map, IntVec3 cell, ThingDef thingDef, CompProperties_SkyfallerCaller compProps) + { + // 1. 检查边界 + if (!cell.InBounds(map)) + return false; + + // 2. 检查整个建筑区域 + CellRect occupiedRect = GenAdj.OccupiedRect(cell, Rot4.North, thingDef.Size); + + foreach (IntVec3 occupiedCell in occupiedRect) + { + if (!occupiedCell.InBounds(map)) + return false; + + // 3. 检查厚岩顶 - 绝对不允许 + RoofDef roof = occupiedCell.GetRoof(map); + if (roof != null && roof.isThickRoof) + { + if (!compProps.allowThickRoof) + return false; + } + + // 4. 检查水体 - 不允许 + TerrainDef terrain = occupiedCell.GetTerrain(map); + if (terrain != null && terrain.IsWater) + return false; + + // 5. 检查建筑 - 不允许(但自然物体如树、石头是允许的) + var things = map.thingGrid.ThingsListAtFast(occupiedCell); + foreach (var thing in things) + { + // 允许自然物体(树、石头等),它们会被空投清除 + if (thing.def.category == ThingCategory.Plant || + thing.def.category == ThingCategory.Item || + thing.def.category == ThingCategory.Filth) + { + continue; + } + + // 不允许建筑、蓝图、框架等 + if (thing.def.category == ThingCategory.Building || + thing.def.IsBlueprint || + thing.def.IsFrame) + { + return false; + } + + // 不允许其他不可清除的物体 + if (thing.def.passability == Traversability.Impassable && + thing.def.category != ThingCategory.Plant) + { + return false; + } + } + + // 6. 检查薄岩顶和普通屋顶的条件 + if (roof != null && !roof.isThickRoof) + { + if (!compProps.allowThinRoof) + return false; + } + } + + return true; + } + + /// + /// 获取基地附近的开阔区域 + /// + private IEnumerable GetOpenAreaCellsNearBase(Map map, IntVec2 size) + { + var homeArea = map.areaManager.Home; + IntVec3 searchCenter; + + if (homeArea != null && homeArea.ActiveCells.Any()) + { + searchCenter = homeArea.ActiveCells.First(); + } + else + { + searchCenter = new IntVec3(map.Size.x / 2, 0, map.Size.z / 2); + } + + int searchRadius = 50; + var searchArea = CellRect.CenteredOn(searchCenter, searchRadius); + + foreach (var cell in searchArea.Cells) + { + if (!cell.InBounds(map)) continue; + + if (IsAreaMostlyOpen(map, cell, size, 0.8f)) + { + yield return cell; + } + } + } + + /// + /// 查找地图上的开阔区域 + /// + private IEnumerable FindOpenAreas(Map map, IntVec2 size, int maxCellsToCheck) + { + int cellsChecked = 0; + var allCells = map.AllCells.Where(c => c.InBounds(map)).ToList(); + + foreach (var cell in allCells) + { + if (cellsChecked >= maxCellsToCheck) yield break; + cellsChecked++; + + if (!cell.InBounds(map) || cell.GetTerrain(map).IsWater) + continue; + + if (IsAreaMostlyOpen(map, cell, size, 0.7f)) + { + yield return cell; + } + } + } + + /// + /// 检查区域是否大部分是开阔的 + /// + private bool IsAreaMostlyOpen(Map map, IntVec3 center, IntVec2 size, float openThreshold) + { + CellRect area = GenAdj.OccupiedRect(center, Rot4.North, size); + int totalCells = area.Area; + int openCells = 0; + + foreach (IntVec3 cell in area) + { + if (!cell.InBounds(map)) + { + continue; + } + + bool hasBlockingBuilding = false; + var things = map.thingGrid.ThingsListAtFast(cell); + foreach (var thing in things) + { + if (thing.def.category == ThingCategory.Building || + thing.def.IsBlueprint || + thing.def.IsFrame || + (thing.def.passability == Traversability.Impassable && + thing.def.category != ThingCategory.Plant)) + { + hasBlockingBuilding = true; + break; + } + } + + bool isWater = cell.GetTerrain(map).IsWater; + + if (!hasBlockingBuilding && !isWater) + { + openCells++; + } + } + + float openRatio = (float)openCells / totalCells; + return openRatio >= openThreshold; + } + } +} diff --git a/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerCompProperties_SimpleTechnologyTrigger.cs b/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerCompProperties_SimpleTechnologyTrigger.cs index e4e880d9..e3080927 100644 --- a/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerCompProperties_SimpleTechnologyTrigger.cs +++ b/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerCompProperties_SimpleTechnologyTrigger.cs @@ -18,10 +18,13 @@ namespace WulaFallenEmpire public QuestScriptDef questDef; // 关联的任务定义(可选) public bool preventDuplicateQuests = true; // 防止重复任务 - // 派系关系校验 - 新增字段 + // 派系关系校验 public FactionDef requiredFaction; // 必须存在的派系 public bool requireNonHostileRelation = true; // 是否要求非敌对关系(默认true) public bool requireFactionExists = true; // 是否要求派系必须存在(默认true) + + // 敌对情况下的替代事件 - 新增字段 + public IncidentDef incidentIfHostile; // 当派系敌对且requireNonHostileRelation为false时触发的事件 // 调试配置 public bool debugLogging = false; // 启用调试日志 diff --git a/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerComp_SimpleTechnologyTrigger.cs b/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerComp_SimpleTechnologyTrigger.cs index fca17fde..839fbf53 100644 --- a/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerComp_SimpleTechnologyTrigger.cs +++ b/Source/WulaFallenEmpire/Storyteller/WULA_SimpleTechnologyTrigger/StorytellerComp_SimpleTechnologyTrigger.cs @@ -12,7 +12,6 @@ namespace WulaFallenEmpire private StorytellerCompProperties_SimpleTechnologyTrigger SimpleProps => (StorytellerCompProperties_SimpleTechnologyTrigger)props; - // 重新实现基类的私有属性 private static int IntervalsPassed => Find.TickManager.TicksGame / 1000; public override IEnumerable MakeIntervalIncidents(IIncidentTarget target) @@ -25,8 +24,13 @@ namespace WulaFallenEmpire if (!PassesIntervalCheck()) yield break; - // 检查派系关系条件 - 新增检查 - if (!PassesRequiredFactionCheck()) + // 检查派系关系条件 + var factionCheckResult = PassesRequiredFactionCheck(); + + // 根据派系关系结果决定触发哪个事件 + IncidentDef incidentToTrigger = GetIncidentBasedOnFactionRelation(factionCheckResult); + + if (incidentToTrigger == null) yield break; // 检查派系过滤条件 @@ -38,30 +42,59 @@ namespace WulaFallenEmpire yield break; // 检查是否防止重复任务 - if (SimpleProps.preventDuplicateQuests && HasActiveQuest()) + if (SimpleProps.preventDuplicateQuests && HasActiveQuest(incidentToTrigger)) yield break; // 触发事件 - IncidentDef techIncident = SimpleProps.incident; - if (techIncident.TargetAllowed(target)) + if (incidentToTrigger.TargetAllowed(target)) { if (SimpleProps.debugLogging) { - Log.Message($"[SimpleTechnologyTrigger] Triggering incident {techIncident.defName} for technology {SimpleProps.technology.defName}"); + Log.Message($"[SimpleTechnologyTrigger] Triggering incident {incidentToTrigger.defName} for technology {SimpleProps.technology.defName}"); + Log.Message($"[SimpleTechnologyTrigger] Faction relation status: {factionCheckResult}"); } - yield return new FiringIncident(techIncident, this, GenerateParms(techIncident.category, target)); + yield return new FiringIncident(incidentToTrigger, this, GenerateParms(incidentToTrigger.category, target)); } } /// - /// 检查必需派系关系条件 - 新增方法 + /// 根据派系关系状态决定触发哪个事件 /// - private bool PassesRequiredFactionCheck() + private IncidentDef GetIncidentBasedOnFactionRelation(FactionRelationResult factionCheckResult) + { + switch (factionCheckResult.Status) + { + case FactionRelationStatus.Valid: + return SimpleProps.incident; + + case FactionRelationStatus.HostileButAllowed: + // 如果配置了敌对情况下的替代事件,则使用替代事件 + if (SimpleProps.incidentIfHostile != null) + { + if (SimpleProps.debugLogging) + { + Log.Message($"[SimpleTechnologyTrigger] Using hostile alternative incident: {SimpleProps.incidentIfHostile.defName}"); + } + return SimpleProps.incidentIfHostile; + } + // 如果没有配置替代事件,则使用原事件 + return SimpleProps.incident; + + case FactionRelationStatus.Invalid: + default: + return null; + } + } + + /// + /// 检查必需派系关系条件 + /// + private FactionRelationResult PassesRequiredFactionCheck() { // 如果没有配置必需派系,直接通过 if (SimpleProps.requiredFaction == null) - return true; + return FactionRelationResult.Valid(); // 查找派系 Faction requiredFactionInstance = Find.FactionManager.FirstFactionOfDef(SimpleProps.requiredFaction); @@ -75,21 +108,35 @@ namespace WulaFallenEmpire { Log.Message($"[SimpleTechnologyTrigger] Required faction {SimpleProps.requiredFaction.defName} does not exist or is defeated"); } - return false; + return FactionRelationResult.Invalid("Faction does not exist or is defeated"); } } // 检查派系关系 - if (SimpleProps.requireNonHostileRelation && requiredFactionInstance != null) + if (requiredFactionInstance != null) { Faction playerFaction = Faction.OfPlayer; - if (requiredFactionInstance.HostileTo(playerFaction)) + bool isHostile = requiredFactionInstance.HostileTo(playerFaction); + + if (isHostile) { - if (SimpleProps.debugLogging) + if (SimpleProps.requireNonHostileRelation) { - Log.Message($"[SimpleTechnologyTrigger] Required faction {SimpleProps.requiredFaction.defName} is hostile to player"); + if (SimpleProps.debugLogging) + { + Log.Message($"[SimpleTechnologyTrigger] Required faction {SimpleProps.requiredFaction.defName} is hostile to player and requireNonHostileRelation is true"); + } + return FactionRelationResult.Invalid("Faction is hostile and requireNonHostileRelation is true"); + } + else + { + // 不要求非敌对关系,但派系是敌对的 - 这是一个特殊状态 + if (SimpleProps.debugLogging) + { + Log.Message($"[SimpleTechnologyTrigger] Required faction {SimpleProps.requiredFaction.defName} is hostile but requireNonHostileRelation is false - allowing with possible alternative"); + } + return FactionRelationResult.HostileButAllowed(); } - return false; } } @@ -98,7 +145,7 @@ namespace WulaFallenEmpire Log.Message($"[SimpleTechnologyTrigger] Required faction {SimpleProps.requiredFaction.defName} check passed"); } - return true; + return FactionRelationResult.Valid(); } /// @@ -106,11 +153,9 @@ namespace WulaFallenEmpire /// private bool PassesIntervalCheck() { - // 简单的周期检查:每 X 天检查一次 int currentInterval = IntervalsPassed; int checkInterval = (int)(SimpleProps.checkIntervalDays * 60); - // 如果检查间隔为0,则每个间隔都检查 if (checkInterval <= 0) return true; @@ -128,7 +173,6 @@ namespace WulaFallenEmpire return false; } - // 简单检查科技是否已研究完成 bool hasTechnology = SimpleProps.technology.IsFinished; if (SimpleProps.debugLogging) @@ -144,16 +188,13 @@ namespace WulaFallenEmpire /// private bool PassesFactionFilter(IIncidentTarget target) { - // 如果不启用派系过滤,直接通过 if (!SimpleProps.useFactionFilter) return true; - // 获取目标的派系 Faction faction = GetTargetFaction(target); if (faction == null) return false; - // 检查黑名单 if (SimpleProps.factionTypeBlacklist != null && SimpleProps.factionTypeBlacklist.Contains(faction.def)) { @@ -164,7 +205,6 @@ namespace WulaFallenEmpire return false; } - // 检查白名单 if (SimpleProps.factionTypeWhitelist != null && SimpleProps.factionTypeWhitelist.Count > 0) { @@ -173,14 +213,8 @@ namespace WulaFallenEmpire switch (SimpleProps.defaultBehavior) { case FactionFilterDefaultBehavior.Allow: - // 白名单模式:在白名单中或默认允许 - if (SimpleProps.debugLogging && !inWhitelist) - { - Log.Message($"[SimpleTechnologyTrigger] Faction {faction.def.defName} not in whitelist, but default behavior is Allow"); - } return true; case FactionFilterDefaultBehavior.Deny: - // 白名单模式:只有在白名单中才允许 if (inWhitelist) { if (SimpleProps.debugLogging) @@ -200,7 +234,6 @@ namespace WulaFallenEmpire } } - // 如果没有设置白名单,根据默认行为决定 switch (SimpleProps.defaultBehavior) { case FactionFilterDefaultBehavior.Allow: @@ -244,20 +277,23 @@ namespace WulaFallenEmpire /// /// 检查是否存在活跃的相同任务 /// - private bool HasActiveQuest() + private bool HasActiveQuest(IncidentDef incident) { - if (SimpleProps.questDef == null) - return false; - - bool hasActiveQuest = Find.QuestManager.QuestsListForReading.Any((Quest q) => - q.root == SimpleProps.questDef && !q.Historical); - - if (SimpleProps.debugLogging && hasActiveQuest) + // 如果配置了防止重复,检查是否有相同根源的任务 + if (SimpleProps.preventDuplicateQuests && SimpleProps.questDef != null) { - Log.Message($"[SimpleTechnologyTrigger] Active quest {SimpleProps.questDef.defName} found, skipping trigger"); + bool hasActiveQuest = Find.QuestManager.QuestsListForReading.Any((Quest q) => + q.root == SimpleProps.questDef && !q.Historical); + + if (SimpleProps.debugLogging && hasActiveQuest) + { + Log.Message($"[SimpleTechnologyTrigger] Active quest {SimpleProps.questDef.defName} found, skipping trigger"); + } + + return hasActiveQuest; } - return hasActiveQuest; + return false; } /// @@ -267,13 +303,23 @@ namespace WulaFallenEmpire { StringBuilder status = new StringBuilder(); status.AppendLine($"Simple Technology Trigger: {SimpleProps.technology?.defName ?? "NULL"}"); + + var factionCheck = PassesRequiredFactionCheck(); + status.AppendLine($"Faction Relation Status: {factionCheck.Status}"); + if (!factionCheck.IsValid) + { + status.AppendLine($"Faction Relation Reason: {factionCheck.Reason}"); + } + status.AppendLine($"Research Status: {(PassesTechnologyCheck() ? "✅ COMPLETED" : "❌ NOT COMPLETED")}"); status.AppendLine($"Required Faction: {SimpleProps.requiredFaction?.defName ?? "NONE"}"); - status.AppendLine($"Faction Relation: {(PassesRequiredFactionCheck() ? "✅ VALID" : "❌ INVALID")}"); + status.AppendLine($"Hostile Alternative: {SimpleProps.incidentIfHostile?.defName ?? "NONE"}"); status.AppendLine($"Check Interval: {SimpleProps.checkIntervalDays} days"); status.AppendLine($"Current Interval: {IntervalsPassed}"); status.AppendLine($"Next Check: {GetNextCheckInterval()} intervals"); - status.AppendLine($"Can Trigger Now: {PassesIntervalCheck() && PassesTechnologyCheck() && PassesRequiredFactionCheck()}"); + + bool canTrigger = PassesIntervalCheck() && PassesTechnologyCheck() && factionCheck.IsValid; + status.AppendLine($"Can Trigger Now: {canTrigger}"); // 详细派系信息 if (SimpleProps.requiredFaction != null) @@ -305,4 +351,39 @@ namespace WulaFallenEmpire return ((currentInterval / checkInterval) + 1) * checkInterval; } } + + /// + /// 派系关系检查结果 + /// + public struct FactionRelationResult + { + public FactionRelationStatus Status { get; } + public string Reason { get; } + public bool IsValid => Status == FactionRelationStatus.Valid || Status == FactionRelationStatus.HostileButAllowed; + + public FactionRelationResult(FactionRelationStatus status, string reason = "") + { + Status = status; + Reason = reason; + } + + public static FactionRelationResult Valid() => new FactionRelationResult(FactionRelationStatus.Valid); + public static FactionRelationResult HostileButAllowed() => new FactionRelationResult(FactionRelationStatus.HostileButAllowed); + public static FactionRelationResult Invalid(string reason) => new FactionRelationResult(FactionRelationStatus.Invalid, reason); + + public override string ToString() + { + return $"{Status}{(string.IsNullOrEmpty(Reason) ? "" : $" ({Reason})")}"; + } + } + + /// + /// 派系关系状态枚举 + /// + public enum FactionRelationStatus + { + Valid, // 关系有效,可以触发原事件 + HostileButAllowed, // 关系敌对但允许,可以触发替代事件 + Invalid // 关系无效,不触发任何事件 + } } diff --git a/Source/WulaFallenEmpire/ThingComp/CompProperties_DelayedDamageIfNotPlayer.cs b/Source/WulaFallenEmpire/ThingComp/CompProperties_DelayedDamageIfNotPlayer.cs new file mode 100644 index 00000000..6c342e55 --- /dev/null +++ b/Source/WulaFallenEmpire/ThingComp/CompProperties_DelayedDamageIfNotPlayer.cs @@ -0,0 +1,106 @@ +using RimWorld; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_DelayedDamageIfNotPlayer : CompProperties + { + public DamageDef damageDef; + public int damageAmount = 10; + public float armorPenetration = 0f; + public BodyPartDef hitPart; + public bool destroyIfKilled = true; + + public CompProperties_DelayedDamageIfNotPlayer() + { + compClass = typeof(CompDelayedDamageIfNotPlayer); + } + } + + public class CompDelayedDamageIfNotPlayer : ThingComp + { + private bool damageApplied = false; + private bool scheduledForNextFrame = false; + + public CompProperties_DelayedDamageIfNotPlayer Props => (CompProperties_DelayedDamageIfNotPlayer)props; + + public override void PostSpawnSetup(bool respawningAfterLoad) + { + base.PostSpawnSetup(respawningAfterLoad); + + // 只在初次生成时检查,重新加载时不重复 + if (!respawningAfterLoad) + { + CheckAndScheduleDamage(); + } + } + + private void CheckAndScheduleDamage() + { + // 检查派系,如果不是玩家派系则安排伤害 + if (parent.Faction != Faction.OfPlayer && !damageApplied && !scheduledForNextFrame) + { + scheduledForNextFrame = true; + + // 使用LongEventHandler来在下一帧执行 + LongEventHandler.ExecuteWhenFinished(ApplyDelayedDamage); + } + } + + private void ApplyDelayedDamage() + { + if (scheduledForNextFrame && !damageApplied) + { + // 再次确认对象仍然存在且未被销毁 + if (parent != null && parent.Spawned && !parent.Destroyed) + { + ApplyDamage(); + } + scheduledForNextFrame = false; + } + } + + private void ApplyDamage() + { + try + { + if (parent == null || parent.Destroyed || damageApplied) + return; + + // 创建伤害信息 + DamageInfo damageInfo = new DamageInfo( + Props.damageDef, + Props.damageAmount, + armorPenetration: Props.armorPenetration, + instigator: parent + ); + + // 施加伤害 + parent.TakeDamage(damageInfo); + + damageApplied = true; + + // 记录日志以便调试 + Log.Message($"[CompDelayedDamage] Applied {Props.damageAmount} {Props.damageDef.defName} damage to {parent.Label} (Faction: {parent.Faction?.Name ?? "None"})"); + + // 检查是否被杀死 + if (Props.destroyIfKilled && (parent.Destroyed || (parent is Pawn pawn && pawn.Dead))) + { + Log.Message($"[CompDelayedDamage] {parent.Label} was destroyed by delayed damage"); + } + } + catch (System.Exception ex) + { + Log.Error($"[CompDelayedDamage] Error applying delayed damage: {ex}"); + } + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref damageApplied, "damageApplied", false); + Scribe_Values.Look(ref scheduledForNextFrame, "scheduledForNextFrame", false); + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index fa986bdc..d8af6820 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -122,6 +122,7 @@ + @@ -259,6 +260,7 @@ + @@ -269,6 +271,7 @@ +