This commit is contained in:
Tourswen
2025-11-22 01:41:05 +08:00
parent 34c93bb18d
commit d0b06cbc72
30 changed files with 1083 additions and 427 deletions

View File

@@ -21,6 +21,9 @@ namespace WulaFallenEmpire
Map map = parent.pawn.MapHeld;
if (map == null) return;
// 新增:在施法前清除与施法者重合的物体
ClearOverlappingObjects(map);
// 获取扇形区域内的所有单元格
List<IntVec3> affectedCells = AffectedCells(target);
@@ -62,6 +65,80 @@ namespace WulaFallenEmpire
}
}
/// <summary>
/// 新增:清除与施法者重合的所有物体
/// </summary>
private void ClearOverlappingObjects(Map map)
{
try
{
IntVec3 casterPos = Pawn.Position;
// 获取施法者位置的所有物体
List<Thing> thingsAtCasterPos = casterPos.GetThingList(map);
foreach (Thing thing in thingsAtCasterPos)
{
// 跳过施法者自己(除非设置影响施法者)
if (thing == Pawn && !Props.affectCaster)
continue;
// 跳过已经销毁的物体
if (thing.Destroyed)
continue;
// 只处理建筑和Pawn
if (thing is Building || thing is Pawn)
{
// 检查是否应该影响这个物体
if (ShouldAffectThing(thing))
{
// 播放清除特效
PlayClearEffecter(thing, map);
// 处理目标
ProcessTarget(thing);
Log.Message($"[AreaDestruction] Cleared overlapping object: {thing.Label} at {casterPos}");
}
}
}
}
catch (System.Exception ex)
{
Log.Warning($"[AreaDestruction] Error clearing overlapping objects: {ex.Message}");
}
}
/// <summary>
/// 新增:播放清除重合物体的特效
/// </summary>
private void PlayClearEffecter(Thing target, Map map)
{
try
{
if (Props.clearEffecter == null) return;
if (target == null || target.Destroyed) return;
// 在目标位置播放清除特效
Effecter effecter = Props.clearEffecter.Spawn(target.Position, map);
if (Props.clearEffecterMaintainTicks > 0)
{
// 维持效果器
parent.AddEffecterToMaintain(effecter, target.Position, Props.clearEffecterMaintainTicks, map);
}
else
{
effecter.Cleanup();
}
}
catch (System.Exception ex)
{
Log.Warning($"[AreaDestruction] Error playing clear effecter: {ex.Message}");
}
}
private void PlayHitEffecter(Thing target, Map map)
{
try
@@ -94,9 +171,6 @@ namespace WulaFallenEmpire
{
effecter.Cleanup();
}
// 可选:记录日志用于调试
// Log.Message($"[AreaDestruction] Played hit effecter on {target.Label} at {target.Position}");
}
catch (System.Exception ex)
{
@@ -209,9 +283,6 @@ namespace WulaFallenEmpire
{
// 检查pawn是否还"活着"(没有核心部位缺失时可能还能存活)
CheckPawnViability(targetPawn);
// 可选:记录日志用于调试
// Log.Message($"[AreaDestruction] Destroyed {partsDestroyed} body parts on {pawnInfo}");
}
}
catch (System.Exception ex)

View File

@@ -12,6 +12,10 @@ namespace WulaFallenEmpire
public EffecterDef castEffecter;
public int castEffecterMaintainTicks = 60;
// 清除特效(用于清除重合物体)
public EffecterDef clearEffecter;
public int clearEffecterMaintainTicks = 30;
// 命中特效(在目标位置)
public EffecterDef hitEffecter;
public int hitEffecterMaintainTicks = 30;

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq; // 添加这个 using 指令
using RimWorld;
using UnityEngine;
using Verse;
@@ -21,83 +22,101 @@ namespace WulaFallenEmpire
Pawn caster = parent.pawn;
Map map = caster.Map;
// 新增:在施法前验证并调整目标位置
LocalTargetInfo adjustedTarget = AdjustTargetForBuildings(target, caster, map);
// 使用调整后的目标位置
IntVec3 finalTargetCell = adjustedTarget.Cell;
// 使用自定义或默认的入口特效
if (Props.customEntryFleck != null)
{
// 自定义入口粒子效果
FleckMaker.Static(caster.Position, map, Props.customEntryFleck);
}
else
{
// 默认入口粒子效果
FleckMaker.Static(caster.Position, map, FleckDefOf.PsycastSkipFlashEntry);
}
// 使用自定义或默认的出口特效
if (Props.customExitFleck != null)
{
// 自定义出口粒子效果
FleckMaker.Static(target.Cell, map, Props.customExitFleck);
// 如果需要更大的效果,可以创建多个粒子
FleckMaker.Static(finalTargetCell, map, Props.customExitFleck);
if (Props.effectScale > 1.5f)
{
for (int i = 0; i < Mathf.FloorToInt(Props.effectScale); i++)
{
Vector3 offset = new Vector3(Rand.Range(-0.5f, 0.5f), 0f, Rand.Range(-0.5f, 0.5f));
FleckMaker.Static(target.Cell.ToVector3Shifted() + offset, map, Props.customExitFleck);
FleckMaker.Static(finalTargetCell.ToVector3Shifted() + offset, map, Props.customExitFleck);
}
}
}
else
{
// 默认出口粒子效果
FleckMaker.Static(target.Cell, map, FleckDefOf.PsycastSkipInnerExit);
FleckMaker.Static(target.Cell, map, FleckDefOf.PsycastSkipOuterRingExit);
FleckMaker.Static(finalTargetCell, map, FleckDefOf.PsycastSkipInnerExit);
FleckMaker.Static(finalTargetCell, map, FleckDefOf.PsycastSkipOuterRingExit);
}
// 播放传送音效
SoundDefOf.Psycast_Skip_Entry.PlayOneShot(new TargetInfo(caster.Position, map));
SoundDefOf.Psycast_Skip_Exit.PlayOneShot(new TargetInfo(target.Cell, map));
SoundDefOf.Psycast_Skip_Exit.PlayOneShot(new TargetInfo(finalTargetCell, map));
// 存储调整后的目标位置供Apply方法使用
// 注意这里使用反射或其他方法来设置目标因为parent.ability可能不可直接访问
StoreAdjustedTarget(finalTargetCell);
},
ticksAwayFromCast = 5
};
}
// 新增:存储调整后的目标位置
private void StoreAdjustedTarget(IntVec3 targetCell)
{
// 这里可以使用一个字段来存储调整后的目标
// 由于RimWorld的Ability类结构我们可能需要使用其他方式
// 暂时使用一个字段来存储
this.adjustedTargetCell = targetCell;
}
private IntVec3 adjustedTargetCell = IntVec3.Invalid;
public override void Apply(LocalTargetInfo target, LocalTargetInfo dest)
{
base.Apply(target, dest);
if (!target.IsValid)
{
return;
}
Pawn caster = parent.pawn;
Map map = caster.Map;
// 新增:最终目标位置验证 - 优先使用调整后的目标
IntVec3 finalTargetCell = this.adjustedTargetCell.IsValid ? this.adjustedTargetCell : target.Cell;
finalTargetCell = ValidateAndAdjustTarget(finalTargetCell, caster, map);
// 重置调整目标
this.adjustedTargetCell = IntVec3.Invalid;
// 如果无法找到有效位置,取消传送
if (!CanTeleportTo(finalTargetCell, map))
{
Messages.Message("TeleportFailedNoValidLocation".Translate(), caster, MessageTypeDefOf.RejectInput);
return;
}
// 使用自定义或默认的入口效果器
EffecterDef entryEffecter = Props.customEntryEffecter ?? EffecterDefOf.Skip_Entry;
Effecter entryEffect = entryEffecter.Spawn(caster, map);
// 应用效果缩放
if (Props.effectScale != 1.0f && entryEffect is Effecter effect)
{
// 这里可以添加效果缩放的逻辑
// 注意Effecter类可能没有直接的缩放属性需要根据具体实现调整
}
parent.AddEffecterToMaintain(entryEffect, caster.Position, 60);
// 使用自定义或默认的出口效果器
EffecterDef exitEffecter = Props.customExitEffecter ?? EffecterDefOf.Skip_Exit;
Effecter exitEffect = exitEffecter.Spawn(target.Cell, map);
parent.AddEffecterToMaintain(exitEffect, target.Cell, 60);
Effecter exitEffect = exitEffecter.Spawn(finalTargetCell, map);
parent.AddEffecterToMaintain(exitEffect, finalTargetCell, 60);
// 唤醒可能休眠的组件
caster.TryGetComp<CompCanBeDormant>()?.WakeUp();
// 执行传送
caster.Position = target.Cell;
caster.Position = finalTargetCell;
caster.Notify_Teleported();
// 如果是玩家阵营,解除战争迷雾
@@ -115,10 +134,81 @@ namespace WulaFallenEmpire
// 播放到达时的喧嚣效果
if (Props.destClamorType != null)
{
// 根据效果缩放调整喧嚣半径
float adjustedRadius = Props.destClamorRadius * Props.effectScale;
GenClamor.DoClamor(caster, target.Cell, adjustedRadius, Props.destClamorType);
GenClamor.DoClamor(caster, finalTargetCell, adjustedRadius, Props.destClamorType);
}
// 记录传送调整信息(调试用)
if (finalTargetCell != target.Cell)
{
Log.Message($"[TeleportSelf] AI传送位置从 {target.Cell} 调整到 {finalTargetCell}");
}
}
/// <summary>
/// 新增:在施法前调整目标位置,防止传送到建筑上
/// </summary>
private LocalTargetInfo AdjustTargetForBuildings(LocalTargetInfo originalTarget, Pawn caster, Map map)
{
IntVec3 originalCell = originalTarget.Cell;
// 如果目标位置不可传送,寻找最近的可行位置
if (!CanTeleportTo(originalCell, map))
{
IntVec3 adjustedCell = FindNearestValidTeleportPosition(originalCell, caster, map);
if (adjustedCell.IsValid)
{
return new LocalTargetInfo(adjustedCell);
}
}
return originalTarget;
}
/// <summary>
/// 新增:最终目标位置验证
/// </summary>
private IntVec3 ValidateAndAdjustTarget(IntVec3 targetCell, Pawn caster, Map map)
{
// 如果目标位置不可传送,寻找替代位置
if (!CanTeleportTo(targetCell, map))
{
IntVec3 adjustedCell = FindNearestValidTeleportPosition(targetCell, caster, map);
if (adjustedCell.IsValid)
{
return adjustedCell;
}
}
return targetCell;
}
/// <summary>
/// 新增:寻找最近的可行传送位置
/// </summary>
private IntVec3 FindNearestValidTeleportPosition(IntVec3 center, Pawn caster, Map map, int maxRadius = 15)
{
// 首先检查中心点本身
if (CanTeleportTo(center, map))
return center;
// 在逐渐增大的半径内搜索
for (int radius = 1; radius <= maxRadius; radius++)
{
// 使用 GenRadial.RadialPattern 而不是 RadialCellsAround
int numCells = GenRadial.NumCellsInRadius(radius);
for (int i = 0; i < numCells; i++)
{
IntVec3 cell = center + GenRadial.RadialPattern[i];
if (cell.InBounds(map) && CanTeleportTo(cell, map))
{
return cell;
}
}
}
// 如果找不到有效位置,返回无效位置
return IntVec3.Invalid;
}
public override bool Valid(LocalTargetInfo target, bool showMessages = true)

View File

@@ -25,6 +25,10 @@ namespace WulaFallenEmpire
public FleckDef customExitFleck;
public float effectScale = 1.0f; // 效果缩放比例
// 新增:位置调整设置
public int maxPositionAdjustRadius = 15; // 最大位置调整半径
public bool allowPositionAdjustment = true; // 是否允许自动调整位置
public CompProperties_AbilityTeleportSelf()
{
compClass = typeof(CompAbilityEffect_TeleportSelf);