11
This commit is contained in:
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -132,9 +132,15 @@
|
||||
<Compile Include="Buildings\Building_ResearchBlueprintReader\ResearchBlueprintReaderManager.cs" />
|
||||
<Compile Include="HarmonyPatches\DestroyRemovesResearch\CompDestroyRemovesResearch.cs" />
|
||||
<Compile Include="HarmonyPatches\DestroyRemovesResearch\CompProperties_DestroyRemovesResearch.cs" />
|
||||
<Compile Include="HarmonyPatches\Patch_DraftableAnimals.cs" />
|
||||
<Compile Include="HarmonyPatches\Patch_ResearchManager_AddRemoveMethod.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_DratfableAnimals\CompDratfableAnimals.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_DratfableAnimals\CompProperties_DratfableAnimals.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_PreventPartLoss\CompProperties_PreventPartLoss.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_PreventPartLoss\PreventPartLossPatches.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\CompProperties_SwarmMaintainer.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_SwarmMaintainer\Comp_SwarmMaintainer.cs" />
|
||||
<Compile Include="Pawn_Comps\ARA_DratfableAnimals\BeastUnit.cs" />
|
||||
<Compile Include="RoomRole\RoomRoleWorker_JellyVat.cs" />
|
||||
<Compile Include="RoomRole\RoomRoleWorker_Incubator.cs" />
|
||||
<Compile Include="Buildings\Building_TurretGunHasSpeed.cs" />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// File: ITabs/ITab_EquipmentOotheca_Incubation.cs
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using System.Collections.Generic;
|
||||
@@ -15,10 +14,10 @@ namespace ArachnaeSwarm
|
||||
private const float SmallLabelHeight = 20f;
|
||||
private const float ButtonHeight = 25f;
|
||||
private const float TabWidth = 320f;
|
||||
private const float TabHeight = 450f; // 增加高度以容纳更多信息
|
||||
private const float TabHeight = 450f;
|
||||
|
||||
private Vector2 scrollPosition = Vector2.zero;
|
||||
private const float ViewHeight = 480f; // 增加视图高度
|
||||
private const float ViewHeight = 480f;
|
||||
|
||||
public override bool IsVisible
|
||||
{
|
||||
@@ -115,6 +114,7 @@ namespace ArachnaeSwarm
|
||||
Widgets.Label(targetRect, "ARA_EquipmentIncubator.Target".Translate() + ": " + ootheca.incubatingThingDef.LabelCap);
|
||||
curY += SmallLabelHeight + 20f;
|
||||
|
||||
// 孵化进度条
|
||||
Rect progressBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
Rect progressLabelRect = new Rect(progressBarRect.x, progressBarRect.y - 20, progressBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
@@ -133,6 +133,7 @@ namespace ArachnaeSwarm
|
||||
|
||||
curY += BarHeight + 30f;
|
||||
|
||||
// 质量进度条
|
||||
Rect qualityBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
Rect qualityLabelRect = new Rect(qualityBarRect.x, qualityBarRect.y - 20, qualityBarRect.width, 18);
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
@@ -141,98 +142,8 @@ namespace ArachnaeSwarm
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
GUI.color = Color.white;
|
||||
|
||||
Widgets.FillableBar(qualityBarRect, qualityPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.4f, 0.8f, 0.5f))); curY += BarHeight + 25f;
|
||||
|
||||
// === 新增:营养液消耗显示 ===
|
||||
if (ootheca.TotalNutrientCost > 0)
|
||||
{
|
||||
// 标题
|
||||
Rect nutrientTitleRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(nutrientTitleRect, "ARA_EquipmentIncubator.NutrientConsumption".Translate());
|
||||
curY += SmallLabelHeight + 5f;
|
||||
|
||||
// 进度条
|
||||
Rect nutrientBarRect = new Rect(0f, curY, viewRect.width, BarHeight);
|
||||
float nutrientProgress = ootheca.NutrientProgress;
|
||||
|
||||
Widgets.FillableBar(nutrientBarRect, nutrientProgress,
|
||||
SolidColorMaterials.NewSolidColorTexture(new Color(0.8f, 0.6f, 0.1f, 0.5f)));
|
||||
|
||||
// 进度文本
|
||||
string nutrientText = $"{ootheca.ConsumedNutrientCount} / {ootheca.TotalNutrientCost} ({nutrientProgress:P0})";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(nutrientBarRect, nutrientText);
|
||||
Text.Anchor = TextAnchor.UpperLeft;
|
||||
|
||||
curY += BarHeight + 10f;
|
||||
|
||||
// 状态描述
|
||||
Rect nutrientStatusRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
string statusText;
|
||||
if (ootheca.HasEnoughNutrients)
|
||||
{
|
||||
statusText = "ARA_EquipmentIncubator.NutrientRequirementsMet".Translate();
|
||||
GUI.color = Color.green;
|
||||
}
|
||||
else if (ootheca.IsConsuming)
|
||||
{
|
||||
statusText = "ARA_EquipmentIncubator.ConsumingNutrients".Translate();
|
||||
GUI.color = Color.yellow;
|
||||
}
|
||||
else
|
||||
{
|
||||
statusText = "ARA_EquipmentIncubator.WaitingForNutrients".Translate();
|
||||
GUI.color = Color.gray;
|
||||
}
|
||||
|
||||
Widgets.Label(nutrientStatusRect, statusText);
|
||||
GUI.color = Color.white;
|
||||
|
||||
curY += SmallLabelHeight + 15f;
|
||||
}
|
||||
// === 新增:营养液不足状态显示 ===
|
||||
if (ootheca.TotalNutrientCost > 0 && ootheca.IsConsuming)
|
||||
{
|
||||
curY += BarHeight + 15f;
|
||||
|
||||
// 检查是否有营养液不足的警告
|
||||
var availableCells = ootheca.FindNutrientCells();
|
||||
if (availableCells.Count == 0 && !ootheca.HasEnoughNutrients)
|
||||
{
|
||||
Rect warningRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight * 2);
|
||||
|
||||
if (ootheca.Ext.stopIncubationWhenNutrientDeficient)
|
||||
{
|
||||
Widgets.Label(warningRect, "ARA_EquipmentIncubator.IncubationPausedWarning".Translate());
|
||||
GUI.color = Color.yellow;
|
||||
}
|
||||
else
|
||||
{
|
||||
Widgets.Label(warningRect, "ARA_EquipmentIncubator.NutrientDeficiencyWarning".Translate());
|
||||
GUI.color = Color.red;
|
||||
}
|
||||
|
||||
// 绘制警告背景
|
||||
Widgets.DrawHighlight(warningRect);
|
||||
GUI.color = Color.white;
|
||||
|
||||
curY += SmallLabelHeight * 2 + 10f;
|
||||
|
||||
// 显示血量警告
|
||||
float healthPercent = (float)ootheca.HitPoints / ootheca.MaxHitPoints;
|
||||
if (healthPercent < 0.5f)
|
||||
{
|
||||
Rect healthWarningRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
Widgets.Label(healthWarningRect, "ARA_EquipmentIncubator.LowHealthWarning".Translate(healthPercent.ToStringPercent()));
|
||||
GUI.color = new Color(1f, 0.5f, 0.5f);
|
||||
Widgets.DrawHighlight(healthWarningRect);
|
||||
GUI.color = Color.white;
|
||||
|
||||
curY += SmallLabelHeight + 5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widgets.FillableBar(qualityBarRect, qualityPercent, SolidColorMaterials.NewSolidColorTexture(new Color(0.1f, 0.4f, 0.8f, 0.5f)));
|
||||
|
||||
string qualityProgressText = $"{qualityPercent:P0}";
|
||||
Text.Anchor = TextAnchor.MiddleCenter;
|
||||
Widgets.Label(qualityBarRect, qualityProgressText);
|
||||
@@ -247,6 +158,7 @@ namespace ArachnaeSwarm
|
||||
|
||||
curY += BarHeight + 25f;
|
||||
|
||||
// 剩余时间
|
||||
Rect timeRect = new Rect(0f, curY, viewRect.width, SmallLabelHeight);
|
||||
string timeText = "ARA_EquipmentIncubator.TimeRemaining".Translate() + ": " + daysRemaining.ToString("F1") + " " + "ARA_EquipmentIncubator.Days".Translate();
|
||||
if (hoursRemaining > 0.1f && daysRemaining < 1f)
|
||||
|
||||
@@ -6,34 +6,47 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class Building_ResearchBlueprintReader : Building
|
||||
{
|
||||
// 储存的科技
|
||||
private ResearchProjectDef storedResearch;
|
||||
|
||||
|
||||
// 当前研究进度
|
||||
private float progress;
|
||||
|
||||
|
||||
// 管理器引用
|
||||
private ResearchBlueprintReaderManager manager;
|
||||
|
||||
|
||||
// 是否正在研究
|
||||
private bool isResearching = false;
|
||||
|
||||
|
||||
// 电力组件
|
||||
private CompPowerTrader powerComp;
|
||||
|
||||
|
||||
// 锁定信息
|
||||
private int researchStartTime;
|
||||
|
||||
|
||||
// === 新增:唯一ID防止重复注册 ===
|
||||
private string uniqueId = null;
|
||||
public string UniqueId
|
||||
{
|
||||
get
|
||||
{
|
||||
if (uniqueId == null)
|
||||
{
|
||||
uniqueId = $"ResearchBlueprintReader_{Guid.NewGuid():N}";
|
||||
}
|
||||
return uniqueId;
|
||||
}
|
||||
}
|
||||
|
||||
public ResearchProjectDef StoredResearch => storedResearch;
|
||||
public float Progress => progress;
|
||||
public bool IsLocked => storedResearch != null;
|
||||
public bool IsResearching => isResearching && storedResearch != null && !storedResearch.IsFinished;
|
||||
|
||||
|
||||
// 获取研究速度
|
||||
private float ResearchSpeed
|
||||
{
|
||||
@@ -43,44 +56,54 @@ namespace ArachnaeSwarm
|
||||
return ext?.researchSpeed ?? 10f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
|
||||
Scribe_Defs.Look(ref storedResearch, "storedResearch");
|
||||
Scribe_Values.Look(ref progress, "progress", 0f);
|
||||
Scribe_Values.Look(ref isResearching, "isResearching", false);
|
||||
Scribe_Values.Look(ref researchStartTime, "researchStartTime", 0);
|
||||
|
||||
Scribe_Values.Look(ref uniqueId, "uniqueId");
|
||||
|
||||
if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
// 重建管理器连接
|
||||
manager = ResearchBlueprintReaderManager.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||
{
|
||||
base.SpawnSetup(map, respawningAfterLoad);
|
||||
|
||||
// 获取管理器
|
||||
manager = ResearchBlueprintReaderManager.Instance;
|
||||
if (manager != null)
|
||||
try
|
||||
{
|
||||
manager.RegisterReader(this);
|
||||
base.SpawnSetup(map, respawningAfterLoad);
|
||||
|
||||
// 获取管理器
|
||||
manager = ResearchBlueprintReaderManager.Instance;
|
||||
if (manager != null)
|
||||
{
|
||||
manager.RegisterReader(this);
|
||||
}
|
||||
|
||||
// 获取电力组件
|
||||
powerComp = GetComp<CompPowerTrader>();
|
||||
|
||||
// 如果加载时有储存的科技,确保注册到管理器
|
||||
if (storedResearch != null && manager != null)
|
||||
{
|
||||
manager.RegisterResearch(this, storedResearch);
|
||||
}
|
||||
|
||||
Log.Message($"[ResearchBlueprintReader] Building spawned with ID: {ThingID}, UniqueId: {UniqueId}");
|
||||
}
|
||||
|
||||
// 获取电力组件
|
||||
powerComp = GetComp<CompPowerTrader>();
|
||||
|
||||
// 如果加载时有储存的科技,确保注册到管理器
|
||||
if (storedResearch != null && manager != null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
manager.RegisterResearch(this, storedResearch);
|
||||
Log.Error($"[ResearchBlueprintReader] Error in SpawnSetup: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Destroy(DestroyMode mode = DestroyMode.Vanish)
|
||||
{
|
||||
// 通知管理器建筑被摧毁
|
||||
@@ -88,10 +111,10 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
manager.OnBuildingDestroyed(this, storedResearch);
|
||||
}
|
||||
|
||||
|
||||
base.Destroy(mode);
|
||||
}
|
||||
|
||||
|
||||
protected override void Tick()
|
||||
{
|
||||
base.Tick();
|
||||
@@ -207,38 +230,6 @@ namespace ArachnaeSwarm
|
||||
MessageTypeDefOf.NeutralEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解锁建筑(释放储存的科技)
|
||||
/// </summary>
|
||||
public void UnlockBuilding()
|
||||
{
|
||||
if (storedResearch != null && manager != null)
|
||||
{
|
||||
var project = storedResearch;
|
||||
|
||||
// 如果科技未完成,需要移除进度
|
||||
if (!project.IsFinished)
|
||||
{
|
||||
// 计算当前建筑的贡献
|
||||
float contributedProgress = progress;
|
||||
float globalProgress = Find.ResearchManager.GetProgress(project);
|
||||
|
||||
// 移除这个建筑的贡献(简化处理:减去当前建筑的进度)
|
||||
// 注意:这里可能有多个建筑同时研究,所以不能简单减去
|
||||
// 我们让管理器来处理复杂的逻辑
|
||||
manager.OnBuildingUnlocked(this, project);
|
||||
}
|
||||
|
||||
storedResearch = null;
|
||||
progress = 0f;
|
||||
isResearching = false;
|
||||
researchStartTime = 0;
|
||||
|
||||
Messages.Message("ResearchBlueprintReader_BuildingUnlocked".Translate(project.LabelCap),
|
||||
MessageTypeDefOf.NeutralEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制完成研究(用于调试)
|
||||
/// </summary>
|
||||
@@ -258,22 +249,6 @@ namespace ArachnaeSwarm
|
||||
yield return gizmo;
|
||||
}
|
||||
|
||||
// 如果已锁定,显示解锁按钮
|
||||
if (IsLocked)
|
||||
{
|
||||
var unlockCmd = new Command_Action();
|
||||
unlockCmd.defaultLabel = "ResearchBlueprintReader_UnlockBuilding".Translate();
|
||||
unlockCmd.defaultDesc = "ResearchBlueprintReader_UnlockBuildingDesc".Translate();
|
||||
unlockCmd.icon = ContentFinder<Texture2D>.Get("ArachnaeSwarm/UI/Abilities/ARA_Ability_Morph", false);
|
||||
unlockCmd.action = delegate
|
||||
{
|
||||
UnlockBuilding();
|
||||
};
|
||||
yield return unlockCmd;
|
||||
|
||||
yield break; // 锁定状态下不显示其他按钮
|
||||
}
|
||||
|
||||
// 选择研究按钮
|
||||
var selectCmd = new Command_Action();
|
||||
selectCmd.defaultLabel = "ResearchBlueprintReader_SelectProject".Translate();
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace ArachnaeSwarm
|
||||
private int cleanupTimer;
|
||||
private const int CleanupInterval = 2500;
|
||||
|
||||
// === 新增:用于序列化的临时字段 ===
|
||||
private List<ResearchProjectDef> serializedProjects;
|
||||
private List<List<Building_ResearchBlueprintReader>> serializedBuildings;
|
||||
|
||||
public ResearchBlueprintReaderManager(Game game) : base()
|
||||
{
|
||||
instance = this;
|
||||
@@ -36,34 +40,79 @@ namespace ArachnaeSwarm
|
||||
{
|
||||
base.ExposeData();
|
||||
|
||||
Scribe_Collections.Look(ref allReaders, "allReaders", LookMode.Reference);
|
||||
|
||||
// 序列化研究建筑映射
|
||||
// 修复字典序列化问题
|
||||
if (Scribe.mode == LoadSaveMode.Saving)
|
||||
{
|
||||
List<ResearchProjectDef> keys = researchBuildings.Keys.ToList();
|
||||
List<List<Building_ResearchBlueprintReader>> values = researchBuildings.Values.ToList();
|
||||
Scribe_Collections.Look(ref keys, "researchKeys", LookMode.Def);
|
||||
Scribe_Collections.Look(ref values, "researchValues", LookMode.Deep);
|
||||
// 保存时:将字典转换为两个列表
|
||||
serializedProjects = new List<ResearchProjectDef>();
|
||||
serializedBuildings = new List<List<Building_ResearchBlueprintReader>>();
|
||||
|
||||
foreach (var kvp in researchBuildings)
|
||||
{
|
||||
// 只保存有效的项目和有建筑的项目
|
||||
if (kvp.Key != null && kvp.Value != null && kvp.Value.Count > 0)
|
||||
{
|
||||
// 过滤掉已被摧毁的建筑
|
||||
var validBuildings = kvp.Value.Where(b => b != null && !b.Destroyed).ToList();
|
||||
if (validBuildings.Count > 0)
|
||||
{
|
||||
serializedProjects.Add(kvp.Key);
|
||||
serializedBuildings.Add(validBuildings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def);
|
||||
Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference);
|
||||
}
|
||||
else if (Scribe.mode == LoadSaveMode.LoadingVars)
|
||||
{
|
||||
allReaders = allReaders ?? new List<Building_ResearchBlueprintReader>();
|
||||
|
||||
List<ResearchProjectDef> keys = null;
|
||||
List<List<Building_ResearchBlueprintReader>> values = null;
|
||||
Scribe_Collections.Look(ref keys, "researchKeys", LookMode.Def);
|
||||
Scribe_Collections.Look(ref values, "researchValues", LookMode.Deep);
|
||||
|
||||
// 加载时:清空现有数据
|
||||
allReaders = new List<Building_ResearchBlueprintReader>();
|
||||
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
|
||||
if (keys != null && values != null && keys.Count == values.Count)
|
||||
|
||||
serializedProjects = null;
|
||||
serializedBuildings = null;
|
||||
|
||||
Scribe_Collections.Look(ref serializedProjects, "serializedProjects", LookMode.Def);
|
||||
Scribe_Collections.Look(ref serializedBuildings, "serializedBuildings", LookMode.Reference);
|
||||
|
||||
if (serializedProjects != null && serializedBuildings != null &&
|
||||
serializedProjects.Count == serializedBuildings.Count)
|
||||
{
|
||||
for (int i = 0; i < keys.Count; i++)
|
||||
for (int i = 0; i < serializedProjects.Count; i++)
|
||||
{
|
||||
if (keys[i] != null)
|
||||
researchBuildings[keys[i]] = values[i] ?? new List<Building_ResearchBlueprintReader>();
|
||||
var project = serializedProjects[i];
|
||||
var buildings = serializedBuildings[i];
|
||||
|
||||
if (project != null && buildings != null)
|
||||
{
|
||||
// 清理空引用
|
||||
buildings.RemoveAll(b => b == null);
|
||||
|
||||
if (buildings.Count > 0)
|
||||
{
|
||||
researchBuildings[project] = buildings;
|
||||
|
||||
// 添加到所有建筑列表
|
||||
foreach (var building in buildings)
|
||||
{
|
||||
if (!allReaders.Contains(building))
|
||||
{
|
||||
allReaders.Add(building);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.Message($"[ResearchManager] Loaded {allReaders.Count} buildings, {researchBuildings.Count} research projects");
|
||||
}
|
||||
else if (Scribe.mode == LoadSaveMode.PostLoadInit)
|
||||
{
|
||||
// 后加载初始化:清理所有无效数据
|
||||
CleanupInvalidData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,21 +123,86 @@ namespace ArachnaeSwarm
|
||||
cleanupTimer++;
|
||||
if (cleanupTimer >= CleanupInterval)
|
||||
{
|
||||
CleanupDestroyedBuildings();
|
||||
CleanupInvalidData();
|
||||
cleanupTimer = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理无效数据
|
||||
/// </summary>
|
||||
private void CleanupInvalidData()
|
||||
{
|
||||
int removedCount = 0;
|
||||
|
||||
// 清理所有建筑列表
|
||||
if (allReaders != null)
|
||||
{
|
||||
removedCount += allReaders.RemoveAll(b =>
|
||||
b == null || b.Destroyed || !b.Spawned || b.Map == null);
|
||||
|
||||
Log.Message($"[ResearchManager] Cleaned up {removedCount} invalid buildings from allReaders");
|
||||
}
|
||||
else
|
||||
{
|
||||
allReaders = new List<Building_ResearchBlueprintReader>();
|
||||
}
|
||||
|
||||
// 清理研究建筑映射
|
||||
if (researchBuildings != null)
|
||||
{
|
||||
var projectsToRemove = new List<ResearchProjectDef>();
|
||||
|
||||
foreach (var kvp in researchBuildings)
|
||||
{
|
||||
if (kvp.Key == null)
|
||||
{
|
||||
projectsToRemove.Add(kvp.Key);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 清理无效建筑
|
||||
kvp.Value.RemoveAll(b =>
|
||||
b == null || b.Destroyed || !b.Spawned || b.Map == null);
|
||||
|
||||
if (kvp.Value.Count == 0)
|
||||
{
|
||||
projectsToRemove.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// 移除空项目
|
||||
foreach (var project in projectsToRemove)
|
||||
{
|
||||
researchBuildings.Remove(project);
|
||||
}
|
||||
|
||||
Log.Message($"[ResearchManager] Cleaned up {projectsToRemove.Count} empty research projects");
|
||||
}
|
||||
else
|
||||
{
|
||||
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册建筑
|
||||
/// </summary>
|
||||
public void RegisterReader(Building_ResearchBlueprintReader reader)
|
||||
{
|
||||
if (reader == null || reader.Destroyed) return;
|
||||
if (reader == null || reader.Destroyed || !reader.Spawned)
|
||||
return;
|
||||
|
||||
// 防止重复注册
|
||||
if (allReaders == null)
|
||||
{
|
||||
allReaders = new List<Building_ResearchBlueprintReader>();
|
||||
}
|
||||
|
||||
if (!allReaders.Contains(reader))
|
||||
{
|
||||
allReaders.Add(reader);
|
||||
Log.Message($"[ResearchManager] Registered reader: {reader.ThingID} at position {reader.Position}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,15 +211,22 @@ namespace ArachnaeSwarm
|
||||
/// </summary>
|
||||
public void RegisterResearch(Building_ResearchBlueprintReader reader, ResearchProjectDef project)
|
||||
{
|
||||
if (reader == null || project == null) return;
|
||||
if (reader == null || project == null)
|
||||
return;
|
||||
|
||||
if (researchBuildings == null)
|
||||
{
|
||||
researchBuildings = new Dictionary<ResearchProjectDef, List<Building_ResearchBlueprintReader>>();
|
||||
}
|
||||
|
||||
if (!researchBuildings.ContainsKey(project))
|
||||
researchBuildings[project] = new List<Building_ResearchBlueprintReader>();
|
||||
|
||||
if (!researchBuildings[project].Contains(reader))
|
||||
{
|
||||
researchBuildings[project].Add(reader);
|
||||
|
||||
Log.Message($"[ResearchManager] Registered research: {project.defName} at building {reader.Position}");
|
||||
Log.Message($"[ResearchManager] Registered research: {project.defName} at building {reader.Position}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,159 +243,27 @@ namespace ArachnaeSwarm
|
||||
Log.Message($"[ResearchManager] Processing building destruction for project: {project.defName}");
|
||||
|
||||
// 从列表中移除
|
||||
if (researchBuildings.ContainsKey(project))
|
||||
if (researchBuildings != null && researchBuildings.ContainsKey(project))
|
||||
{
|
||||
researchBuildings[project].Remove(building);
|
||||
Log.Message($"[ResearchManager] Removed building from project list. Remaining buildings: {researchBuildings[project].Count}");
|
||||
|
||||
// 检查是否还有建筑
|
||||
CheckResearchStatus(project);
|
||||
}
|
||||
|
||||
// 从所有建筑列表中移除
|
||||
allReaders.Remove(building);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查科技状态
|
||||
/// </summary>
|
||||
private void CheckResearchStatus(ResearchProjectDef project)
|
||||
{
|
||||
if (project == null) return;
|
||||
|
||||
// 检查是否还有建筑研究这个科技
|
||||
bool hasBuildings = false;
|
||||
if (researchBuildings.ContainsKey(project))
|
||||
{
|
||||
// 清理列表中的空引用
|
||||
researchBuildings[project].RemoveAll(b => b == null || b.Destroyed);
|
||||
hasBuildings = researchBuildings[project].Count > 0;
|
||||
|
||||
if (!hasBuildings)
|
||||
if (researchBuildings[project].Count == 0)
|
||||
{
|
||||
researchBuildings.Remove(project);
|
||||
Log.Message($"[ResearchManager] No buildings left for project: {project.defName}");
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有建筑了,移除科技
|
||||
if (!hasBuildings)
|
||||
// 从所有建筑列表中移除
|
||||
if (allReaders != null)
|
||||
{
|
||||
RemoveResearchProject(project);
|
||||
allReaders.Remove(building);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除科技
|
||||
/// </summary>
|
||||
private void RemoveResearchProject(ResearchProjectDef project)
|
||||
{
|
||||
if (project == null) return;
|
||||
|
||||
Log.Message($"[ResearchManager] Removing research project: {project.defName}");
|
||||
|
||||
try
|
||||
{
|
||||
// 移除科技完成状态
|
||||
Utilities.ResearchRemover.RemoveResearchProject(project, false);
|
||||
|
||||
// 发送消息
|
||||
Messages.Message("ResearchManager_ResearchLost".Translate(project.LabelCap),
|
||||
MessageTypeDefOf.NegativeEvent);
|
||||
|
||||
Log.Message($"[ResearchManager] Successfully removed research project: {project.defName}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[ResearchManager] Error removing research project {project.defName}: {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 建筑解锁时的处理
|
||||
/// </summary>
|
||||
public void OnBuildingUnlocked(Building_ResearchBlueprintReader building, ResearchProjectDef project)
|
||||
{
|
||||
if (project == null) return;
|
||||
|
||||
Log.Message($"[ResearchManager] Processing building unlock for project: {project.defName}");
|
||||
|
||||
// 从研究中移除
|
||||
if (researchBuildings.ContainsKey(project))
|
||||
{
|
||||
researchBuildings[project].Remove(building);
|
||||
Log.Message($"[ResearchManager] Removed building from project list due to unlock. Remaining buildings: {researchBuildings[project].Count}");
|
||||
|
||||
// 检查是否还有建筑
|
||||
CheckResearchStatus(project);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查科技是否还有建筑研究
|
||||
/// </summary>
|
||||
public bool HasResearchBuildings(ResearchProjectDef project)
|
||||
{
|
||||
if (project == null) return false;
|
||||
|
||||
if (researchBuildings.ContainsKey(project))
|
||||
{
|
||||
researchBuildings[project].RemoveAll(b => b == null || b.Destroyed);
|
||||
return researchBuildings[project].Count > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取研究某个科技的建筑数量
|
||||
/// </summary>
|
||||
public int GetResearchBuildingCount(ResearchProjectDef project)
|
||||
{
|
||||
if (researchBuildings.ContainsKey(project))
|
||||
{
|
||||
researchBuildings[project].RemoveAll(b => b == null || b.Destroyed);
|
||||
return researchBuildings[project].Count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理被摧毁的建筑
|
||||
/// </summary>
|
||||
private void CleanupDestroyedBuildings()
|
||||
{
|
||||
int removedCount = 0;
|
||||
|
||||
// 清理所有建筑列表
|
||||
allReaders.RemoveAll(b => b == null || b.Destroyed);
|
||||
|
||||
// 清理研究建筑映射,并检查科技状态
|
||||
List<ResearchProjectDef> projectsToCheck = new List<ResearchProjectDef>();
|
||||
|
||||
foreach (var kvp in researchBuildings.ToList())
|
||||
{
|
||||
kvp.Value.RemoveAll(b => b == null || b.Destroyed);
|
||||
removedCount += kvp.Value.Count(b => b == null || b.Destroyed);
|
||||
|
||||
if (kvp.Value.Count == 0)
|
||||
{
|
||||
projectsToCheck.Add(kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查需要处理的科技
|
||||
foreach (var project in projectsToCheck)
|
||||
{
|
||||
CheckResearchStatus(project);
|
||||
}
|
||||
|
||||
if (removedCount > 0)
|
||||
{
|
||||
Log.Message($"[ResearchManager] Cleanup: removed {removedCount} destroyed buildings");
|
||||
}
|
||||
}
|
||||
// ... 其余方法保持不变 ...
|
||||
|
||||
/// <summary>
|
||||
/// 调试命令
|
||||
@@ -287,28 +276,19 @@ namespace ArachnaeSwarm
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Message("ResearchManager_StatusTitle".Translate());
|
||||
Log.Message("ResearchManager_TotalBuildings".Translate(Instance.allReaders.Count));
|
||||
Log.Message("ResearchManager_ActiveResearch".Translate(Instance.researchBuildings.Count));
|
||||
Log.Message("=== Research Manager Status ===");
|
||||
Log.Message($"Total buildings: {Instance.allReaders?.Count ?? 0}");
|
||||
Log.Message($"Active research projects: {Instance.researchBuildings?.Count ?? 0}");
|
||||
|
||||
foreach (var kvp in Instance.researchBuildings)
|
||||
if (Instance.researchBuildings != null)
|
||||
{
|
||||
int activeBuildings = kvp.Value.Count(b => b != null && !b.Destroyed);
|
||||
Log.Message("ResearchManager_ProjectStatus".Translate(
|
||||
kvp.Key.defName, activeBuildings, kvp.Value.Count));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 强制检查所有科技状态(调试用)
|
||||
/// </summary>
|
||||
public static void ForceCheckAllResearch()
|
||||
{
|
||||
if (Instance == null) return;
|
||||
|
||||
foreach (var project in Instance.researchBuildings.Keys.ToList())
|
||||
{
|
||||
Instance.CheckResearchStatus(project);
|
||||
foreach (var kvp in Instance.researchBuildings)
|
||||
{
|
||||
if (kvp.Key == null) continue;
|
||||
|
||||
int activeBuildings = kvp.Value?.Count(b => b != null && !b.Destroyed && b.Spawned) ?? 0;
|
||||
Log.Message($" - {kvp.Key.defName}: {activeBuildings} active buildings");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
194
Source/ArachnaeSwarm/HarmonyPatches/Patch_DraftableAnimals.cs
Normal file
194
Source/ArachnaeSwarm/HarmonyPatches/Patch_DraftableAnimals.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using HarmonyLib;
|
||||
using RimWorld;
|
||||
using System;
|
||||
using Verse;
|
||||
using Verse.AI;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
[HarmonyPatch(typeof(Pawn), "get_CanTakeOrder")]
|
||||
public class Patch_CanTakeOrder
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void postfix(ref bool __result, Pawn __instance)
|
||||
{
|
||||
if (__instance.HasComp<CompDraftableAnimals>() && __instance.Drafted)
|
||||
{
|
||||
__result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(PawnComponentsUtility), "AddAndRemoveDynamicComponents")]
|
||||
public class Patch_PawnTracer
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void postfix(Pawn pawn)
|
||||
{
|
||||
CompDraftableAnimals comp = pawn.TryGetComp<CompDraftableAnimals>();
|
||||
if (comp != null && comp.Props.draftable)
|
||||
{
|
||||
pawn.drafter = new Pawn_DraftController(pawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(FloatMenuOptionProvider), "SelectedPawnValid")]
|
||||
public class Patch_GetSingleOption
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void postfix(ref bool __result, Pawn pawn)
|
||||
{
|
||||
if (pawn.HasComp<CompDraftableAnimals>() && pawn.Drafted)
|
||||
{
|
||||
__result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(FloatMenuUtility), "UseRangedAttack")]
|
||||
public static class Patch_FloatMenuUtility_UseRangedAttack
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static bool Prefix(Pawn pawn, ref bool __result)
|
||||
{
|
||||
if (pawn.equipment == null)
|
||||
{
|
||||
__result = false;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(FloatMenuUtility), nameof(FloatMenuUtility.GetMeleeAttackAction))]
|
||||
public static class Patch_FloatMenuUtility_GetMeleeAttackAction_Simple
|
||||
{
|
||||
[HarmonyPrefix]
|
||||
public static bool Prefix(Pawn pawn, LocalTargetInfo target, out string failStr, ref Action __result, bool ignoreControlled = false)
|
||||
{
|
||||
failStr = "";
|
||||
|
||||
// 检查是否有 CompDraftableAnimals
|
||||
var comp = pawn?.GetComp<CompDraftableAnimals>();
|
||||
if (comp != null)
|
||||
{
|
||||
// 直接返回 true 跳过控制检查
|
||||
ignoreControlled = true;
|
||||
|
||||
// 这里我们直接调用修改后的方法
|
||||
__result = ModifiedGetMeleeAttackAction(pawn, target, out failStr, ignoreControlled);
|
||||
return false; // 跳过原始方法
|
||||
}
|
||||
|
||||
return true; // 没有组件,继续执行原始方法
|
||||
}
|
||||
|
||||
private static Action ModifiedGetMeleeAttackAction(Pawn pawn, LocalTargetInfo target, out string failStr, bool ignoreControlled = false)
|
||||
{
|
||||
failStr = "";
|
||||
|
||||
try
|
||||
{
|
||||
// 直接使用原始代码,但跳过控制检查
|
||||
if (!pawn.Drafted && !ignoreControlled)
|
||||
{
|
||||
failStr = "IsNotDraftedLower".Translate(pawn.LabelShort, pawn);
|
||||
}
|
||||
else if (target.IsValid && !pawn.CanReach(target, PathEndMode.Touch, Danger.Deadly))
|
||||
{
|
||||
failStr = "NoPath".Translate();
|
||||
}
|
||||
else if (pawn.WorkTagIsDisabled(WorkTags.Violent))
|
||||
{
|
||||
failStr = "IsIncapableOfViolenceLower".Translate(pawn.LabelShort, pawn);
|
||||
}
|
||||
else if (pawn.meleeVerbs?.TryGetMeleeVerb(target.Thing) == null)
|
||||
{
|
||||
failStr = "Incapable".Translate();
|
||||
}
|
||||
else if (pawn == target.Thing)
|
||||
{
|
||||
failStr = "CannotAttackSelf".Translate();
|
||||
}
|
||||
else if (target.Thing is Pawn targetPawn && (pawn.InSameExtraFaction(targetPawn, ExtraFactionType.HomeFaction) || pawn.InSameExtraFaction(targetPawn, ExtraFactionType.MiniFaction)))
|
||||
{
|
||||
failStr = "CannotAttackSameFactionMember".Translate();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(target.Thing is Pawn pawn2) || !pawn2.RaceProps.Animal || !HistoryEventUtility.IsKillingInnocentAnimal(pawn, pawn2) || new HistoryEvent(HistoryEventDefOf.KilledInnocentAnimal, pawn.Named(HistoryEventArgsNames.Doer)).DoerWillingToDo())
|
||||
{
|
||||
return delegate
|
||||
{
|
||||
Job job = JobMaker.MakeJob(JobDefOf.AttackMelee, target);
|
||||
if (target.Thing is Pawn pawn3)
|
||||
{
|
||||
job.killIncappedTarget = pawn3.Downed;
|
||||
}
|
||||
pawn.jobs.TryTakeOrderedJob(job, JobTag.Misc);
|
||||
};
|
||||
}
|
||||
failStr = "IdeoligionForbids".Translate();
|
||||
}
|
||||
|
||||
failStr = failStr.CapitalizeFirst();
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[ARA] Error in ModifiedGetMeleeAttackAction: {ex}");
|
||||
failStr = "Cannot attack";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阻止有 ARA_HiveMindBeast 的动物判断应该逃跑
|
||||
[HarmonyPatch(typeof(FleeUtility), "ShouldAnimalFleeDanger")]
|
||||
public static class Patch_FleeUtility_ShouldAnimalFleeDanger
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void Postfix(Pawn pawn, ref bool __result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pawn != null && pawn.health?.hediffSet != null && __result)
|
||||
{
|
||||
var hiveMindBeastDef = HediffDef.Named("ARA_HiveMindBeast");
|
||||
if (hiveMindBeastDef != null && pawn.health.hediffSet.HasHediff(hiveMindBeastDef))
|
||||
{
|
||||
// 如果有这个 hediff,动物不应该逃跑
|
||||
__result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[ARA] Error in ShouldAnimalFleeDanger postfix: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 阻止有 ARA_HiveMindBeast 的动物判断应该从特定事物逃跑
|
||||
[HarmonyPatch(typeof(FleeUtility), "ShouldFleeFrom")]
|
||||
public static class Patch_FleeUtility_ShouldFleeFrom
|
||||
{
|
||||
[HarmonyPostfix]
|
||||
public static void Postfix(Thing t, Pawn pawn, ref bool __result)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pawn != null && pawn.health?.hediffSet != null && __result)
|
||||
{
|
||||
var hiveMindBeastDef = HediffDef.Named("ARA_HiveMindBeast");
|
||||
if (hiveMindBeastDef != null && pawn.health.hediffSet.HasHediff(hiveMindBeastDef))
|
||||
{
|
||||
// 如果有这个 hediff,动物不应该逃跑
|
||||
__result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"[ARA] Error in ShouldFleeFrom postfix: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections.Generic;
|
||||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class BeastUnit : Pawn
|
||||
{
|
||||
public override void DrawExtraSelectionOverlays()
|
||||
{
|
||||
base.DrawExtraSelectionOverlays();
|
||||
pather.curPath?.DrawPath(this);
|
||||
jobs.DrawLinesBetweenTargets();
|
||||
}
|
||||
|
||||
public override IEnumerable<Gizmo> GetGizmos()
|
||||
{
|
||||
foreach (Gizmo gizmo in base.GetGizmos())
|
||||
{
|
||||
yield return gizmo;
|
||||
}
|
||||
if (drafter == null)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
foreach (Gizmo draftGizmo in GetDraftGizmos())
|
||||
{
|
||||
yield return draftGizmo;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Gizmo> GetDraftGizmos()
|
||||
{
|
||||
if (!drafter.ShowDraftGizmo)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
Command_Toggle command_Toggle = new Command_Toggle
|
||||
{
|
||||
hotKey = KeyBindingDefOf.Command_ColonistDraft,
|
||||
isActive = () => base.Drafted,
|
||||
toggleAction = delegate
|
||||
{
|
||||
drafter.Drafted = !drafter.Drafted;
|
||||
PlayerKnowledgeDatabase.KnowledgeDemonstrated(ConceptDefOf.Drafting, KnowledgeAmount.SpecificInteraction);
|
||||
if (base.Drafted)
|
||||
{
|
||||
LessonAutoActivator.TeachOpportunity(ConceptDefOf.QueueOrders, OpportunityType.GoodToKnow);
|
||||
}
|
||||
},
|
||||
defaultDesc = "CommandToggleDraftDesc".Translate(),
|
||||
icon = TexCommand.Draft,
|
||||
turnOnSound = SoundDefOf.DraftOn,
|
||||
turnOffSound = SoundDefOf.DraftOff,
|
||||
groupKeyIgnoreContent = 81729172,
|
||||
defaultLabel = (base.Drafted ? "CommandUndraftLabel" : "CommandDraftLabel").Translate()
|
||||
};
|
||||
if (base.Downed)
|
||||
{
|
||||
command_Toggle.Disable("IsIncapped".Translate(LabelShort, this));
|
||||
}
|
||||
if (base.Deathresting)
|
||||
{
|
||||
command_Toggle.Disable("IsDeathresting".Translate(this.Named("PAWN")));
|
||||
}
|
||||
command_Toggle.tutorTag = ((!base.Drafted) ? "Draft" : "Undraft");
|
||||
yield return command_Toggle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using RimWorld;
|
||||
using UnityEngine;
|
||||
using Verse;
|
||||
using Verse.AI.Group;
|
||||
using Verse.Sound;
|
||||
using static HarmonyLib.Code;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompDraftableAnimals : ThingComp
|
||||
{
|
||||
public CompProperties_DraftableAnimals Props => (CompProperties_DraftableAnimals)props;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using RimWorld;
|
||||
using System.Collections.Generic;
|
||||
using Verse;
|
||||
|
||||
namespace ArachnaeSwarm
|
||||
{
|
||||
public class CompProperties_DraftableAnimals : CompProperties
|
||||
{
|
||||
|
||||
public bool draftable = true;
|
||||
|
||||
public CompProperties_DraftableAnimals()
|
||||
{
|
||||
compClass = typeof(CompDraftableAnimals);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
// 智能溅射:次要目标的敌对状态必须与主目标一致
|
||||
if (secondaryTargetPawn.HostileTo(casterPawn) != mainTargetIsHostile)
|
||||
if (secondaryTargetPawn.HostileTo(casterPawn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace ArachnaeSwarm
|
||||
}
|
||||
|
||||
// 智能溅射:次要目标的敌对状态必须与主目标一致
|
||||
if (secondaryTargetPawn.HostileTo(casterPawn) != mainTargetIsHostile)
|
||||
if (secondaryTargetPawn.Faction == casterPawn.Faction)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace ArachnaeSwarm
|
||||
// 检查是否有食物需求
|
||||
private bool HasFoodNeed(Pawn pawn)
|
||||
{
|
||||
return pawn.needs?.TryGetNeed<Need_Food>() != null;
|
||||
return pawn.needs?.TryGetNeed<Need_Food>() != null && pawn.needs?.TryGetNeed<Need_Food>().CurLevelPercentage <= 0.25f;
|
||||
}
|
||||
|
||||
// 检查是否是虫族成员
|
||||
|
||||
Reference in New Issue
Block a user