using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace SoulHarvest.Projectiles;
public class BloodCrescentProjectile : ModProjectile
{
private bool serverAuthorized;
private Vector2 authoritativeCenter;
private Vector2 authoritativeVelocity;
private readonly float[] authoritativeAI = new float[3];
internal void AuthorizeServerMotion()
{
if (Main.netMode == NetmodeID.MultiplayerClient)
return;
serverAuthorized = true;
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
for (int index = 0; index < authoritativeAI.Length; index++)
authoritativeAI[index] = float.IsFinite(Projectile.ai[index]) ? Projectile.ai[index] : 0f;
}
public override void SetStaticDefaults()
{
ProjectileID.Sets.TrailCacheLength[Type] = 12;
ProjectileID.Sets.TrailingMode[Type] = 2;
}
public override void SetDefaults()
{
Projectile.width = 34;
Projectile.height = 34;
Projectile.friendly = true;
Projectile.tileCollide = false;
Projectile.ignoreWater = true;
Projectile.penetrate = 4;
Projectile.timeLeft = 210;
Projectile.DamageType = DamageClass.Melee;
}
public override bool ShouldUpdatePosition() => false;
public override void AI()
{
if (Main.netMode == NetmodeID.Server)
{
if (!serverAuthorized)
{
Projectile.Kill();
return;
}
Projectile.Center = authoritativeCenter;
Projectile.velocity = authoritativeVelocity;
for (int index = 0; index < authoritativeAI.Length; index++)
Projectile.ai[index] = authoritativeAI[index];
}
Projectile.localAI[0]++;
float timer = Projectile.localAI[0];
if (timer >= 210f)
{
Projectile.Kill();
return;
}
Player owner = Main.player[Projectile.owner];
if (!owner.active || owner.dead)
{
Projectile.Kill();
return;
}
float outboundTime = Projectile.ai[0] > 0f ? 52f : 34f;
if (timer < outboundTime)
Projectile.velocity = Projectile.velocity.RotatedBy(0.008f * System.Math.Sign(Projectile.ai[2] == 0f ? 1f : Projectile.ai[2]));
else
{
Vector2 toOwner = owner.Center - Projectile.Center;
float returnSpeed = 13f + Projectile.ai[1] * 5f;
Projectile.velocity = Vector2.Lerp(Projectile.velocity, toOwner.SafeNormalize(Vector2.UnitY) * returnSpeed, 0.11f);
if (timer > outboundTime + 12f && toOwner.LengthSquared() < 24f * 24f)
Projectile.Kill();
}
Projectile.rotation += 0.34f * System.Math.Sign(Projectile.velocity.X);
if (Main.netMode != NetmodeID.Server)
{
Lighting.AddLight(Projectile.Center, new Vector3(0.55f, 0.03f, 0.08f));
if (Main.rand.NextBool(2))
{
Dust dust = Dust.NewDustPerfect(Projectile.Center, DustID.Blood, -Projectile.velocity * 0.1f, 70,
new Color(240, 35, 65), 0.85f + Projectile.ai[1] * 0.25f);
dust.noGravity = true;
}
}
if (!Projectile.active)
return;
Projectile.position += Projectile.velocity;
if (Main.netMode == NetmodeID.Server)
{
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
}
}
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
{
Projectile.velocity = Projectile.velocity.RotatedByRandom(0.35f) * 0.92f;
if (Main.netMode == NetmodeID.Server)
{
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
}
}
public override bool PreDraw(ref Color lightColor) => ReaperProjectileHelper.DrawTrail(Projectile, new Color(245, 25, 70), scaleMultiplier: 1f + Projectile.ai[1] * 0.18f, copies: 10);
}
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;
namespace SoulHarvest.Projectiles;
public class BloodCrescentProjectile : ModProjectile
{
private bool serverAuthorized;
private Vector2 authoritativeCenter;
private Vector2 authoritativeVelocity;
private readonly float[] authoritativeAI = new float[3];
internal void AuthorizeServerMotion()
{
if (Main.netMode == NetmodeID.MultiplayerClient)
return;
serverAuthorized = true;
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
for (int index = 0; index < authoritativeAI.Length; index++)
authoritativeAI[index] = float.IsFinite(Projectile.ai[index]) ? Projectile.ai[index] : 0f;
}
public override void SetStaticDefaults()
{
ProjectileID.Sets.TrailCacheLength[Type] = 12;
ProjectileID.Sets.TrailingMode[Type] = 2;
}
public override void SetDefaults()
{
Projectile.width = 34;
Projectile.height = 34;
Projectile.friendly = true;
Projectile.tileCollide = false;
Projectile.ignoreWater = true;
Projectile.penetrate = 4;
Projectile.timeLeft = 210;
Projectile.DamageType = DamageClass.Melee;
}
public override bool ShouldUpdatePosition() => false;
public override void AI()
{
if (Main.netMode == NetmodeID.Server)
{
if (!serverAuthorized)
{
Projectile.Kill();
return;
}
Projectile.Center = authoritativeCenter;
Projectile.velocity = authoritativeVelocity;
for (int index = 0; index < authoritativeAI.Length; index++)
Projectile.ai[index] = authoritativeAI[index];
}
Projectile.localAI[0]++;
float timer = Projectile.localAI[0];
if (timer >= 210f)
{
Projectile.Kill();
return;
}
Player owner = Main.player[Projectile.owner];
if (!owner.active || owner.dead)
{
Projectile.Kill();
return;
}
float outboundTime = Projectile.ai[0] > 0f ? 52f : 34f;
if (timer < outboundTime)
Projectile.velocity = Projectile.velocity.RotatedBy(0.008f * System.Math.Sign(Projectile.ai[2] == 0f ? 1f : Projectile.ai[2]));
else
{
Vector2 toOwner = owner.Center - Projectile.Center;
float returnSpeed = 13f + Projectile.ai[1] * 5f;
Projectile.velocity = Vector2.Lerp(Projectile.velocity, toOwner.SafeNormalize(Vector2.UnitY) * returnSpeed, 0.11f);
if (timer > outboundTime + 12f && toOwner.LengthSquared() < 24f * 24f)
Projectile.Kill();
}
Projectile.rotation += 0.34f * System.Math.Sign(Projectile.velocity.X);
if (Main.netMode != NetmodeID.Server)
{
Lighting.AddLight(Projectile.Center, new Vector3(0.55f, 0.03f, 0.08f));
if (Main.rand.NextBool(2))
{
Dust dust = Dust.NewDustPerfect(Projectile.Center, DustID.Blood, -Projectile.velocity * 0.1f, 70,
new Color(240, 35, 65), 0.85f + Projectile.ai[1] * 0.25f);
dust.noGravity = true;
}
}
if (!Projectile.active)
return;
Projectile.position += Projectile.velocity;
if (Main.netMode == NetmodeID.Server)
{
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
}
}
public override void OnHitNPC(NPC target, NPC.HitInfo hit, int damageDone)
{
Projectile.velocity = Projectile.velocity.RotatedByRandom(0.35f) * 0.92f;
if (Main.netMode == NetmodeID.Server)
{
authoritativeCenter = Projectile.Center;
authoritativeVelocity = Projectile.velocity;
}
}
public override bool PreDraw(ref Color lightColor) => ReaperProjectileHelper.DrawTrail(Projectile, new Color(245, 25, 70), scaleMultiplier: 1f + Projectile.ai[1] * 0.18f, copies: 10);
}