using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SoulHarvest.Common;
using Terraria;
using Terraria.GameContent;
using Terraria.ID;
namespace SoulHarvest.Projectiles;
internal static class ReaperProjectileHelper
{
internal static void DamageOnDedicatedServer(Projectile projectile)
{
if (Main.netMode != NetmodeID.Server
|| projectile.owner < 0
|| projectile.owner >= Main.maxPlayers)
{
return;
}
// Projectile.Damage only runs friendly-NPC collision for Main.myPlayer.
// A dedicated server has no local player (255), even when it authored the
// projectile. Scope the standard collision pipeline to the real caster so
// all vanilla/tML modifiers, OnHit hooks, immunity and net sync still run.
int previousLocalPlayer = Main.myPlayer;
try
{
Main.myPlayer = projectile.owner;
projectile.Damage();
}
finally
{
Main.myPlayer = previousLocalPlayer;
}
}
internal static void SyncNewProjectile(Projectile projectile)
{
projectile.netUpdate = true;
if (Main.netMode == NetmodeID.Server
&& projectile.active
&& projectile.whoAmI >= 0
&& projectile.whoAmI < Main.maxProjectiles)
{
// NewProjectile can publish the base projectile before a ModProjectile
// has written its snapshot, geometry and damage metadata. Send one
// completed initial state immediately; short-lived slashes otherwise
// finish before their delayed netUpdate reaches clients.
NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null,
projectile.whoAmI);
}
}
public static NPC? FindTarget(Projectile projectile, float maximumDistance)
{
NPC? target = null;
foreach (NPC npc in Main.ActiveNPCs)
{
if (!ReaperTargeting.IsValidWeaponTarget(npc)
|| !ReaperTargeting.IsTrainingDummy(npc)
&& !npc.CanBeChasedBy(projectile))
continue;
float distance = Vector2.Distance(npc.Center, projectile.Center);
if (distance >= maximumDistance)
continue;
maximumDistance = distance;
target = npc;
}
return target;
}
public static bool DrawTrail(Projectile projectile, Color color, float rotationOffset = 0f, float scaleMultiplier = 1f, int copies = 8)
{
Texture2D texture = TextureAssets.Projectile[projectile.type].Value;
Vector2 origin = texture.Size() / 2f;
int count = System.Math.Min(copies, projectile.oldPos.Length);
for (int index = count - 1; index >= 0; index--)
{
if (projectile.oldPos[index] == Vector2.Zero)
continue;
float opacity = (count - index) / (float)(count + 1);
Vector2 drawPosition = projectile.oldPos[index] + projectile.Size / 2f - Main.screenPosition;
float echoScale = projectile.scale * scaleMultiplier * (0.82f + opacity * 0.18f);
Main.EntitySpriteDraw(texture, drawPosition, null,
(color with { A = 0 }) * opacity * 0.18f, projectile.oldRot[index] + rotationOffset, origin,
echoScale * 1.34f, SpriteEffects.None);
Main.EntitySpriteDraw(texture, drawPosition, null,
(color with { A = 0 }) * opacity * 0.48f, projectile.oldRot[index] + rotationOffset, origin,
echoScale, SpriteEffects.None);
}
Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null,
(color with { A = 0 }) * 0.42f, projectile.rotation + rotationOffset, origin,
projectile.scale * scaleMultiplier * 1.22f, SpriteEffects.None);
Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null, Color.White,
projectile.rotation + rotationOffset, origin, projectile.scale * scaleMultiplier, SpriteEffects.None);
return false;
}
}
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SoulHarvest.Common;
using Terraria;
using Terraria.GameContent;
using Terraria.ID;
namespace SoulHarvest.Projectiles;
internal static class ReaperProjectileHelper
{
internal static void DamageOnDedicatedServer(Projectile projectile)
{
if (Main.netMode != NetmodeID.Server
|| projectile.owner < 0
|| projectile.owner >= Main.maxPlayers)
{
return;
}
// Projectile.Damage only runs friendly-NPC collision for Main.myPlayer.
// A dedicated server has no local player (255), even when it authored the
// projectile. Scope the standard collision pipeline to the real caster so
// all vanilla/tML modifiers, OnHit hooks, immunity and net sync still run.
int previousLocalPlayer = Main.myPlayer;
try
{
Main.myPlayer = projectile.owner;
projectile.Damage();
}
finally
{
Main.myPlayer = previousLocalPlayer;
}
}
internal static void SyncNewProjectile(Projectile projectile)
{
projectile.netUpdate = true;
if (Main.netMode == NetmodeID.Server
&& projectile.active
&& projectile.whoAmI >= 0
&& projectile.whoAmI < Main.maxProjectiles)
{
// NewProjectile can publish the base projectile before a ModProjectile
// has written its snapshot, geometry and damage metadata. Send one
// completed initial state immediately; short-lived slashes otherwise
// finish before their delayed netUpdate reaches clients.
NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null,
projectile.whoAmI);
}
}
public static NPC? FindTarget(Projectile projectile, float maximumDistance)
{
NPC? target = null;
foreach (NPC npc in Main.ActiveNPCs)
{
if (!ReaperTargeting.IsValidWeaponTarget(npc)
|| !ReaperTargeting.IsTrainingDummy(npc)
&& !npc.CanBeChasedBy(projectile))
continue;
float distance = Vector2.Distance(npc.Center, projectile.Center);
if (distance >= maximumDistance)
continue;
maximumDistance = distance;
target = npc;
}
return target;
}
public static bool DrawTrail(Projectile projectile, Color color, float rotationOffset = 0f, float scaleMultiplier = 1f, int copies = 8)
{
Texture2D texture = TextureAssets.Projectile[projectile.type].Value;
Vector2 origin = texture.Size() / 2f;
int count = System.Math.Min(copies, projectile.oldPos.Length);
for (int index = count - 1; index >= 0; index--)
{
if (projectile.oldPos[index] == Vector2.Zero)
continue;
float opacity = (count - index) / (float)(count + 1);
Vector2 drawPosition = projectile.oldPos[index] + projectile.Size / 2f - Main.screenPosition;
float echoScale = projectile.scale * scaleMultiplier * (0.82f + opacity * 0.18f);
Main.EntitySpriteDraw(texture, drawPosition, null,
(color with { A = 0 }) * opacity * 0.18f, projectile.oldRot[index] + rotationOffset, origin,
echoScale * 1.34f, SpriteEffects.None);
Main.EntitySpriteDraw(texture, drawPosition, null,
(color with { A = 0 }) * opacity * 0.48f, projectile.oldRot[index] + rotationOffset, origin,
echoScale, SpriteEffects.None);
}
Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null,
(color with { A = 0 }) * 0.42f, projectile.rotation + rotationOffset, origin,
projectile.scale * scaleMultiplier * 1.22f, SpriteEffects.None);
Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null, Color.White,
projectile.rotation + rotationOffset, origin, projectile.scale * scaleMultiplier, SpriteEffects.None);
return false;
}
}