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

DeathMod

【Terraria】DeathMod (now aka Soul Harvest)

公开
关注 0 Fork 0 Star 0
UTF-8
using SoulHarvest.Common;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using Terraria;
using Terraria.GameContent;
using Terraria.ID;
using Terraria.ModLoader;

namespace SoulHarvest.Projectiles;

public class LegacyDeathProjectile : ModProjectile
{
    public override string Texture => "SoulHarvest/Items/DeathSickle";

    public override void SetStaticDefaults()
    {
        ProjectileID.Sets.TrailCacheLength[Type] = 18;
        ProjectileID.Sets.TrailingMode[Type] = 2;
    }

    public override void SetDefaults()
    {
        Projectile.width = 64;
        Projectile.height = 64;
        Projectile.scale = 2.2f;
        Projectile.friendly = true;
        Projectile.hostile = false;
        Projectile.ignoreWater = true;
        Projectile.tileCollide = false;
        Projectile.timeLeft = 600;
        Projectile.penetrate = -1;
        Projectile.aiStyle = ProjAIStyleID.Typhoon;
    }

    public override void AI()
    {
        if (Main.netMode == NetmodeID.Server)
            return;

        Projectile.rotation += 0.19f * (Projectile.direction == 0 ? 1 : Projectile.direction);
        Projectile.scale = 2.15f + (float)Math.Sin(Main.GlobalTimeWrappedHourly * 7.2f + Projectile.identity) * 0.14f;
        Lighting.AddLight(Projectile.Center, new Vector3(0.82f, 0.015f, 0.055f));

        int dustCount = Main.rand.NextBool(2) ? 3 : 2;
        for (int index = 0; index < dustCount; index++)
        {
            Vector2 radial = Main.rand.NextVector2CircularEdge(Projectile.width * 0.8f, Projectile.height * 0.8f);
            Vector2 tangent = radial.SafeNormalize(Vector2.UnitY).RotatedBy(MathHelper.PiOver2)
                * Main.rand.NextFloat(2.2f, 5.4f);
            int dustType = index == 0 ? DustID.Shadowflame : index == 1 ? DustID.BatScepter : DustID.Blood;
            Dust dust = Dust.NewDustPerfect(Projectile.Center + radial, dustType,
                tangent - Projectile.velocity * 0.07f, 45,
                index == 0 ? new Color(36, 0, 16) : new Color(230, 12, 48),
                Main.rand.NextFloat(1.15f, 2.35f));
            dust.noGravity = true;
        }
    }

    public override bool PreDraw(ref Color lightColor)
    {
        Texture2D texture = TextureAssets.Projectile[Type].Value;
        Texture2D pixel = TextureAssets.MagicPixel.Value;
        Vector2 origin = texture.Size() * 0.5f;
        SpriteBatch batch = Main.spriteBatch;

        for (int index = Projectile.oldPos.Length - 1; index >= 0; index--)
        {
            if (Projectile.oldPos[index] == Vector2.Zero)
                continue;
            float strength = 1f - index / (float)Projectile.oldPos.Length;
            Vector2 position = Projectile.oldPos[index] + Projectile.Size * 0.5f - Main.screenPosition;
            float oldRotation = Projectile.oldRot[index];
            Color shadow = new Color(18, 0, 12, 0) * (strength * 0.58f);
            Color blood = new Color(235, 16, 55, 0) * (strength * 0.46f);
            batch.Draw(texture, position, null, shadow, -oldRotation,
                origin, Projectile.scale * (1.28f + strength * 0.24f), SpriteEffects.None, 0f);
            batch.Draw(texture, position, null, blood, oldRotation,
                origin, Projectile.scale * (0.72f + strength * 0.28f), SpriteEffects.None, 0f);
        }

        Vector2 center = Projectile.Center - Main.screenPosition;
        float time = Main.GlobalTimeWrappedHourly;
        DrawOldDeathFaces(batch, pixel, center, time);
        for (int arm = 0; arm < 5; arm++)
        {
            float baseAngle = time * (1.7f + arm * 0.045f) + arm * MathHelper.TwoPi / 5f;
            Vector2 previous = center + baseAngle.ToRotationVector2() * 16f;
            for (int segment = 1; segment <= 10; segment++)
            {
                float amount = segment / 10f;
                float radius = MathHelper.Lerp(18f, 94f, amount);
                float angle = baseAngle + amount * 2.25f;
                Vector2 current = center + angle.ToRotationVector2() * radius;
                DrawSegment(batch, pixel, previous, current,
                    new Color(145, 0, 32, 0) * ((1f - amount) * 0.68f),
                    MathHelper.Lerp(12f, 1.5f, amount));
                DrawSegment(batch, pixel, previous, current,
                    new Color(255, 52, 82, 0) * ((1f - amount) * 0.54f),
                    MathHelper.Lerp(3.2f, 0.7f, amount));
                previous = current;
            }
        }

        batch.Draw(texture, center, null, new Color(120, 0, 26, 0) * 0.62f,
            -Projectile.rotation, origin, Projectile.scale * 1.36f, SpriteEffects.None, 0f);
        batch.Draw(texture, center, null, Color.White, Projectile.rotation,
            origin, Projectile.scale, SpriteEffects.None, 0f);
        return false;
    }

    private void DrawOldDeathFaces(SpriteBatch batch, Texture2D pixel, Vector2 center, float time)
    {
        float pulse = 0.72f + (float)Math.Sin(time * 5.4f + Projectile.identity) * 0.12f;
        Color shadow = new Color(6, 0, 5, 205) * pulse;
        Color blood = new Color(235, 14, 50, 0) * (pulse * 0.66f);
        Vector2 skull = center - Vector2.UnitY * 8f;
        float[] widths = { 34f, 44f, 48f, 45f, 36f, 25f };
        for (int row = 0; row < widths.Length; row++)
        {
            float y = (row - 2.5f) * 8f;
            DrawSegment(batch, pixel, skull + new Vector2(-widths[row], y),
                skull + new Vector2(widths[row], y), shadow, 9f);
        }
        for (int side = -1; side <= 1; side += 2)
        {
            Vector2 eye = skull + new Vector2(side * 18f, -5f);
            DrawSegment(batch, pixel, eye + new Vector2(-7f, -4f), eye + new Vector2(6f, 5f), blood, 5f);
        }
        for (int tooth = -2; tooth <= 2; tooth++)
        {
            Vector2 root = skull + new Vector2(tooth * 9f, 23f);
            DrawSegment(batch, pixel, root, root + Vector2.UnitY * 13f, blood * 0.62f, 2f);
        }

        // Coarse bat silhouettes deliberately retain the relic's old pixel-art
        // language instead of borrowing the polished six-form iconography.
        for (int index = 3; index < Projectile.oldPos.Length; index += 4)
        {
            if (Projectile.oldPos[index] == Vector2.Zero)
                continue;
            Vector2 bat = Projectile.oldPos[index] + Projectile.Size * 0.5f - Main.screenPosition;
            float scale = 8f + (Projectile.oldPos.Length - index) * 0.45f;
            Vector2 left = new(-scale, -scale * 0.45f);
            Vector2 right = new(scale, -scale * 0.45f);
            DrawSegment(batch, pixel, bat, bat + left, shadow, 3.5f);
            DrawSegment(batch, pixel, bat + left, bat + new Vector2(-scale * 1.45f, scale * 0.25f), blood * 0.48f, 2f);
            DrawSegment(batch, pixel, bat, bat + right, shadow, 3.5f);
            DrawSegment(batch, pixel, bat + right, bat + new Vector2(scale * 1.45f, scale * 0.25f), blood * 0.48f, 2f);
        }
    }

    public override void OnKill(int timeLeft)
    {
        if (Main.dedServ)
            return;
        for (int index = 0; index < 32; index++)
        {
            Vector2 velocity = (index * MathHelper.TwoPi / 32f).ToRotationVector2()
                * Main.rand.NextFloat(3f, 9f);
            Dust dust = Dust.NewDustPerfect(Projectile.Center,
                index % 3 == 0 ? DustID.Shadowflame : DustID.Blood,
                velocity, 35, new Color(220, 12, 52), Main.rand.NextFloat(1.2f, 2.4f));
            dust.noGravity = true;
        }
        ReaperVfxDirector.TriggerGlobalImpact(Projectile.velocity.SafeNormalize(Vector2.UnitY),
            6.5f, 9, new Color(225, 18, 58), 0.26f, 5, 0.30f);
    }

    private static void DrawSegment(SpriteBatch batch, Texture2D pixel, Vector2 start, Vector2 end, Color color, float width)
    {
        DeathDomainPrimitiveTextureSystem.DrawSmoothLine(batch, start, end, color, width);
    }
}