XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/DeathMod

修复专服领域斩击伤害结算

0da39c4
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

2 个文件 +92 -59
Modified Common/MyPlayer.cs +82 -15
@@ -46,8 +46,10 @@ public class MyPlayer : ModPlayer
46 46 private float deathDomainScreenShakeStrength;
47 47 private Vector2 deathDomainScreenShakeDirection = Vector2.UnitY;
48 48 private readonly Dictionary<int, PendingDeathDomainCut> deathDomainPendingCuts = [];
49 private readonly List<PendingDeathDomainStrike> pendingDeathDomainStrikes = [];
49 50
50 51 private readonly record struct PendingDeathDomainCut(float Rotation, int ProjectileIndex);
52 private readonly record struct PendingDeathDomainStrike(int NpcIndex, int RemainingFrames, int Damage);
51 53
52 54 public override void Initialize()
53 55 {
@@ -69,6 +71,7 @@ public class MyPlayer : ModPlayer
69 71 deathDomainScreenShakeStrength = 0f;
70 72 deathDomainScreenShakeDirection = Vector2.UnitY;
71 73 deathDomainPendingCuts.Clear();
74 pendingDeathDomainStrikes.Clear();
72 75 }
73 76
74 77 public override void ResetEffects()
@@ -98,6 +101,7 @@ public class MyPlayer : ModPlayer
98 101 if (deathDomainSlashSoundCooldown > 0)
99 102 deathDomainSlashSoundCooldown--;
100 103
104 UpdatePendingDeathDomainStrikes();
101 105 UpdateDeathDomain();
102 106
103 107 if (Player.dead)
@@ -517,7 +521,29 @@ public class MyPlayer : ModPlayer
517 521 int slashDamage = CalculateDeathDomainSlashDamage(target, necklace);
518 522 float scale = MathHelper.Clamp(Math.Max(target.width, target.height) / 52f, 0.85f, 2.4f);
519 523 float visualState = visualMastery + (requiem ? 2f : 0f);
520 bool serverController = Main.netMode == NetmodeID.Server;
524
525 if (Main.netMode == NetmodeID.Server)
526 {
527 for (int slash = 0; slash < necklace.SlashCount; slash++)
528 {
529 pendingDeathDomainStrikes.Add(new PendingDeathDomainStrike(
530 target.whoAmI,
531 DeathDomainHarvestSlashProjectile.SlashImpactFrame
532 + slash * DeathDomainHarvestSlashProjectile.SlashDelayFrames,
533 slashDamage));
534 }
535
536 DeathMod.BroadcastDeathDomainHarvestSlash(
537 Player,
538 target,
539 necklace.SlashCount,
540 visualMastery,
541 requiem,
542 rotation,
543 scale);
544 return;
545 }
546
521 547 int projectileIndex = Projectile.NewProjectile(
522 548 Player.GetSource_Misc("DeathMod:DeathDomain"),
523 549 target.Center,
@@ -528,27 +554,68 @@ public class MyPlayer : ModPlayer
528 554 Player.whoAmI,
529 555 target.whoAmI,
530 556 necklace.SlashCount,
531 visualState + (serverController ? 10f : 0f));
557 visualState);
532 558 if (projectileIndex < 0 || projectileIndex >= Main.maxProjectiles)
533 559 return;
534 560
535 561 Projectile visual = Main.projectile[projectileIndex];
536 562 visual.rotation = rotation;
537 563 visual.scale = scale;
538 if (serverController)
564 }
565
566 private void UpdatePendingDeathDomainStrikes()
567 {
568 if (Main.netMode == NetmodeID.MultiplayerClient || pendingDeathDomainStrikes.Count == 0)
569 return;
570
571 for (int index = pendingDeathDomainStrikes.Count - 1; index >= 0; index--)
539 572 {
540 // The server projectile is only a staggered damage scheduler. Clients
541 // receive an explicit, local-only visual through the mod packet below.
542 visual.netUpdate = false;
543 visual.netImportant = false;
544 DeathMod.BroadcastDeathDomainHarvestSlash(
545 Player,
546 target,
547 necklace.SlashCount,
548 visualMastery,
549 requiem,
550 rotation,
551 scale);
573 PendingDeathDomainStrike pending = pendingDeathDomainStrikes[index];
574 int remainingFrames = pending.RemainingFrames - 1;
575 if (remainingFrames > 0)
576 {
577 pendingDeathDomainStrikes[index] = pending with { RemainingFrames = remainingFrames };
578 continue;
579 }
580
581 pendingDeathDomainStrikes.RemoveAt(index);
582 ApplyDeathDomainStrike(pending.NpcIndex, pending.Damage);
583 }
584 }
585
586 internal void ApplyDeathDomainStrike(int npcIndex, int damage)
587 {
588 if (npcIndex < 0 || npcIndex >= Main.maxNPCs)
589 return;
590
591 NPC target = Main.npc[npcIndex];
592 if (!target.active || target.friendly || target.immortal || target.dontTakeDamage || target.life <= 0)
593 return;
594
595 bool bossOrBossPart = target.boss
596 || NPCID.Sets.ShouldBeCountedAsBoss[target.type]
597 || target.realLife >= 0 && target.realLife < Main.maxNPCs && Main.npc[target.realLife].boss;
598 target.GetGlobalNPC<MyGlobalNPC>().ApplyDeathDomainHitStop(target, bossOrBossPart ? 1 : 3);
599
600 if (Main.netMode == NetmodeID.MultiplayerClient || damage <= 0)
601 return;
602
603 target.GetGlobalNPC<MyGlobalNPC>().RegisterSickleHit(target, Player.whoAmI);
604 target.lastInteraction = Player.whoAmI;
605 NPC.HitInfo harvestHit = new()
606 {
607 Damage = damage,
608 SourceDamage = damage,
609 HitDirection = 0,
610 Knockback = 0f,
611 DamageType = DamageClass.Generic,
612 Crit = false
613 };
614 target.StrikeNPC(harvestHit, fromNet: false, noPlayerInteraction: false);
615 if (Main.netMode == NetmodeID.Server)
616 {
617 NetMessage.SendStrikeNPC(target, in harvestHit);
618 target.netUpdate = true;
552 619 }
553 620 }
554 621
Modified Projectiles/DeathDomainHarvestSlashProjectile.cs +10 -44
@@ -18,7 +18,8 @@ namespace DeathMod.Projectiles;
18 18 public class DeathDomainHarvestSlashProjectile : ModProjectile
19 19 {
20 20 private const int SlashActiveFrames = 60;
21 private const int SlashDelayFrames = 5;
21 internal const int SlashDelayFrames = 5;
22 internal const int SlashImpactFrame = 5;
22 23 private const int EndLingerFrames = 7;
23 24 private const int MaximumSlashCount = 5;
24 25
@@ -83,10 +84,15 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
83 84 int bit = 1 << slash;
84 85 // The visible blade reaches the target centre after five ticks. Apply
85 86 // damage at that moment instead of before the slash has visibly landed.
86 if ((emittedMask & bit) == 0 && slashAge >= 5)
87 if ((emittedMask & bit) == 0 && slashAge >= SlashImpactFrame)
87 88 {
88 89 emittedMask |= bit;
89 ApplyHarvestDamage();
90 if (Projectile.owner >= 0 && Projectile.owner < Main.maxPlayers)
91 {
92 Main.player[Projectile.owner]
93 .GetModPlayer<MyPlayer>()
94 .ApplyDeathDomainStrike(TargetIndex, Projectile.damage);
95 }
90 96 if (createClientEffects)
91 97 SpawnExecutionBurst(slash);
92 98 }
@@ -126,7 +132,7 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
126 132 float impactPulse = 1f + (float)Math.Exp(-Math.Pow((progress - 0.083f) / 0.034f, 2f)) * 0.24f;
127 133 float rotation = GetSlashRotation(Projectile.rotation, slash);
128 134 float length = GetSlashLength(Mastery, Projectile.scale, slash);
129 float width = (21f + Mastery * 13f + (IsRequiem ? 8f : 0f)) * Projectile.scale;
135 float width = (21f + Mastery * 13f + (IsRequiem ? 8f : 0f)) * Projectile.scale * 0.78f;
130 136 Vector2 center = Projectile.Center - Main.screenPosition;
131 137
132 138 Vector2 direction = rotation.ToRotationVector2();
@@ -225,46 +231,6 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
225 231 }
226 232 }
227 233
228 private void ApplyHarvestDamage()
229 {
230 if (Projectile.owner < 0
231 || Projectile.owner >= Main.maxPlayers
232 || TargetIndex < 0
233 || TargetIndex >= Main.maxNPCs)
234 {
235 return;
236 }
237
238 NPC target = Main.npc[TargetIndex];
239 if (!target.active || target.friendly || target.immortal || target.dontTakeDamage || target.life <= 0)
240 return;
241
242 bool bossOrBossPart = target.boss
243 || NPCID.Sets.ShouldBeCountedAsBoss[target.type]
244 || target.realLife >= 0 && target.realLife < Main.maxNPCs && Main.npc[target.realLife].boss;
245 target.GetGlobalNPC<MyGlobalNPC>().ApplyDeathDomainHitStop(target, bossOrBossPart ? 1 : 3);
246
247 // Explicit client visuals repeat the timing of the hidden server scheduler.
248 // They only apply the local hit-stop above; damage remains authoritative.
249 if (Main.netMode == NetmodeID.MultiplayerClient || Projectile.damage <= 0)
250 return;
251
252 target.GetGlobalNPC<MyGlobalNPC>().RegisterSickleHit(target, Projectile.owner);
253 target.lastInteraction = Projectile.owner;
254 NPC.HitInfo harvestHit = new()
255 {
256 Damage = Projectile.damage,
257 SourceDamage = Projectile.damage,
258 HitDirection = 0,
259 Knockback = 0f,
260 DamageType = DamageClass.Generic,
261 Crit = false
262 };
263 target.StrikeNPC(harvestHit, fromNet: false, noPlayerInteraction: false);
264 if (Main.netMode == NetmodeID.Server)
265 NetMessage.SendStrikeNPC(target, in harvestHit);
266 }
267
268 234 private void SpawnExecutionBurst(int slash)
269 235 {
270 236 float rotation = GetSlashRotation(Projectile.rotation, slash);