Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/BuildingComp/WULA_PhaseCombatTower/CompPhaseCombatTower.cs
2025-12-09 17:33:22 +08:00

362 lines
13 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 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
};
}
}
}
}