虫群的自定义袭击

This commit is contained in:
2025-10-16 17:04:41 +08:00
parent 446888d443
commit e42c88ef5a
21 changed files with 1205 additions and 67 deletions

View File

@@ -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": ""
}
]

View File

@@ -120,6 +120,12 @@
<Compile Include="EventSystem\Letter_EventChoice.cs" />
<Compile Include="EventSystem\QuestNode_Root_EventLetter.cs" />
<Compile Include="Jobs\JobDriver_CarryPrisonerToRefuelingVat.cs" />
<Compile Include="Storyteller\CustomRaidDef.cs" />
<Compile Include="Storyteller\CustomRaidTracker.cs" />
<Compile Include="Storyteller\IncidentParmsExtensions.cs" />
<Compile Include="Storyteller\IncidentWorker_CustomRaid.cs" />
<Compile Include="Storyteller\RaidWaveDef.cs" />
<Compile Include="Storyteller\RaidWavePoolDef.cs" />
<Compile Include="Verbs\Verb_ShootWithOffset.cs" />
<Compile Include="Abilities\ARA_ShowTemperatureRange\CompAbilityEffect_AbilityShowTemperatureRange.cs" />
<Compile Include="Abilities\ARA_ShowTemperatureRange\CompProperties_AbilityShowTemperatureRange.cs" />

View File

@@ -0,0 +1,51 @@
using RimWorld;
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public class CustomRaidDef : Def
{
public FactionDef factionDef;
public List<PointWavePool> pointWavePools;
public int baseRaidNembers;
public PointsGrowthPerWave pointsGrowthPerWave;
public override IEnumerable<string> 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;
}
}

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public class CustomRaidTracker : GameComponent
{
private Dictionary<string, int> waveCounters = new Dictionary<string, int>();
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<string, int>();
}
}
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();
}
}
}

View File

@@ -0,0 +1,111 @@
using RimWorld;
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public static class IncidentParmsExtensions
{
// 使用静态字典来存储自定义数据
private static Dictionary<IncidentParms, CustomRaidData> customRaidData = new Dictionary<IncidentParms, CustomRaidData>();
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;
}
}
}

View File

@@ -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<CustomRaidTracker>();
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<Pawn> 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<CustomRaidDef>.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<IncidentDef>.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");
}
}
}
}

View File

@@ -0,0 +1,37 @@
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public class RaidWaveDef : Def
{
public List<PawnComposition> pawnComposition;
public override IEnumerable<string> 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})";
}
}
}

View File

@@ -0,0 +1,24 @@
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public class RaidWavePoolDef : Def
{
public List<RaidWaveDef> waves;
public Dictionary<string, float> selectionWeights;
public override IEnumerable<string> ConfigErrors()
{
foreach (string error in base.ConfigErrors())
{
yield return error;
}
if (waves.NullOrEmpty())
{
yield return "waves list is empty";
}
}
}
}