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

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

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

XFEstudio/DeathMod

为死亡领域新增吸血升级

8025b0e
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

7 个文件 +53 -23
Modified Common/DeathAltarUpgrade.cs +2 -1
@@ -58,7 +58,8 @@ public enum DeathAltarUpgradeType : byte
58 58 NecklaceFrequency,
59 59 NecklaceDamage,
60 60 NecklaceVolley,
61 NecklaceSovereignty
61 NecklaceSovereignty,
62 NecklaceLifeSteal
62 63 }
63 64
64 65 public enum DeathAltarCurrency : byte
Modified Common/MyPlayer.cs +11 -4
@@ -49,7 +49,7 @@ public class MyPlayer : ModPlayer
49 49 private readonly List<PendingDeathDomainStrike> pendingDeathDomainStrikes = [];
50 50
51 51 private readonly record struct PendingDeathDomainCut(float Rotation, int ProjectileIndex);
52 private readonly record struct PendingDeathDomainStrike(int NpcIndex, int RemainingFrames, int Damage);
52 private readonly record struct PendingDeathDomainStrike(int NpcIndex, int RemainingFrames, int Damage, int LifeStealLevel);
53 53
54 54 public override void Initialize()
55 55 {
@@ -530,7 +530,8 @@ public class MyPlayer : ModPlayer
530 530 target.whoAmI,
531 531 DeathDomainHarvestSlashProjectile.SlashImpactFrame
532 532 + slash * DeathDomainHarvestSlashProjectile.SlashDelayFrames,
533 slashDamage));
533 slashDamage,
534 necklace.LifeStealLevel));
534 535 }
535 536
536 537 DeathMod.BroadcastDeathDomainHarvestSlash(
@@ -561,6 +562,7 @@ public class MyPlayer : ModPlayer
561 562 Projectile visual = Main.projectile[projectileIndex];
562 563 visual.rotation = rotation;
563 564 visual.scale = scale;
565 visual.localAI[1] = necklace.LifeStealLevel;
564 566 }
565 567
566 568 private void UpdatePendingDeathDomainStrikes()
@@ -579,11 +581,11 @@ public class MyPlayer : ModPlayer
579 581 }
580 582
581 583 pendingDeathDomainStrikes.RemoveAt(index);
582 ApplyDeathDomainStrike(pending.NpcIndex, pending.Damage);
584 ApplyDeathDomainStrike(pending.NpcIndex, pending.Damage, pending.LifeStealLevel);
583 585 }
584 586 }
585 587
586 internal void ApplyDeathDomainStrike(int npcIndex, int damage)
588 internal void ApplyDeathDomainStrike(int npcIndex, int damage, int lifeStealLevel)
587 589 {
588 590 if (npcIndex < 0 || npcIndex >= Main.maxNPCs)
589 591 return;
@@ -611,7 +613,12 @@ public class MyPlayer : ModPlayer
611 613 DamageType = DamageClass.Generic,
612 614 Crit = false
613 615 };
616 int lifeBeforeHit = target.life;
617 Vector2 lifeStealSource = target.Center;
614 618 target.StrikeNPC(harvestHit, fromNet: false, noPlayerInteraction: false);
619 int actualDamage = Math.Max(0, lifeBeforeHit - Math.Max(0, target.life));
620 int healedLife = TryLifeSteal(actualDamage, lifeStealLevel);
621 LifeStealVisuals.Spawn(lifeStealSource, Player.whoAmI, lifeStealLevel, healedLife);
615 622 if (Main.netMode == NetmodeID.Server)
616 623 {
617 624 NetMessage.SendStrikeNPC(target, in harvestHit);
Modified Items/DeathNecklace.cs +17 -2
@@ -16,6 +16,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
16 16 {
17 17 public const int MaxCoreLevel = 10;
18 18 public const int MaxVolleyLevel = 5;
19 public const int MaxLifeStealLevel = 5;
19 20 public const float RadiusGrowthPerLevel = 42f;
20 21
21 22 private static readonly DeathAltarUpgradeType[] UpgradeTypes =
@@ -24,6 +25,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
24 25 DeathAltarUpgradeType.NecklaceFrequency,
25 26 DeathAltarUpgradeType.NecklaceDamage,
26 27 DeathAltarUpgradeType.NecklaceVolley,
28 DeathAltarUpgradeType.NecklaceLifeSteal,
27 29 DeathAltarUpgradeType.NecklaceSovereignty
28 30 ];
29 31
@@ -31,6 +33,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
31 33 public int FrequencyLevel { get; private set; } = 1;
32 34 public int DamageLevel { get; private set; } = 1;
33 35 public int VolleyLevel { get; private set; } = 1;
36 public int LifeStealLevel { get; private set; }
34 37 public bool SovereigntyUnlocked { get; private set; }
35 38
36 39 public float DomainRadius => 160f + (RadiusLevel - 1) * RadiusGrowthPerLevel;
@@ -44,7 +47,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
44 47 public float BossSlashLifeRatio => DamageLevel * 0.0001f;
45 48 public int SlashCount => VolleyLevel;
46 49 public bool IsFullScreenDomain => SovereigntyUnlocked && AllCoreStatsMaxed;
47 public int MasteryScore => RadiusLevel + FrequencyLevel + DamageLevel + VolleyLevel * 2 + (SovereigntyUnlocked ? 30 : 0);
50 public int MasteryScore => RadiusLevel + FrequencyLevel + DamageLevel + VolleyLevel * 2 + LifeStealLevel + (SovereigntyUnlocked ? 30 : 0);
48 51 public IReadOnlyList<DeathAltarUpgradeType> AltarUpgradeTypes => UpgradeTypes;
49 52
50 53 protected override bool CloneNewInstances => true;
@@ -94,6 +97,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
94 97 NormalSlashLifeRatio * 100f,
95 98 BossSlashLifeRatio * 100f,
96 99 SlashCount,
100 LifeStealLevel,
97 101 Language.GetTextValue(key))) { OverrideColor = new Color(110, 220, 240) });
98 102 tooltips.Add(new TooltipLine(Mod, "DeathDomainToggle", Language.GetTextValue("Mods.DeathMod.UI.DeathDomainToggleHint")));
99 103 tooltips.Add(new TooltipLine(Mod, "DeathModAltarHint", Language.GetTextValue("Mods.DeathMod.UI.AltarHint")));
@@ -107,6 +111,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
107 111 DeathAltarUpgradeType.NecklaceFrequency => FrequencyLevel >= MaxCoreLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence((FrequencyLevel + 1) / 2),
108 112 DeathAltarUpgradeType.NecklaceDamage => DamageLevel >= MaxCoreLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence(DamageLevel),
109 113 DeathAltarUpgradeType.NecklaceVolley => VolleyLevel >= MaxVolleyLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence(VolleyLevel * 3),
114 DeathAltarUpgradeType.NecklaceLifeSteal => LifeStealLevel >= MaxLifeStealLevel ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence(2 + LifeStealLevel * 2),
110 115 DeathAltarUpgradeType.NecklaceSovereignty => SovereigntyUnlocked || !AllCoreStatsMaxed ? DeathAltarPrice.Unavailable : DeathAltarPrice.Essence(30),
111 116 _ => DeathAltarPrice.Unavailable
112 117 };
@@ -130,6 +135,9 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
130 135 case DeathAltarUpgradeType.NecklaceVolley:
131 136 VolleyLevel++;
132 137 break;
138 case DeathAltarUpgradeType.NecklaceLifeSteal:
139 LifeStealLevel++;
140 break;
133 141 case DeathAltarUpgradeType.NecklaceSovereignty:
134 142 SovereigntyUnlocked = true;
135 143 break;
@@ -145,6 +153,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
145 153 DeathAltarUpgradeType.NecklaceFrequency => $"{SpawnInterval / 60f:0.##}s",
146 154 DeathAltarUpgradeType.NecklaceDamage => FormatSlashDamage(NormalSlashLifeRatio, BossSlashLifeRatio),
147 155 DeathAltarUpgradeType.NecklaceVolley => $"×{SlashCount}",
156 DeathAltarUpgradeType.NecklaceLifeSteal => $"{LifeStealLevel}%",
148 157 DeathAltarUpgradeType.NecklaceSovereignty => ToggleValue(SovereigntyUnlocked),
149 158 _ => string.Empty
150 159 };
@@ -155,6 +164,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
155 164 DeathAltarUpgradeType.NecklaceFrequency => $"{Math.Max(34, SpawnInterval - 7) / 60f:0.##}s",
156 165 DeathAltarUpgradeType.NecklaceDamage => FormatSlashDamage(NormalSlashLifeRatio + 0.01f, BossSlashLifeRatio + 0.0001f),
157 166 DeathAltarUpgradeType.NecklaceVolley => $"×{SlashCount + 1}",
167 DeathAltarUpgradeType.NecklaceLifeSteal => $"{LifeStealLevel + 1}%",
158 168 DeathAltarUpgradeType.NecklaceSovereignty => Language.GetTextValue("Mods.DeathMod.UI.FullScreenRequiem"),
159 169 _ => string.Empty
160 170 };
@@ -172,6 +182,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
172 182 tag[nameof(FrequencyLevel)] = FrequencyLevel;
173 183 tag[nameof(DamageLevel)] = DamageLevel;
174 184 tag[nameof(VolleyLevel)] = VolleyLevel;
185 tag[nameof(LifeStealLevel)] = LifeStealLevel;
175 186 tag[nameof(SovereigntyUnlocked)] = SovereigntyUnlocked;
176 187 }
177 188
@@ -181,6 +192,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
181 192 FrequencyLevel = Math.Clamp(tag.GetInt(nameof(FrequencyLevel)), 1, MaxCoreLevel);
182 193 DamageLevel = Math.Clamp(tag.GetInt(nameof(DamageLevel)), 1, MaxCoreLevel);
183 194 VolleyLevel = Math.Clamp(tag.GetInt(nameof(VolleyLevel)), 1, MaxVolleyLevel);
195 LifeStealLevel = Math.Clamp(tag.GetInt(nameof(LifeStealLevel)), 0, MaxLifeStealLevel);
184 196 SovereigntyUnlocked = tag.GetBool(nameof(SovereigntyUnlocked));
185 197 }
186 198
@@ -190,6 +202,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
190 202 writer.Write((byte)FrequencyLevel);
191 203 writer.Write((byte)DamageLevel);
192 204 writer.Write((byte)VolleyLevel);
205 writer.Write((byte)LifeStealLevel);
193 206 writer.Write(SovereigntyUnlocked);
194 207 }
195 208
@@ -199,6 +212,7 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
199 212 FrequencyLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxCoreLevel);
200 213 DamageLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxCoreLevel);
201 214 VolleyLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxVolleyLevel);
215 LifeStealLevel = Math.Clamp((int)reader.ReadByte(), 0, MaxLifeStealLevel);
202 216 SovereigntyUnlocked = reader.ReadBoolean();
203 217 }
204 218
@@ -215,7 +229,8 @@ public class DeathNecklace : ModItem, IDeathAltarUpgradeable
215 229 private bool AllCoreStatsMaxed => RadiusLevel >= MaxCoreLevel
216 230 && FrequencyLevel >= MaxCoreLevel
217 231 && DamageLevel >= MaxCoreLevel
218 && VolleyLevel >= MaxVolleyLevel;
232 && VolleyLevel >= MaxVolleyLevel
233 && LifeStealLevel >= MaxLifeStealLevel;
219 234
220 235 private static string ToggleValue(bool enabled) => Language.GetTextValue(
221 236 enabled ? "Mods.DeathMod.UI.Enabled" : "Mods.DeathMod.UI.Disabled");
Modified Localization/en-US.hjson +3 -2
@@ -151,7 +151,7 @@ Mods: {
151 151
152 152 WingStats: Flight {0}f | Speed {1} | Acceleration {2} | Vertical power {3} | Infinite flight: {4}
153 153 RobeStats: Defense {0} | Life +{1} | Life regeneration +{2} | Debuff immunities {3}/{4} | Lava immunity: {5}
154 NecklaceStats: Domain {0:0.#} tiles | Interval {1:0.##}s | Normal slash {2:0.##}% | Boss slash {3:0.###}% | Multislash ×{4} | Sovereignty: {5}
154 NecklaceStats: Domain {0:0.#} tiles | Interval {1:0.##}s | Normal slash {2:0.##}% | Boss slash {3:0.###}% | Multislash ×{4} | Life steal {5}% | Sovereignty: {6}
155 155 NecklaceSlashDamage: Normal {0:0.##}% / Boss {1:0.###}%
156 156 DeathDomainToggleHint: Press the Death Domain keybind to enable or disable the field
157 157 FullScreenRequiem: Full screen + Death Requiem
@@ -200,7 +200,7 @@ Mods: {
200 200 RequiresProjectile: The current form has no projectile
201 201 RequiresWingMastery: Max all four flight attributes first
202 202 RequiresFatedUnlock: Unlock Fated first
203 RequiresNecklaceMastery: Max all four domain attributes first
203 RequiresNecklaceMastery: Max all five domain attributes first
204 204 RequiresAllSickleUpgrades: Max every other upgrade on this sickle before entering form 5
205 205 }
206 206
@@ -254,6 +254,7 @@ Mods: {
254 254 NecklaceFrequency: Harvest frequency
255 255 NecklaceDamage: Slash percentage
256 256 NecklaceVolley: Multislash
257 NecklaceLifeSteal: Domain life steal
257 258 NecklaceSovereignty: Deathly Sovereignty
258 259 }
259 260
Modified Localization/zh-Hans.hjson +3 -2
@@ -151,7 +151,7 @@ Mods: {
151 151
152 152 WingStats: 飞行 {0}帧 | 速度 {1} | 加速度 {2} | 垂直能力 {3} | 无限飞行:{4}
153 153 RobeStats: 防御 {0} | 生命 +{1} | 生命回复 +{2} | 减益免疫 {3}/{4} | 熔岩免疫:{5}
154 NecklaceStats: 领域 {0:0.#}格 | 间隔 {1:0.##}秒 | 小怪斩击 {2:0.##}% | Boss斩击 {3:0.###}% | 多重斩击 ×{4} | 主权:{5}
154 NecklaceStats: 领域 {0:0.#}格 | 间隔 {1:0.##}秒 | 小怪斩击 {2:0.##}% | Boss斩击 {3:0.###}% | 多重斩击 ×{4} | 吸血 {5}% | 主权:{6}
155 155 NecklaceSlashDamage: 小怪 {0:0.##}% / Boss {1:0.###}%
156 156 DeathDomainToggleHint: 按“开关死亡领域”快捷键展开或收回领域
157 157 FullScreenRequiem: 全屏领域 + 死亡安魂曲
@@ -200,7 +200,7 @@ Mods: {
200 200 RequiresProjectile: 当前形态没有弹幕
201 201 RequiresWingMastery: 需先将四项飞行能力升至满级
202 202 RequiresFatedUnlock: 需先点亮命定
203 RequiresNecklaceMastery: 需先将四项领域能力升至满级
203 RequiresNecklaceMastery: 需先将五项领域能力升至满级
204 204 RequiresAllSickleUpgrades: 进阶第5形态前,需先将当前镰刀的其它升级全部升满
205 205 }
206 206
@@ -254,6 +254,7 @@ Mods: {
254 254 NecklaceFrequency: 收割频率
255 255 NecklaceDamage: 斩击百分比
256 256 NecklaceVolley: 多重斩击
257 NecklaceLifeSteal: 领域吸血
257 258 NecklaceSovereignty: 死寂主权
258 259 }
259 260
Modified Projectiles/DeathDomainHarvestSlashProjectile.cs +4 -1
@@ -91,7 +91,10 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
91 91 {
92 92 Main.player[Projectile.owner]
93 93 .GetModPlayer<MyPlayer>()
94 .ApplyDeathDomainStrike(TargetIndex, Projectile.damage);
94 .ApplyDeathDomainStrike(
95 TargetIndex,
96 Projectile.damage,
97 Main.netMode == NetmodeID.MultiplayerClient ? 0 : (int)Projectile.localAI[1]);
95 98 }
96 99 if (createClientEffects)
97 100 SpawnExecutionBurst(slash);
Modified UI/DeathAltarUISystem.cs +13 -11
@@ -346,9 +346,10 @@ internal class DeathAltarUIState : UIState
346 346 IReadOnlyList<DeathAltarUpgradeType> types = upgradeable.AltarUpgradeTypes;
347 347 int first = currentPage * UpgradesPerPage;
348 348 int count = Math.Min(UpgradesPerPage, types.Count - first);
349 bool convergenceTree = first == 0
350 && count == 5
351 && types[4] is DeathAltarUpgradeType.WingInfiniteFlight or DeathAltarUpgradeType.NecklaceSovereignty;
349 int convergenceRootIndex = first == 0 && count >= 5
350 && types[count - 1] is DeathAltarUpgradeType.WingInfiniteFlight or DeathAltarUpgradeType.NecklaceSovereignty
351 ? count - 1
352 : -1;
352 353 int fatedIndex = -1;
353 354 for (int index = 0; index < count; index++)
354 355 {
@@ -361,11 +362,11 @@ internal class DeathAltarUIState : UIState
361 362 for (int index = 0; index < count; index++)
362 363 {
363 364 AltarSkillNode node = new(types[first + index], this, index);
364 GetNodePosition(index, fatedIndex, convergenceTree, out int column, out int row);
365 float left = convergenceTree && index < 4
365 GetNodePosition(index, fatedIndex, convergenceRootIndex, out int column, out int row);
366 float left = convergenceRootIndex == 4 && index < convergenceRootIndex
366 367 ? TreeLeft + 18f + index * 137f
367 368 : TreeLeft + column * 109f;
368 float top = convergenceTree && index == 4 ? TreeTop + 180f : TreeTop + row * 132f;
369 float top = index == convergenceRootIndex ? TreeTop + 180f : TreeTop + row * 132f;
369 370 node.Left.Set(left, 0f);
370 371 node.Top.Set(top, 0f);
371 372 node.Width.Set(104f, 0f);
@@ -382,12 +383,12 @@ internal class DeathAltarUIState : UIState
382 383 displayedPage = currentPage;
383 384 }
384 385
385 private static void GetNodePosition(int index, int fatedIndex, bool convergenceTree, out int column, out int row)
386 private static void GetNodePosition(int index, int fatedIndex, int convergenceRootIndex, out int column, out int row)
386 387 {
387 if (convergenceTree)
388 if (convergenceRootIndex >= 0)
388 389 {
389 column = index == 4 ? 2 : index;
390 row = index == 4 ? 1 : 0;
390 column = index == convergenceRootIndex ? 2 : index;
391 row = index == convergenceRootIndex ? 1 : 0;
391 392 return;
392 393 }
393 394
@@ -577,7 +578,8 @@ internal class ReaperAltarPanel : UIPanel
577 578 DeathAltarUpgradeType.NecklaceRadius,
578 579 DeathAltarUpgradeType.NecklaceFrequency,
579 580 DeathAltarUpgradeType.NecklaceDamage,
580 DeathAltarUpgradeType.NecklaceVolley
581 DeathAltarUpgradeType.NecklaceVolley,
582 DeathAltarUpgradeType.NecklaceLifeSteal
581 583 ]
582 584 };
583 585