返回提交历史
Modified
Common/MyGlobalNPC.cs
+52
-7
Modified
Common/MyGlobalProjectile.cs
+21
-3
Modified
Common/SickleUpgradeService.cs
+1
-0
Modified
DeathMod.cs
+177
-1
Modified
Items/NormalSickle.cs
+14
-0
Modified
Projectiles/LifeStealWispProjectile.cs
+38
-16
Modified
Projectiles/SickleSwingProjectile.cs
+9
-4
XFEstudio/DeathMod
fix: synchronize reaper combat and altar upgrades
b5fabf7
代码差异
7 个文件
+312
-31
@@ -23,13 +23,31 @@ public class MyGlobalNPC : GlobalNPC
23
23
private readonly int[] fatedStackTimers = new int[AbsoluteMaximumFatedStacks];
24
24
private int lastSicklePlayer = -1;
25
25
private int fatedSecondTimer;
26
private bool deathMarked;
26
27
27
28
public int FatedStackCount { get; private set; }
28
29
30
public override void SetDefaults(NPC npc)
31
{
32
Array.Clear(sickleParticipants);
33
Array.Clear(fatedStackTimers);
34
lastSicklePlayer = -1;
35
fatedSecondTimer = 0;
36
deathMarked = false;
37
FatedStackCount = 0;
38
}
39
29
40
public override void OnHitByItem(NPC npc, Player player, Item item, NPC.HitInfo hit, int damageDone)
30
41
{
31
42
if (item.ModItem is NormalSickle or LegacyDeath)
32
43
RegisterSickleHit(npc, player.whoAmI);
44
45
if (Main.netMode == NetmodeID.MultiplayerClient
46
&& player.whoAmI == Main.myPlayer
47
&& item.ModItem is LegacyDeath)
48
{
49
DeathMod.SendSickleItemHit(npc);
50
}
33
51
}
34
52
35
53
public override void OnHitByProjectile(NPC npc, Projectile projectile, NPC.HitInfo hit, int damageDone)
@@ -48,7 +66,7 @@ public class MyGlobalNPC : GlobalNPC
48
66
49
67
public override void PostDraw(NPC npc, SpriteBatch spriteBatch, Vector2 screenPos, Color drawColor)
50
68
{
51
if (!npc.HasBuff(ModContent.BuffType<DeathMarkBuff>()))
69
if (!deathMarked)
52
70
return;
53
71
54
72
Texture2D markTexture = TextureAssets.Buff[ModContent.BuffType<DeathMarkBuff>()].Value;
@@ -74,11 +92,13 @@ public class MyGlobalNPC : GlobalNPC
74
92
75
93
public override void SendExtraAI(NPC npc, BitWriter bitWriter, BinaryWriter binaryWriter)
76
94
{
95
bitWriter.WriteBit(deathMarked);
77
96
binaryWriter.Write((byte)FatedStackCount);
78
97
}
79
98
80
99
public override void ReceiveExtraAI(NPC npc, BitReader bitReader, BinaryReader binaryReader)
81
100
{
101
deathMarked = bitReader.ReadBit();
82
102
FatedStackCount = Math.Clamp((int)binaryReader.ReadByte(), 0, AbsoluteMaximumFatedStacks);
83
103
}
84
104
@@ -107,13 +127,16 @@ public class MyGlobalNPC : GlobalNPC
107
127
Main.player[lastSicklePlayer].GetModPlayer<MyPlayer>().AddSouls(1);
108
128
}
109
129
110
private void RegisterSickleHit(NPC npc, int playerIndex)
130
internal void RegisterSickleHit(NPC npc, int playerIndex, bool applyDeathMark = true)
111
131
{
112
if (playerIndex < 0 || playerIndex >= Main.maxPlayers || npc.friendly)
132
if (Main.netMode == NetmodeID.MultiplayerClient
133
|| playerIndex < 0
134
|| playerIndex >= Main.maxPlayers
135
|| npc.friendly)
113
136
return;
114
137
115
if (Main.netMode != NetmodeID.MultiplayerClient)
116
npc.AddBuff(ModContent.BuffType<DeathMarkBuff>(), DeathMarkDuration);
138
if (applyDeathMark)
139
MarkForReaping(npc);
117
140
118
141
sickleParticipants[playerIndex] = true;
119
142
lastSicklePlayer = playerIndex;
@@ -145,6 +168,28 @@ public class MyGlobalNPC : GlobalNPC
145
168
npc.netUpdate = true;
146
169
}
147
170
171
internal void MarkForReaping(NPC npc)
172
{
173
bool newlyMarked = !deathMarked;
174
deathMarked = true;
175
npc.AddBuff(ModContent.BuffType<DeathMarkBuff>(), DeathMarkDuration);
176
SyncBuffState(npc);
177
if (newlyMarked)
178
DeathMod.BroadcastDeathMark(npc, marked: true);
179
}
180
181
internal void ReceiveDeathMarkState(bool marked)
182
{
183
deathMarked = marked;
184
}
185
186
internal static void SyncBuffState(NPC npc)
187
{
188
npc.netUpdate = true;
189
if (Main.netMode == NetmodeID.Server)
190
NetMessage.SendData(MessageID.NPCBuffs, -1, -1, null, npc.whoAmI);
191
}
192
148
193
private void UpdateFatedState(NPC npc)
149
194
{
150
195
if (Main.netMode == NetmodeID.MultiplayerClient || FatedStackCount <= 0)
@@ -196,7 +241,7 @@ public class MyGlobalNPC : GlobalNPC
196
241
if (Main.netMode == NetmodeID.Server || !npc.active)
197
242
return;
198
243
199
if (npc.HasBuff(ModContent.BuffType<DeathMarkBuff>()) && Main.rand.NextBool(4))
244
if (deathMarked && Main.rand.NextBool(4))
200
245
{
201
246
float angle = Main.GlobalTimeWrappedHourly * 3.1f + npc.whoAmI * 0.73f + Main.rand.NextFloat(-0.35f, 0.35f);
202
247
Vector2 orbit = new Vector2(Math.Max(12f, npc.width * 0.58f), Math.Max(9f, npc.height * 0.36f));
@@ -205,7 +250,7 @@ public class MyGlobalNPC : GlobalNPC
205
250
markDust.noGravity = true;
206
251
}
207
252
208
if (FatedStackCount <= 0 || !npc.HasBuff(ModContent.BuffType<FatedBuff>()))
253
if (FatedStackCount <= 0)
209
254
return;
210
255
211
256
int particleCount = Main.rand.NextBool(2) ? Math.Min(2, FatedStackCount) : 1;
@@ -103,7 +103,23 @@ public class MyGlobalProjectile : GlobalProjectile
103
103
104
104
public override void OnHitNPC(Projectile projectile, NPC target, NPC.HitInfo hit, int damageDone)
105
105
{
106
if (!IsSickleProjectile || projectile.owner < 0 || projectile.owner >= Main.maxPlayers)
106
if ((!IsSickleProjectile && projectile.ModProjectile is not SickleSwingProjectile)
107
|| projectile.owner < 0
108
|| projectile.owner >= Main.maxPlayers)
109
return;
110
111
if (Main.netMode == NetmodeID.MultiplayerClient)
112
{
113
if (projectile.owner != Main.myPlayer)
114
return;
115
116
Main.player[projectile.owner].GetModPlayer<MyPlayer>().TryLifeSteal(damageDone, LifeStealLevel);
117
LifeStealVisuals.Spawn(target.Center, projectile.owner, LifeStealLevel);
118
DeathMod.SendSickleHit(projectile, target);
119
return;
120
}
121
122
if (Main.netMode == NetmodeID.Server)
107
123
return;
108
124
109
125
Main.player[projectile.owner].GetModPlayer<MyPlayer>().TryLifeSteal(damageDone, LifeStealLevel);
@@ -116,15 +132,17 @@ public class MyGlobalProjectile : GlobalProjectile
116
132
if (Main.netMode == NetmodeID.MultiplayerClient || target.friendly || target.lifeMax <= 5)
117
133
return;
118
134
119
target.AddBuff(ModContent.BuffType<Buffs.DeathMarkBuff>(), MyGlobalNPC.DeathMarkDuration);
135
target.GetGlobalNPC<MyGlobalNPC>().MarkForReaping(target);
120
136
NPC statusTarget = target.realLife >= 0 && target.realLife < Main.maxNPCs && Main.npc[target.realLife].active
121
137
? Main.npc[target.realLife]
122
138
: target;
123
139
if (statusTarget.whoAmI != target.whoAmI)
124
statusTarget.AddBuff(ModContent.BuffType<Buffs.DeathMarkBuff>(), MyGlobalNPC.DeathMarkDuration);
140
statusTarget.GetGlobalNPC<MyGlobalNPC>().MarkForReaping(statusTarget);
125
141
if (debuffType > 0 && debuffDuration > 0)
126
142
statusTarget.AddBuff(debuffType, debuffDuration);
127
143
if (fatedStacks > 0 && fatedMaximumStacks > 0 && fatedDurationFrames > 0)
128
144
statusTarget.GetGlobalNPC<MyGlobalNPC>().AddFatedStacks(statusTarget, fatedStacks, fatedMaximumStacks, fatedDurationFrames);
145
146
MyGlobalNPC.SyncBuffState(statusTarget);
129
147
}
130
148
}
@@ -122,5 +122,6 @@ internal static class DeathAltarUpgradeService
122
122
player.whoAmI,
123
123
PlayerItemSlotID.Inventory0 + slot,
124
124
player.inventory[slot].prefix);
125
DeathMod.SendInventorySlot(player, slot);
125
126
}
126
127
}
@@ -1,10 +1,14 @@
1
1
using DeathMod.Common;
2
using DeathMod.Items;
3
using DeathMod.Projectiles;
2
4
using Microsoft.Xna.Framework;
5
using System;
3
6
using System.IO;
4
7
using Terraria;
5
8
using Terraria.ID;
6
9
using Terraria.Localization;
7
10
using Terraria.ModLoader;
11
using Terraria.ModLoader.IO;
8
12
9
13
namespace DeathMod;
10
14
@@ -16,7 +20,10 @@ public class DeathMod : Mod
16
20
RequestExtractEssence,
17
21
RequestAbsorbEssence,
18
22
RequestAltarUpgrade,
19
OperationResult
23
OperationResult,
24
SickleHitRequest,
25
SyncInventorySlot,
26
SyncDeathMark
20
27
}
21
28
22
29
internal enum OperationResult : byte
@@ -81,6 +88,41 @@ public class DeathMod : Mod
81
88
ShowOperationResult(result);
82
89
break;
83
90
}
91
case MessageType.SickleHitRequest:
92
{
93
int projectileIdentity = reader.ReadInt32();
94
short npcIndex = reader.ReadInt16();
95
if (Main.netMode == NetmodeID.Server)
96
HandleSickleHitRequest(whoAmI, projectileIdentity, npcIndex);
97
break;
98
}
99
case MessageType.SyncInventorySlot:
100
{
101
if (Main.netMode != NetmodeID.MultiplayerClient)
102
break;
103
104
byte slot = reader.ReadByte();
105
Item item = ItemIO.Receive(reader, readStack: true, readFavorite: true);
106
if (slot < 58)
107
{
108
Main.LocalPlayer.inventory[slot] = item;
109
Recipe.FindRecipes(canDelayCheck: true);
110
}
111
break;
112
}
113
case MessageType.SyncDeathMark:
114
{
115
short npcIndex = reader.ReadInt16();
116
bool marked = reader.ReadBoolean();
117
if (Main.netMode == NetmodeID.MultiplayerClient
118
&& npcIndex >= 0
119
&& npcIndex < Main.maxNPCs
120
&& Main.npc[npcIndex].active)
121
{
122
Main.npc[npcIndex].GetGlobalNPC<MyGlobalNPC>().ReceiveDeathMarkState(marked);
123
}
124
break;
125
}
84
126
default:
85
127
Logger.Warn($"Unknown DeathMod packet: {messageType}");
86
128
break;
@@ -104,6 +146,140 @@ public class DeathMod : Mod
104
146
packet.Send(player.whoAmI);
105
147
}
106
148
149
internal static void SendInventorySlot(Player player, int slot)
150
{
151
if (Main.netMode != NetmodeID.Server || slot < 0 || slot >= 58)
152
return;
153
154
ModPacket packet = ModContent.GetInstance<DeathMod>().GetPacket();
155
packet.Write((byte)MessageType.SyncInventorySlot);
156
packet.Write((byte)slot);
157
ItemIO.Send(player.inventory[slot], packet, writeStack: true, writeFavorite: true);
158
packet.Send(player.whoAmI);
159
}
160
161
internal static void BroadcastDeathMark(NPC npc, bool marked)
162
{
163
if (Main.netMode != NetmodeID.Server || npc.whoAmI < 0 || npc.whoAmI >= Main.maxNPCs)
164
return;
165
166
ModPacket packet = ModContent.GetInstance<DeathMod>().GetPacket();
167
packet.Write((byte)MessageType.SyncDeathMark);
168
packet.Write((short)npc.whoAmI);
169
packet.Write(marked);
170
packet.Send();
171
}
172
173
internal static void SendSickleHit(Projectile projectile, NPC target)
174
{
175
if (Main.netMode != NetmodeID.MultiplayerClient || projectile.owner != Main.myPlayer)
176
return;
177
178
SendSickleHit(projectile.identity, target);
179
}
180
181
internal static void SendSickleItemHit(NPC target)
182
{
183
if (Main.netMode != NetmodeID.MultiplayerClient)
184
return;
185
186
SendSickleHit(-1, target);
187
}
188
189
private static void SendSickleHit(int projectileIdentity, NPC target)
190
{
191
if (!target.active || target.whoAmI < 0 || target.whoAmI >= Main.maxNPCs)
192
return;
193
194
ModPacket packet = ModContent.GetInstance<DeathMod>().GetPacket();
195
packet.Write((byte)MessageType.SickleHitRequest);
196
packet.Write(projectileIdentity);
197
packet.Write((short)target.whoAmI);
198
packet.Send();
199
}
200
201
private static void HandleSickleHitRequest(int playerIndex, int projectileIdentity, int npcIndex)
202
{
203
if (playerIndex < 0 || playerIndex >= Main.maxPlayers || npcIndex < 0 || npcIndex >= Main.maxNPCs)
204
return;
205
206
Player player = Main.player[playerIndex];
207
NPC target = Main.npc[npcIndex];
208
if (!player.active || player.dead || !target.active || target.friendly || target.lifeMax <= 5)
209
return;
210
211
Projectile? projectile = projectileIdentity >= 0
212
? FindOwnedProjectile(playerIndex, projectileIdentity)
213
: null;
214
MyGlobalProjectile? projectileData = projectile?.GetGlobalProjectile<MyGlobalProjectile>();
215
NormalSickle? heldSickle = player.HeldItem.ModItem as NormalSickle;
216
bool holdingSickle = player.HeldItem.ModItem is NormalSickle or LegacyDeath;
217
bool validProjectile = projectileData is { IsSickleProjectile: true }
218
|| projectile?.ModProjectile is SickleSwingProjectile
219
|| projectileIdentity >= 0 && holdingSickle;
220
bool validItemHit = projectileIdentity < 0 && holdingSickle;
221
if (!validProjectile && !validItemHit)
222
return;
223
224
int debuffType;
225
int debuffDuration;
226
int fatedStacks;
227
int fatedMaximumStacks;
228
int fatedDurationFrames;
229
if (projectileData is { IsSickleProjectile: true })
230
{
231
debuffType = projectileData.OnHitDebuffType;
232
debuffDuration = projectileData.OnHitDebuffDuration;
233
fatedStacks = projectileData.FatedStacksPerHit;
234
fatedMaximumStacks = projectileData.FatedMaximumStacks;
235
fatedDurationFrames = projectileData.FatedDurationFrames;
236
}
237
else if (heldSickle is not null)
238
{
239
debuffType = heldSickle.OnHitDebuffType;
240
debuffDuration = heldSickle.OnHitDebuffDuration;
241
fatedStacks = heldSickle.FatedStacksPerHit;
242
fatedMaximumStacks = heldSickle.FatedMaximumStacks;
243
fatedDurationFrames = heldSickle.FatedDurationFrames;
244
}
245
else
246
{
247
debuffType = 0;
248
debuffDuration = 0;
249
fatedStacks = 0;
250
fatedMaximumStacks = 0;
251
fatedDurationFrames = 0;
252
}
253
254
target.GetGlobalNPC<MyGlobalNPC>().RegisterSickleHit(target, playerIndex, applyDeathMark: false);
255
MyGlobalProjectile.ApplyStatusEffects(
256
target,
257
debuffType,
258
debuffDuration,
259
fatedStacks,
260
fatedMaximumStacks,
261
fatedDurationFrames);
262
263
if (projectile?.ModProjectile is SickleSwingProjectile
264
&& projectile.ai[1] >= 1f
265
&& heldSickle?.AlternateAttackStyle == SickleAlternateAttackStyle.HarvestUppercut)
266
{
267
SickleSwingProjectile.ApplyHarvestUppercut(target, player.direction, projectile.knockBack);
268
}
269
}
270
271
private static Projectile? FindOwnedProjectile(int playerIndex, int identity)
272
{
273
for (int index = 0; index < Main.maxProjectiles; index++)
274
{
275
Projectile projectile = Main.projectile[index];
276
if (projectile.active && projectile.owner == playerIndex && projectile.identity == identity)
277
return projectile;
278
}
279
280
return null;
281
}
282
107
283
private static void ShowOperationResult(OperationResult result)
108
284
{
109
285
string key = $"Mods.DeathMod.Messages.{result}";
@@ -237,6 +237,20 @@ public class NormalSickle : ModItem, IDeathAltarUpgradeable
237
237
238
238
public override void OnHitNPC(Player player, NPC target, NPC.HitInfo hit, int damageDone)
239
239
{
240
if (Main.netMode == NetmodeID.MultiplayerClient)
241
{
242
if (player.whoAmI != Main.myPlayer)
243
return;
244
245
player.GetModPlayer<MyPlayer>().TryLifeSteal(damageDone, LifeStealLevel);
246
LifeStealVisuals.Spawn(target.Center, player.whoAmI, LifeStealLevel);
247
DeathMod.SendSickleItemHit(target);
248
return;
249
}
250
251
if (Main.netMode == NetmodeID.Server)
252
return;
253
240
254
player.GetModPlayer<MyPlayer>().TryLifeSteal(damageDone, LifeStealLevel);
241
255
LifeStealVisuals.Spawn(target.Center, player.whoAmI, LifeStealLevel);
242
256
MyGlobalProjectile.ApplyStatusEffects(target, OnHitDebuffType, OnHitDebuffDuration, FatedStacksPerHit, FatedMaximumStacks, FatedDurationFrames);
@@ -34,11 +34,13 @@ internal static class LifeStealVisuals
34
34
35
35
public class LifeStealWispProjectile : ModProjectile
36
36
{
37
private const int TrailHistoryLength = 32;
38
37
39
private int LifeStealLevel => (int)Projectile.ai[0];
38
40
39
41
public override void SetStaticDefaults()
40
42
{
41
ProjectileID.Sets.TrailCacheLength[Type] = 12;
43
ProjectileID.Sets.TrailCacheLength[Type] = TrailHistoryLength;
42
44
ProjectileID.Sets.TrailingMode[Type] = 2;
43
45
}
44
46
@@ -119,41 +121,61 @@ public class LifeStealWispProjectile : ModProjectile
119
121
Vector2 origin = texture.Size() * 0.5f;
120
122
float rotation = Projectile.velocity.ToRotation() - MathHelper.PiOver2;
121
123
float baseScale = 0.34f + LifeStealLevel * 0.045f;
122
int trailLength = 2 + LifeStealLevel;
124
int trailPointCount = System.Math.Min(Projectile.oldPos.Length, 14 + LifeStealLevel * 3);
125
float levelRatio = MathHelper.Clamp(LifeStealLevel / 5f, 0f, 1f);
126
Color outerColor = Color.Lerp(new Color(125, 0, 28), new Color(245, 38, 155), levelRatio) with { A = 0 };
127
Color coreColor = Color.Lerp(new Color(235, 22, 48), new Color(255, 155, 220), levelRatio) with { A = 0 };
123
128
124
for (int index = trailLength; index >= 1; index--)
129
for (int index = trailPointCount - 1; index >= 0; index--)
125
130
{
126
131
Vector2 older = Projectile.oldPos[index] + Projectile.Size * 0.5f;
127
Vector2 newer = Projectile.oldPos[index - 1] + Projectile.Size * 0.5f;
128
if (Projectile.oldPos[index] == Vector2.Zero || Projectile.oldPos[index - 1] == Vector2.Zero)
132
Vector2 newer = index == 0
133
? Projectile.Center
134
: Projectile.oldPos[index - 1] + Projectile.Size * 0.5f;
135
if (Projectile.oldPos[index] == Vector2.Zero
136
|| index > 0 && Projectile.oldPos[index - 1] == Vector2.Zero)
129
137
continue;
130
138
131
139
Vector2 segment = newer - older;
132
140
float length = segment.Length();
133
if (length is < 0.5f or > 20f)
141
if (length is < 0.35f or > 40f)
134
142
continue;
135
143
136
float strength = 1f - index / (float)(trailLength + 1);
137
Color ribbonColor = Color.Lerp(new Color(170, 5, 35), new Color(255, 95, 185), LifeStealLevel / 5f) with { A = 0 };
138
Main.EntitySpriteDraw(pixel, older - Main.screenPosition, null, ribbonColor * strength * 0.5f,
139
segment.ToRotation(), new Vector2(0f, pixel.Height * 0.5f),
140
new Vector2(length / pixel.Width, (1.5f + LifeStealLevel * 0.42f) * strength / pixel.Height), SpriteEffects.None);
144
float strength = 1f - index / (float)trailPointCount;
145
float taper = (float)System.Math.Pow(strength, 0.72f);
146
float outerWidth = (2.25f + LifeStealLevel * 0.58f) * taper;
147
float coreWidth = (0.72f + LifeStealLevel * 0.2f) * taper;
148
DrawTrailSegment(pixel, older, segment, outerColor * strength * 0.34f, outerWidth);
149
DrawTrailSegment(pixel, older, segment, coreColor * strength * 0.82f, coreWidth);
141
150
}
142
151
143
for (int index = trailLength; index >= 1; index--)
152
int afterimageCount = System.Math.Min(trailPointCount, 5 + LifeStealLevel);
153
for (int index = afterimageCount - 1; index >= 1; index--)
144
154
{
145
155
if (Projectile.oldPos[index] == Vector2.Zero)
146
156
continue;
147
157
148
float strength = (trailLength - index + 1f) / (trailLength + 1f);
158
float strength = 1f - index / (float)afterimageCount;
149
159
Vector2 position = Projectile.oldPos[index] + Projectile.Size * 0.5f - Main.screenPosition;
150
Color trailColor = Color.Lerp(new Color(220, 20, 45), new Color(255, 100, 190), LifeStealLevel / 5f) with { A = 0 };
151
Main.EntitySpriteDraw(texture, position, null, trailColor * strength * 0.42f,
152
rotation, origin, baseScale * (0.65f + strength * 0.25f), SpriteEffects.None);
160
Main.EntitySpriteDraw(texture, position, null, coreColor * strength * 0.26f,
161
rotation, origin, baseScale * (0.58f + strength * 0.24f), SpriteEffects.None);
153
162
}
154
163
155
164
Main.EntitySpriteDraw(texture, Projectile.Center - Main.screenPosition, null, Color.White,
156
165
rotation, origin, baseScale, SpriteEffects.None);
157
166
return false;
158
167
}
168
169
private static void DrawTrailSegment(Texture2D pixel, Vector2 start, Vector2 segment, Color color, float width)
170
{
171
Main.EntitySpriteDraw(
172
pixel,
173
start - Main.screenPosition,
174
null,
175
color,
176
segment.ToRotation(),
177
new Vector2(0f, pixel.Height * 0.5f),
178
new Vector2(segment.Length() / pixel.Width, width / pixel.Height),
179
SpriteEffects.None);
180
}
159
181
}
@@ -350,7 +350,7 @@ public class SickleSwingProjectile : ModProjectile
350
350
SetArc(aimRotation, 2.35f, -1.15f, EaseOutSine(progress), player.direction, 0);
351
351
gripPosition += aimRotation.ToRotationVector2() * lift * 20f;
352
352
gripPosition.Y -= lift * 12f;
353
ApplyDash(player, sickle, 19.5f, 19, true);
353
ApplyDash(player, sickle, 9.75f, 19, true);
354
354
break;
355
355
}
356
356
case SickleAlternateAttackStyle.BoneBarrage:
@@ -383,15 +383,20 @@ public class SickleSwingProjectile : ModProjectile
383
383
384
384
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
385
385
{
386
if (!IsAlternateAttack || Main.netMode == NetmodeID.MultiplayerClient
386
if (!IsAlternateAttack || Main.netMode != NetmodeID.SinglePlayer
387
387
|| !TryGetSickle(out Player player, out NormalSickle sickle)
388
388
|| sickle.AlternateAttackStyle != SickleAlternateAttackStyle.HarvestUppercut)
389
389
return;
390
390
391
ApplyHarvestUppercut(target, player.direction, Projectile.knockBack);
392
}
393
394
internal static void ApplyHarvestUppercut(NPC target, int direction, float knockback)
395
{
391
396
float resistance = MathHelper.Clamp(target.knockBackResist, 0.15f, 1f);
392
float liftSpeed = (6.5f + Projectile.knockBack * 0.35f) * resistance;
397
float liftSpeed = (6.5f + knockback * 0.35f) * resistance;
393
398
target.velocity.Y = Math.Min(target.velocity.Y, -liftSpeed);
394
target.velocity.X += player.direction * (1.8f + Projectile.knockBack * 0.12f) * resistance;
399
target.velocity.X += direction * (1.8f + knockback * 0.12f) * resistance;
395
400
target.netUpdate = true;
396
401
}
397
402