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

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

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

XFEstudio/DeathMod

新增弹幕持续时间升级并修正齐射中心

7ad93b0
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

9 个文件 +67 -12
Modified Common/DeathAltarUpgrade.cs +1 -0
@@ -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,
Modified Common/MyGlobalProjectile.cs +17 -0
@@ -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 }
Modified Items/NormalSickle.cs +37 -6
@@ -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;
Modified Localization/en-US.hjson +2 -1
@@ -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
Modified Localization/zh-Hans.hjson +2 -1
@@ -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: 吸血改造
Modified README.md +2 -1
@@ -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 |
Modified README.zh-Hans.md +2 -1
@@ -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% | 仅灵魂精华 |
Modified docs/PLAY_GUIDE.md +2 -1
@@ -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
Modified docs/PLAY_GUIDE.zh-Hans.md +2 -1
@@ -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