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 SoulHarvest.Common;
using Terraria;
using Terraria.GameContent;
using Terraria.ID;

namespace SoulHarvest.Projectiles;

internal static class ReaperProjectileHelper
{
    internal static void DamageOnDedicatedServer(Projectile projectile)
    {
        if (Main.netMode != NetmodeID.Server
            || projectile.owner < 0
            || projectile.owner >= Main.maxPlayers)
        {
            return;
        }

        // Projectile.Damage only runs friendly-NPC collision for Main.myPlayer.
        // A dedicated server has no local player (255), even when it authored the
        // projectile. Scope the standard collision pipeline to the real caster so
        // all vanilla/tML modifiers, OnHit hooks, immunity and net sync still run.
        int previousLocalPlayer = Main.myPlayer;
        try
        {
            Main.myPlayer = projectile.owner;
            projectile.Damage();
        }
        finally
        {
            Main.myPlayer = previousLocalPlayer;
        }
    }

    internal static void SyncNewProjectile(Projectile projectile)
    {
        projectile.netUpdate = true;
        if (Main.netMode == NetmodeID.Server
            && projectile.active
            && projectile.whoAmI >= 0
            && projectile.whoAmI < Main.maxProjectiles)
        {
            // NewProjectile can publish the base projectile before a ModProjectile
            // has written its snapshot, geometry and damage metadata. Send one
            // completed initial state immediately; short-lived slashes otherwise
            // finish before their delayed netUpdate reaches clients.
            NetMessage.SendData(MessageID.SyncProjectile, -1, -1, null,
                projectile.whoAmI);
        }
    }

    public static NPC? FindTarget(Projectile projectile, float maximumDistance)
    {
        NPC? target = null;
        foreach (NPC npc in Main.ActiveNPCs)
        {
            if (!ReaperTargeting.IsValidWeaponTarget(npc)
                || !ReaperTargeting.IsTrainingDummy(npc)
                    && !npc.CanBeChasedBy(projectile))
                continue;
            float distance = Vector2.Distance(npc.Center, projectile.Center);
            if (distance >= maximumDistance)
                continue;
            maximumDistance = distance;
            target = npc;
        }
        return target;
    }

    public static bool DrawTrail(Projectile projectile, Color color, float rotationOffset = 0f, float scaleMultiplier = 1f, int copies = 8)
    {
        Texture2D texture = TextureAssets.Projectile[projectile.type].Value;
        Vector2 origin = texture.Size() / 2f;
        int count = System.Math.Min(copies, projectile.oldPos.Length);
        for (int index = count - 1; index >= 0; index--)
        {
            if (projectile.oldPos[index] == Vector2.Zero)
                continue;
            float opacity = (count - index) / (float)(count + 1);
            Vector2 drawPosition = projectile.oldPos[index] + projectile.Size / 2f - Main.screenPosition;
            float echoScale = projectile.scale * scaleMultiplier * (0.82f + opacity * 0.18f);
            Main.EntitySpriteDraw(texture, drawPosition, null,
                (color with { A = 0 }) * opacity * 0.18f, projectile.oldRot[index] + rotationOffset, origin,
                echoScale * 1.34f, SpriteEffects.None);
            Main.EntitySpriteDraw(texture, drawPosition, null,
                (color with { A = 0 }) * opacity * 0.48f, projectile.oldRot[index] + rotationOffset, origin,
                echoScale, SpriteEffects.None);
        }
        Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null,
            (color with { A = 0 }) * 0.42f, projectile.rotation + rotationOffset, origin,
            projectile.scale * scaleMultiplier * 1.22f, SpriteEffects.None);
        Main.EntitySpriteDraw(texture, projectile.Center - Main.screenPosition, null, Color.White,
            projectile.rotation + rotationOffset, origin, projectile.scale * scaleMultiplier, SpriteEffects.None);
        return false;
    }
}