返回提交历史
Modified
Common/MyPlayer.cs
+37
-0
Modified
Projectiles/DeathDomainHarvestSlashProjectile.cs
+49
-27
XFEstudio/DeathMod
重制领域斩击的单向冲击动画
d9311b7
代码差异
2 个文件
+86
-27
@@ -40,6 +40,9 @@ public class MyPlayer : ModPlayer
40
40
private ulong deathWingTrailUpdateTick = ulong.MaxValue;
41
41
private int deathDomainTimer;
42
42
private int deathDomainVolleyCounter;
43
private int deathDomainScreenShakeFrames;
44
private float deathDomainScreenShakeStrength;
45
private Vector2 deathDomainScreenShakeDirection = Vector2.UnitY;
43
46
private readonly Dictionary<int, PendingDeathDomainCut> deathDomainPendingCuts = [];
44
47
45
48
private readonly record struct PendingDeathDomainCut(float Rotation, int ProjectileIndex);
@@ -59,6 +62,9 @@ public class MyPlayer : ModPlayer
59
62
ActiveDeathNecklace = null;
60
63
deathDomainTimer = 0;
61
64
deathDomainVolleyCounter = 0;
65
deathDomainScreenShakeFrames = 0;
66
deathDomainScreenShakeStrength = 0f;
67
deathDomainScreenShakeDirection = Vector2.UnitY;
62
68
deathDomainPendingCuts.Clear();
63
69
}
64
70
@@ -103,6 +109,37 @@ public class MyPlayer : ModPlayer
103
109
DeathWingsActiveLastTick = DeathWingsActiveThisTick;
104
110
}
105
111
112
public override void ModifyScreenPosition()
113
{
114
if (deathDomainScreenShakeFrames <= 0 || deathDomainScreenShakeStrength <= 0.01f)
115
return;
116
117
float remaining = deathDomainScreenShakeFrames / 6f;
118
float phase = (6 - deathDomainScreenShakeFrames) * 2.45f;
119
Vector2 tangent = deathDomainScreenShakeDirection.RotatedBy(MathHelper.PiOver2);
120
Main.screenPosition += deathDomainScreenShakeDirection * ((float)Math.Sin(phase) * deathDomainScreenShakeStrength * remaining)
121
+ tangent * ((float)Math.Sin(phase * 0.63f + 1.1f) * deathDomainScreenShakeStrength * remaining * 0.32f);
122
deathDomainScreenShakeFrames--;
123
if (deathDomainScreenShakeFrames <= 0)
124
deathDomainScreenShakeStrength = 0f;
125
}
126
127
internal void TriggerDeathDomainImpact(Vector2 worldPosition, Vector2 direction, float strength)
128
{
129
if (Main.dedServ || Player.whoAmI != Main.myPlayer)
130
return;
131
132
float distance = Vector2.Distance(Player.Center, worldPosition);
133
float falloff = 1f - MathHelper.Clamp(distance / 1200f, 0f, 1f);
134
strength *= falloff * falloff;
135
if (strength <= deathDomainScreenShakeStrength)
136
return;
137
138
deathDomainScreenShakeStrength = Math.Min(5.2f, strength);
139
deathDomainScreenShakeDirection = direction.SafeNormalize(Vector2.UnitY);
140
deathDomainScreenShakeFrames = 6;
141
}
142
106
143
internal void RecordDeathWingTrail(Vector2 upperTip, Vector2 lowerTip, float mastery)
107
144
{
108
145
if (Main.dedServ || deathWingTrailUpdateTick == Main.GameUpdateCount)
@@ -81,7 +81,9 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
81
81
{
82
82
int slashAge = age - slash * SlashDelayFrames;
83
83
int bit = 1 << slash;
84
if ((emittedMask & bit) == 0 && slashAge >= 0)
84
// The visual blade reaches the target centre after two ticks. Apply
85
// damage at that moment instead of before the slash has visibly landed.
86
if ((emittedMask & bit) == 0 && slashAge >= 2)
85
87
{
86
88
emittedMask |= bit;
87
89
ApplyHarvestDamage();
@@ -89,8 +91,8 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
89
91
SpawnExecutionBurst(slash);
90
92
}
91
93
92
if (createClientEffects && slashAge is >= 0 and < 9)
93
SpawnTravellingEdge(slash, slashAge / 8f);
94
if (createClientEffects && slashAge is >= 0 and < 6)
95
SpawnTravellingEdge(slash, slashAge / 5f);
94
96
}
95
97
Projectile.localAI[0] = emittedMask;
96
98
}
@@ -132,9 +134,14 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
132
134
133
135
private void DrawExecutionBlade(float progress, int slash)
134
136
{
135
float reveal = Smooth01(progress / 0.50f);
136
float disappear = 1f - Smooth01((progress - 0.58f) / 0.42f);
137
float strength = Smooth01(progress / 0.08f) * disappear;
137
// A short anticipation is followed by a very fast ease-out traversal. The
138
// blade covers most of its distance in only a few frames, then the wound
139
// hangs briefly and contracts, which reads as a forceful cut instead of a
140
// line being scaled into existence.
141
float reveal = EaseOutCubic((progress - 0.015f) / 0.31f);
142
float disappear = 1f - Smooth01((progress - 0.52f) / 0.42f);
143
float strength = Smooth01((progress - 0.008f) / 0.055f) * disappear;
144
float impactPulse = 1f + (float)Math.Exp(-Math.Pow((progress - 0.27f) / 0.105f, 2f)) * 0.24f;
138
145
float rotation = GetSlashRotation(Projectile.rotation, slash);
139
146
float length = GetSlashLength(Mastery, Projectile.scale, slash);
140
147
float width = (21f + Mastery * 13f + (IsRequiem ? 8f : 0f)) * Projectile.scale;
@@ -143,33 +150,34 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
143
150
// Draw the long blood-line first. The red-black execution blade is layered
144
151
// over it below, allowing the crimson line to extend beyond both tips while
145
152
// the pure-black core remains completely unbroken.
146
float bloodReveal = Smooth01((progress - 0.08f) / 0.34f);
153
Vector2 direction = rotation.ToRotationVector2();
154
float bloodReveal = EaseOutCubic((progress - 0.005f) / 0.27f);
147
155
float bloodFade = 1f - Smooth01((progress - 0.64f) / 0.28f);
148
156
float bloodStrength = bloodReveal * bloodFade;
149
157
float bloodLength = length * (3f + Mastery * 0.47f + (IsRequiem ? 0.3f : 0f));
150
DeathDomainPrimitiveTextureSystem.DrawBladeCentered(
151
center,
158
Vector2 bloodStart = center - direction * bloodLength * 0.5f;
159
DeathDomainPrimitiveTextureSystem.DrawBlade(
160
bloodStart,
152
161
rotation,
153
162
bloodLength,
154
163
(10f + Mastery * 3.5f) * Projectile.scale,
155
164
new Color(95, 0, 24, 0) * (bloodStrength * 0.72f),
156
165
bloodReveal);
157
DeathDomainPrimitiveTextureSystem.DrawBladeCentered(
158
center,
166
DeathDomainPrimitiveTextureSystem.DrawBlade(
167
bloodStart,
159
168
rotation,
160
169
bloodLength,
161
170
(2.4f + Mastery * 0.85f) * Projectile.scale,
162
171
new Color(255, 0, 38, 0) * bloodStrength,
163
172
bloodReveal);
164
173
165
// Three passes over one continuous high-resolution silhouette produce one
166
// integrated blade. The warning line splits at its centre and opens toward
167
// both tips. No perpendicular tip bars are drawn.
168
DrawTaperedBladeLayer(center, rotation, length, width * 1.52f, reveal,
174
// The red-black body follows the same start-to-end path and is drawn after
175
// the blood-line so its pure-black core always wins the overlap.
176
DrawTaperedBladeLayer(center, rotation, length, width * 1.52f * impactPulse, reveal,
169
177
new Color(92, 0, 22, 0) * (strength * 0.54f));
170
DrawTaperedBladeLayer(center, rotation, length, width, reveal,
178
DrawTaperedBladeLayer(center, rotation, length, width * impactPulse, reveal,
171
179
new Color(255, 8, 48, 255) * strength);
172
DrawTaperedBladeLayer(center, rotation, length * 0.985f, width * 0.62f, reveal,
180
DrawTaperedBladeLayer(center, rotation, length * 0.985f, width * 0.62f * impactPulse, reveal,
173
181
Color.Black * Math.Min(1f, strength * 1.32f));
174
182
}
175
183
@@ -178,7 +186,8 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
178
186
if (maximumWidth <= 0.05f || reveal <= 0f)
179
187
return;
180
188
181
DeathDomainPrimitiveTextureSystem.DrawBladeCentered(center, rotation, length, maximumWidth, color, reveal);
189
Vector2 start = center - rotation.ToRotationVector2() * length * 0.5f;
190
DeathDomainPrimitiveTextureSystem.DrawBlade(start, rotation, length, maximumWidth, color, reveal);
182
191
}
183
192
184
193
private void ApplyHarvestDamage()
@@ -227,13 +236,14 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
227
236
Vector2 direction = rotation.ToRotationVector2();
228
237
Vector2 normal = direction.RotatedBy(MathHelper.PiOver2);
229
238
float length = GetSlashLength(Mastery, Projectile.scale, slash);
230
int count = 10 + (int)(Mastery * 8f) + (IsRequiem ? 5 : 0);
239
int count = 16 + (int)(Mastery * 10f) + (IsRequiem ? 7 : 0);
231
240
for (int i = 0; i < count; i++)
232
241
{
233
float side = Main.rand.NextBool() ? -1f : 1f;
234
Vector2 position = Projectile.Center + direction * Main.rand.NextFloat(-length * 0.035f, length * 0.035f);
235
Vector2 velocity = normal * Main.rand.NextFloat(-4.8f, 4.8f)
236
+ direction * side * Main.rand.NextFloat(1.2f, 3.6f);
242
Vector2 position = Projectile.Center
243
+ direction * Main.rand.NextFloat(-length * 0.06f, length * 0.06f)
244
+ normal * Main.rand.NextFloat(-5f, 5f) * Projectile.scale;
245
Vector2 velocity = normal * Main.rand.NextFloat(-3.8f, 3.8f)
246
+ direction * Main.rand.NextFloat(3.8f, 9.2f);
237
247
int dustType = i % 3 == 0 ? DustID.Shadowflame : DustID.RedTorch;
238
248
Dust dust = Dust.NewDustPerfect(
239
249
position,
@@ -245,21 +255,26 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
245
255
dust.noGravity = true;
246
256
dust.fadeIn = 0.35f;
247
257
}
258
259
Main.LocalPlayer.GetModPlayer<MyPlayer>().TriggerDeathDomainImpact(
260
Projectile.Center,
261
normal,
262
2.2f + Mastery * 1.8f + (IsRequiem ? 1.2f : 0f));
248
263
}
249
264
250
265
private void SpawnTravellingEdge(int slash, float progress)
251
266
{
252
float reveal = Smooth01(progress);
267
float reveal = EaseOutCubic(progress);
253
268
float rotation = GetSlashRotation(Projectile.rotation, slash);
254
269
Vector2 direction = rotation.ToRotationVector2();
255
270
Vector2 normal = direction.RotatedBy(MathHelper.PiOver2);
256
271
float length = GetSlashLength(Mastery, Projectile.scale, slash);
257
float side = Main.rand.NextBool() ? -1f : 1f;
258
Vector2 position = Projectile.Center + direction * (length * reveal * 0.5f * side);
272
Vector2 start = Projectile.Center - direction * length * 0.5f;
273
Vector2 position = start + direction * (length * reveal);
259
274
Dust dust = Dust.NewDustPerfect(
260
275
position + normal * Main.rand.NextFloat(-4f, 4f) * Projectile.scale,
261
276
Main.rand.NextBool(3) ? DustID.Shadowflame : DustID.RedTorch,
262
normal * Main.rand.NextFloat(-2.4f, 2.4f),
277
direction * Main.rand.NextFloat(2.2f, 4.6f) + normal * Main.rand.NextFloat(-2.4f, 2.4f),
263
278
70,
264
279
new Color(255, 10, 50),
265
280
Main.rand.NextFloat(0.62f, 1.05f));
@@ -290,4 +305,11 @@ public class DeathDomainHarvestSlashProjectile : ModProjectile
290
305
value = MathHelper.Clamp(value, 0f, 1f);
291
306
return value * value * (3f - 2f * value);
292
307
}
308
309
private static float EaseOutCubic(float value)
310
{
311
value = MathHelper.Clamp(value, 0f, 1f);
312
float inverse = 1f - value;
313
return 1f - inverse * inverse * inverse;
314
}
293
315
}