using SoulHarvest.Common;
using Microsoft.Xna.Framework;
using System;
using System.IO;
using Terraria;
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.ModLoader;
namespace SoulHarvest.Projectiles;
/// <summary>
/// The thin crimson cut lines placed on every enemy awaiting the next domain harvest.
/// Their deterministic rotations are reused by the actual blades so each execution
/// lands exactly on its own warning line.
/// </summary>
public class DeathDomainHarvestTelegraphProjectile : ModProjectile
{
private int TargetIndex => (int)Projectile.ai[0];
private int TelegraphFrames => Math.Clamp((int)Projectile.ai[1], 1, 180);
private int SlashCount => Math.Clamp((int)Projectile.ai[2], 1, 5);
private float Mastery => MathHelper.Clamp((Projectile.ai[2] - SlashCount) * 10f, 0f, 1f);
public override string Texture => "Terraria/Images/Projectile_0";
public override void SetStaticDefaults()
{
ProjectileID.Sets.DrawScreenCheckFluff[Type] = 3600;
}
public override void SetDefaults()
{
Projectile.width = 2;
Projectile.height = 2;
Projectile.friendly = false;
Projectile.hostile = false;
Projectile.tileCollide = false;
Projectile.ignoreWater = true;
Projectile.penetrate = -1;
Projectile.timeLeft = 120;
Projectile.netImportant = false;
}
public override void OnSpawn(IEntitySource source)
{
Projectile.timeLeft = TelegraphFrames + 6;
}
public override bool? CanDamage() => false;
public override void SendExtraAI(BinaryWriter writer)
{
writer.Write(Projectile.rotation);
writer.Write(Projectile.scale);
}
public override void ReceiveExtraAI(BinaryReader reader)
{
Projectile.rotation = reader.ReadSingle();
Projectile.scale = reader.ReadSingle();
}
public override void AI()
{
if (TargetIndex >= 0 && TargetIndex < Main.maxNPCs && Main.npc[TargetIndex].active)
Projectile.Center = Main.npc[TargetIndex].Center;
if (Main.dedServ || !Main.rand.NextBool(18))
return;
int slash = Main.rand.Next(SlashCount);
float rotation = DeathDomainHarvestSlashProjectile.GetSlashRotation(Projectile.rotation, slash);
float halfLength = DeathDomainHarvestSlashProjectile.GetSlashLength(Mastery, Projectile.scale, slash) * 0.5f;
Vector2 direction = rotation.ToRotationVector2();
Vector2 end = Projectile.Center + direction * (Main.rand.NextBool() ? halfLength : -halfLength);
Dust dust = Dust.NewDustPerfect(
end,
DustID.RedTorch,
direction.RotatedByRandom(0.45f) * Main.rand.NextFloat(0.25f, 1.2f),
95,
new Color(255, 15, 50),
Main.rand.NextFloat(0.45f, 0.8f));
dust.noGravity = true;
}
public override bool PreDraw(ref Color lightColor)
{
float remaining = MathHelper.Clamp((Projectile.timeLeft - 5f) / Math.Max(1f, TelegraphFrames), 0f, 1f);
float urgency = 1f - remaining;
float pulse = 0.72f + (float)Math.Sin(Main.GlobalTimeWrappedHourly * (7f + urgency * 9f) + Projectile.identity) * 0.20f;
Vector2 center = Projectile.Center - Main.screenPosition;
for (int slash = 0; slash < SlashCount; slash++)
{
float rotation = DeathDomainHarvestSlashProjectile.GetSlashRotation(Projectile.rotation, slash);
float length = DeathDomainHarvestSlashProjectile.GetSlashLength(Mastery, Projectile.scale, slash);
float linePulse = pulse * (0.90f + 0.10f * (float)Math.Sin(slash * 1.9f + Main.GlobalTimeWrappedHourly * 3f));
DrawTaperedLine(center, rotation, length, (6f + Mastery * 2f) * Projectile.scale,
new Color(120, 0, 25, 0) * (0.24f + urgency * 0.22f));
DrawTaperedLine(center, rotation, length, (1.35f + urgency * 0.85f) * Projectile.scale,
new Color(255, 8, 48, 0) * linePulse);
}
return false;
}
private static void DrawTaperedLine(Vector2 center, float rotation, float length, float maximumWidth, Color color)
{
Vector2 start = center - rotation.ToRotationVector2() * length * 0.5f;
DeathDomainPrimitiveTextureSystem.DrawBlade(start, rotation, length, maximumWidth, color);
}
}
using SoulHarvest.Common;
using Microsoft.Xna.Framework;
using System;
using System.IO;
using Terraria;
using Terraria.DataStructures;
using Terraria.ID;
using Terraria.ModLoader;
namespace SoulHarvest.Projectiles;
/// <summary>
/// The thin crimson cut lines placed on every enemy awaiting the next domain harvest.
/// Their deterministic rotations are reused by the actual blades so each execution
/// lands exactly on its own warning line.
/// </summary>
public class DeathDomainHarvestTelegraphProjectile : ModProjectile
{
private int TargetIndex => (int)Projectile.ai[0];
private int TelegraphFrames => Math.Clamp((int)Projectile.ai[1], 1, 180);
private int SlashCount => Math.Clamp((int)Projectile.ai[2], 1, 5);
private float Mastery => MathHelper.Clamp((Projectile.ai[2] - SlashCount) * 10f, 0f, 1f);
public override string Texture => "Terraria/Images/Projectile_0";
public override void SetStaticDefaults()
{
ProjectileID.Sets.DrawScreenCheckFluff[Type] = 3600;
}
public override void SetDefaults()
{
Projectile.width = 2;
Projectile.height = 2;
Projectile.friendly = false;
Projectile.hostile = false;
Projectile.tileCollide = false;
Projectile.ignoreWater = true;
Projectile.penetrate = -1;
Projectile.timeLeft = 120;
Projectile.netImportant = false;
}
public override void OnSpawn(IEntitySource source)
{
Projectile.timeLeft = TelegraphFrames + 6;
}
public override bool? CanDamage() => false;
public override void SendExtraAI(BinaryWriter writer)
{
writer.Write(Projectile.rotation);
writer.Write(Projectile.scale);
}
public override void ReceiveExtraAI(BinaryReader reader)
{
Projectile.rotation = reader.ReadSingle();
Projectile.scale = reader.ReadSingle();
}
public override void AI()
{
if (TargetIndex >= 0 && TargetIndex < Main.maxNPCs && Main.npc[TargetIndex].active)
Projectile.Center = Main.npc[TargetIndex].Center;
if (Main.dedServ || !Main.rand.NextBool(18))
return;
int slash = Main.rand.Next(SlashCount);
float rotation = DeathDomainHarvestSlashProjectile.GetSlashRotation(Projectile.rotation, slash);
float halfLength = DeathDomainHarvestSlashProjectile.GetSlashLength(Mastery, Projectile.scale, slash) * 0.5f;
Vector2 direction = rotation.ToRotationVector2();
Vector2 end = Projectile.Center + direction * (Main.rand.NextBool() ? halfLength : -halfLength);
Dust dust = Dust.NewDustPerfect(
end,
DustID.RedTorch,
direction.RotatedByRandom(0.45f) * Main.rand.NextFloat(0.25f, 1.2f),
95,
new Color(255, 15, 50),
Main.rand.NextFloat(0.45f, 0.8f));
dust.noGravity = true;
}
public override bool PreDraw(ref Color lightColor)
{
float remaining = MathHelper.Clamp((Projectile.timeLeft - 5f) / Math.Max(1f, TelegraphFrames), 0f, 1f);
float urgency = 1f - remaining;
float pulse = 0.72f + (float)Math.Sin(Main.GlobalTimeWrappedHourly * (7f + urgency * 9f) + Projectile.identity) * 0.20f;
Vector2 center = Projectile.Center - Main.screenPosition;
for (int slash = 0; slash < SlashCount; slash++)
{
float rotation = DeathDomainHarvestSlashProjectile.GetSlashRotation(Projectile.rotation, slash);
float length = DeathDomainHarvestSlashProjectile.GetSlashLength(Mastery, Projectile.scale, slash);
float linePulse = pulse * (0.90f + 0.10f * (float)Math.Sin(slash * 1.9f + Main.GlobalTimeWrappedHourly * 3f));
DrawTaperedLine(center, rotation, length, (6f + Mastery * 2f) * Projectile.scale,
new Color(120, 0, 25, 0) * (0.24f + urgency * 0.22f));
DrawTaperedLine(center, rotation, length, (1.35f + urgency * 0.85f) * Projectile.scale,
new Color(255, 8, 48, 0) * linePulse);
}
return false;
}
private static void DrawTaperedLine(Vector2 center, float rotation, float length, float maximumWidth, Color color)
{
Vector2 start = center - rotation.ToRotationVector2() * length * 0.5f;
DeathDomainPrimitiveTextureSystem.DrawBlade(start, rotation, length, maximumWidth, color);
}
}