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 Microsoft.Xna.Framework.Graphics;
using Terraria;
using Terraria.GameContent;
using Terraria.ID;
using Terraria.ModLoader;

namespace SoulHarvest.Projectiles;

public class VoidRiftProjectile : ModProjectile
{
    public override void SetStaticDefaults()
    {
        ProjectileID.Sets.TrailCacheLength[Type] = 20;
        ProjectileID.Sets.TrailingMode[Type] = 2;
    }

    public override void SetDefaults()
    {
        Projectile.width = 40;
        Projectile.height = 40;
        Projectile.friendly = true;
        Projectile.tileCollide = false;
        Projectile.ignoreWater = true;
        Projectile.penetrate = -1;
        Projectile.timeLeft = 210;
        Projectile.DamageType = DamageClass.Melee;
    }

    public override void AI()
    {
        Projectile.localAI[0]++;
        float timer = Projectile.localAI[0];
        Projectile.rotation += 0.15f + Projectile.ai[1] * 0.08f;
        if (timer < 34f)
        {
            float curveDirection = System.Math.Sign(Projectile.ai[2] == 0f ? 1f : Projectile.ai[2]);
            Projectile.velocity = Projectile.velocity.RotatedBy(curveDirection * 0.012f) * 0.965f;
            Projectile.scale = MathHelper.Lerp(0.65f, 1.05f + Projectile.ai[1] * 0.45f, timer / 34f);
        }
        else
        {
            Projectile.velocity *= 0.93f;
            Projectile.scale = 1.05f + Projectile.ai[1] * 0.45f + (float)System.Math.Sin(timer * 0.15f) * 0.08f;
            NPC? target = ReaperProjectileHelper.FindTarget(Projectile, 620f + Projectile.ai[1] * 220f);
            if (target is not null)
            {
                Vector2 desired = (target.Center - Projectile.Center).SafeNormalize(Vector2.UnitX) * (3.5f + Projectile.ai[1] * 2.5f);
                Projectile.velocity = Vector2.Lerp(Projectile.velocity, desired, 0.045f);
            }
            PullEnemiesIntoRift(timer);
        }
        Lighting.AddLight(Projectile.Center, new Vector3(0.48f, 0.05f, 0.72f) * Projectile.scale);
        int dustCount = Projectile.ai[0] > 0f ? 3 : 1;
        for (int index = 0; index < dustCount; index++)
        {
            Vector2 offset = Main.rand.NextVector2Circular(28f * Projectile.scale, 28f * Projectile.scale);
            Vector2 velocity = offset.SafeNormalize(Vector2.UnitX).RotatedBy(MathHelper.PiOver2) * 1.5f;
            Dust dust = Dust.NewDustPerfect(Projectile.Center + offset, DustID.Shadowflame, velocity, 40, new Color(195, 45, 255), 1f);
            dust.noGravity = true;
        }
    }

    private void PullEnemiesIntoRift(float timer)
    {
        float empoweredBonus = Projectile.ai[0] > 0f ? 48f : 0f;
        float pullRadius = 240f + Projectile.ai[1] * 160f + empoweredBonus;
        float coreRadius = 18f + Projectile.scale * 12f;
        foreach (NPC npc in Main.ActiveNPCs)
        {
            if (!npc.CanBeChasedBy(Projectile) || IsBossOrBossPart(npc))
                continue;

            // Pull the head/root of segmented non-boss enemies and let vanilla segment AI follow it.
            if (npc.realLife >= 0 && npc.realLife != npc.whoAmI)
                continue;

            Vector2 pull = Projectile.Center - npc.Center;
            float distance = pull.Length();
            if (distance <= 0.01f || distance >= pullRadius)
                continue;

            Vector2 direction = pull / distance;
            float proximity = 1f - distance / pullRadius;
            if (Main.netMode != NetmodeID.Server && Main.rand.NextFloat() < 0.22f + proximity * 0.35f)
            {
                Dust draggedSoul = Dust.NewDustPerfect(
                    npc.Center + Main.rand.NextVector2Circular(npc.width * 0.45f, npc.height * 0.45f),
                    DustID.Shadowflame,
                    direction * (1.4f + proximity * 2.8f),
                    70,
                    new Color(205, 55, 255),
                    0.7f + proximity * 0.45f);
                draggedSoul.noGravity = true;
            }

            if (Main.netMode == NetmodeID.MultiplayerClient)
                continue;

            // Direct positional displacement is intentional. Velocity-only pulls are overwritten by
            // many stationary or scripted NPC AIs, which made the old rift appear to accelerate them.
            float displacement = (2.8f + Projectile.ai[1] * 2.6f)
                * MathHelper.Lerp(0.42f, 1.35f, proximity);
            if (Projectile.ai[0] > 0f)
                displacement *= 1.3f;

            if (distance > coreRadius)
            {
                float step = System.Math.Min(displacement, distance - coreRadius);
                npc.position += direction * step;
                float forcedSpeed = 4.5f + proximity * 5.5f + Projectile.ai[1] * 2f;
                npc.velocity = Vector2.Lerp(npc.velocity, direction * forcedSpeed, 0.72f);
            }
            else
            {
                // Enemies that reach the eye are pinned there even if their own AI normally never moves.
                npc.Center = Vector2.Lerp(npc.Center, Projectile.Center, 0.58f);
                npc.velocity *= 0.12f;
            }

            if (((int)timer + npc.whoAmI + Projectile.identity) % 4 == 0)
                npc.netUpdate = true;
        }
    }

    private static bool IsBossOrBossPart(NPC npc)
    {
        if (npc.boss)
            return true;
        return npc.realLife >= 0
            && npc.realLife < Main.maxNPCs
            && Main.npc[npc.realLife].active
            && Main.npc[npc.realLife].boss;
    }

    public override bool PreDraw(ref Color lightColor)
    {
        ReaperProjectileHelper.DrawTrail(Projectile, new Color(185, 45, 255), copies: 14);
        Texture2D texture = TextureAssets.Projectile[Type].Value;
        Vector2 origin = texture.Size() / 2f;
        Color aura = new Color(210, 55, 255, 0);
        for (int index = 0; index < 4; index++)
        {
            Vector2 offset = (Main.GlobalTimeWrappedHourly * 3f + index * MathHelper.PiOver2).ToRotationVector2() * (3f + Projectile.ai[1] * 4f);
            Main.EntitySpriteDraw(texture, Projectile.Center + offset - Main.screenPosition, null, aura * 0.24f, -Projectile.rotation, origin, Projectile.scale * 1.08f, SpriteEffects.None);
        }
        return false;
    }
}