diff --git a/1.6/1.6/Assemblies/WulaFallenEmpire.dll b/1.6/1.6/Assemblies/WulaFallenEmpire.dll index 7d4ba905..1918b002 100644 Binary files a/1.6/1.6/Assemblies/WulaFallenEmpire.dll and b/1.6/1.6/Assemblies/WulaFallenEmpire.dll differ diff --git a/1.6/1.6/Defs/AbilityDefs/WULA_Misc_Ability.xml b/1.6/1.6/Defs/AbilityDefs/WULA_Misc_Ability.xml index ba1e29a7..5a5d7bdc 100644 --- a/1.6/1.6/Defs/AbilityDefs/WULA_Misc_Ability.xml +++ b/1.6/1.6/Defs/AbilityDefs/WULA_Misc_Ability.xml @@ -49,8 +49,8 @@ WULA_PsiCrusher - - 释放纯净的灵能能量,直接解构面前扇形区域内的所有目标,无论是建筑物还是活物都难逃毁灭。这种术式需要的灵能难以估量,只有搭载大量封闭灵能回路的灵能泰坦可以连续使用。 + + 以灵能能量发出非人尖啸,直接解构面前扇形区域内的所有目标,无论是建筑物还是活物都难逃毁灭。这种术式需要的灵能难以估量,只有搭载大量封闭灵能回路的灵能泰坦可以连续使用。 UI/Abilities/FireSpew True False @@ -72,7 +72,6 @@ Mote_HellsphereCannon_Charge 1.07 32 - Mote_HellsphereCannon_Target true @@ -97,10 +96,31 @@ WULA_AreaDestruction_Hit +
  • + SubEffecter_SprayerTriggered + 0.1 + WULA_Mote_halo + 1~1 + 0.4~0.8 + 0.05~0.05 + OnSource + (255,255,255) +
  • +
  • + SubEffecter_SprayerTriggered + 0.02 + WULA_Mote_halo + 1~1 + 0.3~0.4 + 5~10 + 0.1~0.2 + OnSource + (255,255,255) +
  • SubEffecter_SprayerTriggered WULA_Mote_ChargeLanceShot - 1~4 + 6~12 0.4~0.8 20~40 135~225 @@ -110,7 +130,7 @@
  • SubEffecter_SprayerTriggered WULA_Mote_ChargeLanceShot - 2~3 + 5~9 0.4~0.8 10~20 135~225 @@ -159,6 +179,36 @@
  • + + WULA_Mote_halo + + Wula/Mote/halo + MoteGlow + + MoteOverhead + + 0 + 0 + 0.1 + 40 + true + + + + WULA_Mote_fire + + Wula/Mote/fire + MoteGlow + + MoteOverhead + + 0 + 0 + 0.2 + 8 + true + + WULA_Mote_ChargeLanceShot @@ -194,113 +244,258 @@ - Wula_Psi_Explosive_Shock - - 以灵能能量发出非人尖啸,使得周围的人员感觉到撕心裂肺的痛苦。这不会造成永久的伤害,但是很可能放倒那些无法承受此番痛苦的生灵。 - UI/Abilities/FireSpew + WULA_Psi_Skip + + 使用灵能撕开一个连接自身、虚境和目的地的单向通道,随后以极短的时间穿过整个通道,以瞬间移动到目标地点 + UI/Abilities/Skip True - True - 1200 - False - true - - 12 - + False + false + 600 HoraxianSpellLight_Warmup Verb_CastAbility - Bullet_FleshmelterBolt - 12 - true 1 - WULA_Psi_Explosive_Shock_Sound - false - true - + 65 + WULA_Psi_Skip_Sound - true + true -
  • - CompAbilityEffect_GiveHediffPsychic - 2000~4000 - true - Wula_Psi_Explosive_Shock_Hediff - true - true - 0 -
  • -
  • - PsycastPsychicEffect -
  • -
  • - AgonyPulseExplosion +
  • + 65 + + 10 + 15 + + 100 + Impact + 3 + false + false + true + + + WULA_Psi_Skip_Entry + WULA_Psi_Skip_Exit +
  • - - HediffWithComps - Wula_Psi_Explosive_Shock_Hediff - - 震耳欲聋、撕心裂肺的灵能尖啸所带来的极度痛苦,不会造成永久的伤害,但是需要时间缓解 - 0.001 - 1 - -
  • - true -
  • -
  • - 0.01 -
  • -
    - + + WULA_Psi_Skip_Entry + 180 +
  • - 0 - 2 - + SubEffecter_SprayerTriggeredDelayed + PlainFlash + 1~1 + 17.0~17.0 + OnSource
  • - 0.5 - 0.5 - + SubEffecter_SprayerTriggeredDelayed + PsycastSkipInnerEntry + 11 + 1~1 + 6~6 + 0~0 + OnSource
  • -
    -
    +
  • + SubEffecter_SprayerTriggeredDelayed + PsycastSkipOuterRingEntry + 11 + 1~1 + 6~6 + 0~0 + OnSource +
  • +
  • + SubEffecter_SprayerTriggered + 1.3 + ElectricalSpark + 7~9 + 17.5 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + 1.3 + 5 + ElectricalSpark + 5~7 + 17.5 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + 1.3 + 10 + ElectricalSpark + 3~7 + 12 + OnSource +
  • + + + + WULA_Psi_Skip_Exit + +
  • + SubEffecter_SprayerTriggeredDelayed + PsycastSkipFlashExit + 12 + 1~1 + 6~6 + 0~0 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + PlainFlash + 14 + 1~1 + 17.0~17.0 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + 1.3 + 16 + ElectricalSpark + 7~9 + 12 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + 1.3 + 24 + ElectricalSpark + 5~7 + 12 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + 1.3 + 32 + ElectricalSpark + 3~7 + 10 + OnSource +
  • +
    +
    - Wula_Psi_LightningBombardment - - 以庞大的灵能能量形成一场非自然风暴,持续轰击目标区域,风暴的轰击会产生范围性灵能爆燃,对建筑物有额外的伤害。 - Wula/UI/Abilities/WULA_MW_Scepter_Of_Explosive_Ability - 900 - false - false - 3 - true + WULA_Psi_Black_Hole + + 撕开虚境的裂口,在目标地点召唤一道虚境阴影,它泄露的庞大灵能会持续伤害范围内的敌方单位和建筑,即使是心灵失聪的目标也不能完全免疫这种超现实伤害——对于高心灵敏感度的单位这种伤害则更加致命。 + UI/Abilities/FireSpew + True + False true + 600 + HoraxianSpellLight_Warmup + + 8 + 600 + - Verb_CastAbility - - true - 0.25 - 35.9 - 4 + 1 + 36 + false - True True -
  • - 9 - 3~4 - 25 - 20 - - Wula_Psi_Bomb - 30 - 3 +
  • + WULA_Black_Hole_Entity + true + false +
  • +
  • + Skip_Exit + 60 + 0.42 +
  • +
  • + +
  • PsycastSkipInnerExit
  • +
  • PsycastSkipOuterRingExit
  • + + 0.42 + Psycast_Skip_Exit + 5
    + + WULA_Black_Hole_Entity + + ThingWithComps + Normal + RealtimeOnly + true + PsychicEmitter + MoteOverheadLow + + Graphic_Single + Wula/Weapon/WULA_Weapon_Empty + 2 + + +
  • + WULA_Black_Hole_Effecter +
  • +
  • + 8 + 30 + Wula_Psi_Damage + 5 + true + 0.5 + 5 + false + true + true +
  • +
    +
    + + WULA_Black_Hole_Effecter + 600 + +
  • + SubEffecter_SprayerTriggered + Fleck_BlastMechBandShockwave + 3~5 + OnSource + true + 0~0 +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + PsycastSkipInnerEntry + 11 + 1~1 + 4~4 + 0~0 + OnSource +
  • +
  • + SubEffecter_SprayerTriggeredDelayed + PsycastSkipOuterRingEntry + 11 + 1~1 + 4~4 + 0~0 + OnSource +
  • +
    +
    \ No newline at end of file diff --git a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml index d679d770..c8278734 100644 --- a/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml +++ b/1.6/1.6/Defs/PawnKinds/PawnKinds_Wula.xml @@ -270,8 +270,8 @@
  • WULA_PsiCrusher
  • -
  • Wula_Psi_Explosive_Shock
  • -
  • Wula_Psi_LightningBombardment
  • +
  • WULA_Psi_Skip
  • +
  • WULA_Psi_Black_Hole
  • diff --git a/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml b/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml index 586338de..0f5694c9 100644 --- a/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml +++ b/1.6/1.6/Defs/SoundDefs/Wula_Sound_Weapons.xml @@ -135,7 +135,7 @@ - WULA_Psi_Explosive_Shock_Sound + WULA_Psi_Skip_Sound MapOnly
  • diff --git a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml index f1d78fa9..374b625f 100644 --- a/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml +++ b/1.6/1.6/Defs/ThingDefs_Races/Races_Wulaspecies.xml @@ -1490,8 +1490,8 @@
  • 36000 - 8.2 - 8.4 + 11.2 + 11.4 0.01 4.0 false diff --git a/Content/Textures/Wula/Mote/fire.png b/Content/Textures/Wula/Mote/fire.png new file mode 100644 index 00000000..4537ad85 Binary files /dev/null and b/Content/Textures/Wula/Mote/fire.png differ diff --git a/Content/Textures/Wula/Mote/glow.png b/Content/Textures/Wula/Mote/glow.png new file mode 100644 index 00000000..5cc2e9bd Binary files /dev/null and b/Content/Textures/Wula/Mote/glow.png differ diff --git a/Content/Textures/Wula/Mote/halo.png b/Content/Textures/Wula/Mote/halo.png new file mode 100644 index 00000000..ae7060ee Binary files /dev/null and b/Content/Textures/Wula/Mote/halo.png differ diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilityAreaDestruction/CompAbilityEffect_AreaDestruction.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilityAreaDestruction/CompAbilityEffect_AreaDestruction.cs index e4ad9ea8..51db11b5 100644 --- a/Source/WulaFallenEmpire/Ability/WULA_AbilityAreaDestruction/CompAbilityEffect_AreaDestruction.cs +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilityAreaDestruction/CompAbilityEffect_AreaDestruction.cs @@ -21,9 +21,6 @@ namespace WulaFallenEmpire Map map = parent.pawn.MapHeld; if (map == null) return; - // 播放发射特效(在施法者位置)- 在释放瞬间播放 - //PlayCastEffecter(target, map); - // 获取扇形区域内的所有单元格 List affectedCells = AffectedCells(target); @@ -56,38 +53,15 @@ namespace WulaFallenEmpire // 为每个受影响的目标播放命中效果器并处理效果 foreach (Thing affectedThing in affectedTargets) { - PlayHitEffecter(affectedThing, map); + // 只对建筑和Pawn播放命中特效 + if (affectedThing is Building || affectedThing is Pawn) + { + PlayHitEffecter(affectedThing, map); + } ProcessTarget(affectedThing); } } - private void PlayCastEffecter(LocalTargetInfo target, Map map) - { - try - { - if (Props.castEffecter == null) return; - - // 在释放瞬间创建效果器,确保正确的方向 - Effecter effecter = Props.castEffecter.Spawn(Pawn.Position, target.Cell, map); - - if (Props.castEffecterMaintainTicks > 0) - { - // 使用与参考代码相同的方法来维持效果器 - parent.AddEffecterToMaintain(effecter, Pawn.Position, target.Cell, Props.castEffecterMaintainTicks, map); - } - else - { - effecter.Cleanup(); - } - - Log.Message($"[AreaDestruction] Played cast effecter from {Pawn.Position} to {target.Cell}"); - } - catch (System.Exception ex) - { - Log.Warning($"[AreaDestruction] Error playing cast effecter: {ex.Message}"); - } - } - private void PlayHitEffecter(Thing target, Map map) { try @@ -99,7 +73,6 @@ namespace WulaFallenEmpire Vector3 directionFromCaster = (target.Position.ToVector3Shifted() - Pawn.Position.ToVector3Shifted()).normalized; // 计算反向位置:目标位置 + 反向向量 * 距离 - // 这样特效会从目标位置向施法者的反方向播放 IntVec3 reversePosition = target.Position + new IntVec3( Mathf.RoundToInt(-directionFromCaster.x * 2f), 0, @@ -110,7 +83,6 @@ namespace WulaFallenEmpire reversePosition = reversePosition.ClampInsideMap(map); // 使用两个位置参数来设置效果器方向 - // 从目标位置到反向位置,这样特效会向施法者反方向播放 Effecter effecter = Props.hitEffecter.Spawn(target.Position, reversePosition, map); if (Props.hitEffecterMaintainTicks > 0) @@ -123,7 +95,8 @@ namespace WulaFallenEmpire effecter.Cleanup(); } - Log.Message($"[AreaDestruction] Played hit effecter on {target.Label} at {target.Position} with reverse direction to {reversePosition}"); + // 可选:记录日志用于调试 + // Log.Message($"[AreaDestruction] Played hit effecter on {target.Label} at {target.Position}"); } catch (System.Exception ex) { @@ -156,10 +129,15 @@ namespace WulaFallenEmpire { DestroyAllBodyParts(targetPawn); } + // 其他类型的物体(如物品、植物等)不进行处理 } private bool ShouldAffectThing(Thing thing) { + // 只影响建筑和Pawn + if (!(thing is Building) && !(thing is Pawn)) + return false; + // 检查是否影响施法者自己 if (thing == Pawn && !Props.affectCaster) return false; @@ -190,7 +168,8 @@ namespace WulaFallenEmpire // 直接销毁建筑 building.Destroy(DestroyMode.Vanish); - Log.Message($"[AreaDestruction] Destroyed building: {buildingInfo}"); + // 可选:记录日志用于调试 + // Log.Message($"[AreaDestruction] Destroyed building: {buildingInfo}"); } catch (System.Exception ex) { @@ -213,7 +192,7 @@ namespace WulaFallenEmpire int partsDestroyed = 0; foreach (var bodyPartRecord in bodyPartRecords) { - // 跳过核心部位以避免立即死亡(可选,根据需求调整) + // 跳过核心部位以避免立即死亡 if (IsCoreBodyPart(bodyPartRecord)) continue; // 检查该部位是否已经缺失 @@ -231,7 +210,8 @@ namespace WulaFallenEmpire // 检查pawn是否还"活着"(没有核心部位缺失时可能还能存活) CheckPawnViability(targetPawn); - Log.Message($"[AreaDestruction] Destroyed {partsDestroyed} body parts on {pawnInfo}"); + // 可选:记录日志用于调试 + // Log.Message($"[AreaDestruction] Destroyed {partsDestroyed} body parts on {pawnInfo}"); } } catch (System.Exception ex) @@ -290,7 +270,7 @@ namespace WulaFallenEmpire List thingList = cell.GetThingList(Pawn.Map); for (int i = 0; i < thingList.Count; i++) { - if (thingList[i].Faction == Pawn.Faction) + if (thingList[i] is Pawn pawn && pawn.Faction == Pawn.Faction) { return false; } diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompAbilityEffect_SpawnAligned.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompAbilityEffect_SpawnAligned.cs new file mode 100644 index 00000000..d87b2370 --- /dev/null +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompAbilityEffect_SpawnAligned.cs @@ -0,0 +1,108 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompAbilityEffect_SpawnAligned : CompAbilityEffect_Spawn + { + public new CompProperties_AbilitySpawnAligned Props => (CompProperties_AbilitySpawnAligned)props; + + public override void Apply(LocalTargetInfo target, LocalTargetInfo dest) + { + base.Apply(target, dest); + + // 获取刚刚生成的物品 + Thing spawnedThing = target.Cell.GetFirstThing(parent.pawn.Map, Props.thingDef); + if (spawnedThing != null && Props.alignFaction) + { + AlignThingFaction(spawnedThing); + } + } + + /// + /// 将生成的物品与施法者阵营对齐 + /// + private void AlignThingFaction(Thing spawnedThing) + { + Faction casterFaction = parent.pawn.Faction; + + // 处理生物 + if (spawnedThing is Pawn spawnedPawn) + { + AlignPawnFaction(spawnedPawn, casterFaction); + } + // 处理建筑 + else if (spawnedThing is Building building) + { + AlignBuildingFaction(building, casterFaction); + } + // 处理其他有阵营的物品 + else + { + AlignThingWithCompsFaction(spawnedThing, casterFaction); + } + } + + /// + /// 对齐生物阵营 + /// + private void AlignPawnFaction(Pawn pawn, Faction casterFaction) + { + // 设置生物阵营 + if (pawn.Faction != casterFaction) + { + pawn.SetFaction(casterFaction); + } + + // 如果是野生动物,尝试驯服 + if (pawn.Faction == null && pawn.RaceProps.Animal && casterFaction == Faction.OfPlayer) + { + pawn.SetFaction(casterFaction); + } + } + + /// + /// 对齐建筑阵营 + /// + private void AlignThingWithCompsFaction(Thing thing, Faction casterFaction) + { + if (thing.Faction != casterFaction) + { + thing.SetFaction(casterFaction); + } + } + + /// + /// 对齐建筑阵营 + /// + private void AlignBuildingFaction(Building building, Faction casterFaction) + { + if (building.Faction != casterFaction) + { + building.SetFaction(casterFaction); + } + } + + public override bool Valid(LocalTargetInfo target, bool throwMessages = false) + { + // 先调用基类的验证 + if (!base.Valid(target, throwMessages)) + { + return false; + } + + // 额外的阵营检查 + if (Props.alignFaction && parent.pawn.Faction == null) + { + if (throwMessages) + { + Messages.Message("CannotSpawnAlignedWithoutFaction".Translate(), + parent.pawn, MessageTypeDefOf.RejectInput, false); + } + return false; + } + + return true; + } + } +} diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompProperties_AbilitySpawnAligned.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompProperties_AbilitySpawnAligned.cs new file mode 100644 index 00000000..3910f639 --- /dev/null +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilitySpawnAligned/CompProperties_AbilitySpawnAligned.cs @@ -0,0 +1,16 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_AbilitySpawnAligned : CompProperties_AbilitySpawn + { + // 是否将生成的物品与施法者阵营对齐 + public bool alignFaction = true; + + public CompProperties_AbilitySpawnAligned() + { + compClass = typeof(CompAbilityEffect_SpawnAligned); + } + } +} diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompAbilityEffect_TeleportSelf.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompAbilityEffect_TeleportSelf.cs new file mode 100644 index 00000000..fcf5f1d8 --- /dev/null +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompAbilityEffect_TeleportSelf.cs @@ -0,0 +1,229 @@ +using System.Collections.Generic; +using RimWorld; +using UnityEngine; +using Verse; +using Verse.Sound; + +namespace WulaFallenEmpire +{ + public class CompAbilityEffect_TeleportSelf : CompAbilityEffect + { + public static string SkipUsedSignalTag = "CompAbilityEffect.SkipUsed"; + + public new CompProperties_AbilityTeleportSelf Props => (CompProperties_AbilityTeleportSelf)props; + + public override IEnumerable GetPreCastActions() + { + yield return new PreCastAction + { + action = delegate(LocalTargetInfo target, LocalTargetInfo dest) + { + Pawn caster = parent.pawn; + Map map = caster.Map; + + // 使用自定义或默认的入口特效 + 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); + // 如果需要更大的效果,可以创建多个粒子 + 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); + } + } + } + else + { + // 默认出口粒子效果 + FleckMaker.Static(target.Cell, map, FleckDefOf.PsycastSkipInnerExit); + FleckMaker.Static(target.Cell, map, FleckDefOf.PsycastSkipOuterRingExit); + } + + // 播放传送音效 + SoundDefOf.Psycast_Skip_Entry.PlayOneShot(new TargetInfo(caster.Position, map)); + SoundDefOf.Psycast_Skip_Exit.PlayOneShot(new TargetInfo(target.Cell, map)); + }, + ticksAwayFromCast = 5 + }; + } + + public override void Apply(LocalTargetInfo target, LocalTargetInfo dest) + { + base.Apply(target, dest); + + if (!target.IsValid) + { + return; + } + + Pawn caster = parent.pawn; + Map map = caster.Map; + + // 使用自定义或默认的入口效果器 + 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); + + // 唤醒可能休眠的组件 + caster.TryGetComp()?.WakeUp(); + + // 执行传送 + caster.Position = target.Cell; + caster.Notify_Teleported(); + + // 如果是玩家阵营,解除战争迷雾 + if ((caster.Faction == Faction.OfPlayer || caster.IsPlayerControlled) && caster.Position.Fogged(map)) + { + FloodFillerFog.FloodUnfog(caster.Position, map); + } + + // 传送后眩晕 + caster.stances.stunner.StunFor(Props.stunTicks.RandomInRange, caster, addBattleLog: false, showMote: false); + + // 发送传送信号 + SendSkipUsedSignal(caster.Position, caster); + + // 播放到达时的喧嚣效果 + if (Props.destClamorType != null) + { + // 根据效果缩放调整喧嚣半径 + float adjustedRadius = Props.destClamorRadius * Props.effectScale; + GenClamor.DoClamor(caster, target.Cell, adjustedRadius, Props.destClamorType); + } + } + + public override bool Valid(LocalTargetInfo target, bool showMessages = true) + { + // 检查目的地是否有效 + if (!CanTeleportTo(target.Cell, parent.pawn.Map)) + { + if (showMessages) + { + Messages.Message("CannotTeleportToLocation".Translate(), + new LookTargets(target.Cell, parent.pawn.Map), + MessageTypeDefOf.RejectInput); + } + return false; + } + + return base.Valid(target, showMessages); + } + + /// + /// 检查是否可以命中目标 + /// + public bool CanHitTarget(LocalTargetInfo target) + { + // 检查是否在范围内 + if (Props.range > 0f && target.Cell.DistanceTo(parent.pawn.Position) > Props.range) + { + return false; + } + + // 检查视线(如果需要) + if (Props.requireLineOfSight && !GenSight.LineOfSight(parent.pawn.Position, target.Cell, parent.pawn.Map)) + { + return false; + } + + // 检查是否可以传送到该位置 + return CanTeleportTo(target.Cell, parent.pawn.Map); + } + + /// + /// 检查是否可以传送到指定位置 + /// + private bool CanTeleportTo(IntVec3 cell, Map map) + { + if (!cell.InBounds(map)) + return false; + + // 检查战争迷雾 + if (!Props.canTeleportToFogged && cell.Fogged(map)) + return false; + + // 检查屋顶 + if (!Props.canTeleportToRoofed && map.roofGrid.Roofed(cell)) + return false; + + // 检查是否可站立 + if (!cell.Standable(map)) + return false; + + // 检查是否有障碍物 + Building edifice = cell.GetEdifice(map); + if (edifice != null && edifice.def.surfaceType != SurfaceType.Item && + edifice.def.surfaceType != SurfaceType.Eat && !(edifice is Building_Door { Open: not false })) + { + return false; + } + + // 检查是否有物品阻挡 + List thingList = cell.GetThingList(map); + for (int i = 0; i < thingList.Count; i++) + { + if (thingList[i].def.category == ThingCategory.Item) + { + return false; + } + } + + return true; + } + + public override string ExtraLabelMouseAttachment(LocalTargetInfo target) + { + if (!CanHitTarget(target)) + { + return "CannotTeleportToLocation".Translate(); + } + return base.ExtraLabelMouseAttachment(target); + } + + public override void DrawEffectPreview(LocalTargetInfo target) + { + // 绘制传送目的地的预览 + GenDraw.DrawTargetHighlight(target); + + // 绘制传送范围 + if (Props.range > 0) + { + GenDraw.DrawRadiusRing(parent.pawn.Position, Props.range); + } + } + + public static void SendSkipUsedSignal(LocalTargetInfo target, Thing initiator) + { + Find.SignalManager.SendSignal(new Signal(SkipUsedSignalTag, target.Named("POSITION"), initiator.Named("SUBJECT"))); + } + } +} diff --git a/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompProperties_AbilityTeleportSelf.cs b/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompProperties_AbilityTeleportSelf.cs new file mode 100644 index 00000000..d69456a8 --- /dev/null +++ b/Source/WulaFallenEmpire/Ability/WULA_AbilityTeleportSelf/CompProperties_AbilityTeleportSelf.cs @@ -0,0 +1,33 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_AbilityTeleportSelf : CompProperties_AbilityEffect + { + public float range = 12f; + public IntRange stunTicks = new IntRange(30, 60); + public float maxBodySize = 2f; + + // 到达时的喧嚣效果 + public ClamorDef destClamorType; + public float destClamorRadius = 2f; + + // 传送限制 + public bool requireLineOfSight = true; + public bool canTeleportToFogged = true; + public bool canTeleportToRoofed = true; + + // 自定义效果器 - 为大型生物设计 + public EffecterDef customEntryEffecter; + public EffecterDef customExitEffecter; + public FleckDef customEntryFleck; + public FleckDef customExitFleck; + public float effectScale = 1.0f; // 效果缩放比例 + + public CompProperties_AbilityTeleportSelf() + { + compClass = typeof(CompAbilityEffect_TeleportSelf); + } + } +} diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs new file mode 100644 index 00000000..e2676595 --- /dev/null +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompAreaDamage.cs @@ -0,0 +1,206 @@ +using System.Collections.Generic; +using RimWorld; +using UnityEngine; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompAreaDamage : ThingComp + { + private int ticksUntilNextDamage; + + public CompProperties_AreaDamage Props => (CompProperties_AreaDamage)props; + + public override void Initialize(CompProperties props) + { + base.Initialize(props); + ticksUntilNextDamage = Props.damageIntervalTicks; + } + + public override void CompTick() + { + base.CompTick(); + + if (!parent.Spawned) + return; + + ticksUntilNextDamage--; + if (ticksUntilNextDamage <= 0) + { + DoAreaDamage(); + ticksUntilNextDamage = Props.damageIntervalTicks; + } + } + + private void DoAreaDamage() + { + Map map = parent.Map; + if (map == null) + return; + + // 获取范围内的所有物体 + List thingsInRange = new List(); + foreach (IntVec3 cell in GenRadial.RadialCellsAround(parent.Position, Props.radius, true)) + { + if (!cell.InBounds(map)) + continue; + + List thingList = cell.GetThingList(map); + foreach (Thing thing in thingList) + { + if (IsValidTarget(thing) && !thingsInRange.Contains(thing)) + { + thingsInRange.Add(thing); + } + } + } + + // 对每个有效目标造成伤害 + foreach (Thing target in thingsInRange) + { + ApplyDamageToTarget(target); + } + } + + private bool IsValidTarget(Thing thing) + { + // 检查是否有生命值 + if (thing.def.useHitPoints == false || thing.HitPoints <= 0) + return false; + + // 检查物体类型过滤 + if (thing is Building && !Props.affectBuildings) + return false; + if (thing is Pawn && !Props.affectPawns) + return false; + if (thing is Plant && !Props.affectPlants) + return false; + + // 检查阵营关系(如果是生物) + if (thing is Pawn pawn) + { + Faction targetFaction = pawn.Faction; + Faction parentFaction = parent.Faction; + + if (targetFaction == null) + { + if (!Props.affectNeutral) + return false; + } + else if (targetFaction == parentFaction) + { + if (!Props.affectFriendly) + return false; + } + else if (targetFaction.HostileTo(parentFaction)) + { + if (!Props.affectHostile) + return false; + } + else + { + if (!Props.affectNeutral) + return false; + } + } + + return true; + } + + private void ApplyDamageToTarget(Thing target) + { + if (Props.damageDef == null) + return; + + // 计算最终伤害量(应用缩放) + int finalDamageAmount = CalculateFinalDamage(target); + + // 创建伤害信息 + DamageInfo damageInfo = new DamageInfo( + Props.damageDef, + finalDamageAmount, + armorPenetration: 0f, + instigator: parent, + hitPart: null, + weapon: null, + category: DamageInfo.SourceCategory.ThingOrUnknown + ); + + // 应用伤害 + target.TakeDamage(damageInfo); + } + + /// + /// 计算最终伤害量,应用心灵敏感度缩放和保底伤害 + /// + private int CalculateFinalDamage(Thing target) + { + float damageFactor = 1.0f; + + // 使用固定缩放值 + if (Props.useFixedScaling) + { + damageFactor = Props.fixedDamageFactor; + } + // 使用心灵敏感度缩放 + else if (Props.scaleWithPsychicSensitivity && target is Pawn pawn) + { + damageFactor = CalculatePsychicSensitivityFactor(pawn); + } + + // 确保伤害倍率在最小和最大范围内 + damageFactor = Mathf.Clamp(damageFactor, Props.minDamageFactor, Props.maxDamageFactor); + + // 计算最终伤害 + int finalDamage = Mathf.RoundToInt(Props.damageAmount * damageFactor); + + // 确保至少造成1点伤害 + return Mathf.Max(1, finalDamage); + } + + /// + /// 根据目标的心灵敏感度计算伤害倍率 + /// + private float CalculatePsychicSensitivityFactor(Pawn targetPawn) + { + // 获取心灵敏感度(如果目标没有心灵敏感度,使用默认值0.5) + float psychicSensitivity = 0.5f; + + if (targetPawn.health != null && targetPawn.health.capacities != null) + { + psychicSensitivity = targetPawn.GetStatValue(StatDefOf.PsychicSensitivity); + } + + // 返回心灵敏感度作为伤害倍率 + // 例如:敏感度0.5 = 0.5倍伤害,敏感度1.5 = 1.5倍伤害 + return psychicSensitivity; + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref ticksUntilNextDamage, "ticksUntilNextDamage", Props.damageIntervalTicks); + } + + /// + /// 调试方法:显示伤害计算信息 + /// + public string GetDamageDebugInfo(Thing target) + { + if (target is Pawn pawn) + { + float psychicSensitivity = pawn.GetStatValue(StatDefOf.PsychicSensitivity); + float damageFactor = CalculatePsychicSensitivityFactor(pawn); + int finalDamage = CalculateFinalDamage(target); + + return $"目标: {pawn.Label}\n" + + $"心灵敏感度: {psychicSensitivity:F2}\n" + + $"伤害倍率: {damageFactor:F2}\n" + + $"基础伤害: {Props.damageAmount}\n" + + $"最终伤害: {finalDamage}"; + } + + return $"目标: {target.Label}\n基础伤害: {Props.damageAmount}"; + } + } +} diff --git a/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompProperties_AreaDamage.cs b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompProperties_AreaDamage.cs new file mode 100644 index 00000000..76c53201 --- /dev/null +++ b/Source/WulaFallenEmpire/ThingComp/WULA_AreaDamage/CompProperties_AreaDamage.cs @@ -0,0 +1,33 @@ +using RimWorld; +using Verse; + +namespace WulaFallenEmpire +{ + public class CompProperties_AreaDamage : CompProperties + { + public float radius = 5f; // A: 伤害半径 + public int damageIntervalTicks = 60; // B: 伤害间隔(帧数) + public DamageDef damageDef; // C: 伤害类型 + public int damageAmount = 10; // 基础伤害量 + + // 伤害缩放设置 + public bool scaleWithPsychicSensitivity = false; // 是否随心灵敏感度缩放 + public float minDamageFactor = 0.5f; // 最低伤害倍率(0.0-1.0) + public float maxDamageFactor = 2.0f; // 最高伤害倍率 + public bool useFixedScaling = false; // 是否使用固定缩放值 + public float fixedDamageFactor = 1.0f; // 固定伤害倍率 + + // 目标过滤 + public bool affectFriendly = false; // 是否影响友方 + public bool affectNeutral = true; // 是否影响中立 + public bool affectHostile = true; // 是否影响敌方 + public bool affectBuildings = true; // 是否影响建筑 + public bool affectPawns = true; // 是否影响生物 + public bool affectPlants = false; // 是否影响植物 + + public CompProperties_AreaDamage() + { + compClass = typeof(CompAreaDamage); + } + } +} diff --git a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj index 60fe80bc..2f38d40f 100644 --- a/Source/WulaFallenEmpire/WulaFallenEmpire.csproj +++ b/Source/WulaFallenEmpire/WulaFallenEmpire.csproj @@ -88,6 +88,10 @@ + + + + @@ -224,6 +228,8 @@ + +