返回提交历史
Modified
Common/DeathDomainBackdropTextureSystem.cs
+15
-11
Modified
Common/DeathDomainVisualSystem.cs
+189
-39
Modified
Common/MyPlayer.cs
+1
-12
Added
Common/SickleTrailPrimitiveSystem.cs
+131
-0
Modified
Items/DeathWings.cs
+5
-3
Modified
Items/NormalSickle.cs
+9
-2
Modified
Items/VoidSickle.cs
+0
-1
Modified
Projectiles/SickleSwingProjectile.cs
+10
-56
XFEstudio/DeathMod
统一领域背景层并重构镰刀拖尾
d59791f
代码差异
8 个文件
+360
-124
@@ -14,8 +14,8 @@ namespace DeathMod.Common;
14
14
[Autoload(Side = ModSide.Client)]
15
15
internal sealed class DeathDomainBackdropTextureSystem : ModSystem
16
16
{
17
internal const int LayerWidth = 1024;
18
internal const int LayerHeight = 512;
17
internal const int LayerWidth = 4096;
18
internal const int LayerHeight = 1024;
19
19
20
20
private static readonly Texture2D?[] layers = new Texture2D?[3];
21
21
@@ -48,7 +48,10 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
48
48
float v = (y + 0.5f) / LayerHeight;
49
49
for (int x = 0; x < LayerWidth; x++)
50
50
{
51
float u = (x + 0.5f) / LayerWidth;
51
// Keep roughly the same feature scale as the original 1024-wide
52
// plate while supplying enough unique scenery for a 4K full-screen
53
// view at exactly the same scale as the player's circular window.
54
float u = (x + 0.5f) / 1024f;
52
55
pixels[y * LayerWidth + x] = layer switch
53
56
{
54
57
0 => BuildFarPixel(x, y, u, v),
@@ -70,7 +73,8 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
70
73
71
74
float crimsonCloud = Wave(u, v, 2f, 1f, 0.13f)
72
75
+ Wave(u, v, 5f, -2f, 1.7f) * 0.45f
73
+ Wave(u, v, 9f, 3f, 4.2f) * 0.2f;
76
+ Wave(u, v, 9f, 3f, 4.2f) * 0.2f
77
+ Wave(u, v, 0.37f, 0.45f, 2.3f) * 0.24f;
74
78
crimsonCloud = Smooth01((crimsonCloud + 1.1f) / 2.45f);
75
79
float violetCloud = Smooth01((Wave(u, v, 3f, -2f, 3.4f) + 0.78f) / 1.78f);
76
80
color += new Vector3(0.16f, 0.006f, 0.055f) * crimsonCloud * (0.32f + v * 0.34f);
@@ -90,7 +94,9 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
90
94
// animate on their own: parallax reveals them like distant landmarks while
91
95
// the nearer mountains and blood mist intermittently hide them again.
92
96
ApplyDistantBlackHole(ref color, u, v, 0.18f, 0.27f, 0.034f, 0.22f, 1.7f);
93
ApplyDistantBlackHole(ref color, u, v, 0.79f, 0.64f, 0.022f, -0.38f, 4.9f);
97
ApplyDistantBlackHole(ref color, u, v, 1.43f, 0.64f, 0.022f, -0.38f, 4.9f);
98
ApplyDistantBlackHole(ref color, u, v, 2.72f, 0.36f, 0.029f, 0.31f, 7.3f);
99
ApplyDistantBlackHole(ref color, u, v, 3.61f, 0.72f, 0.019f, -0.17f, 9.8f);
94
100
95
101
return Opaque(color);
96
102
}
@@ -106,10 +112,6 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
106
112
float seed)
107
113
{
108
114
float dx = u - centerU;
109
if (dx > 0.5f)
110
dx -= 1f;
111
else if (dx < -0.5f)
112
dx += 1f;
113
115
float dy = v - centerV;
114
116
float reach = radius * 3.35f;
115
117
if (Math.Abs(dx) > reach || Math.Abs(dy) > reach)
@@ -181,7 +183,8 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
181
183
// Two ranges of dead mountains create the mid-distance depth plane.
182
184
float rearHorizon = 0.59f
183
185
+ (float)Math.Sin(u * MathHelper.TwoPi * 3f + 0.4f) * 0.06f
184
+ (float)Math.Sin(u * MathHelper.TwoPi * 7f) * 0.025f;
186
+ (float)Math.Sin(u * MathHelper.TwoPi * 7f) * 0.025f
187
+ (float)Math.Sin(u * MathHelper.TwoPi * 0.31f + 1.4f) * 0.024f;
185
188
if (v > rearHorizon)
186
189
{
187
190
float depth = Smooth01((v - rearHorizon) / 0.18f);
@@ -201,7 +204,8 @@ internal sealed class DeathDomainBackdropTextureSystem : ModSystem
201
204
{
202
205
float broadMist = Wave(u, v, 2f, 1f, 0.35f)
203
206
+ Wave(u, v, 4f, -2f, 2.2f) * 0.52f
204
+ Wave(u, v, 7f, 3f, 4.6f) * 0.24f;
207
+ Wave(u, v, 7f, 3f, 4.6f) * 0.24f
208
+ Wave(u, v, 0.43f, -0.38f, 5.1f) * 0.26f;
205
209
float curledMist = Wave(u, v, 3f, -3f, 1.1f)
206
210
+ Wave(u, v, 9f, 4f, 3.7f) * 0.34f;
207
211
float body = Smooth01((broadMist + 0.72f) / 2.2f);
@@ -19,6 +19,16 @@ internal class DeathDomainVisualSystem : ModSystem
19
19
private readonly int[] cachedMastery = new int[Main.maxPlayers];
20
20
private readonly bool[] cachedFullScreen = new bool[Main.maxPlayers];
21
21
22
public override void Load()
23
{
24
On_Main.DrawBackground += DrawDomainBackdropsAfterVanillaBackground;
25
}
26
27
public override void Unload()
28
{
29
On_Main.DrawBackground -= DrawDomainBackdropsAfterVanillaBackground;
30
}
31
22
32
public override void PostUpdateEverything()
23
33
{
24
34
if (Main.gameMenu)
@@ -113,14 +123,21 @@ internal class DeathDomainVisualSystem : ModSystem
113
123
continue;
114
124
}
115
125
if (!fullScreen)
116
DrawDomainRing(batch, pixel, screenCenter, radius, mastery, animation);
126
DrawDomainRing(batch, pixel, screenCenter, radius, mastery, animation, drawBackdrop: false);
117
127
else
118
128
DrawFullScreenDomain(batch, pixel, screenCenter, radius, mastery, animation);
119
129
}
120
130
batch.End();
121
131
}
122
132
123
private static void DrawDomainRing(SpriteBatch batch, Texture2D pixel, Vector2 center, float targetRadius, int mastery, float animation)
133
private static void DrawDomainRing(
134
SpriteBatch batch,
135
Texture2D pixel,
136
Vector2 center,
137
float targetRadius,
138
int mastery,
139
float animation,
140
bool drawBackdrop = true)
124
141
{
125
142
float time = Main.GlobalTimeWrappedHourly;
126
143
float reveal = MathHelper.SmoothStep(0f, 1f, animation);
@@ -135,14 +152,23 @@ internal class DeathDomainVisualSystem : ModSystem
135
152
float radius = MathHelper.Lerp(8f, targetRadius, expansion) * overshoot;
136
153
float pulse = (0.82f + (float)Math.Sin(time * 3.2f) * 0.12f) * manifestedReveal;
137
154
float masteryProgress = GetMasteryProgress(mastery);
138
DrawBlackHoleField(batch, pixel, center, radius, masteryProgress, pulse, time, manifestedReveal);
155
DrawBlackHoleField(batch, pixel, center, radius, masteryProgress, pulse, time, manifestedReveal, drawBackdrop);
139
156
DrawNoiseBoundary(batch, pixel, center, radius + 3f, time, 0.4f, 12f, 9f, 0.18f * pulse, masteryProgress, gaps: true);
140
157
DrawNoiseBoundary(batch, pixel, center, radius, time, 1.7f, 9f, 5f, 0.42f * pulse, masteryProgress, gaps: true);
141
158
DrawNoiseBoundary(batch, pixel, center, radius - 2f, time, 3.3f, 7f, 2.7f + masteryProgress, 0.94f * pulse, masteryProgress, gaps: false);
142
159
DrawNoiseBoundary(batch, pixel, center, radius - 7f, -time, 5.1f, 5f, 1.4f, 0.58f * pulse, masteryProgress, gaps: true);
143
160
}
144
161
145
private static void DrawBlackHoleField(SpriteBatch batch, Texture2D pixel, Vector2 center, float radius, float mastery, float pulse, float time, float reveal)
162
private static void DrawBlackHoleField(
163
SpriteBatch batch,
164
Texture2D pixel,
165
Vector2 center,
166
float radius,
167
float mastery,
168
float pulse,
169
float time,
170
float reveal,
171
bool drawBackdrop)
146
172
{
147
173
float coreGap = MathHelper.Lerp(22f, 14f, mastery);
148
174
float coreRadius = radius > coreGap + 6f ? radius - coreGap : radius * 0.58f;
@@ -157,15 +183,18 @@ internal class DeathDomainVisualSystem : ModSystem
157
183
float coreNoiseTime = time * 0.8f;
158
184
const float coreNoiseSeed = 16.2f;
159
185
float coreNoiseAmplitude = Math.Min(coreRadius * 0.18f, MathHelper.Lerp(5f, 10f, mastery) * MathHelper.Lerp(0.35f, 1f, reveal));
160
DrawClippedDeathDomainBackdrop(
161
batch,
162
center,
163
coreRadius,
164
coreNoiseTime,
165
coreNoiseSeed,
166
coreNoiseAmplitude,
167
mastery,
168
reveal);
186
if (drawBackdrop)
187
{
188
DrawClippedDeathDomainBackdrop(
189
batch,
190
center,
191
coreRadius,
192
coreNoiseTime,
193
coreNoiseSeed,
194
coreNoiseAmplitude,
195
mastery,
196
reveal);
197
}
169
198
DrawFilledNoiseDisc(
170
199
batch,
171
200
pixel,
@@ -215,9 +244,6 @@ internal class DeathDomainVisualSystem : ModSystem
215
244
// only three texture batches instead of switching textures for every row.
216
245
for (int layer = 0; layer < 3; layer++)
217
246
{
218
float parallax = layer switch { 0 => 0.07f, 1 => 0.18f, _ => 0.34f };
219
float horizontalViewFraction = layer switch { 0 => 0.68f, 1 => 0.9f, _ => 0.84f };
220
float verticalViewFraction = layer switch { 0 => 0.78f, 1 => 0.9f, _ => 0.86f };
221
247
float opacity = layer switch
222
248
{
223
249
0 => MathHelper.Lerp(0.88f, 1f, mastery) * reveal,
@@ -225,15 +251,8 @@ internal class DeathDomainVisualSystem : ModSystem
225
251
_ => MathHelper.Lerp(0.78f, 0.96f, mastery) * reveal
226
252
};
227
253
Texture2D texture = DeathDomainBackdropTextureSystem.GetLayer(layer);
228
float viewWidth = texture.Width * horizontalViewFraction;
229
float viewHeight = texture.Height * verticalViewFraction;
230
float sourceOffsetX = PositiveModulo(worldCenter.X * parallax, texture.Width);
231
// Vertical sampling traverses the source image only once over the full
232
// world depth. It never wraps across the top/bottom texture edge, so a
233
// second horizon or mountain range cannot be spliced into the domain.
234
float worldHeight = Math.Max(1f, Main.maxTilesY * 16f);
235
float worldDepth = MathHelper.Clamp(worldCenter.Y / worldHeight, 0f, 1f);
236
float sourceOffsetY = worldDepth * Math.Max(0f, texture.Height - viewHeight);
254
GetBackdropSource(layer, texture, worldCenter, 1f, 1f, out float sourceOffsetX,
255
out float sourceOffsetY, out float viewWidth, out float viewHeight);
237
256
238
257
for (int index = 0; index < bands; index++)
239
258
{
@@ -358,24 +377,133 @@ internal class DeathDomainVisualSystem : ModSystem
358
377
int mastery,
359
378
float animation)
360
379
{
361
float reveal = MathHelper.SmoothStep(0f, 1f, animation);
362
float masteryProgress = GetMasteryProgress(mastery);
363
DrawFullScreenBackdrop(batch, masteryProgress, reveal);
364
365
380
// Full-screen mastery removes the circular crop from the domain scene. The
366
381
// player's event horizon is still the same max-level field, rather than a
367
382
// circle enlarged until it reaches the viewport corners.
368
DrawDomainRing(batch, pixel, center, playerDomainRadius, mastery, animation);
383
DrawDomainRing(batch, pixel, center, playerDomainRadius, mastery, animation, drawBackdrop: false);
384
}
385
386
private void DrawDomainBackdropsAfterVanillaBackground(On_Main.orig_DrawBackground orig, Main self)
387
{
388
orig(self);
389
if (Main.gameMenu || !Main.LocalPlayer.active)
390
return;
391
392
bool anyFullScreen = false;
393
bool anyClipped = false;
394
for (int index = 0; index < Main.maxPlayers; index++)
395
{
396
if (domainAnimation[index] <= 0.001f || !Main.player[index].active)
397
continue;
398
anyFullScreen |= cachedFullScreen[index];
399
anyClipped |= !cachedFullScreen[index];
400
}
401
if (!anyFullScreen && !anyClipped)
402
return;
403
404
SpriteBatch batch = Main.spriteBatch;
405
if (anyFullScreen)
406
{
407
batch.Begin(
408
SpriteSortMode.Deferred,
409
BlendState.AlphaBlend,
410
SamplerState.LinearClamp,
411
DepthStencilState.None,
412
RasterizerState.CullNone,
413
null,
414
Matrix.Identity);
415
for (int index = 0; index < Main.maxPlayers; index++)
416
{
417
if (!cachedFullScreen[index] || domainAnimation[index] <= 0.001f || !Main.player[index].active)
418
continue;
419
420
DrawFullScreenBackdrop(
421
batch,
422
GetMasteryProgress(cachedMastery[index]),
423
MathHelper.SmoothStep(0f, 1f, domainAnimation[index]));
424
}
425
batch.End();
426
}
427
428
if (anyClipped)
429
{
430
batch.Begin(
431
SpriteSortMode.Deferred,
432
BlendState.AlphaBlend,
433
SamplerState.LinearClamp,
434
DepthStencilState.None,
435
RasterizerState.CullNone,
436
null,
437
Main.GameViewMatrix.TransformationMatrix);
438
for (int index = 0; index < Main.maxPlayers; index++)
439
{
440
Player player = Main.player[index];
441
float animation = domainAnimation[index];
442
if (cachedFullScreen[index] || animation <= 0.001f || !player.active)
443
continue;
444
445
float targetRadius = Math.Max(160f, cachedRadius[index]);
446
Vector2 center = player.Center - Main.screenPosition;
447
if (center.X < -targetRadius || center.X > Main.screenWidth + targetRadius
448
|| center.Y < -targetRadius || center.Y > Main.screenHeight + targetRadius)
449
{
450
continue;
451
}
452
453
GetAnimatedBackdropGeometry(targetRadius, cachedMastery[index], animation,
454
out float coreRadius, out float noiseTime, out float noiseAmplitude,
455
out float masteryProgress, out float reveal);
456
DrawClippedDeathDomainBackdrop(
457
batch,
458
center,
459
coreRadius,
460
noiseTime,
461
16.2f,
462
noiseAmplitude,
463
masteryProgress,
464
reveal);
465
}
466
batch.End();
467
}
468
}
469
470
private static void GetAnimatedBackdropGeometry(
471
float targetRadius,
472
int mastery,
473
float animation,
474
out float coreRadius,
475
out float noiseTime,
476
out float noiseAmplitude,
477
out float masteryProgress,
478
out float reveal)
479
{
480
reveal = MathHelper.SmoothStep(0f, 1f, animation);
481
float rangeProgress = MathHelper.Clamp(
482
(targetRadius - 160f) / (DeathNecklace.RadiusGrowthPerLevel * (DeathNecklace.MaxCoreLevel - 1)),
483
0f,
484
1f);
485
float manifestedReveal = reveal * MathHelper.Lerp(0.38f, 1f, rangeProgress);
486
float expansion = 1f - (float)Math.Pow(1f - reveal, 3f);
487
float overshoot = 1f + (float)Math.Sin(reveal * MathHelper.Pi) * 0.035f;
488
float radius = MathHelper.Lerp(8f, targetRadius, expansion) * overshoot;
489
masteryProgress = GetMasteryProgress(mastery);
490
float coreGap = MathHelper.Lerp(22f, 14f, masteryProgress);
491
coreRadius = radius > coreGap + 6f ? radius - coreGap : radius * 0.58f;
492
noiseTime = Main.GlobalTimeWrappedHourly * 0.8f;
493
noiseAmplitude = Math.Min(
494
coreRadius * 0.18f,
495
MathHelper.Lerp(5f, 10f, masteryProgress) * MathHelper.Lerp(0.35f, 1f, manifestedReveal));
496
reveal = manifestedReveal;
369
497
}
370
498
371
499
private static void DrawFullScreenBackdrop(SpriteBatch batch, float mastery, float reveal)
372
500
{
373
501
Vector2 worldCenter = Main.screenPosition + new Vector2(Main.screenWidth, Main.screenHeight) * 0.5f;
502
float referenceDiameter = (160f + DeathNecklace.RadiusGrowthPerLevel * (DeathNecklace.MaxCoreLevel - 1)) * 2f;
503
float horizontalScale = Main.screenWidth / referenceDiameter;
504
float verticalScale = Main.screenHeight / referenceDiameter;
374
505
for (int layer = 0; layer < 3; layer++)
375
506
{
376
float parallax = layer switch { 0 => 0.07f, 1 => 0.18f, _ => 0.34f };
377
float horizontalViewFraction = layer switch { 0 => 0.68f, 1 => 0.9f, _ => 0.84f };
378
float verticalViewFraction = layer switch { 0 => 0.78f, 1 => 0.9f, _ => 0.86f };
379
507
float opacity = layer switch
380
508
{
381
509
0 => MathHelper.Lerp(0.88f, 1f, mastery) * reveal,
@@ -383,12 +511,8 @@ internal class DeathDomainVisualSystem : ModSystem
383
511
_ => MathHelper.Lerp(0.78f, 0.96f, mastery) * reveal
384
512
};
385
513
Texture2D texture = DeathDomainBackdropTextureSystem.GetLayer(layer);
386
float viewWidth = texture.Width * horizontalViewFraction;
387
float viewHeight = texture.Height * verticalViewFraction;
388
float sourceOffsetX = PositiveModulo(worldCenter.X * parallax, texture.Width);
389
float worldHeight = Math.Max(1f, Main.maxTilesY * 16f);
390
float worldDepth = MathHelper.Clamp(worldCenter.Y / worldHeight, 0f, 1f);
391
float sourceOffsetY = worldDepth * Math.Max(0f, texture.Height - viewHeight);
514
GetBackdropSource(layer, texture, worldCenter, horizontalScale, verticalScale,
515
out float sourceOffsetX, out float sourceOffsetY, out float viewWidth, out float viewHeight);
392
516
393
517
DrawBackdropBand(
394
518
batch,
@@ -404,6 +528,32 @@ internal class DeathDomainVisualSystem : ModSystem
404
528
}
405
529
}
406
530
531
private static void GetBackdropSource(
532
int layer,
533
Texture2D texture,
534
Vector2 worldCenter,
535
float horizontalScale,
536
float verticalScale,
537
out float sourceOffsetX,
538
out float sourceOffsetY,
539
out float viewWidth,
540
out float viewHeight)
541
{
542
float referenceViewWidth = 1024f * (layer switch { 0 => 0.68f, 1 => 0.9f, _ => 0.84f });
543
float referenceViewHeight = 512f * (layer switch { 0 => 0.78f, 1 => 0.9f, _ => 0.86f });
544
viewWidth = Math.Min(texture.Width, referenceViewWidth * horizontalScale);
545
viewHeight = Math.Min(texture.Height, referenceViewHeight * verticalScale);
546
547
float worldWidth = Math.Max(1f, Main.maxTilesX * 16f);
548
float worldHeight = Math.Max(1f, Main.maxTilesY * 16f);
549
float worldX = MathHelper.Clamp(worldCenter.X / worldWidth, 0f, 1f);
550
float worldY = MathHelper.Clamp(worldCenter.Y / worldHeight, 0f, 1f);
551
float travelFactor = layer switch { 0 => 0.34f, 1 => 0.66f, _ => 1f };
552
float horizontalTravel = Math.Max(0f, texture.Width - viewWidth) * travelFactor;
553
sourceOffsetX = (texture.Width - viewWidth - horizontalTravel) * 0.5f + horizontalTravel * worldX;
554
sourceOffsetY = worldY * Math.Max(0f, texture.Height - viewHeight);
555
}
556
407
557
private static void DrawFilledNoiseDisc(
408
558
SpriteBatch batch,
409
559
Texture2D pixel,
@@ -160,18 +160,7 @@ public class MyPlayer : ModPlayer
160
160
}
161
161
162
162
deathDomainSlashSoundCooldown = 4;
163
SoundEngine.PlaySound(SoundID.DD2_SonicBoomBladeSlash with
164
{
165
Volume = 0.58f + mastery * 0.12f + (requiem ? 0.08f : 0f),
166
Pitch = 0.20f + mastery * 0.08f,
167
PitchVariance = 0.045f
168
}, worldPosition);
169
SoundEngine.PlaySound(SoundID.Item1 with
170
{
171
Volume = 0.30f + mastery * 0.08f,
172
Pitch = 0.52f,
173
PitchVariance = 0.035f
174
}, worldPosition);
163
SoundEngine.PlaySound(SoundID.Item71, worldPosition);
175
164
}
176
165
177
166
internal void RecordDeathWingTrail(Vector2 upperTip, Vector2 lowerTip, float mastery)
@@ -0,0 +1,131 @@
1
using DeathMod.Items;
2
using Microsoft.Xna.Framework;
3
using Microsoft.Xna.Framework.Graphics;
4
using System;
5
using System.Collections.Generic;
6
using Terraria;
7
using Terraria.ModLoader;
8
9
namespace DeathMod.Common;
10
11
[Autoload(Side = ModSide.Client)]
12
internal sealed class SickleTrailPrimitiveSystem : ModSystem
13
{
14
private const int CurveSubdivisions = 4;
15
private static BasicEffect? trailEffect;
16
17
internal static void DrawTrail(IReadOnlyList<Vector2> controlPoints, NormalSickle sickle, bool alternateAttack)
18
{
19
if (Main.dedServ || controlPoints.Count < 2)
20
return;
21
22
List<Vector2> curve = BuildSmoothCurve(controlPoints);
23
if (curve.Count < 2)
24
return;
25
26
BasicEffect effect = trailEffect ??= new BasicEffect(Main.instance.GraphicsDevice)
27
{
28
VertexColorEnabled = true,
29
TextureEnabled = false
30
};
31
VertexPositionColor[] outer = BuildStrip(curve, sickle, alternateAttack, core: false);
32
VertexPositionColor[] core = BuildStrip(curve, sickle, alternateAttack, core: true);
33
if (outer.Length < 4 || core.Length < 4)
34
return;
35
36
GraphicsDevice graphics = Main.instance.GraphicsDevice;
37
Main.spriteBatch.End();
38
graphics.BlendState = BlendState.AlphaBlend;
39
graphics.DepthStencilState = DepthStencilState.None;
40
graphics.RasterizerState = RasterizerState.CullNone;
41
effect.World = Main.GameViewMatrix.TransformationMatrix;
42
effect.View = Matrix.Identity;
43
effect.Projection = Matrix.CreateOrthographicOffCenter(0f, Main.screenWidth, Main.screenHeight, 0f, 0f, 1f);
44
45
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
46
{
47
pass.Apply();
48
graphics.DrawUserPrimitives(PrimitiveType.TriangleStrip, outer, 0, outer.Length - 2);
49
graphics.DrawUserPrimitives(PrimitiveType.TriangleStrip, core, 0, core.Length - 2);
50
}
51
52
Main.spriteBatch.Begin(
53
SpriteSortMode.Deferred,
54
BlendState.AlphaBlend,
55
SamplerState.PointClamp,
56
DepthStencilState.None,
57
RasterizerState.CullNone,
58
null,
59
Main.GameViewMatrix.TransformationMatrix);
60
}
61
62
public override void Unload()
63
{
64
BasicEffect? oldEffect = trailEffect;
65
trailEffect = null;
66
if (oldEffect is not null && !Main.dedServ)
67
Main.QueueMainThreadAction(oldEffect.Dispose);
68
}
69
70
private static List<Vector2> BuildSmoothCurve(IReadOnlyList<Vector2> controlPoints)
71
{
72
List<Vector2> result = new((controlPoints.Count - 1) * CurveSubdivisions + 1)
73
{
74
controlPoints[0]
75
};
76
for (int segment = 0; segment < controlPoints.Count - 1; segment++)
77
{
78
Vector2 p0 = controlPoints[Math.Max(0, segment - 1)];
79
Vector2 p1 = controlPoints[segment];
80
Vector2 p2 = controlPoints[segment + 1];
81
Vector2 p3 = controlPoints[Math.Min(controlPoints.Count - 1, segment + 2)];
82
for (int subdivision = 1; subdivision <= CurveSubdivisions; subdivision++)
83
{
84
float amount = subdivision / (float)CurveSubdivisions;
85
Vector2 point = Vector2.CatmullRom(p0, p1, p2, p3, amount);
86
if (Vector2.DistanceSquared(result[^1], point) > 0.04f)
87
result.Add(point);
88
}
89
}
90
return result;
91
}
92
93
private static VertexPositionColor[] BuildStrip(
94
IReadOnlyList<Vector2> points,
95
NormalSickle sickle,
96
bool alternateAttack,
97
bool core)
98
{
99
VertexPositionColor[] vertices = new VertexPositionColor[points.Count * 2];
100
float attackScale = alternateAttack ? 1.25f : 1f;
101
for (int index = 0; index < points.Count; index++)
102
{
103
float progress = index / (points.Count - 1f);
104
float strength = progress * progress * (3f - 2f * progress);
105
Vector2 previous = points[Math.Max(0, index - 1)];
106
Vector2 next = points[Math.Min(points.Count - 1, index + 1)];
107
Vector2 normal = (next - previous).SafeNormalize(Vector2.UnitX).RotatedBy(MathHelper.PiOver2);
108
109
float width = sickle.TrailWidth * attackScale * MathHelper.Lerp(0.08f, 1f, strength);
110
if (sickle.SwingStyle == SickleSwingStyle.Rising)
111
width *= 0.8f + strength * 0.65f;
112
else if (sickle.SwingStyle == SickleSwingStyle.VoidOrbit)
113
width *= 1f + (float)Math.Sin(progress * MathHelper.Pi * 5f + Main.GlobalTimeWrappedHourly * 8f) * 0.08f;
114
if (core)
115
width *= 0.42f;
116
else
117
width += 4f;
118
119
float opacity = MathHelper.Lerp(0f, core ? 0.68f : 0.38f, (float)Math.Pow(strength, 0.72f));
120
Color color = core
121
? Color.Lerp(sickle.SickleSecondaryColor, Color.White, strength * 0.18f)
122
: Color.Lerp(sickle.SickleColor, sickle.SickleSecondaryColor, strength * 0.22f);
123
color *= opacity;
124
Vector2 screenPoint = points[index] - Main.screenPosition;
125
Vector2 halfWidth = normal * Math.Max(0.5f, width * 0.5f);
126
vertices[index * 2] = new VertexPositionColor(new Vector3(screenPoint - halfWidth, 0f), color);
127
vertices[index * 2 + 1] = new VertexPositionColor(new Vector3(screenPoint + halfWidth, 0f), color);
128
}
129
return vertices;
130
}
131
}
@@ -154,7 +154,7 @@ public class DeathWings : ModItem, IDeathAltarUpgradeable
154
154
DeathAltarUpgradeType.WingVerticalPower => LevelPrice(VerticalPowerLevel, 45),
155
155
DeathAltarUpgradeType.WingInfiniteFlight => InfiniteFlightUnlocked || !AllFlightStatsMaxed
156
156
? DeathAltarPrice.Unavailable
157
: DeathAltarPrice.Essence(25),
157
: DeathAltarPrice.Essence(HalvedCost(25)),
158
158
_ => DeathAltarPrice.Unavailable
159
159
};
160
160
}
@@ -284,10 +284,12 @@ public class DeathWings : ModItem, IDeathAltarUpgradeable
284
284
if (level >= MaxWingLevel)
285
285
return DeathAltarPrice.Unavailable;
286
286
return level < 6
287
? DeathAltarPrice.Souls(level * soulMultiplier)
288
: DeathAltarPrice.Essence(level);
287
? DeathAltarPrice.Souls(HalvedCost(level * soulMultiplier))
288
: DeathAltarPrice.Essence(HalvedCost(level));
289
289
}
290
290
291
private static int HalvedCost(int cost) => Math.Max(1, (cost + 1) / 2);
292
291
293
private static float LevelProgress(int level)
292
294
{
293
295
return MathHelper.Clamp((level - 1) / 9f, 0f, 1f);
@@ -121,7 +121,6 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
121
121
public virtual int MaximumChargeFrames => 55 + SickleTier * 8;
122
122
public virtual int SickleReach => 74 + SickleTier * 10;
123
123
public virtual float SickleCollisionWidth => 18f + SickleTier * 3f;
124
public virtual int ChargedProjectileBonus => SickleTier >= 2 ? 2 : 1;
125
124
public virtual Color SickleColor => new(80, 205, 225);
126
125
public virtual Color SickleSecondaryColor => new(210, 250, 255);
127
126
public virtual int SickleDustType => DustID.AncientLight;
@@ -470,7 +469,15 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
470
469
if (!SupportsProjectileCount || AttackProjectileType <= ProjectileID.None)
471
470
return;
472
471
473
int count = Math.Clamp(ProjectileCount + (heavySlash ? ChargedProjectileBonus : 0), 1, MaxProjectileCount + ChargedProjectileBonus);
472
int count = ProjectileCount;
473
if (heavySlash)
474
{
475
float projectileMultiplier = SupportsCharge
476
? MathHelper.Lerp(1f, 2f, MathHelper.Clamp(charge, 0f, 1f))
477
: 1.5f;
478
count = Math.Max(1, (int)Math.Ceiling(ProjectileCount * projectileMultiplier));
479
}
480
count = Math.Clamp(count, 1, MaxProjectileCount * 2);
474
481
if (heavySlash && AlternateAttackStyle == SickleAlternateAttackStyle.BoneBarrage)
475
482
count = Math.Max(3, count);
476
483
else if (heavySlash && AlternateAttackStyle == SickleAlternateAttackStyle.VoidRitual)
@@ -16,7 +16,6 @@ public class VoidSickle : NormalSickle
16
16
public override int AlternateNextSickleType => ItemID.None;
17
17
public override SickleSwingStyle SwingStyle => SickleSwingStyle.VoidOrbit;
18
18
public override SickleAlternateAttackStyle AlternateAttackStyle => SickleAlternateAttackStyle.VoidRitual;
19
public override int ChargedProjectileBonus => 1;
20
19
public override Color SickleColor => new(190, 55, 255);
21
20
public override Color SickleSecondaryColor => new(255, 85, 235);
22
21
public override int SickleDustType => DustID.Shadowflame;
@@ -3,6 +3,7 @@ using DeathMod.Items;
3
3
using Microsoft.Xna.Framework;
4
4
using Microsoft.Xna.Framework.Graphics;
5
5
using System;
6
using System.Collections.Generic;
6
7
using System.IO;
7
8
using Terraria;
8
9
using Terraria.Audio;
@@ -539,67 +540,20 @@ public class SickleSwingProjectile : ModProjectile
539
540
540
541
private void DrawSlashTrail(NormalSickle sickle)
541
542
{
542
Texture2D pixel = TextureAssets.MagicPixel.Value;
543
543
int segmentCount = Math.Min(HistoryLength - 1, 7 + sickle.SickleTier * 2);
544
float empoweredScale = IsAlternateAttack ? 1.25f : 1f;
545
546
for (int index = segmentCount - 1; index >= 0; index--)
544
List<Vector2> controlPoints = new(segmentCount + 1);
545
for (int index = segmentCount; index >= 0; index--)
547
546
{
548
if (gripHistory[index] == Vector2.Zero || gripHistory[index + 1] == Vector2.Zero)
549
continue;
550
if (sickle.SwingStyle is SickleSwingStyle.Overhead or SickleSwingStyle.CrossCut && index % 3 == 2)
551
continue;
552
553
Vector2 currentTip = GetBladeTip(sickle, gripHistory[index], angleHistory[index]);
554
Vector2 oldTip = GetBladeTip(sickle, gripHistory[index + 1], angleHistory[index + 1]);
555
Vector2 difference = oldTip - currentTip;
556
float length = difference.Length();
557
float maximumSegmentLength = 28f + sickle.SickleTier * 4f;
558
if (length < 0.5f || length > maximumSegmentLength)
547
if (gripHistory[index] == Vector2.Zero)
559
548
continue;
560
561
float strength = 1f - index / (float)segmentCount;
562
float width = sickle.TrailWidth * strength * empoweredScale;
563
if (sickle.SwingStyle == SickleSwingStyle.Rising)
564
width *= 0.8f + strength * 0.65f;
565
if (sickle.SwingStyle == SickleSwingStyle.VoidOrbit)
566
width *= 1f + (float)Math.Sin(index * 1.7f + Main.GlobalTimeWrappedHourly * 8f) * 0.18f;
567
568
DrawTrailSegment(pixel, currentTip, difference, sickle.SickleColor with { A = 0 }, width + 4f, strength * 0.34f);
569
DrawTrailSegment(pixel, currentTip, difference, sickle.SickleSecondaryColor with { A = 0 }, width * 0.42f, strength * 0.62f);
570
571
if (sickle.SwingStyle == SickleSwingStyle.Circular)
572
{
573
Vector2 innerCurrent = Vector2.Lerp(gripHistory[index], currentTip, 0.82f);
574
Vector2 innerOld = Vector2.Lerp(gripHistory[index + 1], oldTip, 0.82f);
575
DrawTrailSegment(pixel, innerCurrent, innerOld - innerCurrent, sickle.SickleSecondaryColor with { A = 0 }, width * 0.32f, strength * 0.5f);
576
}
577
else if (sickle.SwingStyle == SickleSwingStyle.SoulOrbit)
578
{
579
float wave = (float)Math.Sin(index * 1.4f + Main.GlobalTimeWrappedHourly * 7f) * 7f;
580
Vector2 normal = difference.SafeNormalize(Vector2.UnitX).RotatedBy(MathHelper.PiOver2) * wave;
581
DrawTrailSegment(pixel, currentTip + normal, difference, sickle.SickleSecondaryColor with { A = 0 }, width * 0.28f, strength * 0.52f);
582
}
583
else if (sickle.SwingStyle == SickleSwingStyle.VoidOrbit)
584
{
585
Vector2 midpoint = currentTip + difference * 0.5f;
586
float moteSize = 2.5f + strength * 4f;
587
Main.EntitySpriteDraw(pixel, midpoint - Main.screenPosition, null, sickle.SickleSecondaryColor with { A = 0 },
588
MathHelper.PiOver4, pixel.Size() * 0.5f,
589
new Vector2(moteSize / pixel.Width, moteSize / pixel.Height), SpriteEffects.None);
590
}
549
Vector2 tip = GetBladeTip(sickle, gripHistory[index], angleHistory[index]);
550
if (controlPoints.Count > 0 && Vector2.DistanceSquared(controlPoints[^1], tip) > 120f * 120f)
551
controlPoints.Clear();
552
if (controlPoints.Count == 0 || Vector2.DistanceSquared(controlPoints[^1], tip) > 0.25f)
553
controlPoints.Add(tip);
591
554
}
592
}
593
594
private static void DrawTrailSegment(Texture2D pixel, Vector2 start, Vector2 difference, Color color, float width, float opacity)
595
{
596
float length = difference.Length();
597
if (length <= 0.5f)
598
return;
599
555
600
Main.EntitySpriteDraw(pixel, start - Main.screenPosition, null, color * opacity,
601
difference.ToRotation(), new Vector2(0f, pixel.Height * 0.5f),
602
new Vector2(length / pixel.Width, Math.Max(1f, width) / pixel.Height), SpriteEffects.None);
556
SickleTrailPrimitiveSystem.DrawTrail(controlPoints, sickle, IsAlternateAttack);
603
557
}
604
558
605
559
private static void DrawWeapon(Texture2D texture, NormalSickle sickle, Vector2 position, float angle, bool flipped, Color color, float opacity, float scale)