XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
UTF-8
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ID;
using Terraria.ModLoader;

namespace SoulHarvest.Projectiles;

public class DeathSickleProjectile : ModProjectile
{
    private bool serverAuthorized;
    private Vector2 authoritativeCenter;
    private Vector2 authoritativeVelocity;

    internal void AuthorizeServerMotion()
    {
        if (Main.netMode == NetmodeID.MultiplayerClient)
            return;
        serverAuthorized = true;
        authoritativeCenter = Projectile.Center;
        authoritativeVelocity = Projectile.velocity;
    }

    public override void SetDefaults()
    {
        Projectile.friendly = true;
        Projectile.hostile = false;
        Projectile.width = 56;
        Projectile.height = 56;
        Projectile.tileCollide = false;
        Projectile.penetrate = -1;
        Projectile.ignoreWater = true;
        Projectile.timeLeft = 480;
        Projectile.light = 0.8f;
        Projectile.localNPCHitCooldown = 15;
        Projectile.usesLocalNPCImmunity = true;
    }

    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;
        }
        Projectile.localAI[0]++;
        if (Projectile.localAI[0] >= 480f)
        {
            Projectile.Kill();
            return;
        }
        Projectile.rotation += 0.48f;

        if (Main.netMode != NetmodeID.Server)
        {
            Dust blood = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.Blood, Scale: 1.1f);
            blood.noGravity = true;
            blood.velocity *= 0.2f;
            if (Main.rand.NextBool(2))
            {
                Dust soul = Dust.NewDustDirect(Projectile.position, Projectile.width, Projectile.height, DustID.AncientLight, Scale: 0.85f);
                soul.noGravity = true;
                soul.velocity *= 0.1f;
            }
        }

        NPC? target = FindTarget(700f);
        if (target is not null)
        {
            float speed = Projectile.velocity.Length();
            float curve = MathHelper.ToRadians(18f) * (float)System.Math.Sin(Projectile.localAI[0] * 0.09f);
            Vector2 desiredVelocity = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitX).RotatedBy(curve) * speed;
            Projectile.velocity = Vector2.Lerp(Projectile.velocity, desiredVelocity, 0.09f);
        }
        Projectile.position += Projectile.velocity;
        if (Main.netMode == NetmodeID.Server)
        {
            authoritativeCenter = Projectile.Center;
            authoritativeVelocity = Projectile.velocity;
        }
    }

    private NPC? FindTarget(float maximumDistance)
    {
        NPC? target = null;
        foreach (NPC npc in Main.ActiveNPCs)
        {
            if (!npc.CanBeChasedBy(Projectile))
                continue;

            float distance = Vector2.Distance(npc.Center, Projectile.Center);
            if (distance < maximumDistance)
            {
                maximumDistance = distance;
                target = npc;
            }
        }
        return target;
    }
}