// Custom Simple Trails
const string g_classname = "star_trail";

const array<string> g_trail_sprites = {
    "arrows.spr", "chenzen.spr", "chinaflag.spr", "datboi.spr", "doge.spr",
    "dualline.spr", "flagaus.spr", "flagfin.spr", "flagger.spr", "flagjap.spr",
    "flaguk.spr", "hotdog.spr", "joyface.spr", "lol.spr", "moneyface.spr",
    "point.spr", "pointscroll.spr", "rainbow.spr", "ruflag.spr", "segfault.spr",
    "serious.spr", "squarewave.spr", "svenlogo.spr", "taco.spr", "thinkingface.spr",
    "usflag.spr", "weed.spr"
};

class CustomPlayerTrail : ScriptBaseEntity {
    void Spawn() {
        if (self.pev.owner is null) { g_EntityFuncs.Remove(self); return; }
        g_EntityFuncs.SetOrigin(self, self.pev.owner.vars.origin);
        @self.pev.aiment = @self.pev.owner;
        self.pev.movetype = MOVETYPE_FOLLOW;
        self.pev.solid = SOLID_NOT;
        self.pev.rendermode = kRenderTransTexture;
        self.pev.renderamt = 0;
        SetThink(null);
        
        string spritename = string(self.pev.netname);
        
        NetworkMessage m(MSG_BROADCAST, NetworkMessages::SVC_TEMPENTITY);
            m.WriteByte(TE_BEAMFOLLOW);
            m.WriteShort(self.entindex());
            m.WriteShort(g_EngineFuncs.ModelIndex(spritename));
            m.WriteByte(100);
            m.WriteByte(12);
            m.WriteByte(255);
            m.WriteByte(255);
            m.WriteByte(255);
            m.WriteByte(200);
        m.End();

        BaseClass.Spawn();
    }
}

array<int> g_trail_ents(33, -1);

void PluginInit() {
    g_Module.ScriptInfo.SetAuthor("Antigravity");
    g_Module.ScriptInfo.SetContactInfo("-");

    g_Hooks.RegisterHook(Hooks::Player::ClientSay, @ClientSay);
    g_Hooks.RegisterHook(Hooks::Player::ClientDisconnect, @ClientDisconnect);
    g_Hooks.RegisterHook(Hooks::Player::PlayerKilled, @PlayerKilled);
    
    g_CustomEntityFuncs.RegisterCustomEntity("CustomPlayerTrail", g_classname);
}

void MapInit() {
    for (uint i = 0; i < g_trail_sprites.length(); i++) {
        g_Game.PrecacheModel("sprites/chenzen/trails/" + g_trail_sprites[i]);
    }
    g_Game.PrecacheOther(g_classname);
    for (uint i = 0; i < 33; i++) g_trail_ents[i] = -1;
}

void kill_trail(int idx) {
    if (g_trail_ents[idx] > 0) {
        CBaseEntity@ oldent = g_EntityFuncs.Instance(g_trail_ents[idx]);
        if (oldent !is null) {
            NetworkMessage m(MSG_BROADCAST, NetworkMessages::SVC_TEMPENTITY);
            m.WriteByte(TE_KILLBEAM);
            m.WriteShort(oldent.entindex());
            m.End();
            g_EntityFuncs.Remove(oldent);
        }
        g_trail_ents[idx] = -1;
    }
}

HookReturnCode ClientDisconnect(CBasePlayer@ plr) {
    if (plr !is null) kill_trail(plr.entindex());
    return HOOK_CONTINUE;
}

HookReturnCode PlayerKilled(CBasePlayer@ plr, CBaseEntity@ pAttacker, int iGib) {
    if (plr !is null) kill_trail(plr.entindex());
    return HOOK_CONTINUE;
}

HookReturnCode ClientSay(SayParameters@ pParams) {
    CBasePlayer@ plr = pParams.GetPlayer();
    const CCommand@ args = pParams.GetArguments();
    if (plr is null) return HOOK_CONTINUE;

    if (args.ArgC() > 0 && args.Arg(0).StartsWith(".trail")) {
        pParams.ShouldHide = true;
        int idx = plr.entindex();
        
        kill_trail(idx);

        if (args.ArgC() > 1 && args.Arg(1) != "off") {
            string spath = "sprites/chenzen/trails/" + args.Arg(1) + ".spr";
            CBaseEntity@ newent = g_EntityFuncs.Create(g_classname, plr.pev.origin, plr.pev.angles, true, plr.edict());
            newent.pev.netname = spath;
            g_EntityFuncs.DispatchSpawn(newent.edict());
            g_trail_ents[idx] = newent.entindex();
            g_PlayerFuncs.ClientPrint(plr, HUD_PRINTTALK, "[Trails] Activated " + args.Arg(1) + "\n");
        } else {
            g_PlayerFuncs.ClientPrint(plr, HUD_PRINTTALK, "[Trails] Disabled trail.\n");
        }
    }
    return HOOK_CONTINUE;
}
