三大系统

This commit is contained in:
Tourswen
2025-12-16 02:13:18 +08:00
parent 15404222fd
commit b17407b53f
55 changed files with 4892 additions and 644 deletions

View File

@@ -0,0 +1,438 @@
// File: Need_ChitinArmor.cs
using RimWorld;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class NeedDefExtension_ChitinLevels : DefModExtension
{
// 关联的Hediff
public HediffDef hediff = null;
// 严重性映射范围默认是1:1映射即Need值=严重性值)
[XmlElement("severityRange")]
public FloatRange severityRange = new FloatRange(0f, 1f);
// 是否死亡时移除Hediff
public bool removeOnDeath = true;
// 基础增长速率系数
public float baseGrowthRate = 0.1f;
// 甲壳数量平方的系数
public float squareCoefficient = 1f / 100f; // 默认 1/100
}
public class Need_ChitinArmor : Need
{
// 甲壳增长基础值每tick
private const float BaseChitinGainPerTick = 0.0001f;
// 关联的Hediff
private Hediff chitinHediff;
// 上次更新Hediff的时间
private int lastHediffUpdateTick = -99999;
private const int HediffUpdateInterval = 60; // 每60tick更新一次Hediff
// 甲壳部位名称
private const string CHITIN_SHELL_PART_NAME = "ARA_Chitin_Shell";
// 缓存的身体部位数量(用于减少计算)
private int cachedShellPartCount = -1;
private int lastPartCountCheckTick = -99999;
private const int PartCountCheckInterval = 120; // 每120tick检查一次
// 获取ModExtension配置
public NeedDefExtension_ChitinLevels Extension => def.GetModExtension<NeedDefExtension_ChitinLevels>();
// 计算甲壳最大值基础值1 + 每个ARA_Chitin_Shell部位增加1
public override float MaxLevel
{
get
{
int shellCount = GetChitinShellPartCount();
return 1f + shellCount;
}
}
// 获取当前等级百分比用于UI显示
public new float CurLevelPercentage => CurLevel / MaxLevel;
// 获取甲壳增长速率
public float GrowthRatePerTick
{
get
{
int shellCount = GetChitinShellPartCount();
// 计算增长速率:((甲壳数量的平方) * 系数) + 基础值
float squareCoefficient = Extension?.squareCoefficient ?? (1f / 100f);
float baseRate = Extension?.baseGrowthRate ?? 0.1f;
return ((shellCount * shellCount) * squareCoefficient) + baseRate;
}
}
// 获取每秒增长速率用于UI显示
public float GrowthRatePerSecond
{
get
{
// RimWorld中1秒 = 60ticks
// 实际每秒增长量 = 每tick增长速率 * 60
// 注意BaseChitinGainPerTick是基础增长值GrowthRatePerTick是增长系数
// 实际增长公式每tick增长量 = BaseChitinGainPerTick * GrowthRatePerTick
// 所以每秒增长量 = BaseChitinGainPerTick * GrowthRatePerTick * 60
return BaseChitinGainPerTick * GrowthRatePerTick * 60f;
}
}
// 获取每2.5秒增长速率用于UI显示每150tick
public float GrowthRatePer2_5Seconds => GrowthRatePerSecond * 2.5f;
public Need_ChitinArmor(Pawn newPawn) : base(newPawn)
{
// 初始化时设置为空
curLevelInt = 0f;
// 设置默认阈值点
SetDefaultThresholds();
// 初始化缓存
UpdateCachedShellPartCount();
}
public override void ExposeData()
{
base.ExposeData();
Scribe_References.Look(ref chitinHediff, "chitinHediff");
Scribe_Values.Look(ref cachedShellPartCount, "cachedShellPartCount", -1);
Scribe_Values.Look(ref lastPartCountCheckTick, "lastPartCountCheckTick", -99999);
}
private void SetDefaultThresholds()
{
// 默认阈值25%、50%、75%用于UI显示
threshPercents = new List<float> { 0.25f, 0.5f, 0.75f };
}
public override void NeedInterval()
{
// 检查是否需要冻结
if (IsFrozen)
{
return;
}
// 定期更新身体部位数量缓存
int currentTick = Find.TickManager.TicksGame;
if (currentTick - lastPartCountCheckTick >= PartCountCheckInterval)
{
UpdateCachedShellPartCount();
lastPartCountCheckTick = currentTick;
}
// 计算增长量:基础增长速率 * 每150tick的间隔 * 甲壳增长速率系数
float growthAmount = BaseChitinGainPerTick * 150f * GrowthRatePerTick;
// 应用增长
CurLevel += growthAmount;
// 确保不超过最大值不低于0
float maxLevel = MaxLevel; // 计算一次并缓存
if (CurLevel > maxLevel)
CurLevel = maxLevel;
else if (CurLevel < 0f)
CurLevel = 0f;
// 定期更新Hediff每60tick一次
if (currentTick - lastHediffUpdateTick >= HediffUpdateInterval)
{
UpdateChitinHediff();
lastHediffUpdateTick = currentTick;
}
}
// 获取ARA_Chitin_Shell身体部位的数量
private int GetChitinShellPartCount()
{
// 使用缓存值(如果有效)
if (cachedShellPartCount >= 0 && pawn != null && !pawn.Dead)
{
return cachedShellPartCount;
}
// 重新计算
UpdateCachedShellPartCount();
return cachedShellPartCount;
}
// 更新缓存的身体部位数量
private void UpdateCachedShellPartCount()
{
if (pawn == null || pawn.Dead || pawn.RaceProps == null || pawn.RaceProps.body == null)
{
cachedShellPartCount = 0;
return;
}
// 计算身体部位数量
int count = 0;
// 方法1从pawn的身体部位记录中查找
foreach (BodyPartRecord part in pawn.RaceProps.body.AllParts)
{
if (part.def.defName == CHITIN_SHELL_PART_NAME)
{
count++;
}
}
// 方法2如果找不到检查Hediff中是否有甲壳作为备用方法
if (count == 0 && pawn.health != null && pawn.health.hediffSet != null)
{
foreach (Hediff hediff in pawn.health.hediffSet.hediffs)
{
if (hediff.Part != null && hediff.Part.def != null &&
hediff.Part.def.defName == CHITIN_SHELL_PART_NAME)
{
count++;
}
}
}
cachedShellPartCount = count;
}
// 重新计算身体部位数量(当身体发生变化时调用)
public void RecalculateShellPartCount()
{
UpdateCachedShellPartCount();
}
// 更新甲壳Hediff
private void UpdateChitinHediff()
{
if (Extension == null || Extension.hediff == null || pawn.Dead)
return;
// 直接使用CurLevel作为严重性但可以根据配置的范围进行调整
float severity = CurLevel;
// 如果需要,可以应用范围限制
FloatRange severityRange = Extension.severityRange;
if (severity > severityRange.max)
severity = severityRange.max;
else if (severity < severityRange.min)
severity = severityRange.min;
// 如果严重性为0或接近0移除Hediff
if (severity <= 0.001f)
{
RemoveChitinHediff();
return;
}
// 确保Hediff存在
EnsureChitinHediff();
// 设置严重性
if (chitinHediff != null)
{
chitinHediff.Severity = severity;
}
}
// 确保Hediff存在
private void EnsureChitinHediff()
{
if (chitinHediff == null || chitinHediff.pawn != pawn)
{
// 移除旧的Hediff
if (chitinHediff != null && chitinHediff.pawn == pawn)
{
pawn.health.RemoveHediff(chitinHediff);
}
// 创建新的Hediff
chitinHediff = HediffMaker.MakeHediff(Extension.hediff, pawn);
pawn.health.AddHediff(chitinHediff);
}
}
// 移除Hediff
private void RemoveChitinHediff()
{
if (chitinHediff != null && chitinHediff.pawn == pawn)
{
pawn.health.RemoveHediff(chitinHediff);
chitinHediff = null;
}
}
// 减少甲壳存量(例如受伤时)
public void ReduceChitin(float amount)
{
CurLevel -= amount;
if (CurLevel < 0f)
CurLevel = 0f;
// 立即更新Hediff
UpdateChitinHediff();
}
// 强制清空甲壳
public void EmptyChitin()
{
CurLevel = 0f;
RemoveChitinHediff();
}
// 重置到初始状态
public override void SetInitialLevel()
{
// 初始为空
CurLevel = 0f;
RemoveChitinHediff();
UpdateCachedShellPartCount();
}
// 获取当前严重性
public float GetCurrentSeverity()
{
if (chitinHediff == null)
return 0f;
return chitinHediff.Severity;
}
// 获取提示字符串
public override string GetTipString()
{
string text = (LabelCap + ": " + CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor);
text += "\n" + def.description;
int shellCount = GetChitinShellPartCount();
text += $"\n{"ARA_Chitin.ShellParts".Translate()}: {shellCount}";
// 显示每秒增长速率(更直观)
text += $"\n{"ARA_Chitin.GrowthRate".Translate()}: {GrowthRatePerSecond:0.#####}/ {"LetterSecond".Translate()}";
return text;
}
// 在UI上绘制
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
{
// 确保阈值已设置
if (threshPercents == null)
{
SetDefaultThresholds();
}
base.DrawOnGUI(rect, maxThresholdMarkers, customMargin, false, doTooltip, rectForTooltip, drawLabel);
}
// 是否冻结
protected override bool IsFrozen
{
get
{
// 如果基础条件冻结,则甲壳生长也冻结
if (base.IsFrozen)
return true;
// 如果生物死亡,则冻结
if (pawn.Dead)
return true;
return false;
}
}
// GUI变化箭头总是显示增长
public override int GUIChangeArrow => 1;
// 调试调整百分比
protected override void OffsetDebugPercent(float offsetPercent)
{
base.OffsetDebugPercent(offsetPercent);
UpdateChitinHediff();
}
// 当生物死亡时清理Hediff
public void OnPawnDeath()
{
if (Extension?.removeOnDeath ?? true)
{
RemoveChitinHediff();
}
}
// 当生物重生时恢复Hediff
public void OnPawnResurrected()
{
if (CurLevel > 0f && Extension?.hediff != null)
{
UpdateChitinHediff();
}
UpdateCachedShellPartCount();
}
// 当身体部位发生变化时调用
public void NotifyBodyPartChanged()
{
UpdateCachedShellPartCount();
// 如果最大容量减少,确保当前值不超过新最大值
if (CurLevel > MaxLevel)
{
CurLevel = MaxLevel;
UpdateChitinHediff();
}
}
public Comp_ChitinStripping GetStripComp()
{
if (pawn == null)
return null;
return pawn.TryGetComp<Comp_ChitinStripping>();
}
// 获取是否可以剥离
public bool CanStripChitin()
{
var stripComp = GetStripComp();
if (stripComp == null)
return false;
return stripComp.CanStripNow(pawn);
}
// 获取剥离信息字符串
public string GetStripInfoString()
{
var stripComp = GetStripComp();
if (stripComp == null)
return "ARA_ChitinStripping_Disabled".Translate();
if (!stripComp.CanStripNow(pawn))
{
int cooldownTicks = stripComp.CooldownTicksRemaining;
if (cooldownTicks > 0)
{
float cooldownSeconds = cooldownTicks / 60f;
return "ARA_ChitinStripping_Cooldown".Translate(cooldownSeconds.ToString("F1"));
}
else
{
return "ARA_ChitinStripping_Threshold".Translate((stripComp.StripThreshold * 100f).ToString("F0"));
}
}
return "ARA_ChitinStripping_Ready".Translate();
}
}
}

View File

@@ -1,13 +1,52 @@
// File: Need_HoneyProduction.cs
using RimWorld;
using UnityEngine;
using Verse;
namespace ArachnaeSwarm
{
public class HoneyProductionExtension : DefModExtension
{
// 蜜罐生产的基础转化率(相对于食物流失的百分比)
public float baseConversionRate = 0.5f;
// 最大蜜罐容量(可选,覆盖默认值)
public float maxHoneyCapacity = 1f;
// 是否启用蜜罐生产
public bool enableHoneyProduction = true;
// 生产速率乘数(影响生产速度)
public float productionSpeedFactor = 1f;
// 蜜罐类别对应的生产效率(可选,覆盖默认值)
public float fullProductionEfficiency = 1.5f;
public float highProductionEfficiency = 1.2f;
public float mediumProductionEfficiency = 1f;
public float lowProductionEfficiency = 0.5f;
public float emptyProductionEfficiency = 0f;
// 生产间隔ticks可选覆盖默认值
public int productionInterval = 150;
public static HoneyProductionExtension Get(Pawn pawn)
{
if (pawn?.def?.GetModExtension<HoneyProductionExtension>() is HoneyProductionExtension ext)
return ext;
return null;
}
// 获取转化率
public float GetConversionRate()
{
return baseConversionRate * productionSpeedFactor;
}
}
public class Need_HoneyProduction : Need
{
// 基础流失速率(与食物需要对应)
private const float BaseHoneyGainPerTick = 2.6666667E-05f * 0.5f; // 食物流失速率的50%
private const float BaseHoneyGainPerTick = 2.6666667E-05f * 0.5f; // 食物流失速率的50%作为默认值
// 用于存储对食物需要的引用
private Need_Food cachedFoodNeed;
@@ -18,8 +57,22 @@ namespace ArachnaeSwarm
// 上次满的时间点
private int lastFullTick = -99999;
// 蜜罐的最大容量(可能需要调整)
public override float MaxLevel => 1f;
// 缓存的ModExtension
private HoneyProductionExtension cachedExtension;
// 蜜罐的最大容量 - 优先使用ModExtension的值
public override float MaxLevel
{
get
{
var ext = GetExtension();
if (ext != null && ext.maxHoneyCapacity > 0)
{
return ext.maxHoneyCapacity;
}
return FoodNeed?.MaxLevel ?? 1f;
}
}
// 当前类别
public HoneyProductionCategory CurCategory => curCategoryInt;
@@ -35,6 +88,29 @@ namespace ArachnaeSwarm
{
get
{
var ext = GetExtension();
// 如果有扩展定义,使用扩展的值
if (ext != null)
{
switch (curCategoryInt)
{
case HoneyProductionCategory.Full:
return ext.fullProductionEfficiency;
case HoneyProductionCategory.High:
return ext.highProductionEfficiency;
case HoneyProductionCategory.Medium:
return ext.mediumProductionEfficiency;
case HoneyProductionCategory.Low:
return ext.lowProductionEfficiency;
case HoneyProductionCategory.Empty:
return ext.emptyProductionEfficiency;
default:
return 0f;
}
}
// 默认值
switch (curCategoryInt)
{
case HoneyProductionCategory.Full:
@@ -53,12 +129,32 @@ namespace ArachnaeSwarm
}
}
// 获取扩展
private HoneyProductionExtension GetExtension()
{
if (cachedExtension == null && pawn != null)
{
cachedExtension = pawn.def?.GetModExtension<HoneyProductionExtension>();
}
return cachedExtension;
}
// 是否启用蜜罐生产
private bool IsEnabled
{
get
{
var ext = GetExtension();
return ext == null || ext.enableHoneyProduction; // 默认启用
}
}
// 获取食物需要的引用
private Need_Food FoodNeed
{
get
{
if (cachedFoodNeed == null || cachedFoodNeed.pawn != pawn)
if (cachedFoodNeed == null)
{
cachedFoodNeed = pawn.needs?.TryGetNeed<Need_Food>();
}
@@ -86,7 +182,9 @@ namespace ArachnaeSwarm
public override void NeedInterval()
{
base.NeedInterval();
// 如果不启用,直接返回
if (!IsEnabled)
return;
// 检查是否需要冻结(与食物需要类似的条件)
if (IsFrozen)
@@ -97,11 +195,21 @@ namespace ArachnaeSwarm
// 获取食物需要的流失速率
float foodFallRate = GetFoodFallRate();
// 蜜罐的增长速率是食物流失速率的50%
float honeyGainRate = foodFallRate * 0.5f;
// 获取转化率从ModExtension或使用默认值
float conversionRate = GetExtension()?.GetConversionRate() ?? 0.5f;
// 应用150 ticks的间隔
CurLevel += honeyGainRate * 150f;
// 蜜罐的增长速率 = 食物流失速率 × 转化率
float honeyGainRate = foodFallRate * conversionRate;
// 获取生产间隔
int interval = GetExtension()?.productionInterval ?? 150;
// 应用间隔
CurLevel += honeyGainRate * interval;
// 确保不超过最大容量
if (CurLevel > MaxLevel)
CurLevel = MaxLevel;
// 更新类别
UpdateCategory();
@@ -172,15 +280,39 @@ namespace ArachnaeSwarm
{
string text = (LabelCap + ": " + CurLevelPercentage.ToStringPercent()).Colorize(ColoredText.TipSectionTitleColor);
text += "\n" + def.description;
text += $"\n\n{"AS.HoneyProduction.CurrentLevel".Translate()}: {CurLevel:0.##} / {MaxLevel:0.##}";
text += $"\n{"AS.HoneyProduction.Category".Translate()}: {GetCategoryLabel().CapitalizeFirst()}";
text += $"\n{"AS.HoneyProduction.Efficiency".Translate()}: {ProductionEfficiency.ToStringPercent()}";
text += $"\n{"AS.HoneyProduction.FoodDrainRate".Translate()}: {GetFoodFallRate():0.#####}/tick";
text += $"\n{"AS.HoneyProduction.HoneyGainRate".Translate()}: {(GetFoodFallRate() * 0.5f):0.#####}/tick";
text += $"\n{"ARA_HoneyProduction.Efficiency".Translate()} {ProductionEfficiency.ToStringPercent()}";
// 获取每tick的速率
float foodFallPerTick = GetFoodFallRate();
float conversionRate = GetExtension()?.GetConversionRate() ?? 0.5f;
float honeyGainPerTick = foodFallPerTick * conversionRate;
// 转换为每秒1秒 = 60tick
float foodFallPerSecond = foodFallPerTick * 60f;
float honeyGainPerSecond = honeyGainPerTick * 60f;
text += $"\n{"ARA_HoneyProduction.FoodDrainRate".Translate()}: {foodFallPerSecond:0.#####}/ {"LetterSecond".Translate()}";
text += $"\n{"ARA_HoneyProduction.HoneyGainRate".Translate()}: {honeyGainPerSecond:0.#####}/ {"LetterSecond".Translate()}";
// 显示转化率信息
if (GetExtension() != null)
{
text += $"\n{"ARA_HoneyProduction.ConversionRate".Translate()}: {conversionRate:P1}";
if (GetExtension().productionSpeedFactor != 1f)
{
text += $"\n{"ARA_HoneyProduction.SpeedFactor".Translate()}: {GetExtension().productionSpeedFactor:F2}";
}
}
if (IsFull)
{
text += $"\n\n{"AS.HoneyProduction.FullWarning".Translate()}";
text += $"\n\n{"ARA_HoneyProduction.FullWarning".Translate()}";
}
// 显示是否启用
if (!IsEnabled)
{
text += $"\n\n<color=orange>{"ARA_HoneyProduction.Disabled".Translate()}</color>";
}
return text;
@@ -192,15 +324,15 @@ namespace ArachnaeSwarm
switch (curCategoryInt)
{
case HoneyProductionCategory.Full:
return "AS.HoneyProduction.Full".Translate();
return "ARA_HoneyProduction.Full".Translate();
case HoneyProductionCategory.High:
return "AS.HoneyProduction.High".Translate();
return "ARA_HoneyProduction.High".Translate();
case HoneyProductionCategory.Medium:
return "AS.HoneyProduction.Medium".Translate();
return "ARA_HoneyProduction.Medium".Translate();
case HoneyProductionCategory.Low:
return "AS.HoneyProduction.Low".Translate();
return "ARA_HoneyProduction.Low".Translate();
case HoneyProductionCategory.Empty:
return "AS.HoneyProduction.Empty".Translate();
return "ARA_HoneyProduction.Empty".Translate();
default:
return "Unknown";
}
@@ -209,6 +341,10 @@ namespace ArachnaeSwarm
// 在UI上绘制
public override void DrawOnGUI(Rect rect, int maxThresholdMarkers = int.MaxValue, float customMargin = -1f, bool drawArrows = true, bool doTooltip = true, Rect? rectForTooltip = null, bool drawLabel = true)
{
// 如果不启用,不显示
if (!IsEnabled)
return;
if (threshPercents == null)
{
threshPercents = new System.Collections.Generic.List<float>
@@ -229,10 +365,6 @@ namespace ArachnaeSwarm
if (base.IsFrozen)
return true;
// 如果没有食物需要,或者食物需要被冻结,则蜜罐生产也冻结
if (FoodNeed == null || FoodNeed.IsFrozen)
return true;
// 如果生物死亡,则冻结
if (pawn.Dead)
return true;
@@ -242,7 +374,7 @@ namespace ArachnaeSwarm
}
// GUI变化箭头总是显示增长
public override int GUIChangeArrow => 1;
public override int GUIChangeArrow => IsEnabled ? 1 : 0;
// 调试调整百分比
protected override void OffsetDebugPercent(float offsetPercent)