This commit is contained in:
2025-12-09 17:33:22 +08:00
parent 975a3bad52
commit dd32bb4306
8 changed files with 731 additions and 26 deletions

View File

@@ -0,0 +1,361 @@
using System;
using System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.AI;
using Verse.Sound;
using System.Linq;
namespace WulaFallenEmpire
{
public class CompPhaseCombatTower : ThingComp
{
// 组件状态枚举
public enum TowerState
{
Idle, // 空闲(未激活)
Warmup, // 启动期
Exploding, // 爆炸阶段
SpawningPawns, // 生成Pawn阶段
Finished // 完成
}
private CompProperties_PhaseCombatTower Props => (CompProperties_PhaseCombatTower)props;
// 状态变量
private TowerState currentState = TowerState.Idle;
private int ticksInCurrentState = 0;
private int currentExplosionIndex = 0;
private int pawnsSpawned = 0;
private int nextSpawnTick = 0;
// 缓存
private List<PawnKindDef> cachedPawnKindDefs = null;
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
if (!respawningAfterLoad)
{
// 初次生成时开始启动期
StartWarmup();
}
}
// 开始启动期
private void StartWarmup()
{
currentState = TowerState.Warmup;
ticksInCurrentState = 0;
currentExplosionIndex = 0;
pawnsSpawned = 0;
}
// 开始爆炸阶段
private void StartExplosionPhase()
{
currentState = TowerState.Exploding;
ticksInCurrentState = 0;
currentExplosionIndex = 0;
if (Props.explosions.Count == 0)
{
StartSpawningPhase();
}
}
// 开始生成Pawn阶段
private void StartSpawningPhase()
{
currentState = TowerState.SpawningPawns;
ticksInCurrentState = 0;
pawnsSpawned = 0;
// 初始化Pawn种类缓存
if (cachedPawnKindDefs == null)
{
cachedPawnKindDefs = new List<PawnKindDef>();
foreach (string pawnKindName in Props.pawnKindDefs)
{
PawnKindDef pawnKindDef = DefDatabase<PawnKindDef>.GetNamedSilentFail(pawnKindName);
if (pawnKindDef != null)
{
cachedPawnKindDefs.Add(pawnKindDef);
}
else
{
Log.Error($"PhaseCombatTower: 找不到PawnKindDef '{pawnKindName}'");
}
}
}
if (cachedPawnKindDefs.Count > 0 && Props.spawnCount > 0)
{
nextSpawnTick = Find.TickManager.TicksGame + Props.spawnIntervalTicks;
}
else
{
currentState = TowerState.Finished;
}
}
public override void CompTick()
{
base.CompTick();
if (parent.Map == null || parent.Destroyed)
return;
switch (currentState)
{
case TowerState.Warmup:
TickWarmup();
break;
case TowerState.Exploding:
TickExploding();
break;
case TowerState.SpawningPawns:
TickSpawningPawns();
break;
}
}
private void TickWarmup()
{
ticksInCurrentState++;
// 启动期结束
if (ticksInCurrentState >= Props.warmupTicks)
{
StartExplosionPhase();
}
}
private void TickExploding()
{
ticksInCurrentState++;
// 检查是否需要执行下一次爆炸
if (currentExplosionIndex < Props.explosions.Count)
{
// 第一次爆炸或冷却期已过
if (currentExplosionIndex == 0 ||
ticksInCurrentState >= Props.explosionCooldownTicks * currentExplosionIndex)
{
ExecuteExplosion(currentExplosionIndex);
currentExplosionIndex++;
// 如果这是最后一次爆炸开始生成Pawn阶段
if (currentExplosionIndex >= Props.explosions.Count)
{
StartSpawningPhase();
}
}
}
}
private void TickSpawningPawns()
{
if (Find.TickManager.TicksGame >= nextSpawnTick && pawnsSpawned < Props.spawnCount)
{
SpawnPawn();
pawnsSpawned++;
if (pawnsSpawned >= Props.spawnCount)
{
currentState = TowerState.Finished;
}
else
{
nextSpawnTick = Find.TickManager.TicksGame + Props.spawnIntervalTicks;
}
}
}
// 执行爆炸 - 使用标准爆炸方法,支持气体释放
private void ExecuteExplosion(int explosionIndex)
{
if (explosionIndex < 0 || explosionIndex >= Props.explosions.Count)
return;
var explosionData = Props.explosions[explosionIndex];
// 使用RimWorld标准爆炸方法
if (parent.Map != null)
{
// 调用GenExplosion.DoExplosion方法包含气体参数
GenExplosion.DoExplosion(
center: parent.Position, // 爆炸中心
map: parent.Map, // 地图
radius: explosionData.radius, // 爆炸半径
damType: explosionData.damageDef ?? DamageDefOf.Bomb, // 伤害类型
instigator: parent, // 爆炸者
damAmount: explosionData.damageAmount, // 伤害值
armorPenetration: explosionData.armorPenetration, // 穿甲系数
explosionSound: explosionData.explosionSound, // 爆炸声音
weapon: null, // 武器(可选)
projectile: null, // 抛射物(可选)
intendedTarget: null, // 预定目标(可选)
// 爆炸前生成物
preExplosionSpawnThingDef: explosionData.preExplosionSpawnThingDef,
preExplosionSpawnChance: explosionData.preExplosionSpawnChance,
preExplosionSpawnThingCount: explosionData.preExplosionSpawnThingCount,
// 爆炸后生成物
postExplosionSpawnThingDef: explosionData.postExplosionSpawnThingDef,
postExplosionSpawnChance: explosionData.postExplosionSpawnChance,
postExplosionSpawnThingCount: explosionData.postExplosionSpawnThingCount,
// 气体释放参数
postExplosionGasType: explosionData.postExplosionGasType, // 气体类型
postExplosionGasRadiusOverride: explosionData.postExplosionGasRadiusOverride, // 气体半径
postExplosionGasAmount: explosionData.postExplosionGasAmount, // 气体数量
// 其他参数
applyDamageToExplosionCellsNeighbors: explosionData.applyDamageToExplosionCellsNeighbors,
chanceToStartFire: explosionData.chanceToStartFire,
damageFalloff: explosionData.damageFalloff,
direction: explosionData.direction,
ignoredThings: null,
affectedAngle: explosionData.affectedAngle,
doVisualEffects: true, // 总是显示视觉效果
propagationSpeed: explosionData.propagationSpeed,
excludeRadius: explosionData.excludeRadius,
doSoundEffects: explosionData.explosionSound != null,
screenShakeFactor: explosionData.screenShakeFactor
);
}
}
// 生成Pawn
private void SpawnPawn()
{
if (cachedPawnKindDefs == null || cachedPawnKindDefs.Count == 0)
return;
// 随机选择Pawn种类
PawnKindDef pawnKindDef = cachedPawnKindDefs.RandomElement();
// 寻找合适的生成位置
IntVec3 spawnPosition = FindSpawnPosition();
if (!spawnPosition.IsValid)
return;
// 生成Pawn
PawnGenerationRequest request = new PawnGenerationRequest(
pawnKindDef,
faction: parent.Faction,
forceGenerateNewPawn: true,
canGeneratePawnRelations: false,
fixedBiologicalAge: 0,
fixedChronologicalAge: 0
);
Pawn pawn = PawnGenerator.GeneratePawn(request);
// 生成Pawn到地图
GenSpawn.Spawn(pawn, spawnPosition, parent.Map);
// 添加生成效果
FleckMaker.ThrowDustPuff(spawnPosition, parent.Map, 2f);
}
// 寻找生成位置
private IntVec3 FindSpawnPosition()
{
Map map = parent.Map;
// 尝试在建筑周围寻找合适的空单元格
for (int radius = 1; radius <= 5; radius++)
{
CellRect rect = CellRect.CenteredOn(parent.Position, radius);
List<IntVec3> validCells = new List<IntVec3>();
foreach (IntVec3 cell in rect)
{
if (cell.InBounds(map) &&
cell.Walkable(map) &&
!cell.Fogged(map) &&
map.thingGrid.ThingsAt(cell).Count() == 0)
{
validCells.Add(cell);
}
}
if (validCells.Count > 0)
{
return validCells.RandomElement();
}
}
// 如果找不到合适位置,使用建筑位置(可能会重叠)
return parent.Position;
}
// 获取当前状态描述用于UI显示
public string GetStatusDescription()
{
switch (currentState)
{
case TowerState.Warmup:
float progress = (float)ticksInCurrentState / Props.warmupTicks;
return $"启动中: {Mathf.RoundToInt(progress * 100)}%";
case TowerState.Exploding:
return $"爆炸阶段: {currentExplosionIndex + 1}/{Props.explosions.Count}";
case TowerState.SpawningPawns:
return $"生成单位: {pawnsSpawned}/{Props.spawnCount}";
case TowerState.Finished:
return "已完成";
default:
return "待机";
}
}
// 保存和加载状态
public override void PostExposeData()
{
base.PostExposeData();
Scribe_Values.Look(ref currentState, "currentState", TowerState.Idle);
Scribe_Values.Look(ref ticksInCurrentState, "ticksInCurrentState", 0);
Scribe_Values.Look(ref currentExplosionIndex, "currentExplosionIndex", 0);
Scribe_Values.Look(ref pawnsSpawned, "pawnsSpawned", 0);
Scribe_Values.Look(ref nextSpawnTick, "nextSpawnTick", 0);
}
public override IEnumerable<Gizmo> CompGetGizmosExtra()
{
// 添加调试Gizmo开发模式下
if (DebugSettings.godMode)
{
yield return new Command_Action
{
defaultLabel = "强制启动",
action = () => StartWarmup(),
icon = TexCommand.ForbidOff
};
yield return new Command_Action
{
defaultLabel = "跳至爆炸阶段",
action = () => StartExplosionPhase(),
icon = TexCommand.Attack
};
yield return new Command_Action
{
defaultLabel = "跳至生成阶段",
action = () => StartSpawningPhase(),
icon = TexCommand.Attack
};
}
}
}
}