返回提交历史
Modified
Common/DeathAltarUpgrade.cs
+2
-1
Modified
Common/MyPlayer.cs
+11
-4
Modified
Items/DeathNecklace.cs
+17
-2
Modified
Localization/en-US.hjson
+3
-2
Modified
Localization/zh-Hans.hjson
+3
-2
Modified
Projectiles/DeathDomainHarvestSlashProjectile.cs
+4
-1
Modified
UI/DeathAltarUISystem.cs
+13
-11
XFEstudio/DeathMod
为死亡领域新增吸血升级
8025b0e
代码差异
7 个文件
+53
-23
@@ -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
@@ -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);
@@ -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");
@@ -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
@@ -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
@@ -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);
@@ -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