This commit is contained in:
2025-12-09 12:02:39 +08:00
parent 720487805f
commit 142df124dd
22 changed files with 991 additions and 539 deletions

View File

@@ -15,9 +15,10 @@ namespace WulaFallenEmpire
// 图形缓存 - 现在包含Shader信息
private Dictionary<string, Graphic> graphicsCache = new Dictionary<string, Graphic>();
// 动画状态 - 每个图层的独立浮动
// 动画状态 - 每个图层的独立状态
private Dictionary<int, float> layerHoverOffsets = new Dictionary<int, float>();
private Dictionary<int, float> layerAnimationTimes = new Dictionary<int, float>();
private Dictionary<int, float> layerRotationAngles = new Dictionary<int, float>();
private int lastTick = -1;
public ExtraGraphicsExtension ModExtension
@@ -122,8 +123,8 @@ namespace WulaFallenEmpire
{
// 不调用基类的 DrawAt完全自定义渲染
// 更新悬浮动画
UpdateHoverAnimation();
// 更新动画状态
UpdateAnimations();
// 绘制所有配置的图形层
DrawGraphicLayers(drawLoc, flip);
// 新增:绘制护盾
@@ -152,7 +153,7 @@ namespace WulaFallenEmpire
}
}
// 绘制单个图形层
// 绘制单个图形层 - 现在支持旋转动画
private void DrawGraphicLayer(Vector3 baseDrawPos, bool flip, GraphicLayerData layer)
{
if (string.IsNullOrEmpty(layer.texturePath))
@@ -167,27 +168,89 @@ namespace WulaFallenEmpire
// 获取图形现在传入Shader
Graphic graphic = GetCachedGraphic(layer.texturePath, layer.scale, layer.color, shader);
// 计算图层动偏移
float hoverOffset = 0f;
if (layer.enableHover)
// 计算图层动偏移
Vector3 animationOffset = Vector3.zero;
float rotationAngle = 0f;
int layerIndex = ModExtension.graphicLayers.IndexOf(layer);
// 根据动画类型应用不同的动画效果
switch (layer.animationType)
{
int layerIndex = ModExtension.graphicLayers.IndexOf(layer);
if (layerHoverOffsets.ContainsKey(layerIndex))
{
hoverOffset = layerHoverOffsets[layerIndex];
}
case AnimationType.Hover:
if (layer.enableAnimation && layerHoverOffsets.ContainsKey(layerIndex))
{
animationOffset.z = layerHoverOffsets[layerIndex];
}
break;
case AnimationType.Rotate:
if (layer.enableAnimation && layerRotationAngles.ContainsKey(layerIndex))
{
rotationAngle = layerRotationAngles[layerIndex];
}
break;
}
// 最终绘制位置 = 基础位置 + 图层偏移 + 动偏移
Vector3 drawPos = baseDrawPos + layer.offset;
drawPos.z += hoverOffset;
// 绘制图形
graphic.Draw(drawPos, flip ? base.Rotation.Opposite : base.Rotation, this, 0f);
// 最终绘制位置 = 基础位置 + 图层偏移 + 动偏移
Vector3 drawPos = baseDrawPos + layer.offset + animationOffset;
// 如果启用了旋转动画,使用矩阵变换绘制
if (layer.animationType == AnimationType.Rotate && layer.enableAnimation && rotationAngle != 0f)
{
DrawWithRotation(graphic, drawPos, flip, rotationAngle, layer);
}
else
{
// 普通绘制
graphic.Draw(drawPos, flip ? base.Rotation.Opposite : base.Rotation, this, 0f);
}
}
// 更新每个图层的独立悬浮动画
private void UpdateHoverAnimation()
// 使用矩阵变换绘制旋转图形
private void DrawWithRotation(Graphic graphic, Vector3 drawPos, bool flip, float rotationAngle, GraphicLayerData layer)
{
try
{
// 获取网格和材质
Mesh mesh = graphic.MeshAt(flip ? base.Rotation.Opposite : base.Rotation);
Material mat = graphic.MatAt(flip ? base.Rotation.Opposite : base.Rotation);
if (mesh == null || mat == null)
{
Log.Warning($"Building_ExtraGraphics: Unable to get mesh or material for rotating layer");
return;
}
// 创建旋转矩阵
Quaternion rotation = Quaternion.Euler(0f, 0f, rotationAngle);
// 如果图层有旋转中心偏移,需要调整位置
Vector3 pivotOffset = new Vector3(layer.pivotOffset.x, layer.pivotOffset.y, 0f);
// 计算最终矩阵
Matrix4x4 matrix = Matrix4x4.TRS(
drawPos + pivotOffset, // 位置
rotation, // 旋转
new Vector3(layer.scale.x, layer.scale.y, 1f) // 缩放
);
// 绘制网格
Graphics.DrawMesh(mesh, matrix, mat, 0);
// 如果需要,绘制第二面(双面渲染)
if (layer.doubleSided)
{
Graphics.DrawMesh(mesh, matrix, mat, 0, null, 0, null, UnityEngine.Rendering.ShadowCastingMode.Off, true);
}
}
catch (Exception ex)
{
Log.Error($"Building_ExtraGraphics: Error drawing rotating layer: {ex}");
}
}
// 更新所有图层的动画状态
private void UpdateAnimations()
{
int currentTick = Find.TickManager.TicksGame;
@@ -198,23 +261,47 @@ namespace WulaFallenEmpire
{
var layer = ModExtension.graphicLayers[i];
if (layer.enableHover)
if (!layer.enableAnimation)
continue;
// 初始化动画时间
if (!layerAnimationTimes.ContainsKey(i))
{
// 初始化动画时间
if (!layerAnimationTimes.ContainsKey(i))
{
layerAnimationTimes[i] = 0f;
}
// 更新动画时间
layerAnimationTimes[i] += Time.deltaTime;
// 计算该图层的悬浮偏移
float hoverSpeed = layer.hoverSpeed > 0 ? layer.hoverSpeed : ModExtension.globalHoverSpeed;
float hoverIntensity = layer.hoverIntensity > 0 ? layer.hoverIntensity : ModExtension.globalHoverIntensity;
float hoverOffset = Mathf.Sin(layerAnimationTimes[i] * hoverSpeed + layer.hoverPhase) * hoverIntensity;
layerHoverOffsets[i] = hoverOffset;
layerAnimationTimes[i] = layer.animationStartTime;
}
// 更新动画时间
layerAnimationTimes[i] += Time.deltaTime;
// 根据动画类型更新不同的状态
switch (layer.animationType)
{
case AnimationType.Hover:
// 计算该图层的悬浮偏移
float hoverSpeed = layer.animationSpeed > 0 ? layer.animationSpeed : ModExtension.globalAnimationSpeed;
float hoverIntensity = layer.animationIntensity > 0 ? layer.animationIntensity : ModExtension.globalAnimationIntensity;
float hoverOffset = Mathf.Sin(layerAnimationTimes[i] * hoverSpeed + layer.animationPhase) * hoverIntensity;
layerHoverOffsets[i] = hoverOffset;
break;
case AnimationType.Rotate:
// 计算该图层的旋转角度
float rotateSpeed = layer.animationSpeed > 0 ? layer.animationSpeed : ModExtension.globalAnimationSpeed;
float maxAngle = layer.animationIntensity > 0 ? layer.animationIntensity : ModExtension.globalAnimationIntensity;
// 旋转角度(循环)
float rotationAngle = (layerAnimationTimes[i] * rotateSpeed * 360f) % 360f;
// 限制旋转角度范围(如果设置了最大角度)
if (maxAngle > 0 && maxAngle < 360f)
{
// 使用正弦波限制旋转角度范围
rotationAngle = Mathf.Sin(layerAnimationTimes[i] * rotateSpeed) * maxAngle;
}
layerRotationAngles[i] = rotationAngle;
break;
}
}
@@ -230,12 +317,20 @@ namespace WulaFallenEmpire
}
}
// 动画类型枚举
public enum AnimationType
{
None, // 无动画
Hover, // 上下浮动
Rotate // 自旋转
}
// 主要的 ModExtension 定义
public class ExtraGraphicsExtension : DefModExtension
{
// 全局悬浮参数(作为默认值)
public float globalHoverSpeed = 2f; // 全局悬浮速度
public float globalHoverIntensity = 0.1f; // 全局悬浮强度
// 全局动画参数(作为默认值)
public float globalAnimationSpeed = 2f; // 全局动画速度
public float globalAnimationIntensity = 0.1f; // 全局动画强度
// 图形层配置
public List<GraphicLayerData> graphicLayers = new List<GraphicLayerData>();
@@ -250,7 +345,7 @@ namespace WulaFallenEmpire
}
}
// 单个图形层的配置数据 - 添加shaderName字段
// 单个图形层的配置数据 - 增强版
public class GraphicLayerData
{
// 基础配置
@@ -258,16 +353,56 @@ namespace WulaFallenEmpire
public Vector2 scale = Vector2.one; // 缩放比例
public Color color = Color.white; // 颜色
public int drawOrder = 0; // 绘制顺序(数字小的先绘制)
public string shaderName = "TransparentPostLight"; // Shader名称(新增)
public string shaderName = "TransparentPostLight"; // Shader名称
// 位置配置 - 使用环世界坐标系
// X: 左右偏移, Y: 图层深度, Z: 上下偏移
public Vector3 offset = Vector3.zero;
// 独立悬浮配置
public bool enableHover = true; // 是否启用悬浮
public float hoverSpeed = 0f; // 悬浮速度0表示使用全局速度
public float hoverIntensity = 0f; // 悬浮强0表示使用全局度)
public float hoverPhase = 0f; // 悬浮相位(用于错开浮动
// 动画配置
public AnimationType animationType = AnimationType.Hover; // 动画类型
public bool enableAnimation = true; // 是否启用动画
public float animationSpeed = 0f; // 动画速0表示使用全局度)
public float animationIntensity = 0f; // 动画强度0表示使用全局强度
public float animationPhase = 0f; // 动画相位(用于错开动画)
public float animationStartTime = 0f; // 动画开始时间偏移
// 旋转动画专用配置
public Vector2 pivotOffset = Vector2.zero; // 旋转中心偏移(相对于图层的中心)
public bool doubleSided = false; // 是否双面渲染(对于旋转物体)
// 兼容旧字段(为了向后兼容)
[Obsolete("Use enableAnimation instead")]
public bool enableHover
{
get => enableAnimation && animationType == AnimationType.Hover;
set
{
enableAnimation = value;
if (value && animationType == AnimationType.None)
animationType = AnimationType.Hover;
}
}
[Obsolete("Use animationSpeed instead")]
public float hoverSpeed
{
get => animationSpeed;
set => animationSpeed = value;
}
[Obsolete("Use animationIntensity instead")]
public float hoverIntensity
{
get => animationIntensity;
set => animationIntensity = value;
}
[Obsolete("Use animationPhase instead")]
public float hoverPhase
{
get => animationPhase;
set => animationPhase = value;
}
}
}

View File

@@ -201,15 +201,22 @@ namespace WulaFallenEmpire
{
if (MechPawn == null || !CanBeAutonomous)
yield break;
// 工作模式切换按钮
if (CanWorkAutonomously)
{
yield return new DroneGizmo(this);
DroneGizmo droneGizmo = new DroneGizmo(this);
if (droneGizmo != null)
{
yield return droneGizmo;
}
}
// 更换武器按钮 - 确保不返回null
Gizmo weaponSwitchGizmo = CreateWeaponSwitchGizmo();
if (weaponSwitchGizmo != null)
{
yield return weaponSwitchGizmo;
}
// 更换武器按钮
yield return CreateWeaponSwitchGizmo();
}
/// <summary>
@@ -217,20 +224,43 @@ namespace WulaFallenEmpire
/// </summary>
private Gizmo CreateWeaponSwitchGizmo()
{
// 检查Pawn是否属于玩家派系
if (MechPawn?.Faction != Faction.OfPlayer)
try
{
return null; // 非玩家派系时不显示
// 检查Pawn是否属于玩家派系
if (MechPawn?.Faction != Faction.OfPlayer)
{
return null; // 非玩家派系时不显示
}
// 检查Pawn是否有效
if (MechPawn == null || MechPawn.Dead || MechPawn.Destroyed)
{
return null;
}
// 检查equipment是否有效
if (MechPawn.equipment == null)
{
return null;
}
Command_Action switchWeaponCommand = new Command_Action
{
defaultLabel = "WULA_SwitchWeapon".Translate(),
defaultDesc = "WULA_SwitchWeapon_Desc".Translate(),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Abilities/WULA_WeaponSwitchAbility", false) ?? BaseContent.BadTex,
action = SwitchWeapon,
};
// 确保Command不为null
if (switchWeaponCommand == null)
{
Log.Error($"Failed to create weapon switch gizmo for {MechPawn?.LabelCap}");
return null;
}
return switchWeaponCommand;
}
Command_Action switchWeaponCommand = new Command_Action
catch (System.Exception ex)
{
defaultLabel = "WULA_SwitchWeapon".Translate(),
defaultDesc = "WULA_SwitchWeapon_Desc".Translate(),
icon = ContentFinder<Texture2D>.Get("Wula/UI/Abilities/WULA_WeaponSwitchAbility", false) ?? BaseContent.BadTex,
action = SwitchWeapon
};
return switchWeaponCommand;
Log.Error($"Error creating weapon switch gizmo: {ex}");
return null;
}
}
/// <summary>

View File

@@ -20,6 +20,9 @@ namespace WulaFallenEmpire
// 新增:记录最后一次检查敌人的时间
private int lastEnemyCheckTick = -99999;
// 新增:记录最后一次发信的时间
private int lastLetterTick = -99999;
public HediffDef GetTargetInvisibilityDef()
{
return Props.InvisibilityDef;
@@ -49,6 +52,7 @@ namespace WulaFallenEmpire
Scribe_Values.Look(ref lastDetectedTick, "lastDetectedTick", 0);
Scribe_Values.Look(ref lastRevealedTick, "lastRevealedTick", 0);
Scribe_Values.Look(ref lastEnemyCheckTick, "lastEnemyCheckTick", 0);
Scribe_Values.Look(ref lastLetterTick, "lastLetterTick", 0);
}
public override void CompTick()
@@ -78,6 +82,9 @@ namespace WulaFallenEmpire
Invisibility.BecomeVisible();
lastDetectedTick = Find.TickManager.TicksGame;
// 触发显现事件
TrySendLetter("attack");
}
/// <summary>
@@ -85,7 +92,6 @@ namespace WulaFallenEmpire
/// </summary>
private void CheckForEnemiesInSight()
{
// 检查频率每30 tick检查一次约0.5秒)
if (!Sightstealer.IsHashIntervalTick(30) ||
Find.TickManager.TicksGame <= lastEnemyCheckTick + 30)
@@ -95,12 +101,6 @@ namespace WulaFallenEmpire
lastEnemyCheckTick = Find.TickManager.TicksGame;
// 如果配置为只在战斗状态时检查,且当前不在战斗状态,则跳过
if (Props.onlyCheckInCombat && !IsInCombatState())
{
return;
}
// 检查视线内是否有敌人
bool enemyInSight = false;
List<Pawn> enemiesInSight = new List<Pawn>();
@@ -156,108 +156,110 @@ namespace WulaFallenEmpire
lastDetectedTick = Find.TickManager.TicksGame;
lastRevealedTick = Find.TickManager.TicksGame;
// 可选:添加视觉或声音效果
if (Props.showRevealEffect)
// 触发显现事件
TrySendLetter("detected", enemiesInSight);
}
}
/// <summary>
/// 尝试发送信件
/// </summary>
private void TrySendLetter(string cause, List<Pawn> enemies = null)
{
// 检查是否应该发送信件
if (!ShouldSendLetter())
return;
// 发送信件
SendLetter(cause, enemies);
}
/// <summary>
/// 检查是否应该发送信件
/// </summary>
private bool ShouldSendLetter()
{
// 如果配置为不发信直接返回false
if (!Props.sendLetterOnReveal)
return false;
// 检查发送间隔
int currentTick = Find.TickManager.TicksGame;
if (currentTick < lastLetterTick + Props.letterIntervalTicks)
{
// 还没到发送间隔
return false;
}
// 检查Pawn是否非玩家控制
if (Sightstealer.Faction == Faction.OfPlayer)
{
// 玩家控制的Pawn不发送信件
return false;
}
return true;
}
/// <summary>
/// 发送信件
/// </summary>
private void SendLetter(string cause, List<Pawn> enemies = null)
{
try
{
int currentTick = Find.TickManager.TicksGame;
// 获取信件标题和内容
string title = Props.letterTitle;
string text = Props.letterText;
// 如果标题或内容为空,使用默认值
if (string.IsNullOrEmpty(title))
title = "隐身单位现身";
if (string.IsNullOrEmpty(text))
{
ShowRevealEffect(enemiesInSight);
string enemyInfo = "";
if (enemies != null && enemies.Count > 0)
{
if (enemies.Count == 1)
{
enemyInfo = $"被 {enemies[0].LabelCap} 发现";
}
else
{
enemyInfo = $"被 {enemies.Count} 个敌人发现";
}
}
else if (cause == "attack")
{
enemyInfo = "发动了攻击";
}
text = $"{Sightstealer.LabelCap}{Sightstealer.Faction?.Name ?? ""})在 {Sightstealer.Map?.Parent?.LabelCap ?? ""} 现身了。\n\n{enemyInfo}\n位置{Sightstealer.Position}";
}
// 可选:发送消息
if (Props.sendRevealMessage && Sightstealer.Faction == Faction.OfPlayer)
{
SendRevealMessage(enemiesInSight);
}
}
}
/// <summary>
/// 检查是否处于战斗状态
/// </summary>
private bool IsInCombatState()
{
// 如果有当前工作且是战斗相关工作
if (Sightstealer.CurJob != null)
{
JobDef jobDef = Sightstealer.CurJob.def;
if (jobDef == JobDefOf.AttackMelee ||
jobDef == JobDefOf.AttackStatic ||
jobDef == JobDefOf.Wait_Combat ||
jobDef == JobDefOf.Flee ||
jobDef == JobDefOf.FleeAndCower)
{
return true;
}
}
// 如果有敌人目标
if (Sightstealer.mindState.enemyTarget != null)
{
return true;
}
// 如果最近受到过伤害
if (Find.TickManager.TicksGame - Sightstealer.mindState.lastHarmTick < 300) // 最近5秒内受到伤害
{
return true;
}
// 如果最近攻击过目标
if (Find.TickManager.TicksGame - Sightstealer.mindState.lastAttackTargetTick < 300)
{
return true;
}
return false;
}
/// <summary>
/// 显示解除隐身的效果
/// </summary>
private void ShowRevealEffect(List<Pawn> enemies)
{
if (Sightstealer.Map == null) return;
// 创建一个闪光效果
FleckMaker.ThrowLightningGlow(Sightstealer.Position.ToVector3Shifted(),
Sightstealer.Map, 2f);
// 可选:播放声音
if (Props.revealSound != null)
{
Props.revealSound.PlayOneShot(new TargetInfo(Sightstealer.Position, Sightstealer.Map));
}
}
/// <summary>
/// 发送解除隐身消息
/// </summary>
private void SendRevealMessage(List<Pawn> enemies)
{
if (enemies.Count == 0) return;
string message;
if (enemies.Count == 1)
{
message = "WFE.RevealedBySingleEnemy".Translate(
Sightstealer.LabelShort,
enemies[0].LabelShort
// 发送信件
Letter letter = LetterMaker.MakeLetter(
title,
text,
LetterDefOf.NeutralEvent,
new LookTargets(Sightstealer)
);
Find.LetterStack.ReceiveLetter(letter);
// 更新最后发信时间
lastLetterTick = currentTick;
}
else
catch (System.Exception ex)
{
message = "WFE.RevealedByMultipleEnemies".Translate(
Sightstealer.LabelShort,
enemies.Count
);
Log.Error($"CompFighterInvisible: Error sending letter for {Sightstealer?.LabelCap}: {ex}");
}
Messages.Message(message, Sightstealer, MessageTypeDefOf.NeutralEvent);
}
/// <summary>
/// 获取下次可以隐身的时间
/// </summary>
public int NextInvisibilityTick => lastDetectedTick + Props.stealthCooldownTicks;
// ... 其他方法保持不变 ...
/// <summary>
/// 手动触发解除隐身(供外部调用)
@@ -269,6 +271,11 @@ namespace WulaFallenEmpire
Invisibility.BecomeVisible();
lastDetectedTick = Find.TickManager.TicksGame;
lastRevealedTick = Find.TickManager.TicksGame;
// 尝试发送信件
TrySendLetter("manual");
}
// ... 其他方法保持不变 ...
}
}

View File

@@ -46,24 +46,31 @@ namespace WulaFallenEmpire
// 新增:是否忽略某些状态的敌人(如倒地、死亡等)
public bool ignoreDownedEnemies = true;
public bool ignoreSleepingEnemies = false;
// 新增:简化发信配置
public bool sendLetterOnReveal = false;
public string letterTitle = "";
public string letterText = "";
public int letterIntervalTicks = 1200;
public CompProperties_FighterInvisible()
{
compClass = typeof(CompFighterInvisible);
}
public override IEnumerable<string> ConfigErrors(ThingDef parentDef)
{
foreach (string error in base.ConfigErrors(parentDef))
{
yield return error;
}
if (InvisibilityDef == null)
{
yield return "InvisibilityDef is not defined for CompProperties_FighterInvisible";
}
if (revealDetectionRadius <= 0)
{
revealDetectionRadius = FirstDetectedRadius;

View File

@@ -0,0 +1,183 @@
using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI;
using Verse.Sound;
namespace WulaFallenEmpire
{
public class PawnsArrivalModeWorker_EdgeTeleport : PawnsArrivalModeWorker
{
public override void Arrive(List<Pawn> pawns, IncidentParms parms)
{
Map map = (Map)parms.target;
// 如果没有指定生成中心则使用EdgeDrop的查找方式
if (!parms.spawnCenter.IsValid)
{
parms.spawnCenter = DropCellFinder.FindRaidDropCenterDistant(map);
}
// 为每个Pawn分配一个传送位置在生成中心附近
foreach (Pawn pawn in pawns)
{
if (pawn == null || pawn.Dead || pawn.Destroyed)
continue;
// 找到可用的传送位置
IntVec3 teleportPos = FindTeleportPosition(map, parms.spawnCenter);
// 如果Pawn已经在其他地图需要先将其移到当前地图
if (pawn.Map != map)
{
// 确保Pawn不在任何地图中
if (pawn.Spawned)
{
pawn.DeSpawn();
}
// 将Pawn放入当前地图
GenSpawn.Spawn(pawn, teleportPos, map, parms.spawnRotation);
}
else
{
// 如果已经在当前地图,直接移动位置
pawn.Position = teleportPos;
pawn.Notify_Teleported(true, false);
}
// 播放传送效果
PlayTeleportEffect(pawn, teleportPos, map);
// 确保Pawn有适当的状态
EnsurePawnStateAfterTeleport(pawn);
}
}
public override bool TryResolveRaidSpawnCenter(IncidentParms parms)
{
Map map = (Map)parms.target;
// 与EdgeDrop相同的方式解析生成中心
if (!parms.spawnCenter.IsValid)
{
parms.spawnCenter = DropCellFinder.FindRaidDropCenterDistant(map);
}
parms.spawnRotation = Rot4.Random;
return true;
}
/// <summary>
/// 找到可用的传送位置
/// </summary>
private IntVec3 FindTeleportPosition(Map map, IntVec3 center)
{
// 在中心点附近寻找可用的单元格
// 我们使用与EdgeWalkInGroups类似的逻辑但立即传送
if (CellFinder.TryFindRandomCellNear(center, map, 10,
c => c.Standable(map) &&
!c.Fogged(map) &&
c.GetRoof(map) != RoofDefOf.RoofRockThick && // 排除厚岩顶
map.reachability.CanReachColony(c),
out IntVec3 result))
{
return result;
}
// 如果找不到合适的单元格,使用备选方案
if (RCellFinder.TryFindRandomPawnEntryCell(out result, map, CellFinder.EdgeRoadChance_Hostile))
{
return result;
}
// 最后的手段:使用中心点
return center;
}
/// <summary>
/// 播放传送效果
/// </summary>
private void PlayTeleportEffect(Pawn pawn, IntVec3 pos, Map map)
{
try
{
// 播放Skip_ExitNoDelay效果
EffecterDef teleportEffect = DefDatabase<EffecterDef>.GetNamed("Skip_ExitNoDelay");
if (teleportEffect != null)
{
Effecter effecter = teleportEffect.Spawn();
effecter.ticksLeft = 30; // 设置效果持续时间
effecter.Trigger(new TargetInfo(pos, map), new TargetInfo(pos, map));
effecter.Cleanup();
}
else
{
// 如果找不到指定的效果,使用跳跃效果
EffecterDef jumpEffect = EffecterDefOf.Skip_Exit;
if (jumpEffect != null)
{
Effecter effecter = jumpEffect.Spawn();
effecter.ticksLeft = 30;
effecter.Trigger(new TargetInfo(pos, map), new TargetInfo(pos, map));
effecter.Cleanup();
}
}
// 可选:播放声音效果
SoundDef sound = SoundDefOf.PsychicPulseGlobal;
if (sound != null)
{
sound.PlayOneShot(new TargetInfo(pos, map));
}
}
catch (System.Exception ex)
{
Log.Warning($"Failed to play teleport effect for {pawn?.LabelCap}: {ex}");
}
}
/// <summary>
/// 确保Pawn传送后的状态
/// </summary>
private void EnsurePawnStateAfterTeleport(Pawn pawn)
{
if (pawn == null)
return;
// 重置当前工作
if (pawn.CurJob != null)
{
pawn.jobs.StopAll();
}
// 如果是殖民者或友军,设置为等待战斗状态
if (pawn.Faction == Faction.OfPlayer || !pawn.HostileTo(Faction.OfPlayer))
{
pawn.jobs.StartJob(new Job(JobDefOf.Wait_Combat, 600, true),
JobCondition.InterruptForced, null, false, true, null, null, false);
}
// 重置心理状态
if (pawn.mindState != null)
{
pawn.mindState.enemyTarget = null;
pawn.mindState.mentalStateHandler?.Reset();
}
// 如果是机械族,可能需要特殊处理
if (pawn.RaceProps.IsMechanoid)
{
var comp = pawn.GetComp<CompAutonomousMech>();
if (comp != null)
{
// 如果是自主机械,确保进入适当状态
if (!pawn.Drafted && pawn.Faction == Faction.OfPlayer)
{
pawn.drafter.Drafted = false;
}
}
}
}
}
}

View File

@@ -53,9 +53,6 @@ namespace WulaFallenEmpire
{
pawn.drafter.Drafted = true;
}
// 发送生成消息
Messages.Message("SkyfallerPawnLanded".Translate(pawn.LabelShortCap), pawn, MessageTypeDefOf.NeutralEvent);
}
private Faction GetFaction()

View File

@@ -250,6 +250,7 @@
<Compile Include="HediffComp\WULA_HediffSpawner\Tools.cs" />
<Compile Include="Job\JobDriver_InspectBuilding.cs" />
<Compile Include="Job\JobGiver_InspectBuilding.cs" />
<Compile Include="PawnsArrivalMode\PawnsArrivalModeWorker_EdgeTeleport.cs" />
<Compile Include="Pawn\Comp_MultiTurretGun.cs" />
<Compile Include="Pawn\Comp_PawnRenderExtra.cs" />
<Compile Include="Pawn\WULA_AutoMechCarrier\CompAutoMechCarrier.cs" />