fix: 修复多个组件的空引用、调试日志和编码问题
### HediffComp_GestaltNode - 添加 pawn 空引用检查,防止 NullReferenceException - 将 Log.Message 改为 ArachnaeLog.Debug 统一日志管理 - 新增 Notify_PawnDied 方法处理 Pawn 死亡时的过渡状态清理 - 修复 UpdateTransitionState 中重复声明 pawn 变量的问题 ### CompAbilityEffect_LaunchMultiProjectile - 添加目标有效性检查,处理目标死亡或消失的情况 - 实现动态目标追踪,更新目标位置 - 移除未使用的 parametersInitialized 字段 - 新增 ForceReinitialize 方法支持状态变化时重新初始化 ### CompHediffGiver - 改进异常处理,记录警告日志而非静默吞掉异常 - 重构 IsSymmetricalPart 方法,使用翻译键和 BodyPartTagDef 支持本地化 ### HediffComp_Spawner - 将 DebugSettings.debugLogging 改为 Prefs.DevMode - 修复所有 UTF-8 编码乱码注释(约30处) ### Comp_PawnResearchBlueprintReader - 修复灵能科研点消耗时机,确保先检查→再消耗→最后添加进度 - 提高研究进度添加的原子性
This commit is contained in:
Binary file not shown.
@@ -13,7 +13,6 @@ namespace ArachnaeSwarm
|
|||||||
private int nextProjectileTick;
|
private int nextProjectileTick;
|
||||||
private int projectilesFired;
|
private int projectilesFired;
|
||||||
private IntVec3? targetCell;
|
private IntVec3? targetCell;
|
||||||
private bool parametersInitialized;
|
|
||||||
|
|
||||||
// 缓存当前状态的参数
|
// 缓存当前状态的参数
|
||||||
private int currentNumProjectiles;
|
private int currentNumProjectiles;
|
||||||
@@ -139,17 +138,20 @@ namespace ArachnaeSwarm
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitializeParameters()
|
private void InitializeParameters()
|
||||||
{
|
{
|
||||||
if (parametersInitialized)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var state = GetCurrentState();
|
var state = GetCurrentState();
|
||||||
|
|
||||||
currentNumProjectiles = state?.numProjectiles ?? Props.numProjectiles;
|
currentNumProjectiles = state?.numProjectiles ?? Props.numProjectiles;
|
||||||
currentProjectileDef = state?.projectileDef ?? Props.projectileDef;
|
currentProjectileDef = state?.projectileDef ?? Props.projectileDef;
|
||||||
currentOffsetRadius = state?.offsetRadius ?? Props.offsetRadius;
|
currentOffsetRadius = state?.offsetRadius ?? Props.offsetRadius;
|
||||||
currentShotIntervalTicks = state?.shotIntervalTicks ?? Props.shotIntervalTicks;
|
currentShotIntervalTicks = state?.shotIntervalTicks ?? Props.shotIntervalTicks;
|
||||||
|
}
|
||||||
parametersInitialized = true;
|
|
||||||
|
/// <summary>
|
||||||
|
/// 强制重新初始化参数(当状态变化时调用)
|
||||||
|
/// </summary>
|
||||||
|
public void ForceReinitialize()
|
||||||
|
{
|
||||||
|
InitializeParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -182,7 +184,31 @@ namespace ArachnaeSwarm
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Pawn pawn = parent.pawn;
|
Pawn pawn = parent.pawn;
|
||||||
|
|
||||||
|
// 检查目标有效性(目标可能已移动或消失)
|
||||||
LocalTargetInfo finalTarget = target;
|
LocalTargetInfo finalTarget = target;
|
||||||
|
if (Props.useSustainedJob && target.Pawn != null)
|
||||||
|
{
|
||||||
|
// 如果是持续模式且有目标Pawn,尝试追踪目标
|
||||||
|
if (target.Pawn.Dead || !target.Pawn.Spawned)
|
||||||
|
{
|
||||||
|
// 目标已死亡或消失,使用最后已知位置
|
||||||
|
if (targetCell.HasValue)
|
||||||
|
{
|
||||||
|
finalTarget = new LocalTargetInfo(targetCell.Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return; // 无法发射
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 更新目标位置
|
||||||
|
targetCell = target.Pawn.Position;
|
||||||
|
finalTarget = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 如果有偏移范围,计算偏移后的目标
|
// 如果有偏移范围,计算偏移后的目标
|
||||||
if (Props.useRandomOffset && currentOffsetRadius > 0)
|
if (Props.useRandomOffset && currentOffsetRadius > 0)
|
||||||
@@ -205,7 +231,6 @@ namespace ArachnaeSwarm
|
|||||||
nextProjectileTick = 0;
|
nextProjectileTick = 0;
|
||||||
projectilesFired = 0;
|
projectilesFired = 0;
|
||||||
targetCell = null;
|
targetCell = null;
|
||||||
parametersInitialized = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ namespace ArachnaeSwarm
|
|||||||
return comp.GestaltTracker;
|
return comp.GestaltTracker;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracker == null && NodeType == GestaltNodeType.OverlordNode)
|
if (tracker == null && NodeType == GestaltNodeType.OverlordNode && pawn != null)
|
||||||
{
|
{
|
||||||
tracker = new Pawn_GestaltTracker(pawn);
|
tracker = new Pawn_GestaltTracker(pawn);
|
||||||
}
|
}
|
||||||
@@ -247,7 +247,7 @@ namespace ArachnaeSwarm
|
|||||||
TryFindOverlord();
|
TryFindOverlord();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Message($"[GestaltNode] {pawn.LabelShort} (HiveNode) 延迟初始化完成,当前连接状态: {IsConnectedToOverlord()}");
|
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} (HiveNode) 延迟初始化完成,当前连接状态: {IsConnectedToOverlord()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,6 +256,15 @@ namespace ArachnaeSwarm
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateTransitionState()
|
private void UpdateTransitionState()
|
||||||
{
|
{
|
||||||
|
// 检查Pawn是否死亡或无效
|
||||||
|
var pawn = Pawn;
|
||||||
|
if (pawn == null || pawn.Dead)
|
||||||
|
{
|
||||||
|
isTransitioning = false;
|
||||||
|
transitionStartTick = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isTransitioning || transitionStartTick < 0)
|
if (!isTransitioning || transitionStartTick < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -267,14 +276,13 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
parent.Severity = targetSeverityAfterTransition;
|
parent.Severity = targetSeverityAfterTransition;
|
||||||
|
|
||||||
// 通知Pawn状态改变
|
// 通知Pawn状态改变(使用方法开头声明的pawn变量)
|
||||||
var pawn = Pawn;
|
|
||||||
if (pawn?.health != null)
|
if (pawn?.health != null)
|
||||||
{
|
{
|
||||||
pawn.health.Notify_HediffChanged(parent);
|
pawn.health.Notify_HediffChanged(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Message($"[GestaltNode] {Pawn?.LabelShort} 过渡完成,严重性: {targetSeverityAfterTransition}");
|
ArachnaeLog.Debug($"[GestaltNode] {pawn?.LabelShort} 过渡完成,严重性: {targetSeverityAfterTransition}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重置过渡状态
|
// 重置过渡状态
|
||||||
@@ -316,7 +324,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Message($"[GestaltNode] {Pawn?.LabelShort} 开始过渡,目标: {(isConnecting ? "连接" : "断开")} ({targetSeverityAfterTransition})");
|
ArachnaeLog.Debug($"[GestaltNode] {Pawn?.LabelShort} 开始过渡,目标: {(isConnecting ? "连接" : "断开")} ({targetSeverityAfterTransition})");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -434,7 +442,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
UpdateSeverityBasedOnConnection();
|
UpdateSeverityBasedOnConnection();
|
||||||
|
|
||||||
Log.Message($"[GestaltNode] {pawn.LabelShort} 连接到 Overlord: {bestOverlord.LabelShort}");
|
ArachnaeLog.Debug($"[GestaltNode] {pawn.LabelShort} 连接到 Overlord: {bestOverlord.LabelShort}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,6 +474,10 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
base.CompPostPostRemoved();
|
base.CompPostPostRemoved();
|
||||||
|
|
||||||
|
// 清理过渡状态
|
||||||
|
isTransitioning = false;
|
||||||
|
transitionStartTick = -1;
|
||||||
|
|
||||||
// 当Hediff被移除时,如果连接到Overlord,需要断开连接
|
// 当Hediff被移除时,如果连接到Overlord,需要断开连接
|
||||||
if (NodeType == GestaltNodeType.HiveNode && IsConnectedToOverlord())
|
if (NodeType == GestaltNodeType.HiveNode && IsConnectedToOverlord())
|
||||||
{
|
{
|
||||||
@@ -483,6 +495,20 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pawn 死亡时的处理
|
||||||
|
/// </summary>
|
||||||
|
public override void Notify_PawnDied(DamageInfo? dinfo, Hediff culprit = null)
|
||||||
|
{
|
||||||
|
base.Notify_PawnDied(dinfo, culprit);
|
||||||
|
|
||||||
|
// 清理过渡状态
|
||||||
|
isTransitioning = false;
|
||||||
|
transitionStartTick = -1;
|
||||||
|
|
||||||
|
ArachnaeLog.Debug($"[GestaltNode] {Pawn?.LabelShort} 死亡,清理过渡状态");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 序列化
|
/// 序列化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
if (this.Props.animalThing)
|
if (this.Props.animalThing)
|
||||||
{
|
{
|
||||||
// 鍔ㄧ墿鐢熸垚閫昏緫淇濇寔涓嶅彉
|
// 动物生成逻辑保持不变
|
||||||
if (this.Props.spawnMaxAdjacent > 0 && pawn.Map.mapPawns.AllPawns.Where(delegate(Pawn mP)
|
if (this.Props.spawnMaxAdjacent > 0 && pawn.Map.mapPawns.AllPawns.Where(delegate(Pawn mP)
|
||||||
{
|
{
|
||||||
ThingDef defToCompare = this.Props.animalThing ? this.Props.animalToSpawn?.race : this.Props.thingToSpawn;
|
ThingDef defToCompare = this.Props.animalThing ? this.Props.animalToSpawn?.race : this.Props.thingToSpawn;
|
||||||
@@ -402,10 +402,10 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 閲嶆柊璁捐鐗╁搧鐢熸垚閫昏緫锛氭寜浼樺厛绾ч『搴忓皾璇?
|
// 重新设计物品生成逻辑:按优先级顺序尝试
|
||||||
bool success = TrySpawnItemWithPriority(pawn);
|
bool success = TrySpawnItemWithPriority(pawn);
|
||||||
|
|
||||||
// === 鏂板锛氬鏋滈厤缃簡閿€姣侀殢鏈洪儴浣嶏紝鍦ㄦ垚鍔熺敓鎴愮墿鍝佸悗鎵ц ===
|
// === 新增:如果配置了销毁随机部位,在成功生成物品后执行 ===
|
||||||
if (success && this.Props.destroyRandomBodyPart)
|
if (success && this.Props.destroyRandomBodyPart)
|
||||||
{
|
{
|
||||||
DestroyRandomBodyPart(pawn);
|
DestroyRandomBodyPart(pawn);
|
||||||
@@ -415,7 +415,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鏂板锛氶攢姣侀殢鏈鸿韩浣撻儴浣嶏紙鍙傝€?CompAbilityEffect_DestroyOwnBodyPart锛?
|
// 新增:销毁随机身体部位(参考 CompAbilityEffect_DestroyOwnBodyPart)
|
||||||
private void DestroyRandomBodyPart(Pawn pawn)
|
private void DestroyRandomBodyPart(Pawn pawn)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -426,7 +426,7 @@ namespace ArachnaeSwarm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鑾峰彇鎵€鏈夊彲浠ラ攢姣佺殑韬綋閮ㄤ綅
|
// 获取所有可以销毁的身体部位
|
||||||
List<BodyPartRecord> possibleParts = GetDestroyableBodyParts(pawn);
|
List<BodyPartRecord> possibleParts = GetDestroyableBodyParts(pawn);
|
||||||
|
|
||||||
if (possibleParts.Count == 0)
|
if (possibleParts.Count == 0)
|
||||||
@@ -435,7 +435,7 @@ namespace ArachnaeSwarm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 闅忔満閫夋嫨涓€涓儴浣?
|
// 随机选择一个部位
|
||||||
BodyPartRecord partToDestroy = possibleParts.RandomElement();
|
BodyPartRecord partToDestroy = possibleParts.RandomElement();
|
||||||
|
|
||||||
if (partToDestroy == null)
|
if (partToDestroy == null)
|
||||||
@@ -444,10 +444,10 @@ namespace ArachnaeSwarm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 璁板綍閮ㄤ綅鍚嶇О
|
// 记录部位名称
|
||||||
string partName = partToDestroy.def?.label ?? "鏈煡閮ㄤ綅";
|
string partName = partToDestroy.def?.label ?? "未知部位";
|
||||||
|
|
||||||
// 娣诲姞缂哄け閮ㄤ綅hediff
|
// 添加缺失部位hediff
|
||||||
pawn.health.AddHediff(HediffDefOf.MissingBodyPart, partToDestroy);
|
pawn.health.AddHediff(HediffDefOf.MissingBodyPart, partToDestroy);
|
||||||
|
|
||||||
Warn($"Destroyed {partName} on {pawn.LabelShort}", this.myDebug);
|
Warn($"Destroyed {partName} on {pawn.LabelShort}", this.myDebug);
|
||||||
@@ -458,7 +458,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鏂板锛氳幏鍙栧彲浠ラ攢姣佺殑韬綋閮ㄤ綅鍒楄〃
|
// 新增:获取可以销毁的身体部位列表
|
||||||
private List<BodyPartRecord> GetDestroyableBodyParts(Pawn pawn)
|
private List<BodyPartRecord> GetDestroyableBodyParts(Pawn pawn)
|
||||||
{
|
{
|
||||||
List<BodyPartRecord> destroyableParts = new List<BodyPartRecord>();
|
List<BodyPartRecord> destroyableParts = new List<BodyPartRecord>();
|
||||||
@@ -466,20 +466,20 @@ namespace ArachnaeSwarm
|
|||||||
if (pawn?.health?.hediffSet == null)
|
if (pawn?.health?.hediffSet == null)
|
||||||
return destroyableParts;
|
return destroyableParts;
|
||||||
|
|
||||||
// 鑾峰彇鎵€鏈夎韩浣撻儴浣?
|
// 获取所有身体部位
|
||||||
List<BodyPartRecord> allParts = pawn.RaceProps.body.AllParts;
|
List<BodyPartRecord> allParts = pawn.RaceProps.body.AllParts;
|
||||||
|
|
||||||
foreach (BodyPartRecord part in allParts)
|
foreach (BodyPartRecord part in allParts)
|
||||||
{
|
{
|
||||||
// 鎺掗櫎鏍稿績閮ㄤ綅锛堥伩鍏嶆浜★級
|
// 排除核心部位(避免死亡)
|
||||||
if (IsCriticalBodyPart(part))
|
if (IsCriticalBodyPart(part))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 鎺掗櫎宸茬粡缂哄け鐨勯儴浣?
|
// 排除已经缺失的部位
|
||||||
if (pawn.health.hediffSet.PartIsMissing(part))
|
if (pawn.health.hediffSet.PartIsMissing(part))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 鎺掗櫎宸茬粡鏈変弗閲嶄激瀹崇殑閮ㄤ綅锛堝彲閫夛級
|
// 排除已经有严重伤害的部位(可选)
|
||||||
if (pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part))
|
if (pawn.health.hediffSet.PartOrAnyAncestorHasDirectlyAddedParts(part))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -492,34 +492,34 @@ namespace ArachnaeSwarm
|
|||||||
return destroyableParts;
|
return destroyableParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鏂板锛氭鏌ユ槸鍚︽槸鍏抽敭韬綋閮ㄤ綅
|
// 新增:检查是否是关键身体部位
|
||||||
private bool IsCriticalBodyPart(BodyPartRecord part)
|
private bool IsCriticalBodyPart(BodyPartRecord part)
|
||||||
{
|
{
|
||||||
if (part == null)
|
if (part == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// 鏍规嵁鏍囩鍒ゆ柇鏄惁涓哄叧閿儴浣?
|
// 根据标签判断是否为关键部位
|
||||||
if (part.def.tags != null)
|
if (part.def.tags != null)
|
||||||
{
|
{
|
||||||
// 杩欎簺鏍囩閫氬父琛ㄧず鍏抽敭閮ㄤ綅
|
// 这些标签通常表示关键部位
|
||||||
if (part.def.tags.Contains(BodyPartTagDefOf.ConsciousnessSource) || // 鎰忚瘑婧愶紙澶ц剳锛?
|
if (part.def.tags.Contains(BodyPartTagDefOf.ConsciousnessSource) || // 意识源(大脑)
|
||||||
part.def.tags.Contains(BodyPartTagDefOf.BloodPumpingSource) || // 琛€娑叉车婧愶紙蹇冭剰锛?
|
part.def.tags.Contains(BodyPartTagDefOf.BloodPumpingSource) || // 血液泵源(心脏)
|
||||||
part.def.tags.Contains(BodyPartTagDefOf.BreathingSource) || // 鍛煎惛婧愶紙鑲猴級
|
part.def.tags.Contains(BodyPartTagDefOf.BreathingSource) || // 呼吸源(肺)
|
||||||
part.def.tags.Contains(BodyPartTagDefOf.MetabolismSource) // 浠h阿婧愶紙鑲濊剰锛?
|
part.def.tags.Contains(BodyPartTagDefOf.MetabolismSource) // 代谢源(肝脏)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鏍规嵁娣卞害鍒ゆ柇锛堟繁搴﹁緝娣辩殑閫氬父鏄唴閮ㄥ櫒瀹橈級
|
// 根据深度判断(深度较深的通常是内部器官)
|
||||||
if (part.depth == BodyPartDepth.Inside && part.parent == null)
|
if (part.depth == BodyPartDepth.Inside && part.parent == null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 鏂板锛氭寜浼樺厛绾ч『搴忓皾璇曠敓鎴愮墿鍝?
|
// 新增:按优先级顺序尝试生成物品
|
||||||
private bool TrySpawnItemWithPriority(Pawn pawn)
|
private bool TrySpawnItemWithPriority(Pawn pawn)
|
||||||
{
|
{
|
||||||
Thing thing = ThingMaker.MakeThing(this.Props.thingToSpawn, null);
|
Thing thing = ThingMaker.MakeThing(this.Props.thingToSpawn, null);
|
||||||
@@ -739,19 +739,19 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 淇敼杩欓噷锛氬皢鍗婂緞浠?鍑忓皯鍒?锛岃鐢熸垚浣嶇疆鏇撮潬杩憄awn
|
// 修改这里:将半径从3减少到2,让生成位置更靠近Pawn
|
||||||
int searchRadius = 2;
|
int searchRadius = 2;
|
||||||
|
|
||||||
// 棣栧厛灏濊瘯鍦╬awn鐨勭浉閭诲崟鍏冩牸鐢熸垚锛堝崐寰勪负1锛?
|
// 首先尝试在Pawn的相邻单元格生成(半径为1)
|
||||||
result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, 1, null);
|
result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, 1, null);
|
||||||
|
|
||||||
// 濡傛灉鐩搁偦鍗曞厓鏍兼壘涓嶅埌鍚堥€備綅缃紝鍐嶅皾璇曠◢杩滀竴鐐癸紙鍗婂緞涓?锛?
|
// 如果相邻单元格找不到合适位置,再尝试稍远一点(半径为2)
|
||||||
if (!result.IsValid)
|
if (!result.IsValid)
|
||||||
{
|
{
|
||||||
result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, searchRadius, null);
|
result = CellFinder.RandomClosewalkCellNear(this.pawn.Position, map, searchRadius, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 濡傛灉杩樻槸鎵句笉鍒帮紝灏濊瘯pawn褰撳墠浣嶇疆锛堜綔涓烘渶鍚庢墜娈碉級
|
// 如果还是找不到,尝试Pawn当前位置(作为最后手段)
|
||||||
if (!result.IsValid && this.pawn.Position.IsValid && this.pawn.Position.Walkable(map))
|
if (!result.IsValid && this.pawn.Position.IsValid && this.pawn.Position.Walkable(map))
|
||||||
{
|
{
|
||||||
result = this.pawn.Position;
|
result = this.pawn.Position;
|
||||||
@@ -848,7 +848,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// === 鏁村悎鐨?Tools 鏂规硶 ===
|
// === 整合的 Tools 方法 ===
|
||||||
|
|
||||||
private void DestroyParentHediff(Hediff parentHediff, bool debug = false)
|
private void DestroyParentHediff(Hediff parentHediff, bool debug = false)
|
||||||
{
|
{
|
||||||
@@ -968,7 +968,7 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
private void Warn(string warning, bool debug = false)
|
private void Warn(string warning, bool debug = false)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug && Prefs.DevMode)
|
||||||
{
|
{
|
||||||
Log.Message($"[HediffComp_Spawner] {warning}");
|
Log.Message($"[HediffComp_Spawner] {warning}");
|
||||||
}
|
}
|
||||||
@@ -990,4 +990,3 @@ namespace ArachnaeSwarm
|
|||||||
private readonly int errorSpawnCount = 750;
|
private readonly int errorSpawnCount = 750;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,8 +117,9 @@ namespace ArachnaeSwarm
|
|||||||
ArachnaeLog.Debug($"Added hediff {hediffDef.defName} to {pawn.Label} " +
|
ArachnaeLog.Debug($"Added hediff {hediffDef.defName} to {pawn.Label} " +
|
||||||
$"{(bodyPart != null ? $"on {bodyPart.def.defName}" : "to whole body")}");
|
$"{(bodyPart != null ? $"on {bodyPart.def.defName}" : "to whole body")}");
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Log.Warning($"[CompHediffGiver] Failed to add hediff {hediffDef?.defName ?? "null"} to {pawn?.Label ?? "null"}: {ex.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,27 +253,50 @@ namespace ArachnaeSwarm
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool IsSymmetricalPart(BodyPartRecord part1, BodyPartRecord part2)
|
private bool IsSymmetricalPart(BodyPartRecord part1, BodyPartRecord part2)
|
||||||
{
|
{
|
||||||
// 简单的对称检测逻辑
|
// 优先使用 BodyPartDef 的对称标签检测
|
||||||
|
if (part1.def == part2.def)
|
||||||
|
{
|
||||||
|
// 检查是否有对称标签
|
||||||
|
if (part1.def.tags != null)
|
||||||
|
{
|
||||||
|
// 使用 BodyPartTagDef 进行对称检测
|
||||||
|
bool part1Left = part1.def.tags.Any(t => t.defName.Contains("Left"));
|
||||||
|
bool part1Right = part1.def.tags.Any(t => t.defName.Contains("Right"));
|
||||||
|
bool part2Left = part2.def.tags.Any(t => t.defName.Contains("Left"));
|
||||||
|
bool part2Right = part2.def.tags.Any(t => t.defName.Contains("Right"));
|
||||||
|
|
||||||
|
if ((part1Left && part2Right) || (part1Right && part2Left))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 备用方案:使用自定义标签检测(支持本地化)
|
||||||
string label1 = part1.customLabel ?? part1.def.label;
|
string label1 = part1.customLabel ?? part1.def.label;
|
||||||
string label2 = part2.customLabel ?? part2.def.label;
|
string label2 = part2.customLabel ?? part2.def.label;
|
||||||
|
|
||||||
// 检查是否包含对称标识符
|
// 使用翻译键检测,而非硬编码英文
|
||||||
string[] symmetryKeywords = { "Left", "Right", "Left", "Right", "Front", "Back", "Upper", "Lower" };
|
string leftKey = "Left".Translate();
|
||||||
|
string rightKey = "Right".Translate();
|
||||||
|
|
||||||
foreach (var keyword in symmetryKeywords)
|
bool label1HasLeft = label1.Contains(leftKey) || label1.Contains("Left");
|
||||||
{
|
bool label1HasRight = label1.Contains(rightKey) || label1.Contains("Right");
|
||||||
if (label1.Contains(keyword) && label2.Contains(keyword))
|
bool label2HasLeft = label2.Contains(leftKey) || label2.Contains("Left");
|
||||||
{
|
bool label2HasRight = label2.Contains(rightKey) || label2.Contains("Right");
|
||||||
// 检查是否是对称的关键词对
|
|
||||||
if ((keyword == "Left" && label2.Contains("Right")) ||
|
if ((label1HasLeft && label2HasRight) || (label1HasRight && label2HasLeft))
|
||||||
(keyword == "Right" && label2.Contains("Left")) ||
|
return true;
|
||||||
(keyword == "Front" && label2.Contains("Back")) ||
|
|
||||||
(keyword == "Back" && label2.Contains("Front")))
|
// 检查前后对称
|
||||||
{
|
string frontKey = "Front".Translate();
|
||||||
return true;
|
string backKey = "Back".Translate();
|
||||||
}
|
|
||||||
}
|
bool label1HasFront = label1.Contains(frontKey) || label1.Contains("Front");
|
||||||
}
|
bool label1HasBack = label1.Contains(backKey) || label1.Contains("Back");
|
||||||
|
bool label2HasFront = label2.Contains(frontKey) || label2.Contains("Front");
|
||||||
|
bool label2HasBack = label2.Contains(backKey) || label2.Contains("Back");
|
||||||
|
|
||||||
|
if ((label1HasFront && label2HasBack) || (label1HasBack && label2HasFront))
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,10 +345,11 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
int pointsToAdd = Mathf.FloorToInt(accumulatedResearchPoints);
|
int pointsToAdd = Mathf.FloorToInt(accumulatedResearchPoints);
|
||||||
|
|
||||||
// 消耗灵能科研点
|
// 先检查并消耗灵能科研点,再添加进度(确保原子性)
|
||||||
if (Props.usePsychicResearchPoints && spellHolder != null)
|
if (Props.usePsychicResearchPoints && spellHolder != null)
|
||||||
{
|
{
|
||||||
if (!spellHolder.ConsumePsychicResearchPoints(pointsToAdd, $"研究 {currentResearch.LabelCap}"))
|
// 先检查是否有足够的灵能科研点
|
||||||
|
if (!spellHolder.HasEnoughPsychicResearchPoints(pointsToAdd))
|
||||||
{
|
{
|
||||||
// 灵能科研点不足,停止研究
|
// 灵能科研点不足,停止研究
|
||||||
StopResearching();
|
StopResearching();
|
||||||
@@ -356,9 +357,17 @@ namespace ArachnaeSwarm
|
|||||||
Pawn, MessageTypeDefOf.NegativeEvent);
|
Pawn, MessageTypeDefOf.NegativeEvent);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 消耗灵能科研点
|
||||||
|
if (!spellHolder.ConsumePsychicResearchPoints(pointsToAdd, $"研究 {currentResearch.LabelCap}"))
|
||||||
|
{
|
||||||
|
// 消耗失败(理论上不应该发生,因为已经检查过了)
|
||||||
|
StopResearching();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加到全局研究进度
|
// 添加到全局研究进度(在消耗成功后)
|
||||||
AddResearchProgress(pointsToAdd);
|
AddResearchProgress(pointsToAdd);
|
||||||
|
|
||||||
// 减去已添加的点数
|
// 减去已添加的点数
|
||||||
|
|||||||
Reference in New Issue
Block a user