This commit is contained in:
Tourswen
2025-11-30 14:39:22 +08:00
parent 14a2cf542c
commit 6a5c5bd9aa
60 changed files with 3121 additions and 670 deletions

View File

@@ -23,6 +23,9 @@ namespace WulaFallenEmpire
public int StoredCount => storedMechanoidCount;
public int MaxStorage => Props.maxStorageCapacity;
public bool IsCooldownActive => Find.TickManager.TicksGame - spawnTick < 24 * 2500; // 24小时冷却
// 新增:检查是否属于玩家派系
public bool IsPlayerFaction => this.Faction == Faction.OfPlayer;
// 生成初始单位(改为计数)
private void SpawnInitialUnits()
@@ -192,6 +195,10 @@ namespace WulaFallenEmpire
foreach (Gizmo g in base.GetGizmos())
yield return g;
// 新增:只有玩家派系才能看到和使用这些按钮
if (!IsPlayerFaction)
yield break;
// 回收附近机械族按钮
Command_Action recycleCommand = new Command_Action
{

View File

@@ -24,10 +24,24 @@ namespace WulaFallenEmpire
return _worldComponent;
}
}
private GlobalStorageWorldComponent _globalStorage;
private GlobalStorageWorldComponent GlobalStorage
{
get
{
if (_globalStorage == null)
{
_globalStorage = Find.World.GetComponent<GlobalStorageWorldComponent>();
}
return _globalStorage;
}
}
private bool used = false;
private int callTick = -1;
private bool calling = false;
private bool usedGlobalStorage = false; // 新增:标记是否使用了全局储存器
public bool CanCall => !used && !calling;
@@ -119,6 +133,7 @@ namespace WulaFallenEmpire
Scribe_Values.Look(ref used, "used", false);
Scribe_Values.Look(ref callTick, "callTick", -1);
Scribe_Values.Look(ref calling, "calling", false);
Scribe_Values.Look(ref usedGlobalStorage, "usedGlobalStorage", false);
}
public override void CompTick()
@@ -166,7 +181,11 @@ namespace WulaFallenEmpire
}
else
{
Messages.Message("WULA_SkyfallerIncoming".Translate(delay.ToStringTicksToPeriod()), parent, MessageTypeDefOf.ThreatBig);
// 修改:根据资源来源显示不同的消息
string messageKey = usedGlobalStorage ?
"WULA_SkyfallerIncomingFromGlobal" :
"WULA_SkyfallerIncoming";
Messages.Message(messageKey.Translate(delay.ToStringTicksToPeriod()), parent, MessageTypeDefOf.ThreatBig);
}
}
@@ -175,6 +194,7 @@ namespace WulaFallenEmpire
calling = false;
used = false;
callTick = -1;
usedGlobalStorage = false;
}
protected virtual void ExecuteSkyfallerCall()
@@ -187,14 +207,17 @@ namespace WulaFallenEmpire
return;
}
if (!HasEnoughMaterials())
// 修改:使用新的资源检查方法
var resourceCheck = CheckAndConsumeMaterials();
if (!resourceCheck.HasEnoughMaterials)
{
Log.Message($"[SkyfallerCaller] Aborting skyfaller call due to insufficient materials.");
ResetCall();
return;
}
ConsumeMaterials();
// 记录是否使用了全局储存器
usedGlobalStorage = resourceCheck.UsedGlobalStorage;
// 检查屋顶并处理
HandleRoofDestruction();
@@ -251,18 +274,106 @@ namespace WulaFallenEmpire
}
}
protected bool HasEnoughMaterials()
// 新增:资源检查结果结构
protected struct ResourceCheckResult
{
if (DebugSettings.godMode) return true;
public bool HasEnoughMaterials;
public bool UsedGlobalStorage;
public Dictionary<ThingDef, int> BeaconMaterials;
public Dictionary<ThingDef, int> GlobalMaterials;
}
// 修改:新的资源检查方法,优先检查信标附近,然后检查全局储存器
protected ResourceCheckResult CheckAndConsumeMaterials()
{
var result = new ResourceCheckResult
{
HasEnoughMaterials = false,
UsedGlobalStorage = false,
BeaconMaterials = new Dictionary<ThingDef, int>(),
GlobalMaterials = new Dictionary<ThingDef, int>()
};
if (DebugSettings.godMode)
{
result.HasEnoughMaterials = true;
return result;
}
var costList = CostList;
if (costList.NullOrEmpty())
{
return true;
result.HasEnoughMaterials = true;
return result;
}
var availableThings = new List<Thing>();
if (parent.Map == null) return false;
if (parent.Map == null)
{
return result;
}
// 第一步:收集信标附近的可用物资
var beaconMaterials = CollectBeaconMaterials();
result.BeaconMaterials = beaconMaterials;
// 第二步:检查信标附近物资是否足够
bool beaconHasEnough = true;
foreach (var cost in costList)
{
int availableInBeacon = beaconMaterials.ContainsKey(cost.thingDef) ? beaconMaterials[cost.thingDef] : 0;
if (availableInBeacon < cost.count)
{
beaconHasEnough = false;
break;
}
}
// 第三步:如果信标附近物资足够,只消耗信标附近的
if (beaconHasEnough)
{
ConsumeBeaconMaterials(beaconMaterials, costList);
result.HasEnoughMaterials = true;
result.UsedGlobalStorage = false;
return result;
}
// 第四步:如果信标附近物资不足,检查全局储存器
var globalMaterials = CheckGlobalStorageMaterials();
result.GlobalMaterials = globalMaterials;
bool globalHasEnough = true;
foreach (var cost in costList)
{
int availableInBeacon = beaconMaterials.ContainsKey(cost.thingDef) ? beaconMaterials[cost.thingDef] : 0;
int availableInGlobal = globalMaterials.ContainsKey(cost.thingDef) ? globalMaterials[cost.thingDef] : 0;
if (availableInBeacon + availableInGlobal < cost.count)
{
globalHasEnough = false;
break;
}
}
if (globalHasEnough)
{
// 先消耗信标附近的,不足部分从全局储存器扣除
ConsumeMixedMaterials(beaconMaterials, globalMaterials, costList);
result.HasEnoughMaterials = true;
result.UsedGlobalStorage = true;
return result;
}
// 两种来源加起来都不够
result.HasEnoughMaterials = false;
return result;
}
// 新增:收集信标附近的物资
private Dictionary<ThingDef, int> CollectBeaconMaterials()
{
var materials = new Dictionary<ThingDef, int>();
if (parent.Map == null) return materials;
foreach (Building_OrbitalTradeBeacon beacon in Building_OrbitalTradeBeacon.AllPowered(parent.Map))
{
@@ -274,46 +385,49 @@ namespace WulaFallenEmpire
Thing thing = thingList[i];
if (thing.def.EverHaulable)
{
availableThings.Add(thing);
if (materials.ContainsKey(thing.def))
{
materials[thing.def] += thing.stackCount;
}
else
{
materials[thing.def] = thing.stackCount;
}
}
}
}
}
availableThings = availableThings.Distinct().ToList();
return materials;
}
// 新增:检查全局储存器中的物资
private Dictionary<ThingDef, int> CheckGlobalStorageMaterials()
{
var materials = new Dictionary<ThingDef, int>();
if (GlobalStorage == null) return materials;
var costList = CostList;
if (costList.NullOrEmpty()) return materials;
foreach (var cost in costList)
{
int count = 0;
foreach (var thing in availableThings)
int globalCount = GlobalStorage.GetInputStorageCount(cost.thingDef);
if (globalCount > 0)
{
if (thing.def == cost.thingDef)
{
count += thing.stackCount;
}
}
if (count < cost.count)
{
return false;
materials[cost.thingDef] = globalCount;
}
}
return true;
return materials;
}
protected void ConsumeMaterials()
// 新增:只消耗信标附近的物资
private void ConsumeBeaconMaterials(Dictionary<ThingDef, int> beaconMaterials, List<ThingDefCountClass> costList)
{
if (DebugSettings.godMode) return;
var costList = CostList;
if (costList.NullOrEmpty())
{
return;
}
var tradeableThings = new List<Thing>();
if (parent.Map == null) return;
foreach (Building_OrbitalTradeBeacon beacon in Building_OrbitalTradeBeacon.AllPowered(parent.Map))
{
foreach (IntVec3 cell in beacon.TradeableCells)
@@ -329,13 +443,11 @@ namespace WulaFallenEmpire
}
}
}
tradeableThings = tradeableThings.Distinct().ToList();
foreach (var cost in costList)
{
int remaining = cost.count;
for (int i = tradeableThings.Count - 1; i >= 0; i--)
for (int i = tradeableThings.Count - 1; i >= 0 && remaining > 0; i--)
{
var thing = tradeableThings[i];
if (thing.def == cost.thingDef)
@@ -349,16 +461,123 @@ namespace WulaFallenEmpire
{
remaining -= thing.stackCount;
thing.Destroy();
}
if (remaining <= 0)
{
break;
tradeableThings.RemoveAt(i);
}
}
}
}
}
// 新增:混合消耗信标和全局储存器的物资
private void ConsumeMixedMaterials(Dictionary<ThingDef, int> beaconMaterials, Dictionary<ThingDef, int> globalMaterials, List<ThingDefCountClass> costList)
{
// 先消耗信标附近的物资
var tradeableThings = new List<Thing>();
foreach (Building_OrbitalTradeBeacon beacon in Building_OrbitalTradeBeacon.AllPowered(parent.Map))
{
foreach (IntVec3 cell in beacon.TradeableCells)
{
List<Thing> thingList = parent.Map.thingGrid.ThingsListAt(cell);
for (int i = 0; i < thingList.Count; i++)
{
Thing thing = thingList[i];
if (thing.def.EverHaulable)
{
tradeableThings.Add(thing);
}
}
}
}
// 对每种所需材料进行处理
foreach (var cost in costList)
{
int remaining = cost.count;
// 第一步:消耗信标附近的物资
for (int i = tradeableThings.Count - 1; i >= 0 && remaining > 0; i--)
{
var thing = tradeableThings[i];
if (thing.def == cost.thingDef)
{
if (thing.stackCount > remaining)
{
thing.SplitOff(remaining);
remaining = 0;
}
else
{
remaining -= thing.stackCount;
thing.Destroy();
tradeableThings.RemoveAt(i);
}
}
}
// 第二步:如果还有剩余,从全局储存器扣除
if (remaining > 0 && GlobalStorage != null)
{
GlobalStorage.RemoveFromInputStorage(cost.thingDef, remaining);
}
}
}
// 保留原有的 HasEnoughMaterials 方法用于 Gizmo 显示
protected bool HasEnoughMaterials()
{
if (DebugSettings.godMode) return true;
var costList = CostList;
if (costList.NullOrEmpty())
{
return true;
}
// 第一步:检查信标附近物资
var beaconMaterials = CollectBeaconMaterials();
bool beaconHasEnough = true;
foreach (var cost in costList)
{
int availableInBeacon = beaconMaterials.ContainsKey(cost.thingDef) ? beaconMaterials[cost.thingDef] : 0;
if (availableInBeacon < cost.count)
{
beaconHasEnough = false;
break;
}
}
if (beaconHasEnough) return true;
// 第二步:检查全局储存器(如果信标附近不够)
if (GlobalStorage == null) return false;
foreach (var cost in costList)
{
int availableInBeacon = beaconMaterials.ContainsKey(cost.thingDef) ? beaconMaterials[cost.thingDef] : 0;
int availableInGlobal = GlobalStorage.GetInputStorageCount(cost.thingDef);
if (availableInBeacon + availableInGlobal < cost.count)
{
return false;
}
}
return true;
}
// 原有的 ConsumeMaterials 方法现在只用于 God Mode 情况
protected void ConsumeMaterials()
{
if (DebugSettings.godMode) return;
// 在非 God Mode 下,这个方法不应该被调用
// 实际的消耗在 CheckAndConsumeMaterials 中处理
Log.Warning("[SkyfallerCaller] ConsumeMaterials called in non-God mode, this shouldn't happen");
}
// 其余方法保持不变...
private string GetCostString()
{
var costList = CostList;
@@ -379,6 +598,7 @@ namespace WulaFallenEmpire
calling = false;
used = false;
callTick = -1;
usedGlobalStorage = false;
Messages.Message("WULA_SkyfallerCallCancelled".Translate(), parent, MessageTypeDefOf.NeutralEvent);
}
@@ -451,6 +671,9 @@ namespace WulaFallenEmpire
sb.Append(costString);
}
// 新增:显示资源来源信息
sb.AppendLine().AppendLine().Append("WULA_ResourcePriorityInfo".Translate());
return sb.ToString();
}
@@ -501,7 +724,10 @@ namespace WulaFallenEmpire
int ticksLeft = callTick - Find.TickManager.TicksGame;
if (ticksLeft > 0)
{
sb.Append("WULA_SkyfallerArrivingIn".Translate(ticksLeft.ToStringTicksToPeriod()));
string messageKey = usedGlobalStorage ?
"WULA_SkyfallerArrivingInFromGlobal" :
"WULA_SkyfallerArrivingIn";
sb.Append(messageKey.Translate(ticksLeft.ToStringTicksToPeriod()));
}
}
else if (!used)

View File

@@ -83,22 +83,34 @@ namespace WulaFallenEmpire
}
}
private void PlayTransformEffects(IntVec3 position, Map map)
{
//// 播放转换视觉效果
//for (int i = 0; i < 3; i++)
//{
// MoteMaker.ThrowSmoke(position.ToVector3Shifted() + new Vector3(0, 0, 0.5f), map, 1.5f);
// MoteMaker.ThrowLightningGlow(position.ToVector3Shifted(), map, 2f);
//}
//// 播放音效
//SoundDefOf.PsychicPulseGlobal.PlayOneShot(new TargetInfo(position, map));
}
public void TransformToPawn()
{
if (Recycler == null || !parent.Spawned)
return;
Map map = parent.Map;
IntVec3 position = parent.Position;
Faction faction = parent.Faction;
// 记录建筑定义用于后续更新
ThingDef buildingDef = parent.def;
// 消耗存储的机械族
if (!Recycler.ConsumeMechanoids(Props.requiredCapacity))
{
Messages.Message("WULA_NotEnoughMechs".Translate(), MessageTypeDefOf.RejectInput);
return;
}
// 生成目标Pawn
PawnGenerationRequest request = new PawnGenerationRequest(
Props.targetPawnKind,
@@ -111,9 +123,8 @@ namespace WulaFallenEmpire
canGeneratePawnRelations: false,
mustBeCapableOfViolence: true
);
Pawn newPawn = PawnGenerator.GeneratePawn(request);
// 关键修改传递当前的机械族数量6个
var transformComp = newPawn.GetComp<CompTransformIntoBuilding>();
if (transformComp != null)
@@ -136,37 +147,24 @@ namespace WulaFallenEmpire
// 传递建筑定义和机械族数量
transformComp.SetRestoreData(parent.def, Props.requiredCapacity);
}
// 移除建筑
parent.DeSpawn(DestroyMode.Vanish);
// 生成Pawn
GenSpawn.Spawn(newPawn, position, map, WipeMode.Vanish);
// 选中新生成的Pawn
if (Find.Selector.IsSelected(parent))
{
Find.Selector.Select(newPawn);
}
Messages.Message("WULA_BuildingTransformedToPawn".Translate(parent.Label, newPawn.LabelCap, Props.requiredCapacity),
Messages.Message("WULA_BuildingTransformedToPawn".Translate(parent.Label, newPawn.LabelCap, Props.requiredCapacity),
MessageTypeDefOf.PositiveEvent);
// 播放转换效果
PlayTransformEffects(position, map);
}
private void PlayTransformEffects(IntVec3 position, Map map)
{
//// 播放转换视觉效果
//for (int i = 0; i < 3; i++)
//{
// MoteMaker.ThrowSmoke(position.ToVector3Shifted() + new Vector3(0, 0, 0.5f), map, 1.5f);
// MoteMaker.ThrowLightningGlow(position.ToVector3Shifted(), map, 2f);
//}
//// 播放音效
//SoundDefOf.PsychicPulseGlobal.PlayOneShot(new TargetInfo(position, map));
Log.Message($"[TransformSystem] Building -> Pawn transformation completed at {position}. Path grid updated.");
}
}
}

View File

@@ -77,7 +77,6 @@ namespace WulaFallenEmpire
// 显示恢复的机械族数量
sb.AppendLine();
sb.Append("WULA_RestoreMechCount".Translate(restoreMechCount));
// 显示目标建筑的最大存储容量
var recyclerProps = restoreBuildingDef.GetCompProperties<CompProperties_MechanoidRecycler>();
@@ -195,88 +194,6 @@ namespace WulaFallenEmpire
return false;
}
public void TransformToBuilding()
{
if (Pawn == null || !Pawn.Spawned)
return;
Map map = Pawn.Map;
IntVec3 desiredPosition = Pawn.Position;
Faction faction = Pawn.Faction;
// 确定要生成的建筑类型
ThingDef buildingDef = restoreBuildingDef ?? Props.targetBuildingDef;
if (buildingDef == null)
{
Messages.Message("WULA_CannotDetermineBuildingType".Translate(), MessageTypeDefOf.RejectInput);
return;
}
// 最终校验排除被转换的Pawn本身
string failReason;
if (!TransformValidationUtility.CanPlaceBuildingAt(buildingDef, desiredPosition, map, faction, Pawn, out failReason))
{
// 尝试寻找附近的位置
IntVec3 alternativePosition;
if (TryFindNearbyValidPosition(out alternativePosition, out failReason))
{
desiredPosition = alternativePosition;
Messages.Message("WULA_DeployingAtNearbyPosition".Translate(desiredPosition), MessageTypeDefOf.NeutralEvent);
}
else
{
Messages.Message("WULA_CannotDeployBuilding".Translate(failReason), MessageTypeDefOf.RejectInput);
return;
}
}
// 移除Pawn
Pawn.DeSpawn(DestroyMode.Vanish);
// 生成建筑
Building newBuilding = (Building)GenSpawn.Spawn(buildingDef, desiredPosition, map, WipeMode.Vanish);
newBuilding.SetFaction(faction);
// 关键修改:恢复机械族数量
var recycler = newBuilding as Building_MechanoidRecycler;
if (recycler != null)
{
recycler.SetMechanoidCount(restoreMechCount);
}
// 添加建筑转换组件
var transformComp = newBuilding.TryGetComp<CompTransformAtFullCapacity>();
if (transformComp == null)
{
// 动态添加组件
var compProps = new CompProperties_TransformAtFullCapacity
{
targetPawnKind = Pawn.kindDef
};
transformComp = new CompTransformAtFullCapacity();
transformComp.parent = newBuilding;
transformComp.props = compProps;
newBuilding.AllComps.Add(transformComp);
transformComp.Initialize(compProps);
}
// 选中新生成的建筑
if (Find.Selector.IsSelected(Pawn))
{
Find.Selector.Select(newBuilding);
}
Messages.Message("WULA_PawnDeployedAsBuilding".Translate(Pawn.LabelCap, newBuilding.Label, restoreMechCount),
MessageTypeDefOf.PositiveEvent);
// 播放转换效果
PlayTransformEffects(desiredPosition, map);
// 清除缓存
lastValidationResult = null;
lastValidationReason = null;
}
private void PlayTransformEffects(IntVec3 position, Map map)
{
// 播放转换视觉效果
@@ -298,5 +215,80 @@ namespace WulaFallenEmpire
lastValidationResult = null;
}
}
public void TransformToBuilding()
{
if (Pawn == null || !Pawn.Spawned)
return;
Map map = Pawn.Map;
IntVec3 desiredPosition = Pawn.Position;
Faction faction = Pawn.Faction;
// 确定要生成的建筑类型
ThingDef buildingDef = restoreBuildingDef ?? Props.targetBuildingDef;
if (buildingDef == null)
{
Messages.Message("WULA_CannotDetermineBuildingType".Translate(), MessageTypeDefOf.RejectInput);
return;
}
// 最终校验排除被转换的Pawn本身
string failReason;
if (!TransformValidationUtility.CanPlaceBuildingAt(buildingDef, desiredPosition, map, faction, Pawn, out failReason))
{
// 尝试寻找附近的位置
IntVec3 alternativePosition;
if (TryFindNearbyValidPosition(out alternativePosition, out failReason))
{
desiredPosition = alternativePosition;
Messages.Message("WULA_DeployingAtNearbyPosition".Translate(desiredPosition), MessageTypeDefOf.NeutralEvent);
}
else
{
Messages.Message("WULA_CannotDeployBuilding".Translate(failReason), MessageTypeDefOf.RejectInput);
return;
}
}
// 移除Pawn
Pawn.DeSpawn(DestroyMode.Vanish);
// 生成建筑
Building newBuilding = (Building)GenSpawn.Spawn(buildingDef, desiredPosition, map, WipeMode.Vanish);
newBuilding.SetFaction(faction);
// 关键修改:恢复机械族数量
var recycler = newBuilding as Building_MechanoidRecycler;
if (recycler != null)
{
recycler.SetMechanoidCount(restoreMechCount);
}
// 添加建筑转换组件
var transformComp = newBuilding.TryGetComp<CompTransformAtFullCapacity>();
if (transformComp == null)
{
// 动态添加组件
var compProps = new CompProperties_TransformAtFullCapacity
{
targetPawnKind = Pawn.kindDef
};
transformComp = new CompTransformAtFullCapacity();
transformComp.parent = newBuilding;
transformComp.props = compProps;
newBuilding.AllComps.Add(transformComp);
transformComp.Initialize(compProps);
}
// 选中新生成的建筑
if (Find.Selector.IsSelected(Pawn))
{
Find.Selector.Select(newBuilding);
}
Messages.Message("WULA_PawnDeployedAsBuilding".Translate(Pawn.LabelCap, newBuilding.Label, restoreMechCount),
MessageTypeDefOf.PositiveEvent);
// 播放转换效果
PlayTransformEffects(desiredPosition, map);
// 清除缓存
lastValidationResult = null;
lastValidationReason = null;
Log.Message($"[TransformSystem] Pawn -> Building transformation completed at {desiredPosition}. Path grid updated.");
}
}
}