This commit is contained in:
Tourswen
2025-12-19 03:08:16 +08:00
parent ad42832aa7
commit 6d7ac8f054
45 changed files with 2187 additions and 1403 deletions

View File

@@ -1,4 +1,3 @@
// File: Buildings/Building_EquipmentOotheca.cs
using RimWorld;
using System.Collections.Generic;
using System.Text;
@@ -34,23 +33,9 @@ namespace ArachnaeSwarm
private float qualityProgress = 0f;
private float qualityTotal = 0f;
// === 修复后的营养液消耗相关字段 ===
private int totalNutrientCost = 0; // 总共需要的营养液地块数量
private int consumedNutrientCount = 0; // 已消耗的营养液地块数量
private int lastConsumeCheckTick = -1; // 上次检查消耗的时间
private const int ConsumeCheckInterval = 250; // 检查间隔tick
private List<IntVec3> consumedCells = new List<IntVec3>(); // 已消耗的单元格记录
private bool isConsuming = false; // 是否正在消耗营养液
private int consecutiveFailedConsumptions = 0; // 连续失败的消耗次数
private const int MaxConsecutiveFailures = 10; // 最大连续失败次数,超过则暂停检查
private bool nutrientDeficiencyPause = false; // 是否因营养液不足而暂停
// === 新增属性 ===
public int TotalNutrientCost => totalNutrientCost;
public int ConsumedNutrientCount => consumedNutrientCount;
public float NutrientProgress => totalNutrientCost > 0 ? (float)consumedNutrientCount / totalNutrientCost : 0f;
public bool HasEnoughNutrients => consumedNutrientCount >= totalNutrientCost;
public bool IsConsuming => isConsuming;
// === 简化后的营养液系统:只用于速度加成,不消耗 ===
private int totalNutrientCost = 0; // 总共需要的营养液地块数量(仅用于信息显示)
private int currentNutrientCount = 0; // 当前周围存在的营养液数量
// 缓存的ModExtension
private OothecaIncubatorExtension cachedExtension;
@@ -86,6 +71,10 @@ namespace ArachnaeSwarm
public float QualityProgress => qualityProgress;
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
// 营养液加成属性
public int CurrentNutrientCount => currentNutrientCount;
public float NutrientSpeedBonus => currentNutrientCount * Ext.nutrientSolutionBonusPerTile;
// 进度百分比
public float AdjustedProgressPercent
{
@@ -96,288 +85,30 @@ namespace ArachnaeSwarm
}
}
// === 修复后的初始化营养液消耗方法 ===
private void InitializeNutrientConsumption()
// === 简化的初始化营养液方法 ===
private void InitializeNutrientInfo()
{
if (incubatingThingDef == null)
return;
// 获取孵化成本统计值
// 获取孵化成本统计值(仅用于信息显示)
var costStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationCost");
if (costStat != null)
{
totalNutrientCost = Mathf.RoundToInt(incubatingThingDef.GetStatValueAbstract(costStat, null));
Log.Message($"[ARA] 初始化营养液消耗: {incubatingThingDef.defName} 需要 {totalNutrientCost} 个营养液地块");
Log.Message($"[ARA] 孵化 {incubatingThingDef.defName} 建议有 {totalNutrientCost} 个营养液地块以获得最佳速度");
}
else
{
totalNutrientCost = 0;
Log.Message($"[ARA] 孵化 {incubatingThingDef.defName} 不需要营养液");
Log.Message($"[ARA] 孵化 {incubatingThingDef.defName} 不需要营养液加成");
}
consumedNutrientCount = 0;
consumedCells.Clear();
isConsuming = true; // 立即开始消耗
consecutiveFailedConsumptions = 0;
nutrientDeficiencyPause = false;
// 立即检查一次营养液
lastConsumeCheckTick = Find.TickManager.TicksGame - ConsumeCheckInterval; // 强制立即检查
// 立即更新一次营养液计数
UpdateNutrientCount();
}
// === 修复后的检查并消耗营养液方法 ===
private void CheckAndConsumeNutrients()
{
if (!isIncubating || incubatingThingDef == null)
return;
// 如果已经满足需求,停止消耗
if (HasEnoughNutrients)
{
if (isConsuming)
{
Log.Message($"[ARA] 营养液需求已满足: {consumedNutrientCount}/{totalNutrientCost}");
isConsuming = false;
nutrientDeficiencyPause = false; // 重置暂停标志
}
return;
}
// 计算需要消耗的数量(基于当前进度)
float targetProgress = AdjustedProgressPercent;
int targetConsumed = Mathf.RoundToInt(targetProgress * totalNutrientCost);
int toConsume = Mathf.Max(1, targetConsumed - consumedNutrientCount);
if (toConsume <= 0)
return;
// 查找可消耗的营养液单元格
List<IntVec3> availableCells = FindNutrientCells();
if (availableCells.Count == 0)
{
consecutiveFailedConsumptions++;
nutrientDeficiencyPause = true; // 设置为暂停
// 如果没有找到营养液,检查是否应该应用伤害
if (Ext.nutrientDeficiencyDamageEnabled && toConsume > 0)
{
ApplyNutrientDeficiencyDamage();
// 显示消息(频率控制)
if (Find.TickManager.TicksGame % 2000 == 0 && Rand.Chance(0.3f))
{
Messages.Message("ARA_EquipmentIncubator.NoNutrientsFound".Translate(),
this, MessageTypeDefOf.NegativeEvent);
}
Log.Warning($"[ARA] 未找到营养液,连续失败次数: {consecutiveFailedConsumptions}");
}
return;
}
// 重置失败计数和暂停标志
consecutiveFailedConsumptions = 0;
nutrientDeficiencyPause = false; // 有营养液可用,取消暂停
// 开始消耗
int consumedThisTick = 0;
for (int i = 0; i < Mathf.Min(toConsume, availableCells.Count); i++)
{
if (ConsumeNutrientCell(availableCells[i]))
{
consumedThisTick++;
consumedNutrientCount++;
consumedCells.Add(availableCells[i]);
if (HasEnoughNutrients)
break;
}
}
if (consumedThisTick > 0)
{
Log.Message($"[ARA] 消耗了 {consumedThisTick} 个营养液,总计: {consumedNutrientCount}/{totalNutrientCost}");
// 显示消息
if (consumedThisTick > 0 && Find.TickManager.TicksGame % 1000 == 0)
{
Messages.Message($"ARA_EquipmentIncubator.NutrientConsumed".Translate(consumedThisTick, consumedNutrientCount, totalNutrientCost),
this, MessageTypeDefOf.SilentInput);
}
// 如果达到需求,显示完成消息
if (HasEnoughNutrients)
{
Messages.Message("ARA_EquipmentIncubator.NutrientRequirementsMet".Translate(),
this, MessageTypeDefOf.PositiveEvent);
}
}
}
// === 修复后的应用营养液不足伤害方法 ===
private void ApplyNutrientDeficiencyDamage()
{
if (Ext.nutrientDeficiencyDamageAmount <= 0f || Ext.nutrientDamageType == null)
return;
try
{
// 计算实际伤害量
float damageAmount = Ext.nutrientDeficiencyDamageAmount;
// 如果建筑血量已经很低,减少伤害以避免立即摧毁
float healthPercent = (float)HitPoints / MaxHitPoints;
if (healthPercent < 0.3f)
{
damageAmount *= 0.5f; // 血量低于30%时,伤害减半
}
if (healthPercent < 0.1f)
{
damageAmount *= 0.2f; // 血量低于10%时伤害减为20%
}
// 应用伤害
DamageInfo damageInfo = new DamageInfo(
Ext.nutrientDamageType,
damageAmount,
armorPenetration: 0,
angle: -1f,
instigator: null,
hitPart: null,
weapon: null,
category: DamageInfo.SourceCategory.ThingOrUnknown,
intendedTarget: this
);
TakeDamage(damageInfo);
// 显示伤害消息(几率性)
if (Ext.showDamageMessages && Rand.Chance(Ext.damageMessageChance))
{
Messages.Message("ARA_EquipmentIncubator.NutrientDeficiencyDamage".Translate(damageAmount.ToString("F1")),
this, MessageTypeDefOf.NegativeEvent);
}
// 更新质量乘数(因为血量变化会影响质量)
UpdateQualityMultiplier();
}
catch (Exception ex)
{
Log.Error($"Failed to apply nutrient deficiency damage: {ex.Message}");
}
}
// === 修复后的查找营养液单元格方法 ===
public List<IntVec3> FindNutrientCells()
{
List<IntVec3> availableCells = new List<IntVec3>();
var map = Map;
if (map == null)
return availableCells;
// 使用ModExtension中定义的营养液检测半径
int searchRadius = Ext.NutrientSolutionRadiusInt;
TerrainDef nutrientDef = DefDatabase<TerrainDef>.GetNamedSilentFail("ARA_Incubator_Nutrient_Solution");
if (nutrientDef == null)
{
Log.Error("[ARA] 未找到营养液地形定义: ARA_Incubator_Nutrient_Solution");
return availableCells;
}
// 优化搜索:先从内圈开始,逐步扩大
int minRadius = 1; // 最小搜索半径
int currentRadius = Mathf.Min(searchRadius, Mathf.Max(minRadius, consecutiveFailedConsumptions + 1));
for (int x = -currentRadius; x <= currentRadius; x++)
{
for (int z = -currentRadius; z <= currentRadius; z++)
{
IntVec3 cell = Position + new IntVec3(x, 0, z);
// 排除自己的位置和已消耗的单元格
if (cell == Position || consumedCells.Contains(cell))
continue;
// 检查是否在边界内
if (cell.InBounds(map))
{
TerrainDef terrain = map.terrainGrid.TerrainAt(cell);
if (terrain == nutrientDef)
{
availableCells.Add(cell);
}
}
}
}
// 随机排序,避免总是从固定位置开始消耗
if (availableCells.Count > 1)
{
availableCells.Shuffle();
}
return availableCells;
}
// === 修复后的消耗单个营养液单元格方法 ===
private bool ConsumeNutrientCell(IntVec3 cell)
{
var map = Map;
if (map == null)
return false;
// 获取目标地貌定义
TerrainDef insectCreepDef = DefDatabase<TerrainDef>.GetNamedSilentFail("ARA_InsectCreep");
TerrainDef nutrientDef = DefDatabase<TerrainDef>.GetNamedSilentFail("ARA_Incubator_Nutrient_Solution");
if (insectCreepDef == null || nutrientDef == null)
return false;
// 记录原来的地貌
TerrainDef originalTerrain = map.terrainGrid.TerrainAt(cell);
// 转换为昆虫爬行地貌
map.terrainGrid.SetTerrain(cell, insectCreepDef);
// 创建营养液蓝图
try
{
// 使用PlaceBlueprintForBuild方法创建蓝图
Blueprint_Build blueprint = GenConstruct.PlaceBlueprintForBuild(
nutrientDef,
cell,
map,
Rot4.North,
Faction.OfPlayer,
null
);
if (blueprint != null)
{
// 显示转换效果
if (Find.TickManager.TicksGame % 10 == 0)
{
MoteMaker.ThrowText(cell.ToVector3Shifted(), map,
"ARA_Consumed".Translate(), Color.yellow);
}
return true;
}
}
catch (Exception ex)
{
Log.Error($"Failed to place nutrient solution blueprint at {cell}: {ex.Message}");
// 如果蓝图放置失败,恢复原貌
map.terrainGrid.SetTerrain(cell, originalTerrain);
return false;
}
return false;
}
// === 修复后的Tick方法 ===
// === 简化的Tick方法 ===
protected override void Tick()
{
base.Tick();
@@ -396,39 +127,11 @@ namespace ArachnaeSwarm
UpdateQualityMultiplier();
}
// 检查营养液消耗
if (lastConsumeCheckTick < 0 || Find.TickManager.TicksGame - lastConsumeCheckTick >= ConsumeCheckInterval)
{
lastConsumeCheckTick = Find.TickManager.TicksGame;
CheckAndConsumeNutrients();
}
float currentSpeed = SpeedMultiplier;
// 决定是否应该增加进度
bool shouldProgress = true;
// 检查是否因营养液不足而暂停
if (Ext.stopIncubationWhenNutrientDeficient &&
totalNutrientCost > 0 &&
!HasEnoughNutrients &&
nutrientDeficiencyPause)
{
shouldProgress = false;
// 显示暂停消息(频率控制)
if (Find.TickManager.TicksGame % 2000 == 0 && Rand.Chance(0.2f))
{
Messages.Message("ARA_EquipmentIncubator.IncubationPausedNoNutrients".Translate(incubatingThingDef?.LabelCap ?? "Unknown"),
this, MessageTypeDefOf.NeutralEvent);
}
}
if (shouldProgress)
{
incubationProgress += currentSpeed;
qualityProgress += currentSpeed * QualityMultiplier;
}
// 始终增加进度(不再有营养液不足的暂停)
incubationProgress += currentSpeed;
qualityProgress += currentSpeed * QualityMultiplier;
if (incubationProgress >= incubationDuration)
{
@@ -458,7 +161,7 @@ namespace ArachnaeSwarm
int nutrientSolutionCount = CountNearbyNutrientSolutions();
if (nutrientSolutionCount > 0)
{
builder.AppendLine("ARA_EquipmentIncubator.NutrientSolutions".Translate(
builder.AppendLine("ARA_EquipmentIncubator.NutrientSolutionsBonus".Translate(
nutrientSolutionCount,
nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile * 100));
}
@@ -522,39 +225,34 @@ namespace ArachnaeSwarm
return builder.ToString().TrimEndNewlines();
}
// === 获取营养液消耗描述 ===
public string GetNutrientConsumptionDescription()
// === 获取营养液信息描述 ===
public string GetNutrientInfoDescription()
{
var builder = new StringBuilder();
builder.AppendLine("ARA_EquipmentIncubator.NutrientConsumption".Translate());
builder.AppendLine("ARA_EquipmentIncubator.NutrientInfo".Translate());
builder.AppendLine();
if (totalNutrientCost == 0)
{
builder.AppendLine("ARA_EquipmentIncubator.NoNutrientCost".Translate());
return builder.ToString().TrimEndNewlines();
}
// 显示当前营养液数量和加成
builder.AppendLine("ARA_EquipmentIncubator.CurrentNutrientCount".Translate(currentNutrientCount));
builder.AppendLine("ARA_EquipmentIncubator.NutrientSpeedBonus".Translate(NutrientSpeedBonus.ToStringPercent()));
builder.AppendLine("ARA_EquipmentIncubator.NutrientRequirement".Translate(totalNutrientCost));
builder.AppendLine("ARA_EquipmentIncubator.NutrientConsumed".Translate(consumedNutrientCount));
builder.AppendLine("ARA_EquipmentIncubator.NutrientProgress".Translate(NutrientProgress.ToStringPercent()));
if (HasEnoughNutrients)
// 显示建议的营养液数量
if (totalNutrientCost > 0 && incubatingThingDef != null)
{
builder.AppendLine();
builder.AppendLine("ARA_EquipmentIncubator.NutrientRequirementsMet".Translate());
}
else if (isConsuming)
{
builder.AppendLine();
builder.AppendLine("ARA_EquipmentIncubator.ConsumingNutrients".Translate());
}
if (nutrientDeficiencyPause)
{
builder.AppendLine();
builder.AppendLine("ARA_EquipmentIncubator.NutrientDeficiencyPaused".Translate());
builder.AppendLine("ARA_EquipmentIncubator.RecommendedNutrients".Translate(incubatingThingDef.LabelCap, totalNutrientCost));
// 显示加成效果
if (currentNutrientCount >= totalNutrientCost)
{
builder.AppendLine("ARA_EquipmentIncubator.MaximumBonusActive".Translate());
}
else
{
int needed = totalNutrientCost - currentNutrientCount;
builder.AppendLine("ARA_EquipmentIncubator.AddMoreNutrients".Translate(needed));
}
}
return builder.ToString().TrimEndNewlines();
@@ -684,8 +382,8 @@ namespace ArachnaeSwarm
UpdateQualityMultiplier();
UpdateSpeedMultiplier();
// 初始化营养液消耗
InitializeNutrientConsumption();
// 初始化营养液信息(仅用于显示和建议)
InitializeNutrientInfo();
assignedLarva = null;
larvaOperateTicksRemaining = 0;
@@ -709,8 +407,9 @@ namespace ArachnaeSwarm
qualityProgress = 0f;
qualityTotal = 0f;
// 重置营养液消耗状态
ResetNutrientConsumptionState();
// 重置营养液信息
totalNutrientCost = 0;
currentNutrientCount = 0;
Messages.Message("ARA_EquipmentIncubator.IncubationCancelled".Translate() + " " + "ARA_EquipmentIncubator.ContentsLost".Translate(),
MessageTypeDefOf.NeutralEvent);
@@ -725,16 +424,6 @@ namespace ArachnaeSwarm
float finalQualityPercent = QualityPercent;
// 检查营养液是否满足要求
if (totalNutrientCost > 0 && consumedNutrientCount < totalNutrientCost)
{
Messages.Message("ARA_EquipmentIncubator.IncubationCompleteNutrientDeficient".Translate(incubatingThingDef.LabelCap),
this, MessageTypeDefOf.NegativeEvent);
// 生成物品但应用质量惩罚
finalQualityPercent *= Mathf.Lerp(0.3f, 1.0f, NutrientProgress);
}
// 生成物品
Thing thing = ThingMaker.MakeThing(incubatingThingDef);
ApplyQualityEffects(thing, finalQualityPercent);
@@ -785,18 +474,6 @@ namespace ArachnaeSwarm
}
}
// === 重置营养液消耗状态 ===
private void ResetNutrientConsumptionState()
{
totalNutrientCost = 0;
consumedNutrientCount = 0;
isConsuming = false;
consumedCells.Clear();
consecutiveFailedConsumptions = 0;
nutrientDeficiencyPause = false;
lastConsumeCheckTick = -1;
}
// === 重置孵化状态 ===
private void ResetIncubationState()
{
@@ -806,9 +483,8 @@ namespace ArachnaeSwarm
incubatingThingDef = null;
qualityProgress = 0f;
qualityTotal = 0f;
// 重置营养液消耗状态
ResetNutrientConsumptionState();
totalNutrientCost = 0;
currentNutrientCount = 0;
}
// === 获取剩余时间 ===
@@ -865,34 +541,14 @@ namespace ArachnaeSwarm
}
builder.Append(timeText);
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
"ARA_EquipmentIncubator.Quality".Translate() + ": " + QualityMultiplier.ToStringPercent());
// 显示营养液消耗信息
if (totalNutrientCost > 0)
builder.Append("ARA_EquipmentIncubator.Speed".Translate() + ": " + SpeedMultiplier.ToStringPercent());
// 显示营养液加成信息
if (currentNutrientCount > 0)
{
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.NutrientConsumption".Translate() + ": " +
consumedNutrientCount + " / " + totalNutrientCost +
" (" + NutrientProgress.ToStringPercent() + ")");
if (!HasEnoughNutrients)
{
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.NutrientDeficient".Translate());
if (nutrientDeficiencyPause)
{
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.NutrientDeficiencyPaused".Translate());
}
if (consecutiveFailedConsumptions > 0)
{
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.ConsecutiveFailures".Translate(consecutiveFailedConsumptions));
}
}
builder.Append("ARA_EquipmentIncubator.NutrientBonusActive".Translate() + ": " +
currentNutrientCount + " tiles (" + NutrientSpeedBonus.ToStringPercent() + ")");
}
}
else if (assignedLarva != null)
@@ -916,19 +572,15 @@ namespace ArachnaeSwarm
if (builder.Length > 0) builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.Target".Translate() + ": " + config.thingDef.LabelCap);
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent() + ", " +
"ARA_EquipmentIncubator.QualityMultiplier".Translate() + ": " + QualityMultiplier.ToStringPercent());
// 显示预计的营养液需求
var costStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationCost");
if (costStat != null)
builder.Append("ARA_EquipmentIncubator.SpeedMultiplier".Translate() + ": " + SpeedMultiplier.ToStringPercent());
// 显示当前营养液加成
UpdateNutrientCount();
if (currentNutrientCount > 0)
{
int estimatedCost = Mathf.RoundToInt(config.thingDef.GetStatValueAbstract(costStat, null));
if (estimatedCost > 0)
{
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.EstimatedNutrientCost".Translate() + ": " + estimatedCost);
}
builder.AppendLine();
builder.Append("ARA_EquipmentIncubator.CurrentNutrientBonus".Translate() + ": " +
currentNutrientCount + " tiles (" + NutrientSpeedBonus.ToStringPercent() + ")");
}
}
}
@@ -1041,6 +693,18 @@ namespace ArachnaeSwarm
{
builder.AppendLine("ARA_EquipmentIncubator.NoResearchRequired".Translate());
}
// 显示营养液建议
var costStat = DefDatabase<StatDef>.GetNamedSilentFail("ARA_IncubationCost");
if (costStat != null)
{
int recommendedCost = Mathf.RoundToInt(config.thingDef.GetStatValueAbstract(costStat, null));
if (recommendedCost > 0)
{
builder.AppendLine();
builder.AppendLine("ARA_EquipmentIncubator.RecommendedNutrientsForSpeed".Translate(recommendedCost));
}
}
}
builder.AppendLine();
@@ -1220,6 +884,12 @@ namespace ArachnaeSwarm
return count;
}
// === 更新营养液计数 ===
private void UpdateNutrientCount()
{
currentNutrientCount = CountNearbyNutrientSolutions();
}
// === 计算房间质量因子 ===
private float GetRoomQualityFactor()
{
@@ -1293,9 +963,11 @@ namespace ArachnaeSwarm
multiplier *= Ext.speedPenaltyOutsideIncubator;
}
int nutrientSolutionCount = CountNearbyNutrientSolutions();
float nutrientBonus = 1.0f + (nutrientSolutionCount * Ext.nutrientSolutionBonusPerTile);
// 更新营养液计数
UpdateNutrientCount();
// 应用营养液加成
float nutrientBonus = 1.0f + (currentNutrientCount * Ext.nutrientSolutionBonusPerTile);
multiplier *= nutrientBonus;
speedMultiplier = multiplier;
@@ -1342,28 +1014,8 @@ namespace ArachnaeSwarm
Scribe_Values.Look(ref qualityMultiplier, "qualityMultiplier", 1.0f);
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
// 保存营养液消耗状态
Scribe_Values.Look(ref totalNutrientCost, "totalNutrientCost", 0);
Scribe_Values.Look(ref consumedNutrientCount, "consumedNutrientCount", 0);
Scribe_Values.Look(ref lastConsumeCheckTick, "lastConsumeCheckTick", -1);
Scribe_Values.Look(ref isConsuming, "isConsuming", false);
Scribe_Values.Look(ref consecutiveFailedConsumptions, "consecutiveFailedConsumptions", 0);
Scribe_Values.Look(ref nutrientDeficiencyPause, "nutrientDeficiencyPause", false);
Scribe_Collections.Look(ref consumedCells, "consumedCells", LookMode.Value);
if (Scribe.mode == LoadSaveMode.PostLoadInit)
{
// 确保列表不为null
if (consumedCells == null)
consumedCells = new List<IntVec3>();
// 确保状态一致性
if (isIncubating && totalNutrientCost > 0 && !isConsuming)
{
isConsuming = true; // 加载后恢复消耗状态
}
}
Scribe_Values.Look(ref currentNutrientCount, "currentNutrientCount", 0);
}
}
}