返回提交历史
Modified
Common/DeathAltarUpgrade.cs
+1
-0
Modified
Common/MyGlobalProjectile.cs
+17
-0
Modified
Items/NormalSickle.cs
+37
-6
Modified
Localization/en-US.hjson
+2
-1
Modified
Localization/zh-Hans.hjson
+2
-1
Modified
README.md
+2
-1
Modified
README.zh-Hans.md
+2
-1
Modified
docs/PLAY_GUIDE.md
+2
-1
Modified
docs/PLAY_GUIDE.zh-Hans.md
+2
-1
XFEstudio/DeathMod
新增弹幕持续时间升级并修正齐射中心
7ad93b0
代码差异
9 个文件
+67
-12
@@ -10,6 +10,7 @@ public enum DeathAltarUpgradeType : byte
10
10
AlternateAdvancement,
11
11
Damage,
12
12
ProjectileCount,
13
ProjectileDuration,
13
14
ArmorPenetration,
14
15
LifeSteal,
15
16
AttackSpeed,
@@ -18,6 +18,7 @@ public class MyGlobalProjectile : GlobalProjectile
18
18
public bool IsDeathDomainProjectile { get; private set; }
19
19
public int LifeStealLevel { get; private set; }
20
20
public int ArmorPenetrationLevel { get; private set; }
21
public int ProjectileDurationLevel { get; private set; } = 1;
21
22
public int HitCooldownFrames { get; private set; }
22
23
public int OnHitDebuffType { get; private set; }
23
24
public int OnHitDebuffDuration { get; private set; }
@@ -31,6 +32,7 @@ public class MyGlobalProjectile : GlobalProjectile
31
32
{
32
33
LifeStealLevel = sickle.LifeStealLevel;
33
34
ArmorPenetrationLevel = sickle.ArmorPenetrationLevel;
35
ProjectileDurationLevel = sickle.ProjectileDurationLevel;
34
36
HitCooldownFrames = sickle.HitCooldownFrames;
35
37
OnHitDebuffType = sickle.OnHitDebuffType;
36
38
OnHitDebuffDuration = sickle.OnHitDebuffDuration;
@@ -48,6 +50,7 @@ public class MyGlobalProjectile : GlobalProjectile
48
50
{
49
51
LifeStealLevel = parentGlobal.LifeStealLevel;
50
52
ArmorPenetrationLevel = parentGlobal.ArmorPenetrationLevel;
53
ProjectileDurationLevel = parentGlobal.ProjectileDurationLevel;
51
54
HitCooldownFrames = parentGlobal.HitCooldownFrames;
52
55
OnHitDebuffType = parentGlobal.OnHitDebuffType;
53
56
OnHitDebuffDuration = parentGlobal.OnHitDebuffDuration;
@@ -65,6 +68,7 @@ public class MyGlobalProjectile : GlobalProjectile
65
68
projectile.usesIDStaticNPCImmunity = false;
66
69
projectile.usesLocalNPCImmunity = true;
67
70
projectile.localNPCHitCooldown = HitCooldownFrames;
71
ScaleProjectileLifetime(projectile);
68
72
}
69
73
70
74
public override void SendExtraAI(Projectile projectile, BitWriter bitWriter, BinaryWriter binaryWriter)
@@ -75,6 +79,7 @@ public class MyGlobalProjectile : GlobalProjectile
75
79
76
80
binaryWriter.Write((byte)LifeStealLevel);
77
81
binaryWriter.Write((byte)ArmorPenetrationLevel);
82
binaryWriter.Write((byte)ProjectileDurationLevel);
78
83
binaryWriter.Write((byte)HitCooldownFrames);
79
84
binaryWriter.Write((ushort)OnHitDebuffType);
80
85
binaryWriter.Write((ushort)OnHitDebuffDuration);
@@ -91,6 +96,7 @@ public class MyGlobalProjectile : GlobalProjectile
91
96
92
97
LifeStealLevel = binaryReader.ReadByte();
93
98
ArmorPenetrationLevel = binaryReader.ReadByte();
99
ProjectileDurationLevel = Math.Clamp((int)binaryReader.ReadByte(), 1, NormalSickle.MaxProjectileDurationLevel);
94
100
HitCooldownFrames = binaryReader.ReadByte();
95
101
OnHitDebuffType = binaryReader.ReadUInt16();
96
102
OnHitDebuffDuration = binaryReader.ReadUInt16();
@@ -111,6 +117,7 @@ public class MyGlobalProjectile : GlobalProjectile
111
117
{
112
118
LifeStealLevel = sickle.LifeStealLevel;
113
119
ArmorPenetrationLevel = sickle.ArmorPenetrationLevel;
120
ProjectileDurationLevel = sickle.ProjectileDurationLevel;
114
121
HitCooldownFrames = sickle.HitCooldownFrames;
115
122
OnHitDebuffType = sickle.OnHitDebuffType;
116
123
OnHitDebuffDuration = sickle.OnHitDebuffDuration;
@@ -127,6 +134,7 @@ public class MyGlobalProjectile : GlobalProjectile
127
134
projectile.usesIDStaticNPCImmunity = false;
128
135
projectile.usesLocalNPCImmunity = true;
129
136
projectile.localNPCHitCooldown = HitCooldownFrames;
137
ScaleProjectileLifetime(projectile);
130
138
projectile.netUpdate = true;
131
139
}
132
140
@@ -195,4 +203,13 @@ public class MyGlobalProjectile : GlobalProjectile
195
203
196
204
MyGlobalNPC.SyncBuffState(statusTarget);
197
205
}
206
207
private void ScaleProjectileLifetime(Projectile projectile)
208
{
209
if (projectile.ModProjectile is SickleSwingProjectile || ProjectileDurationLevel <= 1)
210
return;
211
212
float multiplier = 1f + (ProjectileDurationLevel - 1) * 0.12f;
213
projectile.timeLeft = Math.Max(1, (int)Math.Round(projectile.timeLeft * multiplier));
214
}
198
215
}
@@ -43,6 +43,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
43
43
public const int BaseHitCooldownFrames = 15;
44
44
public const int MaxDamageLevel = 40;
45
45
public const int MaxProjectileCount = 7;
46
public const int MaxProjectileDurationLevel = 10;
46
47
public const int MaxArmorPenetrationLevel = 20;
47
48
public const int MaxLifeStealLevel = 5;
48
49
public const int MaxAttackSpeedLevel = 10;
@@ -61,6 +62,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
61
62
DeathAltarUpgradeType.AttackSpeed,
62
63
DeathAltarUpgradeType.Knockback,
63
64
DeathAltarUpgradeType.ProjectileCount,
65
DeathAltarUpgradeType.ProjectileDuration,
64
66
DeathAltarUpgradeType.ArmorPenetration,
65
67
DeathAltarUpgradeType.HitCooldown,
66
68
DeathAltarUpgradeType.LifeSteal,
@@ -78,6 +80,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
78
80
DeathAltarUpgradeType.AttackSpeed,
79
81
DeathAltarUpgradeType.Knockback,
80
82
DeathAltarUpgradeType.ProjectileCount,
83
DeathAltarUpgradeType.ProjectileDuration,
81
84
DeathAltarUpgradeType.ArmorPenetration,
82
85
DeathAltarUpgradeType.HitCooldown,
83
86
DeathAltarUpgradeType.LifeSteal,
@@ -89,6 +92,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
89
92
90
93
public int DamageLevel { get; internal set; } = 1;
91
94
public int ProjectileCount { get; internal set; } = 1;
95
public int ProjectileDurationLevel { get; internal set; } = 1;
92
96
public int ArmorPenetrationLevel { get; internal set; } = 1;
93
97
public int LifeStealLevel { get; internal set; }
94
98
public int AttackSpeedLevel { get; internal set; } = 1;
@@ -125,6 +129,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
125
129
public virtual int OnHitDebuffDuration => 0;
126
130
127
131
public bool SupportsProjectileCount => AttackProjectileType > ProjectileID.None;
132
public bool SupportsProjectileDuration => AttackProjectileType > ProjectileID.None;
128
133
public bool HasAlternateAttack => AlternateAttackStyle != SickleAlternateAttackStyle.None;
129
134
public bool SupportsCharge => AlternateAttackStyle is SickleAlternateAttackStyle.BloodCharge
130
135
or SickleAlternateAttackStyle.FrostCharge
@@ -135,6 +140,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
135
140
public float KnockbackBonus => (KnockbackLevel - 1) * 0.5f;
136
141
public float TotalBaseKnockback => BaseKnockback + KnockbackBonus;
137
142
public float ArmorPenetrationPercent => ArmorPenetrationLevel / 100f;
143
public float ProjectileLifetimeMultiplier => 1f + (ProjectileDurationLevel - 1) * 0.12f;
138
144
public int HitCooldownFrames => BaseHitCooldownFrames - (HitCooldownLevel - 1);
139
145
public int FatedMaximumStacks => FatedUnlocked ? GetFatedMaximumStacks(FatedMaximumStacksLevel) : 0;
140
146
public int FatedStacksPerHit => FatedUnlocked ? FatedStacksPerHitLevel : 0;
@@ -280,7 +286,8 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
280
286
LifeStealLevel,
281
287
AttackUseTime,
282
288
TotalBaseKnockback.ToString("0.0"),
283
HitCooldownFrames);
289
HitCooldownFrames,
290
ProjectileLifetimeMultiplier);
284
291
285
292
tooltips.Add(new TooltipLine(Mod, "DeathModUpgradeStats", stats)
286
293
{
@@ -331,6 +338,9 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
331
338
DeathAltarUpgradeType.ProjectileCount => !SupportsProjectileCount || ProjectileCount >= MaxProjectileCount
332
339
? DeathAltarPrice.Unavailable
333
340
: DeathAltarPrice.Essence(1 << (ProjectileCount - 1)),
341
DeathAltarUpgradeType.ProjectileDuration => !SupportsProjectileDuration || ProjectileDurationLevel >= MaxProjectileDurationLevel
342
? DeathAltarPrice.Unavailable
343
: DeathAltarPrice.Essence(1 + (ProjectileDurationLevel - 1) / 2),
334
344
DeathAltarUpgradeType.ArmorPenetration => ArmorPenetrationLevel >= MaxArmorPenetrationLevel
335
345
? DeathAltarPrice.Unavailable
336
346
: DeathAltarPrice.Essence(1 + (ArmorPenetrationLevel - 1) / 3),
@@ -378,6 +388,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
378
388
DeathAltarUpgradeType.AttackSpeed => Language.GetTextValue("Mods.DeathMod.UI.UpgradeValues.Frames", AttackUseTime),
379
389
DeathAltarUpgradeType.Knockback => TotalBaseKnockback.ToString("0.0"),
380
390
DeathAltarUpgradeType.ProjectileCount => $"×{ProjectileCount}",
391
DeathAltarUpgradeType.ProjectileDuration => $"{ProjectileLifetimeMultiplier:P0}",
381
392
DeathAltarUpgradeType.ArmorPenetration => $"{ArmorPenetrationLevel}%",
382
393
DeathAltarUpgradeType.HitCooldown => Language.GetTextValue("Mods.DeathMod.UI.UpgradeValues.Frames", HitCooldownFrames),
383
394
DeathAltarUpgradeType.LifeSteal => $"{LifeStealLevel}%",
@@ -399,6 +410,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
399
410
DeathAltarUpgradeType.AttackSpeed => Language.GetTextValue("Mods.DeathMod.UI.UpgradeValues.Frames", AttackUseTime - 1),
400
411
DeathAltarUpgradeType.Knockback => (TotalBaseKnockback + 0.5f).ToString("0.0"),
401
412
DeathAltarUpgradeType.ProjectileCount => $"×{ProjectileCount + 1}",
413
DeathAltarUpgradeType.ProjectileDuration => $"{1f + ProjectileDurationLevel * 0.12f:P0}",
402
414
DeathAltarUpgradeType.ArmorPenetration => $"{ArmorPenetrationLevel + 1}%",
403
415
DeathAltarUpgradeType.HitCooldown => Language.GetTextValue("Mods.DeathMod.UI.UpgradeValues.Frames", HitCooldownFrames - 1),
404
416
DeathAltarUpgradeType.LifeSteal => $"{LifeStealLevel + 1}%",
@@ -412,7 +424,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
412
424
413
425
public DeathAltarUnavailableReason GetUnavailableReason(DeathAltarUpgradeType upgradeType)
414
426
{
415
if ((upgradeType is DeathAltarUpgradeType.ProjectileCount or DeathAltarUpgradeType.HitCooldown) && !SupportsProjectileCount)
427
if ((upgradeType is DeathAltarUpgradeType.ProjectileCount or DeathAltarUpgradeType.ProjectileDuration or DeathAltarUpgradeType.HitCooldown) && !SupportsProjectileCount)
416
428
return DeathAltarUnavailableReason.RequiresProjectile;
417
429
if ((upgradeType is DeathAltarUpgradeType.FatedMaxStacks or DeathAltarUpgradeType.FatedStacksPerHit or DeathAltarUpgradeType.FatedDuration) && !FatedUnlocked)
418
430
return DeathAltarUnavailableReason.RequiresFatedUnlock;
@@ -438,10 +450,10 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
438
450
439
451
for (int index = 0; index < count; index++)
440
452
{
441
float centeredIndex = index - (count - 1) / 2f;
453
float spreadSlot = GetForwardBiasedSpreadSlot(index, (swingProjectile.identity & 1) == 0 ? 1f : -1f);
442
454
Vector2 projectileDirection = heavySlash && AlternateAttackStyle == SickleAlternateAttackStyle.VoidRitual
443
455
? aim.RotatedBy(index * MathHelper.TwoPi / count)
444
: aim.RotatedBy(centeredIndex * spread);
456
: aim.RotatedBy(spreadSlot * spread);
445
457
Vector2 projectileVelocity = projectileDirection * speed;
446
458
Projectile.NewProjectile(
447
459
source,
@@ -453,7 +465,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
453
465
player.whoAmI,
454
466
heavySlash ? 1f : 0f,
455
467
charge,
456
centeredIndex);
468
spreadSlot);
457
469
}
458
470
}
459
471
@@ -470,6 +482,9 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
470
482
case DeathAltarUpgradeType.ProjectileCount:
471
483
ProjectileCount++;
472
484
break;
485
case DeathAltarUpgradeType.ProjectileDuration:
486
ProjectileDurationLevel++;
487
break;
473
488
case DeathAltarUpgradeType.ArmorPenetration:
474
489
ArmorPenetrationLevel++;
475
490
break;
@@ -515,6 +530,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
515
530
516
531
int damageLevel = DamageLevel;
517
532
int projectileCount = ProjectileCount;
533
int projectileDurationLevel = ProjectileDurationLevel;
518
534
int armorPenetrationLevel = ArmorPenetrationLevel;
519
535
int lifeStealLevel = LifeStealLevel;
520
536
int attackSpeedLevel = AttackSpeedLevel;
@@ -536,6 +552,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
536
552
537
553
upgraded.DamageLevel = damageLevel;
538
554
upgraded.ProjectileCount = projectileCount;
555
upgraded.ProjectileDurationLevel = projectileDurationLevel;
539
556
upgraded.ArmorPenetrationLevel = armorPenetrationLevel;
540
557
upgraded.LifeStealLevel = lifeStealLevel;
541
558
upgraded.AttackSpeedLevel = attackSpeedLevel;
@@ -554,6 +571,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
554
571
{
555
572
tag[nameof(DamageLevel)] = DamageLevel;
556
573
tag[nameof(ProjectileCount)] = ProjectileCount;
574
tag[nameof(ProjectileDurationLevel)] = ProjectileDurationLevel;
557
575
tag[nameof(ArmorPenetrationLevel)] = ArmorPenetrationLevel;
558
576
tag[nameof(LifeStealLevel)] = LifeStealLevel;
559
577
tag[nameof(AttackSpeedLevel)] = AttackSpeedLevel;
@@ -569,6 +587,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
569
587
{
570
588
DamageLevel = Math.Clamp(tag.GetInt(nameof(DamageLevel)), 1, MaxDamageLevel);
571
589
ProjectileCount = Math.Clamp(tag.GetInt(nameof(ProjectileCount)), 1, MaxProjectileCount);
590
ProjectileDurationLevel = Math.Clamp(tag.GetInt(nameof(ProjectileDurationLevel)), 1, MaxProjectileDurationLevel);
572
591
ArmorPenetrationLevel = Math.Clamp(tag.GetInt(nameof(ArmorPenetrationLevel)), 1, MaxArmorPenetrationLevel);
573
592
LifeStealLevel = Math.Clamp(tag.GetInt(nameof(LifeStealLevel)), 0, MaxLifeStealLevel);
574
593
AttackSpeedLevel = Math.Clamp(tag.GetInt(nameof(AttackSpeedLevel)), 1, MaxAttackSpeedLevel);
@@ -585,6 +604,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
585
604
{
586
605
writer.Write((byte)DamageLevel);
587
606
writer.Write((byte)ProjectileCount);
607
writer.Write((byte)ProjectileDurationLevel);
588
608
writer.Write((byte)ArmorPenetrationLevel);
589
609
writer.Write((byte)LifeStealLevel);
590
610
writer.Write((byte)AttackSpeedLevel);
@@ -600,6 +620,7 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
600
620
{
601
621
DamageLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxDamageLevel);
602
622
ProjectileCount = Math.Clamp((int)reader.ReadByte(), 1, MaxProjectileCount);
623
ProjectileDurationLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxProjectileDurationLevel);
603
624
ArmorPenetrationLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxArmorPenetrationLevel);
604
625
LifeStealLevel = Math.Clamp((int)reader.ReadByte(), 0, MaxLifeStealLevel);
605
626
AttackSpeedLevel = Math.Clamp((int)reader.ReadByte(), 1, MaxAttackSpeedLevel);
@@ -679,11 +700,21 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
679
700
float spread = MathHelper.ToRadians(7f);
680
701
for (int index = 0; index < count; index++)
681
702
{
682
float offset = (index - (count - 1) / 2f) * spread;
703
float offset = GetForwardBiasedSpreadSlot(index, 1f) * spread;
683
704
Projectile.NewProjectile(source, position, velocity.RotatedBy(offset), type, damage, knockback, owner);
684
705
}
685
706
}
686
707
708
private static float GetForwardBiasedSpreadSlot(int index, float firstSide)
709
{
710
if (index <= 0)
711
return 0f;
712
713
int distance = (index + 1) / 2;
714
float side = index % 2 == 1 ? firstSide : -firstSide;
715
return distance * side;
716
}
717
687
718
private Color GetGradientColor()
688
719
{
689
720
float pulse = (float)Math.Sin(Main.GlobalTimeWrappedHourly * 2.4f) * 0.16f + 0.84f;
@@ -130,7 +130,7 @@ Mods: {
130
130
SickleStats:
131
131
'''
132
132
Altar upgrades: Damage Lv.{0} (current-form base damage {1}) | Speed {5}f | Knockback {6}
133
Projectiles {2} | Penetration {3} | Life steal {4}% | Hit cooldown {7}f
133
Projectiles {2} | Lifetime {8:P0} | Penetration {3} | Life steal {4}% | Hit cooldown {7}f
134
134
'''
135
135
ChargeHint: Right-click to charge with a separate soul-gathering pose, then release a high-multiplier heavy slash and empowered projectile pattern
136
136
AlternateCooldown: Right-click cooldown: {0:0.##}s
@@ -207,6 +207,7 @@ Mods: {
207
207
AttackSpeed: Attack speed
208
208
Knockback: Knockback
209
209
ProjectileCount: Projectile multiplication
210
ProjectileDuration: Projectile lifetime
210
211
ArmorPenetration: Penetration
211
212
HitCooldown: Hit cooldown
212
213
LifeSteal: Life steal
@@ -130,7 +130,7 @@ Mods: {
130
130
SickleStats:
131
131
'''
132
132
祭坛改造:攻击 Lv.{0}(当前阶段基础伤害 {1}) | 攻速 {5}帧 | 击退 {6}
133
弹幕 {2} | 穿透 {3} | 吸血 {4}% | 伤害间隔 {7}帧
133
弹幕 {2} | 持续时间 {8:P0} | 穿透 {3} | 吸血 {4}% | 伤害间隔 {7}帧
134
134
'''
135
135
ChargeHint: 右键蓄力:使用独立聚魂动作,松开后施展高倍率重斩与强化弹幕
136
136
AlternateCooldown: 右键冷却:{0:0.##}秒
@@ -207,6 +207,7 @@ Mods: {
207
207
AttackSpeed: 攻速改造
208
208
Knockback: 击退改造
209
209
ProjectileCount: 弹幕增殖
210
ProjectileDuration: 弹幕持续时间
210
211
ArmorPenetration: 穿透
211
212
HitCooldown: 伤害间隔
212
213
LifeSteal: 吸血改造
@@ -98,7 +98,7 @@ At the altar, unlock Fated on any regular sickle for 1 Soul Essence. The skill t
98
98
99
99
Every Fated stack deals damage once per second equal to one third of a normal enemy's maximum life. Bosses and boss bodies use a reduced 1% maximum-life rate per stack. Fated damage inherits the life-steal level of the player who applied each stack. Each stack has its own duration timer, and the target displays a magenta icon, stack count, and inward-moving particles.
100
100
101
Projectile count, percentage penetration, hit cooldown, and life steal consume Soul Essence from their first purchase. Penetration ignores the displayed percentage of the target's armor. Damage, attack speed, and knockback retain soul-injection steps at low levels before switching to essence later. Life steal restores its purchased percentage of damage against missing life and creates one returning blood-soul wisp per 20 life actually restored, with one minimum feedback wisp for smaller heals.
101
Projectile count, projectile lifetime, percentage penetration, hit cooldown, and life steal consume Soul Essence from their first purchase. Lifetime rises by 12% per level, while penetration ignores the displayed percentage of the target's armor. Damage, attack speed, and knockback retain soul-injection steps at low levels before switching to essence later. Life steal restores its purchased percentage of damage against missing life and creates one returning blood-soul wisp per 20 life actually restored, with one minimum feedback wisp for smaller heals.
102
102
103
103
After entering Hardmode, craft Wings of Death from Souls of Flight and train flight time, horizontal speed, acceleration, and vertical power. Max all four branches to unlock infinite flight. The Death Robe can be trained in defense, maximum life, regeneration, mobility, minions, sentries, placement range, lava immunity, utility immunities, and 15 separately purchased debuff immunities.
104
104
@@ -120,6 +120,7 @@ The Death Necklace unfolds a small field while equipped and enabled with the **T
120
120
| Attack speed | 25 frames | 16 frames | Early souls, later essence |
121
121
| Knockback | 4.0 | 8.5 | Early souls, later essence |
122
122
| Projectile count | 1 | 7 | Essence only; unavailable on Harvest |
123
| Projectile lifetime | 100% | 208% | +12% per level; Essence only; unavailable on Harvest |
123
124
| Penetration | 1% | 20% | Percentage of target armor ignored; Essence only |
124
125
| Hit cooldown | 15 frames | 6 frames | Essence only; requires a projectile form |
125
126
| Life steal | 0% | 5% | Essence only |
@@ -76,7 +76,7 @@ Soul Harvest(内部模组名 `DeathMod`)是一款围绕死神镰刀、人物
76
76
77
77
命定每层每秒对普通敌人造成 `33.33% 最大生命`伤害,对 Boss 及其主体部件降低为 `1% 最大生命`。命定伤害会继承对应层施加者当时的吸血等级;目标头顶会显示洋红色图标与层数,并产生向内收束粒子。
78
78
79
弹幕数量、穿透、伤害间隔与吸血从第一次升级起就需要灵魂精华。穿透按显示百分比无视目标护甲。攻击、攻速、击退仍可在低级阶段直接注入人物灵魂。吸血按造成伤害的等级百分比回复实际缺失生命,每回复 20 点生成 1 个沿曲线飞回人物的血魂;不足 20 点时仍生成 1 个反馈粒子。
79
弹幕数量、弹幕持续时间、穿透、伤害间隔与吸血从第一次升级起就需要灵魂精华。持续时间每级增加 12%,穿透按显示百分比无视目标护甲。攻击、攻速、击退仍可在低级阶段直接注入人物灵魂。吸血按造成伤害的等级百分比回复实际缺失生命,每回复 20 点生成 1 个沿曲线飞回人物的血魂;不足 20 点时仍生成 1 个反馈粒子。
80
80
81
81
困难模式后可以制作死亡之翼,分别提升飞行时间、水平速度、加速度与垂直能力,四项满级后解锁无限飞行。死神长袍则可提升防御、生命、回复、机动、仆从、哨兵、放置距离、熔岩免疫及功能免疫;15 种减益免疫必须逐项购买。
82
82
@@ -97,6 +97,7 @@ Soul Harvest(内部模组名 `DeathMod`)是一款围绕死神镰刀、人物
97
97
| 攻速 | 25 帧 | 16 帧 | 低级灵魂、高级精华 |
98
98
| 击退 | 4.0 | 8.5 | 低级灵魂、高级精华 |
99
99
| 弹幕数量 | 1 | 7 | 仅灵魂精华;收魂形态不可用 |
100
| 弹幕持续时间 | 100% | 208% | 每级 +12%;仅灵魂精华;收魂形态不可用 |
100
101
| 穿透 | 1% | 20% | 按比例无视目标护甲;仅灵魂精华 |
101
102
| 伤害间隔 | 15 帧 | 6 帧 | 仅灵魂精华;需要弹幕形态 |
102
103
| 吸血 | 0% | 5% | 仅灵魂精华 |
@@ -110,11 +110,12 @@ The letter `L` below means the current level. `N` means the current projectile c
110
110
| Attack speed | 25 to 16 use frames | `25L` souls below Lv. 6; essence afterward |
111
111
| Knockback | 4.0 to 8.5 | `15L` souls below Lv. 6; essence afterward |
112
112
| Projectile count | 1 to 7 | Essence only: 1, 2, 4, 8, 16, 32 |
113
| Projectile lifetime | 100% to 208% | +12% per level; essence only: 1, 1, 2, 2, 3, 3, 4, 4, 5 |
113
114
| Penetration | 1% to 20% | Ignores that percentage of target armor; essence only: `1 + floor((L-1)/3)` |
114
115
| Hit cooldown | 15 to 6 frames | Essence only: `1 + floor((L-1)/2)` |
115
116
| Life steal | 0% to 5% | Essence only: 1, 3, 5, 7, 9 |
116
117
117
Projectile count and hit cooldown are unavailable while holding the projectile-less Harvest form. Advance once to expose them.
118
Projectile count, projectile lifetime, and hit cooldown are unavailable while holding the projectile-less Harvest form. Advance once to expose them. Every volley reserves one projectile directly on the aim vector; extra projectiles alternate to either side, so even-sized volleys no longer leave a gap at the cursor.
118
119
119
120
### Damage curve
120
121
@@ -110,11 +110,12 @@ Boss 不会直接掉落灵魂精华;请通过灵魂罐将奖励凝聚为精华
110
110
| 攻速 | 25 帧降至 16 帧 | 6 级前消耗 `25L` 灵魂,之后消耗精华 |
111
111
| 击退 | 4.0 提升至 8.5 | 6 级前消耗 `15L` 灵魂,之后消耗精华 |
112
112
| 弹幕数量 | 1 提升至 7 | 仅精华:1、2、4、8、16、32 |
113
| 弹幕持续时间 | 100% 提升至 208% | 每级 +12%;仅精华:1、1、2、2、3、3、4、4、5 |
113
114
| 穿透 | 1% 提升至 20% | 按显示比例无视目标护甲;仅精华:`1 + floor((L-1)/3)` |
114
115
| 伤害间隔 | 15 帧降至 6 帧 | 仅精华:`1 + floor((L-1)/2)` |
115
116
| 吸血 | 0% 提升至 5% | 仅精华:1、3、5、7、9 |
116
117
117
收魂镰没有投射物,因此弹幕数量和伤害间隔按钮不可用;首次进阶后开放。
118
收魂镰没有投射物,因此弹幕数量、弹幕持续时间和伤害间隔按钮不可用;首次进阶后开放。每轮齐射固定保留一发正对准星,其余弹幕依次交替分布在两侧,因此偶数弹幕也不会在鼠标正前方留下空缺。
118
119
119
120
### 攻击曲线
120
121