diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index b1e57e8..fffe6fb 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/1.6/1.6/Defs/AbilityDefs/Abilities_EggSpew.xml b/1.6/1.6/Defs/AbilityDefs/Abilities_EggSpew.xml index 7a5cb08..e71af7e 100644 --- a/1.6/1.6/Defs/AbilityDefs/Abilities_EggSpew.xml +++ b/1.6/1.6/Defs/AbilityDefs/Abilities_EggSpew.xml @@ -699,12 +699,12 @@ AcidSpray_Resolve
  • - ARA_Cocoon_Weapon_2Stage + ARA_Cocoon_Medicine_From_Death 温度要求 true
  • - ARA_Cocoon_Weapon_2Stage + ARA_Cocoon_Medicine_From_Death 可孵化物品列表 true true diff --git a/1.6/1.6/Defs/FactionDefs/ARA_Factions_Hostile_Hive.xml b/1.6/1.6/Defs/FactionDefs/ARA_Factions_Hostile_Hive.xml new file mode 100644 index 0000000..ab74b32 --- /dev/null +++ b/1.6/1.6/Defs/FactionDefs/ARA_Factions_Hostile_Hive.xml @@ -0,0 +1,45 @@ + + + + ARA_Hostile_Hive + + 向闪耀世界方向侵略的阿拉克涅虫巢舰队被闪耀世界联军击败后,残留于星域中的虫群子个体。这些虫群子个体由于无法和蜂巢网络建立联系,其自行组织的反常网络只有低度的智能,只能让其成员如野兽般行动——然而她们依然是一群危险的敌人,于无数敌手交战留下的基因性反射使得她们的锋芒不减当年。\n\n她们不会对任何人展现仁慈,即使她们的对手是自己的同族。 + 虫群 + 虫群 + 1 + 阿拉克涅断须 + World/WorldObjects/Expanding/Insects + +
  • (0.44, 0.41, 0.32)
  • +
  • (0.61, 0.58, 0.49)
  • +
  • (0.60, 0.49, 0.36)
  • + + + +
  • (0, 0)
  • +
    +
    + + +
  • (100,100)
  • +
  • (10000,10000)
  • +
    +
    + + + + false + true + false + false + Animal + false + +
  • Entities
  • +
    + World/WorldObjects/DefaultSettlement + -2000~2000 + 1 + 1000 + + \ No newline at end of file diff --git a/1.6/1.6/Defs/FactionDefs/ARA_Factions_Player.xml b/1.6/1.6/Defs/FactionDefs/ARA_Factions_Player.xml index 1d71bc0..4c95cb5 100644 --- a/1.6/1.6/Defs/FactionDefs/ARA_Factions_Player.xml +++ b/1.6/1.6/Defs/FactionDefs/ARA_Factions_Player.xml @@ -19,7 +19,8 @@ ARA_New_Hive_NamerFaction - NamerSettlementOutlander + ARA_NamerSettlement + ARA_NamerInitialSettlement
  • Astropolitan
  • World/WorldObjects/Expanding/Town @@ -41,29 +42,58 @@
  • r_name->[hivename1] [hivename2]
  • -
  • hivename1->猩红
  • -
  • hivename1->至高
  • -
  • hivename1->唯一
  • -
  • hivename1->蔓延
  • -
  • hivename1->永恒
  • -
  • hivename1->永续
  • +
  • hivename1->虚空
  • +
  • hivename1->深渊
  • +
  • hivename1->吞噬
  • +
  • hivename1->进化
  • +
  • hivename1->原生
  • +
  • hivename1->融合
  • +
  • hivename1->蚀骨
  • -
  • hivename2->核心
  • -
  • hivename2->内核
  • -
  • hivename2->要点
  • -
  • hivename2->中心
  • -
  • hivename2->焦点
  • -
  • hivename2->原点
  • -
  • hivename2->支点
  • -
  • hivename2->枢轴
  • -
  • hivename2->中枢
  • -
  • hivename2->母体
  • -
  • hivename2->源泉
  • -
  • hivename2->源地
  • -
  • hivename2->基体
  • -
  • hivename2->始祖
  • -
  • hivename2->主脑
  • -
  • hivename2->巢心
  • +
  • hivename2->蜂巢
  • +
  • hivename2->虫群
  • +
  • hivename2->爪牙
  • +
  • hivename2->兽群
  • +
  • hivename2->触须
  • +
    +
    + + + ARA_NamerSettlement + + +
  • r_name->[hivesettlementname1] [hivesettlementname2]
  • +
  • hivesettlementname1->猩红
  • +
  • hivesettlementname1->至高
  • +
  • hivesettlementname1->唯一
  • +
  • hivesettlementname1->蔓延
  • +
  • hivesettlementname1->永恒
  • +
  • hivesettlementname1->永续
  • + +
  • hivesettlementname2->核心
  • +
  • hivesettlementname2->内核
  • +
  • hivesettlementname2->要点
  • +
  • hivesettlementname2->中心
  • +
  • hivesettlementname2->焦点
  • +
  • hivesettlementname2->原点
  • +
  • hivesettlementname2->支点
  • +
  • hivesettlementname2->枢轴
  • +
  • hivesettlementname2->中枢
  • +
  • hivesettlementname2->母体
  • +
  • hivesettlementname2->源泉
  • +
  • hivesettlementname2->源地
  • +
  • hivesettlementname2->基体
  • +
  • hivesettlementname2->始祖
  • +
  • hivesettlementname2->主脑
  • +
  • hivesettlementname2->巢心
  • +
    +
    +
    + + ARA_NamerInitialSettlement + + +
  • r_name->虫巢
  • diff --git a/1.6/1.6/Defs/HiveRaidDef/ARA_CustomRaidDef.xml b/1.6/1.6/Defs/HiveRaidDef/ARA_CustomRaidDef.xml new file mode 100644 index 0000000..9ef4f2f --- /dev/null +++ b/1.6/1.6/Defs/HiveRaidDef/ARA_CustomRaidDef.xml @@ -0,0 +1,192 @@ + + + + + ARA_Stage1_Raid + ARA_Hostile_Hive + +
  • + 0 + 800 + ARA_WavePool_Stage1 +
  • +
    + 3 + + Linear + 1.2 + +
    + + + ARA_WavePool_Stage1 + +
  • ARA_Wave_Scout_Patrol
  • +
  • ARA_Wave_Assault_Team
  • +
  • ARA_Wave_Acid_Swarm
  • +
  • ARA_Wave_Heavy_Defense
  • +
  • ARA_Wave_Mixed_Forces
  • +
    + +
  • + ARA_Wave_Scout_Patrol + 0.25 +
  • +
  • + ARA_Wave_Assault_Team + 0.25 +
  • +
  • + ARA_Wave_Acid_Swarm + 0.20 +
  • +
  • + ARA_Wave_Heavy_Defense + 0.15 +
  • +
  • + ARA_Wave_Mixed_Forces + 0.15 +
  • +
    +
    + + + + ARA_Wave_Scout_Patrol + + 一支小型侦察队伍,主要由远程单位组成,进行骚扰射击 + +
  • + ARA_Raid_Shooter + 0.7 + 2 + 6 + true +
  • +
  • + ARA_Raid_Assault + 0.3 + 1 + 3 +
  • +
    +
    + + + ARA_Wave_Assault_Team + + 以近战单位为主的快速突击队伍,擅长冲锋陷阵 + +
  • + ARA_Raid_Assault + 0.6 + 3 + 8 + true +
  • +
  • + ARA_Raid_Shooter + 0.4 + 2 + 4 +
  • +
    +
    + + + ARA_Wave_Acid_Swarm + + 大量酸噬种辅虫组成的虫海战术,数量庞大但个体脆弱 + +
  • + ARA_Raid_AcidSwarm + 0.8 + 8 + 20 + true +
  • +
  • + ARA_Raid_Assault + 0.2 + 2 + 5 +
  • +
    +
    + + + ARA_Wave_Heavy_Defense + + 以盾头种为主的防御型队伍,移动缓慢但防御力强 + +
  • + ARA_Raid_Heavy + 0.5 + 2 + 6 + true +
  • +
  • + ARA_Raid_Shooter + 0.3 + 2 + 4 +
  • +
  • + ARA_Raid_Acidling + 0.2 + 3 + 8 +
  • +
    + Defensive +
    + + + ARA_Wave_Mixed_Forces + + 均衡配置的混合部队,包含各种单位类型 + +
  • + ARA_Raid_Assault + 0.3 + 2 + 5 +
  • +
  • + ARA_Raid_Shooter + 0.3 + 2 + 5 +
  • +
  • + ARA_Raid_Heavy + 0.2 + 1 + 3 +
  • +
  • + ARA_Raid_AcidSwarm + 0.2 + 3 + 6 + true +
  • +
    + Balanced +
    + + + + ARA_Raid_Incident + + ArachnaeSwarm.IncidentWorker_CustomRaid + Special + 5 + 0 + +
  • Map_PlayerHome
  • +
    +
    +
    diff --git a/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml b/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml new file mode 100644 index 0000000..39e1e51 --- /dev/null +++ b/1.6/1.6/Defs/PawnKindDef/ARA_Hostile_Hive_PawnKinds.xml @@ -0,0 +1,144 @@ + + + + + 150 + true + false + 0 + true + true + 99~99 + 99~99 + 1 + true + 2 + 1 + false + ARA_Hostile_Hive + 0 + +
  • Violent
  • +
    + +
  • + ARA_Creep + 3.0 +
  • +
    +
    + + + + + ARA_Raid_Assault + + ArachnaeNode_Race_Fighter + 200 + +
  • ARA_Armed_Organ_Melee
  • +
    + +
  • ARA_Inner
  • +
  • ARA_Clothes
  • +
    + 200 + 200 + +
  • ARA_BaseRace_Acid_Launcher
  • +
    +
    + + + ARA_Raid_Shooter + + ArachnaeNode_Race_Fighter + 180 + +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • +
  • ARA_Armed_Organ_Small_Ranged_Acid
  • +
    + +
  • ARA_Inner
  • +
    + 150 + 400 + 100 + +
  • ARA_Hibernate_Ability
  • +
    +
    + + + ARA_Raid_AcidSwarm + + 80 + 0 + 0 + 0 + ArachnaeBase_Race_Acidcut + +
  • + + ArachnaeSwarm/Things/ARA_Acidcut/Bodies/Naked_Thin + 1 + + (0.4, 0.5, 0.37) + (0,0,-0.15) + + + + Things/Pawn/Animal/Spelopede/Dessicated_Spelopede + 1 + +
  • +
    +
    + + + + + ARA_Raid_Heavy + + ArachnaeNode_Race_ShieldHead + 350 + +
  • ARA_Armed_Organ_Melee
  • +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • +
  • ARA_Armed_Organ_Small_Ranged_Acid
  • +
    + +
  • ARA_Inner
  • +
  • ARA_Clothes
  • +
    + 400 + 600 + 0 +
    + + + ARA_Raid_Acidling + + ArachnaeBase_Race_Acidling + 50 + 0 + 0 + 0 + +
  • + + ArachnaeSwarm/Things/ARA_Acidling/Bodies/Naked_Thin + 1 + + (0.4, 0.5, 0.37) + (0,0,-0.15) + + + + Things/Pawn/Animal/Spelopede/Dessicated_Spelopede + 1 + +
  • +
    +
    +
    diff --git a/1.6/1.6/Defs/StoryTellers/ARA_Storytellers.xml b/1.6/1.6/Defs/StoryTellers/ARA_Storytellers.xml index b08d1e2..26545dd 100644 --- a/1.6/1.6/Defs/StoryTellers/ARA_Storytellers.xml +++ b/1.6/1.6/Defs/StoryTellers/ARA_Storytellers.xml @@ -9,8 +9,14 @@ 20 + -
  • ThreatBig 15.0 diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml index c74d103..b5bcb12 100644 --- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml +++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceQueen.xml @@ -11,6 +11,8 @@ + + Megaspider Humanlike HumanlikeConstant diff --git a/1.6/1.6/Defs/Thing_Misc/ARA_Medicine.xml b/1.6/1.6/Defs/Thing_Misc/ARA_Medicine.xml index b278580..bbf88a2 100644 --- a/1.6/1.6/Defs/Thing_Misc/ARA_Medicine.xml +++ b/1.6/1.6/Defs/Thing_Misc/ARA_Medicine.xml @@ -31,6 +31,7 @@
  • ARA_Cocoon_Medicine
  • +
  • ARA_Cocoon_Medicine_From_Death
  • ARA_BioforgeIncubator_Thing
  • @@ -87,6 +88,7 @@
  • ARA_Cocoon_Medicine
  • +
  • ARA_Cocoon_Medicine_From_Death
  • ARA_BioforgeIncubator_Thing
  • diff --git a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml index 079db41..d43b40d 100644 --- a/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml +++ b/1.6/1.6/Defs/Thing_Misc/Weapons/ARA_Weapon.xml @@ -12,6 +12,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Melee
  • ARA_Armed_Organ_T1
  • +
  • ARA_MW_Bone_Sword
  • ArachnaeSwarm/Weapon/ARA_MW_Bone_Sword @@ -313,6 +314,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T1
  • +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • 0 None @@ -427,6 +429,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • 0 None @@ -524,6 +527,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • 0 None @@ -637,6 +641,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Huge_Ranged_Needle
  • 0 None @@ -752,6 +757,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Small_Ranged_Needle
  • 0 None @@ -854,6 +860,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T1
  • +
  • ARA_Armed_Organ_Small_Ranged_Acid
  • 0 None @@ -969,6 +976,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Huge_Ranged_Acid
  • 0 None @@ -1118,6 +1126,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Huge_Ranged_Acid
  • 0 None @@ -1236,6 +1245,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T3
  • +
  • ARA_Armed_Organ_Small_Ranged_Acid
  • 0 None @@ -1370,6 +1380,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T3
  • +
  • ARA_Armed_Organ_Huge_Ranged_Acid
  • 0 None @@ -1506,6 +1517,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T1
  • +
  • ARA_Armed_Organ_Small_Ranged_SP
  • 0 None @@ -1658,6 +1670,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Small_Ranged_Energy
  • 0 None @@ -1764,6 +1777,7 @@
  • ARA_Armed_Organ
  • ARA_Armed_Organ_Ranged
  • ARA_Armed_Organ_T2
  • +
  • ARA_Armed_Organ_Huge_Ranged_Energy
  • 0 None diff --git a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml index 141b984..4d958b8 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_InteractiveEggSac.xml @@ -694,7 +694,7 @@ true 0.2 1 - 999 + 20
    @@ -715,7 +715,7 @@ true 1 1 - 999 + 20 @@ -804,7 +804,7 @@ true 0.2 1 - 999 + 20 @@ -825,7 +825,7 @@ true 1 1 - 999 + 20 @@ -922,7 +922,7 @@ true 0.2 1 - 999 + 60 @@ -943,7 +943,7 @@ true 1 1 - 999 + 60 @@ -1035,7 +1035,7 @@ true 0.2 1 - 999 + 60 @@ -1056,7 +1056,7 @@ true 1 1 - 999 + 60 @@ -1145,7 +1145,7 @@ true 0.2 1 - 999 + 110 @@ -1166,7 +1166,7 @@ true 1 1 - 999 + 110 @@ -1279,7 +1279,7 @@ true 0.2 1 - 999 + 110 @@ -1300,7 +1300,7 @@ true 1 1 - 999 + 110 diff --git a/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml b/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml index d81b3da..8616d04 100644 --- a/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml +++ b/1.6/1.6/Defs/Thing_building/ARA_RefuelingVat.xml @@ -71,9 +71,8 @@ 20 0 true - 0 + -1 true - false @@ -82,7 +81,7 @@ false - true + false true diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo index 3730808..c151d56 100644 Binary files a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo and b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/.suo differ diff --git a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json index 3073341..1c86b0f 100644 --- a/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json +++ b/Source/ArachnaeSwarm/.vs/ArachnaeSwarm/v17/DocumentLayout.json @@ -3,12 +3,8 @@ "WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\", "Documents": [ { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:abilities\\compabilityeffect_transformcorpse.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" - }, - { - "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", - "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:building_comps\\comprefuelablenutrition.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" + "AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\storyteller\\incidentworker_customraid.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}", + "RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:storyteller\\incidentworker_customraid.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}" } ], "DocumentGroupContainers": [ @@ -18,35 +14,23 @@ "DocumentGroups": [ { "DockedWidth": 200, - "SelectedChildIndex": 2, + "SelectedChildIndex": 1, "Children": [ { "$type": "Bookmark", "Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}" }, - { - "$type": "Document", - "DocumentIndex": 1, - "Title": "CompRefuelableNutrition.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs", - "RelativeDocumentMoniker": "Building_Comps\\CompRefuelableNutrition.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Building_Comps\\CompRefuelableNutrition.cs", - "RelativeToolTip": "Building_Comps\\CompRefuelableNutrition.cs", - "ViewState": "AgIAABAAAAAAAAAAAAAuwBYAAAAhAAAAAAAAAA==", - "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-15T08:04:45.513Z" - }, { "$type": "Document", "DocumentIndex": 0, - "Title": "CompAbilityEffect_TransformCorpse.cs", - "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs", - "RelativeDocumentMoniker": "Abilities\\CompAbilityEffect_TransformCorpse.cs", - "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Abilities\\CompAbilityEffect_TransformCorpse.cs", - "RelativeToolTip": "Abilities\\CompAbilityEffect_TransformCorpse.cs", - "ViewState": "AgIAAAAAAAAAAAAAAAAAABIAAABCAAAAAAAAAA==", + "Title": "IncidentWorker_CustomRaid.cs", + "DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Storyteller\\IncidentWorker_CustomRaid.cs", + "RelativeDocumentMoniker": "Storyteller\\IncidentWorker_CustomRaid.cs", + "ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Storyteller\\IncidentWorker_CustomRaid.cs", + "RelativeToolTip": "Storyteller\\IncidentWorker_CustomRaid.cs", + "ViewState": "AgIAAAYBAAAAAAAAAAAgwBYBAAAyAAAAAAAAAA==", "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|", - "WhenOpened": "2025-10-15T08:02:12.842Z", + "WhenOpened": "2025-10-16T07:14:58.682Z", "EditorCaption": "" } ] diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index ee5f244..e32f2e2 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -120,6 +120,12 @@ + + + + + + diff --git a/Source/ArachnaeSwarm/Storyteller/CustomRaidDef.cs b/Source/ArachnaeSwarm/Storyteller/CustomRaidDef.cs new file mode 100644 index 0000000..b20c625 --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/CustomRaidDef.cs @@ -0,0 +1,51 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; + +namespace ArachnaeSwarm +{ + public class CustomRaidDef : Def + { + public FactionDef factionDef; + public List pointWavePools; + public int baseRaidNembers; + public PointsGrowthPerWave pointsGrowthPerWave; + + public override IEnumerable ConfigErrors() + { + foreach (string error in base.ConfigErrors()) + { + yield return error; + } + + if (factionDef == null) + { + yield return "factionDef is not defined"; + } + + if (pointWavePools.NullOrEmpty()) + { + yield return "pointWavePools is empty"; + } + + if (baseRaidNembers <= 0) + { + yield return "baseRaidNembers must be positive"; + } + } + } + + public class PointWavePool + { + public float minPoints; + public float maxPoints = 99999f; // 默认值表示无上限 + public RaidWavePoolDef wavePool; + } + + public class PointsGrowthPerWave + { + public string growthType = "Linear"; // Linear/Exponential + public float linearGrowth = 1f; + public float exponentialBase = 1.15f; + } +} diff --git a/Source/ArachnaeSwarm/Storyteller/CustomRaidTracker.cs b/Source/ArachnaeSwarm/Storyteller/CustomRaidTracker.cs new file mode 100644 index 0000000..8f3bb18 --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/CustomRaidTracker.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using Verse; + +namespace ArachnaeSwarm +{ + public class CustomRaidTracker : GameComponent + { + private Dictionary waveCounters = new Dictionary(); + + public CustomRaidTracker(Game game) + { + // 构造函数 + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Collections.Look(ref waveCounters, "waveCounters", LookMode.Value, LookMode.Value); + + // 如果waveCounters为null(加载旧存档时可能发生),初始化它 + if (waveCounters == null) + { + waveCounters = new Dictionary(); + } + } + + public int GetCurrentWave(CustomRaidDef raidDef) + { + if (raidDef == null) + { + Log.Warning("GetCurrentWave called with null raidDef"); + return 0; + } + + string key = raidDef.defName; + if (!waveCounters.ContainsKey(key)) + { + waveCounters[key] = 0; + } + + return waveCounters[key]; + } + + public void IncrementWave(CustomRaidDef raidDef) + { + if (raidDef != null) + { + string key = raidDef.defName; + int currentWave = GetCurrentWave(raidDef); + waveCounters[key] = currentWave + 1; + + Log.Message($"CustomRaidTracker: Incremented wave for {raidDef.defName} to {waveCounters[key]}"); + } + else + { + Log.Warning("IncrementWave called with null raidDef"); + } + } + + public void ResetWave(CustomRaidDef raidDef) + { + if (raidDef != null) + { + waveCounters[raidDef.defName] = 0; + } + } + + public void ResetAllWaves() + { + waveCounters.Clear(); + } + } +} diff --git a/Source/ArachnaeSwarm/Storyteller/IncidentParmsExtensions.cs b/Source/ArachnaeSwarm/Storyteller/IncidentParmsExtensions.cs new file mode 100644 index 0000000..e1996b2 --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/IncidentParmsExtensions.cs @@ -0,0 +1,111 @@ +using RimWorld; +using System.Collections.Generic; +using Verse; + +namespace ArachnaeSwarm +{ + public static class IncidentParmsExtensions + { + // 使用静态字典来存储自定义数据 + private static Dictionary customRaidData = new Dictionary(); + + public class CustomRaidData + { + public RaidWaveDef WaveDef { get; set; } + public int RaidSize { get; set; } = -1; + public CustomRaidDef RaidDef { get; set; } + public int WaveNumber { get; set; } + } + + public static void SetCustomRaidWave(this IncidentParms parms, RaidWaveDef waveDef) + { + if (!customRaidData.ContainsKey(parms)) + customRaidData[parms] = new CustomRaidData(); + + customRaidData[parms].WaveDef = waveDef; + } + + public static RaidWaveDef GetCustomRaidWave(this IncidentParms parms) + { + if (!customRaidData.ContainsKey(parms)) + return null; + + return customRaidData[parms].WaveDef; + } + + public static void SetCustomRaidSize(this IncidentParms parms, int raidSize) + { + if (!customRaidData.ContainsKey(parms)) + customRaidData[parms] = new CustomRaidData(); + + customRaidData[parms].RaidSize = raidSize; + } + + public static int GetCustomRaidSize(this IncidentParms parms) + { + if (!customRaidData.ContainsKey(parms)) + return -1; + + return customRaidData[parms].RaidSize; + } + + public static void SetCustomRaidDef(this IncidentParms parms, CustomRaidDef raidDef) + { + if (!customRaidData.ContainsKey(parms)) + customRaidData[parms] = new CustomRaidData(); + + customRaidData[parms].RaidDef = raidDef; + } + + public static CustomRaidDef GetCustomRaidDef(this IncidentParms parms) + { + if (!customRaidData.ContainsKey(parms)) + return null; + + return customRaidData[parms].RaidDef; + } + + public static void SetCustomRaidWaveNumber(this IncidentParms parms, int waveNumber) + { + if (!customRaidData.ContainsKey(parms)) + customRaidData[parms] = new CustomRaidData(); + + customRaidData[parms].WaveNumber = waveNumber; + } + + public static int GetCustomRaidWaveNumber(this IncidentParms parms) + { + if (!customRaidData.ContainsKey(parms)) + return 0; + + return customRaidData[parms].WaveNumber; + } + + public static bool IsCustomRaid(this IncidentParms parms) + { + return parms.GetCustomRaidWave() != null; + } + + // 清理方法,在事件完成后调用 + public static void ClearCustomData(this IncidentParms parms) + { + if (customRaidData.ContainsKey(parms)) + customRaidData.Remove(parms); + } + + // 批量清理方法,用于清理所有不再使用的 IncidentParms + public static void CleanupOrphanedData() + { + // 这里可以添加逻辑来清理不再使用的 IncidentParms 引用 + // 例如,如果 IncidentParms 已经被销毁,我们可以从字典中移除 + // 由于 RimWorld 没有提供弱引用,这个清理可能需要手动触发 + // 或者定期调用 + } + + // 获取所有存储的自定义数据(用于调试) + public static int GetStoredDataCount() + { + return customRaidData.Count; + } + } +} diff --git a/Source/ArachnaeSwarm/Storyteller/IncidentWorker_CustomRaid.cs b/Source/ArachnaeSwarm/Storyteller/IncidentWorker_CustomRaid.cs new file mode 100644 index 0000000..2f13f16 --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/IncidentWorker_CustomRaid.cs @@ -0,0 +1,418 @@ +using System.Collections.Generic; +using System.Linq; +using RimWorld; +using Verse; + +namespace ArachnaeSwarm +{ + public class IncidentWorker_CustomRaid : IncidentWorker_Raid + { + private CustomRaidTracker GetTracker() + { + if (Current.ProgramState != ProgramState.Playing) return null; + + Game game = Current.Game; + if (game == null) return null; + + CustomRaidTracker tracker = game.GetComponent(); + if (tracker == null) + { + tracker = new CustomRaidTracker(game); + game.components.Add(tracker); + } + return tracker; + } + + protected override bool CanFireNowSub(IncidentParms parms) + { + // 获取自定义袭击定义 + CustomRaidDef raidDef = GetCustomRaidDef(); + if (raidDef == null) + { + Log.Warning("CustomRaidDef not found in CanFireNowSub"); + return false; + } + + // 检查最小天数 + if (GenDate.DaysPassedSinceSettle < 15f) // 可以配置化 + { + Log.Message($"Custom raid cannot fire: only {GenDate.DaysPassedSinceSettle} days passed, need 15"); + return false; + } + + // 检查目标是否有效 + if (parms.target == null) + { + Log.Warning("Custom raid target is null"); + return false; + } + + // 检查目标是否有有效的地图 + Map map = parms.target as Map; + if (map == null) + { + Log.Warning("Custom raid target is not a Map or map is null"); + return false; + } + + // 检查派系是否存在 + Faction faction = Find.FactionManager.FirstFactionOfDef(raidDef.factionDef); + if (faction == null) + { + Log.Warning($"Faction {raidDef.factionDef?.defName} not found for custom raid"); + return false; + } + + return base.CanFireNowSub(parms); + } + + protected override bool TryExecuteWorker(IncidentParms parms) + { + Log.Message("=== Custom Raid Incident Started ==="); + + // 检查目标地图 + Map map = parms.target as Map; + if (map == null) + { + Log.Error("Custom raid target is not a valid Map"); + return false; + } + + CustomRaidDef raidDef = GetCustomRaidDef(); + if (raidDef == null) + { + Log.Error("CustomRaidDef not found"); + return false; + } + + CustomRaidTracker tracker = GetTracker(); + if (tracker == null) + { + Log.Error("CustomRaidTracker not found"); + return false; + } + + // 获取当前波次 + int currentWave = tracker.GetCurrentWave(raidDef); + Log.Message($"Current wave: {currentWave}"); + + // 计算袭击规模 + int raidSize = CalculateRaidSize(currentWave, raidDef); + Log.Message($"Calculated raid size: {raidSize}"); + + // 选择波次定义 + RaidWaveDef waveDef = SelectWaveForSize(raidSize, raidDef); + if (waveDef == null) + { + Log.Error($"No wave found for raid size {raidSize}"); + return false; + } + Log.Message($"Selected wave: {waveDef.defName}"); + + // 设置派系 + parms.faction = Find.FactionManager.FirstFactionOfDef(raidDef.factionDef); + if (parms.faction == null) + { + Log.Error($"Faction {raidDef.factionDef.defName} not found"); + return false; + } + + // 设置点数 + parms.points = CalculateThreatPoints(raidSize); + Log.Message($"Threat points: {parms.points}"); + + // 设置袭击策略 + parms.raidStrategy = RaidStrategyDefOf.ImmediateAttack; + + // 设置自定义参数 + parms.SetCustomRaidWave(waveDef); + parms.SetCustomRaidSize(raidSize); + parms.SetCustomRaidDef(raidDef); + parms.SetCustomRaidWaveNumber(currentWave); + + Log.Message($"Custom raid parameters set: wave={waveDef.defName}, size={raidSize}, waveNum={currentWave}"); + + // 执行袭击 + bool success = base.TryExecuteWorker(parms); + + if (success) + { + // 成功执行后增加波次 + tracker.IncrementWave(raidDef); + Log.Message($"Custom raid wave {currentWave + 1} executed successfully. Next wave will be {currentWave + 2}"); + } + else + { + Log.Error("Custom raid execution failed"); + } + + Log.Message("=== Custom Raid Incident Finished ==="); + return success; + } + + protected override bool TryResolveRaidFaction(IncidentParms parms) + { + // 对于自定义袭击,我们已经通过扩展设置了派系 + if (parms.faction != null) + { + Log.Message($"Raid faction resolved: {parms.faction.Name}"); + return true; + } + + // 如果没有设置派系,尝试从自定义袭击定义中获取 + CustomRaidDef raidDef = parms.GetCustomRaidDef(); + if (raidDef?.factionDef != null) + { + parms.faction = Find.FactionManager.FirstFactionOfDef(raidDef.factionDef); + bool success = parms.faction != null; + Log.Message($"Resolved faction from raidDef: {raidDef.factionDef.defName}, success: {success}"); + return success; + } + + Log.Warning("Could not resolve raid faction"); + return false; + } + + public override void ResolveRaidStrategy(IncidentParms parms, PawnGroupKindDef groupKind) + { + // 如果已经设置了袭击策略,直接使用 + if (parms.raidStrategy != null) + { + Log.Message($"Raid strategy already set: {parms.raidStrategy.defName}"); + return; + } + + // 从自定义波次定义中获取策略 + RaidWaveDef waveDef = parms.GetCustomRaidWave(); + if (waveDef != null) + { + // 这里可以根据 waveDef 的内容设置不同的策略 + // 例如,如果有特定标签就使用特定策略 + parms.raidStrategy = RaidStrategyDefOf.ImmediateAttack; + Log.Message($"Set raid strategy from waveDef: {parms.raidStrategy.defName}"); + return; + } + + // 默认策略 + parms.raidStrategy = RaidStrategyDefOf.ImmediateAttack; + Log.Message($"Set default raid strategy: {parms.raidStrategy.defName}"); + } + + protected override void ResolveRaidPoints(IncidentParms parms) + { + // 如果已经设置了点数,直接使用 + if (parms.points > 0) + { + Log.Message($"Raid points already set: {parms.points}"); + return; + } + + // 从自定义袭击规模计算点数 + int raidSize = parms.GetCustomRaidSize(); + if (raidSize > 0) + { + parms.points = CalculateThreatPoints(raidSize); + Log.Message($"Set raid points from custom size: {raidSize} -> {parms.points}"); + return; + } + + // 回退到原版点数计算 + parms.points = StorytellerUtility.DefaultThreatPointsNow(parms.target); + Log.Message($"Set raid points from default calculation: {parms.points}"); + } + + protected override string GetLetterLabel(IncidentParms parms) + { + // 自定义袭击的信件标签 + RaidWaveDef waveDef = parms.GetCustomRaidWave(); + int waveNumber = parms.GetCustomRaidWaveNumber(); + CustomRaidDef raidDef = parms.GetCustomRaidDef(); + + if (waveDef != null && raidDef != null) + { + return $"Special Attack Wave {waveNumber + 1} - {waveDef.label ?? waveDef.defName}"; + } + + return "Special Attack"; + } + + protected override string GetLetterText(IncidentParms parms, List pawns) + { + // 自定义袭击的信件文本 + RaidWaveDef waveDef = parms.GetCustomRaidWave(); + int waveNumber = parms.GetCustomRaidWaveNumber(); + Faction faction = parms.faction; + + string waveName = waveDef?.label ?? waveDef?.defName ?? "Unknown"; + string baseText = $"A special attack wave {waveNumber + 1} - {waveName} from {faction.Name} is approaching!"; + + // 添加袭击策略信息 + if (parms.raidStrategy != null) + { + baseText += "\n\n" + parms.raidStrategy.arrivalTextEnemy; + } + + return baseText; + } + + protected override LetterDef GetLetterDef() + { + // 使用威胁大的信件定义 + return LetterDefOf.ThreatBig; + } + + protected override string GetRelatedPawnsInfoLetterText(IncidentParms parms) + { + // 如果有相关pawn的信息,返回相应的文本 + return "LetterRelatedPawnsRaid".Translate(Faction.OfPlayer.def.pawnsPlural, parms.faction.def.pawnsPlural); + } + + // 自定义方法 + private CustomRaidDef GetCustomRaidDef() + { + // 从 DefDatabase 获取自定义袭击定义 + return DefDatabase.GetNamedSilentFail("ARA_SpecialAttack"); + } + + private int CalculateRaidSize(int currentWave, CustomRaidDef raidDef) + { + int baseSize = raidDef.baseRaidNembers; + var growthConfig = raidDef.pointsGrowthPerWave; + + Log.Message($"Calculating raid size: base={baseSize}, wave={currentWave}, growthType={growthConfig.growthType}"); + + if (growthConfig.growthType == "Linear") + { + int result = baseSize + (int)(currentWave * growthConfig.linearGrowth); + Log.Message($"Linear growth: {baseSize} + ({currentWave} * {growthConfig.linearGrowth}) = {result}"); + return result; + } + else if (growthConfig.growthType == "Exponential") + { + int result = (int)(baseSize * System.Math.Pow(growthConfig.exponentialBase, currentWave)); + Log.Message($"Exponential growth: {baseSize} * {growthConfig.exponentialBase}^{currentWave} = {result}"); + return result; + } + + // 默认线性增长 + int defaultResult = baseSize + currentWave; + Log.Message($"Default growth: {baseSize} + {currentWave} = {defaultResult}"); + return defaultResult; + } + + private RaidWaveDef SelectWaveForSize(int raidSize, CustomRaidDef raidDef) + { + Log.Message($"Selecting wave for size: {raidSize}"); + + foreach (var poolRange in raidDef.pointWavePools) + { + bool minCondition = raidSize >= poolRange.minPoints; + bool maxCondition = poolRange.maxPoints >= 99999f || raidSize < poolRange.maxPoints; + + Log.Message($"Checking pool range: min={poolRange.minPoints}, max={poolRange.maxPoints}, matches={minCondition && maxCondition}"); + + if (minCondition && maxCondition) + { + var selectedWave = SelectWaveFromPool(poolRange.wavePool); + Log.Message($"Selected wave from pool {poolRange.wavePool.defName}: {selectedWave?.defName}"); + return selectedWave; + } + } + + // 如果没有匹配的区间,返回最后一个池 + if (raidDef.pointWavePools.Count > 0) + { + var lastPool = raidDef.pointWavePools[raidDef.pointWavePools.Count - 1]; + var selectedWave = SelectWaveFromPool(lastPool.wavePool); + Log.Message($"Selected wave from last pool {lastPool.wavePool.defName}: {selectedWave?.defName}"); + return selectedWave; + } + + Log.Error("No wave pools found in CustomRaidDef"); + return null; + } + + private RaidWaveDef SelectWaveFromPool(RaidWavePoolDef wavePool) + { + if (wavePool == null) + { + Log.Error("WavePool is null"); + return null; + } + + if (wavePool.waves.NullOrEmpty()) + { + Log.Error($"WavePool {wavePool.defName} has no waves"); + return null; + } + + // 如果有权重配置,使用权重随机 + if (wavePool.selectionWeights != null && wavePool.selectionWeights.Count > 0) + { + var weightedWaves = wavePool.waves.Where(w => wavePool.selectionWeights.ContainsKey(w.defName)).ToList(); + if (weightedWaves.Any()) + { + var selected = weightedWaves.RandomElementByWeight(waveDef => wavePool.selectionWeights[waveDef.defName]); + Log.Message($"Selected weighted wave: {selected.defName}"); + return selected; + } + } + + // 否则均匀随机 + var randomWave = wavePool.waves.RandomElement(); + Log.Message($"Selected random wave: {randomWave.defName}"); + return randomWave; + } + + private float CalculateThreatPoints(int raidSize) + { + // 根据袭击规模计算威胁点数 + // 这里可以基于原版的威胁点数计算逻辑进行调整 + float points = raidSize * 100f; + Log.Message($"Calculated threat points: {raidSize} * 100 = {points}"); + return points; + } + + // 重写生成pawn的方法,确保使用自定义波次定义 + public override void ResolveRaidArriveMode(IncidentParms parms) + { + if (parms.raidArrivalMode != null) + { + Log.Message($"Raid arrival mode already set: {parms.raidArrivalMode.defName}"); + return; + } + // 对于自定义袭击,默认使用边缘进入 + parms.raidArrivalMode = PawnsArrivalModeDefOf.EdgeWalkIn; + Log.Message($"Set raid arrival mode: {parms.raidArrivalMode.defName}"); + } + + // 可选:重写其他方法以提供更好的调试信息 + public override string ToString() + { + return base.ToString() + " (CustomRaid)"; + } + + public static void TestCustomRaid() + { + Map map = Find.CurrentMap; + if (map == null) + { + Log.Error("No current map found"); + return; + } + + IncidentDef raidIncident = DefDatabase.GetNamed("CustomRaidIncident"); + if (raidIncident != null) + { + var parms = StorytellerUtility.DefaultParmsNow(raidIncident.category, map); + bool success = raidIncident.Worker.TryExecute(parms); + Messages.Message(success ? "Custom raid test executed!" : "Custom raid test failed", + success ? MessageTypeDefOf.PositiveEvent : MessageTypeDefOf.NegativeEvent); + } + else + { + Log.Error("CustomRaidIncident not found"); + } + } + } +} diff --git a/Source/ArachnaeSwarm/Storyteller/RaidWaveDef.cs b/Source/ArachnaeSwarm/Storyteller/RaidWaveDef.cs new file mode 100644 index 0000000..800508b --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/RaidWaveDef.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Verse; + +namespace ArachnaeSwarm +{ + public class RaidWaveDef : Def + { + public List pawnComposition; + + public override IEnumerable ConfigErrors() + { + foreach (string error in base.ConfigErrors()) + { + yield return error; + } + + if (pawnComposition.NullOrEmpty()) + { + yield return "pawnComposition is empty"; + } + } + } + + public class PawnComposition + { + public PawnKindDef pawnKind; + public float ratio = 1f; + public int minCount = 0; + public int maxCount = 0; // 0表示无限制 + public bool DefaultUnit = false; + + public override string ToString() + { + return $"{pawnKind?.defName ?? "null"} (ratio: {ratio}, min: {minCount}, max: {maxCount}, default: {DefaultUnit})"; + } + } +} diff --git a/Source/ArachnaeSwarm/Storyteller/RaidWavePoolDef.cs b/Source/ArachnaeSwarm/Storyteller/RaidWavePoolDef.cs new file mode 100644 index 0000000..ff69b5f --- /dev/null +++ b/Source/ArachnaeSwarm/Storyteller/RaidWavePoolDef.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Verse; + +namespace ArachnaeSwarm +{ + public class RaidWavePoolDef : Def + { + public List waves; + public Dictionary selectionWeights; + + public override IEnumerable ConfigErrors() + { + foreach (string error in base.ConfigErrors()) + { + yield return error; + } + + if (waves.NullOrEmpty()) + { + yield return "waves list is empty"; + } + } + } +}