Files
ArachnaeSwarm/Source/ArachnaeSwarm/PowerArmor/ARA_PowerArmor.cs
ProjectKoi-Kalo\Kalo 675ac8b298 创建了 ArachnaeSwarmSettings.cs - 包含 enableDebugLogs 字段
 创建了 ArachnaeLog.cs - 中央化日志类,仅检查mod设置(不检查DevMode)
 创建了 ArachnaeSwarmMod.cs - Mod主类,提供UI设置选项
 修改了 MainHarmony.cs - 移除重复的Harmony初始化(现在由ArachnaeSwarmMod处理)
 修改了 .csproj - 添加了3个新文件到编译列表
 替换了所有582个 Log.Message/Error/Warning 调用为 ArachnaeLog.Debug()
2025-12-15 13:11:45 +08:00

575 lines
22 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RimWorld;
using UnityEngine;
using Verse;
using System.Collections.Generic;
using System.Linq;
namespace ArachnaeSwarm
{
public static class ARA_Translations
{
// 武装方案相关
public static readonly string UnknownScheme = "ARA_UnknownScheme";
public static readonly string SchemeFormat = "ARA_SchemeFormat";
// 消息提示
public static readonly string PowerArmorDamaged = "ARA_PowerArmorDamaged";
public static readonly string SwitchedToMode = "ARA_SwitchedToMode";
public static readonly string EquipPowerArmorFailed = "ARA_EquipPowerArmorFailed";
public static readonly string AlreadySelectedScheme = "ARA_AlreadySelectedScheme";
// Gizmo 按钮文本
public static readonly string SwitchWeapon = "ARA_SwitchWeapon";
public static readonly string SwitchWeaponDesc = "ARA_SwitchWeaponDesc";
public static readonly string SwitchToScheme = "ARA_SwitchToScheme";
// 默认值
public static readonly string Default = "ARA_Default";
}
public interface IStructurePoints
{
float StructurePoints { get; }
float StructurePointsMax { get; }
float StructurePointsPercent { get; }
string Label { get; }
}
public class PowerArmorWeaponSet
{
public string label; // 方案名称显示在UI上
public string description; // 方案描述显示在按钮的desc上
public ThingDef weapon; // 武器定义
public List<HediffDef> hediffsToAdd; // 切换到此方案时添加的Hediff
public List<HediffDef> hediffsToRemove; // 切换到此方案时移除的Hediff
public string iconPath; // 可选的图标路径
}
public class PowerArmorExtension : DefModExtension
{
public ThingDef buildingDef;
public float structurePointsMax = 500f;
public HediffDef hediffOnEmptyFuel;
public float fuelConsumptionRate = 0.5f; // Nutrition per day
// 废弃原来的单个武器,改用列表
public List<PowerArmorWeaponSet> weaponSets = new List<PowerArmorWeaponSet>();
// 默认武装方案索引
public int defaultWeaponSetIndex = 0;
}
[StaticConstructorOnStartup]
public class ARA_PowerArmor : Apparel, IStructurePoints
{
#region Properties
private PowerArmorExtension ext;
public PowerArmorExtension Ext => ext ??= def.GetModExtension<PowerArmorExtension>();
public override string Label => base.Label;
private float structurePoints = -1f;
public float StructurePointsMax => Ext?.structurePointsMax ?? 500f;
public float StructurePoints
{
get
{
if (structurePoints < 0)
{
structurePoints = StructurePointsMax;
}
return structurePoints;
}
set
{
structurePoints = Mathf.Clamp(value, 0, StructurePointsMax);
}
}
public float StructurePointsPercent => StructurePoints / StructurePointsMax;
public Building sourceBuilding;
private ThingWithComps originalWeapon;
private ThingWithComps currentPowerArmorWeapon;
// 新增字段:武装方案管理
private int currentWeaponSetIndex = 0;
private List<Hediff> activeHediffs = new List<Hediff>();
public int CurrentWeaponSetIndex => currentWeaponSetIndex;
public PowerArmorWeaponSet CurrentWeaponSet =>
Ext?.weaponSets != null && Ext.weaponSets.Count > currentWeaponSetIndex ?
Ext.weaponSets[currentWeaponSetIndex] : null;
public int WeaponSetCount => Ext?.weaponSets?.Count ?? 0;
public void SetOriginalWeapon(ThingWithComps weapon)
{
originalWeapon = weapon;
}
public void SetCurrentPowerArmorWeapon(ThingWithComps weapon)
{
currentPowerArmorWeapon = weapon;
}
#endregion
#region /
public override void Notify_Equipped(Pawn pawn)
{
base.Notify_Equipped(pawn);
// 设置默认武装方案
currentWeaponSetIndex = Ext?.defaultWeaponSetIndex ?? 0;
// 应用初始武装方案
ApplyWeaponSet(pawn, CurrentWeaponSet);
ArachnaeLog.Debug($"[PA_Debug] 装备动力装甲,应用武装方案: {CurrentWeaponSet?.label ?? ""}");
}
public override void Notify_Unequipped(Pawn pawn)
{
// 清除所有激活的Hediff
foreach (var hediff in activeHediffs)
{
if (pawn.health.hediffSet.hediffs.Contains(hediff))
{
pawn.health.RemoveHediff(hediff);
}
}
activeHediffs.Clear();
base.Notify_Unequipped(pawn);
// 原有卸下逻辑保持不变...
if (Ext?.weaponSets != null && Ext.weaponSets.Count > 0)
{
// 销毁当前动力装甲武器
if (currentPowerArmorWeapon != null)
{
if (pawn?.equipment != null && pawn.equipment.Contains(currentPowerArmorWeapon))
{
pawn.equipment.Remove(currentPowerArmorWeapon);
}
else if (pawn?.inventory?.innerContainer != null && pawn.inventory.innerContainer.Contains(currentPowerArmorWeapon))
{
pawn.inventory.innerContainer.Remove(currentPowerArmorWeapon);
}
else if (currentPowerArmorWeapon.Spawned)
{
currentPowerArmorWeapon.DeSpawn();
}
string destroyedWeaponLabel = currentPowerArmorWeapon.Label;
currentPowerArmorWeapon.Destroy();
ArachnaeLog.Debug($"[PA_Debug] Notify_Unequipped: 销毁动力装甲武器 {destroyedWeaponLabel}.");
currentPowerArmorWeapon = null;
}
// 恢复原始武器
if (originalWeapon != null && pawn?.equipment != null)
{
string originalWeaponLabel = originalWeapon.Label;
pawn.equipment.MakeRoomFor(originalWeapon);
pawn.equipment.AddEquipment(originalWeapon);
ArachnaeLog.Debug($"[PA_Debug] Notify_Unequipped: 恢复原始武器 {originalWeaponLabel}.");
originalWeapon = null;
}
}
Building building = sourceBuilding;
// 如果源建筑引用丢失,创建新建筑作为回退
if (building == null)
{
ThingDef buildingDef = Ext?.buildingDef;
if (buildingDef == null)
{
ArachnaeLog.Debug($"[ArachnaeSwarm] 动力装甲 {this.def.defName} 卸下但在其PowerArmorExtension中未定义buildingDef且源建筑引用丢失。");
this.Destroy(DestroyMode.Vanish);
return;
}
building = (Building)ThingMaker.MakeThing(buildingDef);
}
// 同步健康值回建筑
building.HitPoints = Mathf.Max(1, Mathf.RoundToInt(this.StructurePoints));
// 同步燃料回建筑
var apparelFuelComp = this.GetComp<CompRefuelableNutrition>();
var buildingFuelComp = building.GetComp<CompRefuelableNutrition>();
if (apparelFuelComp != null && buildingFuelComp != null)
{
buildingFuelComp.ConsumeFuel(buildingFuelComp.Fuel);
buildingFuelComp.ReceiveFuel(apparelFuelComp.Fuel);
}
// 同步质量回建筑
if (this.TryGetComp<CompQuality>() is CompQuality apparelQuality && building.TryGetComp<CompQuality>() is CompQuality buildingQuality)
{
buildingQuality.SetQuality(apparelQuality.Quality, ArtGenerationContext.Colony);
}
ArachnaeLog.Debug($"[PA_Debug] Notify_Unequipped: 生成建筑前 (ID: {building.thingIDNumber}) - HitPoints: {building.HitPoints}, StackCount: {building.stackCount}");
// 确保建筑堆叠数至少为1
if (building.stackCount <= 0)
{
building.stackCount = 1;
ArachnaeLog.Debug($"[PA_Debug] Notify_Unequipped: 修正建筑 (ID: {building.thingIDNumber}) 堆叠数为1因为原为0。");
}
// 设置派系
building.SetFaction(pawn.Faction);
// 重新生成原始建筑实例
GenPlace.TryPlaceThing(building, pawn.Position, pawn.Map, ThingPlaceMode.Near);
ArachnaeLog.Debug($"[PA_Debug] Notify_Unequipped: 生成建筑后 (ID: {building.thingIDNumber}) - HitPoints: {building.HitPoints}, StackCount: {building.stackCount}");
}
#endregion
#region
/// <summary>
/// 切换到下一个武装方案
/// </summary>
public void CycleToNextWeaponSet()
{
if (WeaponSetCount <= 1) return;
var oldSet = CurrentWeaponSet;
currentWeaponSetIndex = (currentWeaponSetIndex + 1) % WeaponSetCount;
var newSet = CurrentWeaponSet;
ArachnaeLog.Debug($"[PA_Debug] 切换武装方案: {oldSet?.label ?? ""} -> {newSet?.label ?? ""}");
ApplyWeaponSet(Wearer, newSet, oldSet);
}
/// <summary>
/// 切换到指定索引的武装方案
/// </summary>
public void SwitchToWeaponSet(int index)
{
if (index < 0 || index >= WeaponSetCount) return;
var oldSet = CurrentWeaponSet;
currentWeaponSetIndex = index;
var newSet = CurrentWeaponSet;
ArachnaeLog.Debug($"[PA_Debug] 切换到武装方案: {oldSet?.label ?? ""} -> {newSet?.label ?? ""}");
ApplyWeaponSet(Wearer, newSet, oldSet);
}
/// <summary>
/// 应用指定的武装方案
/// </summary>
private void ApplyWeaponSet(Pawn pawn, PowerArmorWeaponSet newSet, PowerArmorWeaponSet oldSet = null)
{
if (pawn == null) return;
// 移除旧方案的Hediff
if (oldSet?.hediffsToRemove != null)
{
foreach (var hediffDef in oldSet.hediffsToRemove)
{
var hediff = pawn.health.hediffSet.GetFirstHediffOfDef(hediffDef);
if (hediff != null)
{
pawn.health.RemoveHediff(hediff);
}
}
}
// 清除当前激活的Hediff
foreach (var hediff in activeHediffs.ToList())
{
if (pawn.health.hediffSet.hediffs.Contains(hediff))
{
pawn.health.RemoveHediff(hediff);
}
}
activeHediffs.Clear();
// 添加新方案的Hediff
if (newSet?.hediffsToAdd != null)
{
foreach (var hediffDef in newSet.hediffsToAdd)
{
var hediff = pawn.health.GetOrAddHediff(hediffDef);
activeHediffs.Add(hediff);
ArachnaeLog.Debug($"[PA_Debug] 添加Hediff: {hediffDef.defName}");
}
}
// 处理武器切换
HandleWeaponSwitch(pawn, newSet);
// 显示切换消息
if (newSet != null)
{
Messages.Message(ARA_Translations.SwitchedToMode.Translate(newSet.label), pawn, MessageTypeDefOf.NeutralEvent);
}
}
/// <summary>
/// 处理武器切换逻辑
/// </summary>
private void HandleWeaponSwitch(Pawn pawn, PowerArmorWeaponSet newSet)
{
if (pawn?.equipment == null) return;
// 销毁当前动力装甲武器
if (currentPowerArmorWeapon != null)
{
if (pawn.equipment.Contains(currentPowerArmorWeapon))
{
pawn.equipment.Remove(currentPowerArmorWeapon);
}
currentPowerArmorWeapon.Destroy();
currentPowerArmorWeapon = null;
ArachnaeLog.Debug($"[PA_Debug] 销毁当前动力装甲武器");
}
// 如果新方案有武器,装备新武器
if (newSet?.weapon != null)
{
ThingWithComps weapon = (ThingWithComps)ThingMaker.MakeThing(newSet.weapon);
// 同步武器质量
if (this.TryGetComp<CompQuality>() is CompQuality apparelQuality &&
weapon.TryGetComp<CompQuality>() is CompQuality weaponQuality)
{
weaponQuality.SetQuality(apparelQuality.Quality, ArtGenerationContext.Colony);
}
pawn.equipment.MakeRoomFor(weapon);
pawn.equipment.AddEquipment(weapon);
SetCurrentPowerArmorWeapon(weapon);
ArachnaeLog.Debug($"[PA_Debug] 装备新武器: {weapon.Label}");
}
// 如果没有武器,恢复原始武器
else if (originalWeapon != null)
{
pawn.equipment.MakeRoomFor(originalWeapon);
pawn.equipment.AddEquipment(originalWeapon);
ArachnaeLog.Debug($"[PA_Debug] 恢复原始武器: {originalWeapon.Label}");
}
}
/// <summary>
/// 获取武装方案显示名称
/// </summary>
public string GetWeaponSetDisplayName(int index)
{
if (index < 0 || index >= WeaponSetCount) return ARA_Translations.UnknownScheme.Translate();
var set = Ext.weaponSets[index];
return set.label ?? ARA_Translations.SchemeFormat.Translate(index + 1);
}
/// <summary>
/// 获取武装方案描述
/// </summary>
public string GetWeaponSetDescription(int index)
{
if (index < 0 || index >= WeaponSetCount) return string.Empty;
var set = Ext.weaponSets[index];
// 如果设置了自定义描述,使用自定义描述
if (!string.IsNullOrEmpty(set.description))
{
return set.description;
}
// 否则使用默认的翻译文本
return ARA_Translations.SwitchToScheme.Translate(
set.label ?? ARA_Translations.SchemeFormat.Translate(index + 1));
}
#endregion
#region Ticker
protected override void Tick()
{
base.Tick();
if (this.Wearer == null)
{
if (!this.Destroyed)
{
this.Destroy();
}
return;
}
var fuelComp = this.GetComp<CompRefuelableNutrition>();
if (fuelComp != null)
{
// 设置消耗率
fuelComp.currentConsumptionRate = Ext?.fuelConsumptionRate ?? 0f;
fuelComp.CompTick();
// 处理空燃料Hediff
if (this.Wearer.IsHashIntervalTick(60))
{
var hediffDef = Ext?.hediffOnEmptyFuel;
if (hediffDef != null)
{
var hediff = this.Wearer.health.hediffSet.GetFirstHediffOfDef(hediffDef);
if (!fuelComp.HasFuel)
{
if (hediff == null)
{
this.Wearer.health.AddHediff(hediffDef);
}
}
else
{
if (hediff != null)
{
this.Wearer.health.RemoveHediff(hediff);
}
}
}
}
}
}
#endregion
#region
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref structurePoints, "structurePoints", -1f);
Scribe_References.Look(ref sourceBuilding, "sourceBuilding");
Scribe_References.Look(ref originalWeapon, "originalWeapon");
Scribe_References.Look(ref currentPowerArmorWeapon, "currentPowerArmorWeapon");
Scribe_Values.Look(ref currentWeaponSetIndex, "currentWeaponSetIndex", 0);
// 注意Hediff不需要保存因为会在加载时重新应用
}
#endregion
#region Gizmo
public override IEnumerable<Gizmo> GetWornGizmos()
{
// 基础Gizmo
foreach (var gizmo in base.GetWornGizmos())
{
yield return gizmo;
}
// 结构点面板
yield return new Gizmo_StructurePanel(this);
// 武装方案切换按钮(只有在有多个方案时显示)
if (WeaponSetCount > 1)
{
// 主切换按钮(已注释,但保留翻译)
/*
yield return new Command_Action
{
defaultLabel = ARA_Translations.SwitchWeapon.Translate(CurrentWeaponSet?.label ?? ARA_Translations.Default.Translate()),
defaultDesc = ARA_Translations.SwitchWeaponDesc.Translate(
CurrentWeaponSet?.label ?? ARA_Translations.Default.Translate(),
WeaponSetCount),
icon = ContentFinder<Texture2D>.Get("UI/Commands/Attack") ?? BaseContent.BadTex,
action = CycleToNextWeaponSet
};
*/
// 为每个武装方案提供单独的切换按钮
for (int i = 0; i < WeaponSetCount; i++)
{
int currentIndex = i; // 创建局部变量捕获当前索引
var set = Ext.weaponSets[currentIndex];
var command = new Command_Action
{
defaultLabel = set.label ?? ARA_Translations.SchemeFormat.Translate(currentIndex + 1),
defaultDesc = GetWeaponSetDescription(currentIndex), // 使用新的描述获取方法
icon = set.iconPath != null ? ContentFinder<Texture2D>.Get(set.iconPath) : ContentFinder<Texture2D>.Get("UI/Commands/Attack"),
action = () => SwitchToWeaponSet(currentIndex) // 使用局部变量
};
// 正确禁用当前已选择的方案按钮
if (currentIndex == currentWeaponSetIndex)
{
command.Disable(ARA_Translations.AlreadySelectedScheme.Translate());
}
yield return command;
}
}
// 燃料组件Gizmo
var fuelComp = this.GetComp<CompRefuelableNutrition>();
if (fuelComp != null)
{
foreach (var gizmo in fuelComp.CompGetGizmosExtra())
{
yield return gizmo;
}
}
}
#endregion
#region
public override bool CheckPreAbsorbDamage(DamageInfo dinfo)
{
if (this.Wearer == null || !dinfo.Def.harmsHealth || dinfo.Amount <= 0.001f)
{
return false;
}
float finalDamage = GetPostArmorDamage(ref dinfo);
if (finalDamage > 0)
{
this.StructurePoints -= finalDamage;
EffecterDefOf.DamageDiminished_Metal.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
if (this.StructurePoints <= 0)
{
Messages.Message(ARA_Translations.PowerArmorDamaged.Translate(this.Label, this.Wearer.LabelShort), this, MessageTypeDefOf.NegativeEvent);
this.Destroy(DestroyMode.KillFinalize);
}
}
else
{
EffecterDefOf.Deflect_Metal_Bullet.SpawnAttached(this.Wearer, this.Wearer.Map, 1f);
}
// 返回true表示伤害已被完全处理不应继续传递给pawn
return true;
}
private float GetPostArmorDamage(ref DamageInfo dinfo)
{
float amount = dinfo.Amount;
if (dinfo.Def.armorCategory != null)
{
StatDef armorRatingStat = dinfo.Def.armorCategory.armorRatingStat;
float armorRating = this.GetStatValue(armorRatingStat);
float armorPenetration = dinfo.ArmorPenetrationInt;
float num = Mathf.Max(armorRating - armorPenetration, 0f);
float value = Rand.Value;
float num2 = num * 0.5f;
float num3 = num;
if (value < num2)
{
amount = 0f;
}
else if (value < num3)
{
amount = GenMath.RoundRandom(amount / 2f);
if (dinfo.Def.armorCategory == DamageArmorCategoryDefOf.Sharp)
{
dinfo.Def = DamageDefOf.Blunt;
}
}
}
return amount;
}
#endregion
}
}