Promuj serwer
csb-jetpack / addons / amxmodx / scripting / csb_jetpack.sma
188 lines 5.2 KiB Pawn Raw Permalink History
/*
 * CSB Jetpack
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * A fuel-limited jetpack. Bind a key to +jetpack: while held, the player is
 * pushed along their aim direction with a little lift, a thrust light burns at
 * their feet and the fuel bar drains. Standing on the ground refills the fuel.
 * Access can be restricted to a flag so it becomes a VIP perk.
 *
 * Inspired by VEN's classic Jetpack plugin for AMX Mod X. This is an
 * independent GPL re-implementation; no original code is reused.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version. It is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
 */

#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <fun>

new const PLUGIN[] = "CSB Jetpack"
new const VERSION[] = "1.0.0"
new const AUTHOR[]  = "counter-strike-boost.com"

#define SVC_TEMPENTITY 23
#define TE_DLIGHT      27
#define TASK_THINK     5500

new g_pEnabled, g_pPower, g_pLift, g_pDrain, g_pRegen, g_pAccess, g_pSound

new bool:g_bThrust[33]
new Float:g_fFuel[33]
new g_szSound[64]
new g_iSyncHud

public plugin_precache()
{
    g_pSound = register_cvar("csb_jet_sound", "")
    get_pcvar_string(g_pSound, g_szSound, charsmax(g_szSound))

    if (g_szSound[0])
        precache_sound(g_szSound)
}

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    g_pEnabled = register_cvar("csb_jet_enabled", "1")
    g_pPower   = register_cvar("csb_jet_power", "320")     // forward speed
    g_pLift    = register_cvar("csb_jet_lift", "170.0")    // upward push
    g_pDrain   = register_cvar("csb_jet_drain", "1.5")     // fuel per tick
    g_pRegen   = register_cvar("csb_jet_regen", "2.0")     // fuel per tick on ground
    g_pAccess  = register_cvar("csb_jet_flag", "")         // required admin flag(s), empty = everyone

    register_clcmd("+jetpack", "cmdThrustOn")
    register_clcmd("-jetpack", "cmdThrustOff")

    g_iSyncHud = CreateHudSyncObj()

    set_task(0.1, "taskThink", TASK_THINK, _, _, "b")
}

public client_putinserver(id)
{
    g_bThrust[id] = false
    g_fFuel[id]   = 100.0
}

public client_disconnected(id)
{
    g_bThrust[id] = false
}

bool:hasAccess(id)
{
    new flags[8]
    get_pcvar_string(g_pAccess, flags, charsmax(flags))

    if (!flags[0])
        return true

    return (get_user_flags(id) & read_flags(flags)) ? true : false
}

public cmdThrustOn(id)
{
    if (!get_pcvar_num(g_pEnabled))
        return PLUGIN_HANDLED

    if (!hasAccess(id))
    {
        client_print(id, print_chat, "[CSB] The jetpack is reserved for VIP players.")
        return PLUGIN_HANDLED
    }

    g_bThrust[id] = true
    return PLUGIN_HANDLED
}

public cmdThrustOff(id)
{
    g_bThrust[id] = false
    return PLUGIN_HANDLED
}

public taskThink()
{
    new Float:power = float(get_pcvar_num(g_pPower))
    new Float:lift  = get_pcvar_float(g_pLift)
    new Float:drain = get_pcvar_float(g_pDrain)
    new Float:regen = get_pcvar_float(g_pRegen)

    new players[32], num, pid, origin[3]
    get_players(players, num, "a")

    for (new i = 0; i < num; i++)
    {
        pid = players[i]

        new bool:onGround = (pev(pid, pev_flags) & FL_ONGROUND) ? true : false

        if (g_bThrust[pid] && g_fFuel[pid] > 0.0 && get_pcvar_num(g_pEnabled))
        {
            new Float:aim[3]
            velocity_by_aim(pid, floatround(power), aim)

            new Float:vel[3]
            pev(pid, pev_velocity, vel)
            vel[0] = aim[0]
            vel[1] = aim[1]
            vel[2] = aim[2] + lift
            set_pev(pid, pev_velocity, vel)

            g_fFuel[pid] -= drain
            if (g_fFuel[pid] < 0.0)
                g_fFuel[pid] = 0.0

            /* thrust light at the feet */
            get_user_origin(pid, origin)
            message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
            write_byte(TE_DLIGHT)
            write_coord(origin[0])
            write_coord(origin[1])
            write_coord(origin[2] - 20)
            write_byte(6)
            write_byte(255)
            write_byte(random_num(120, 200))
            write_byte(0)
            write_byte(2)
            write_byte(4)
            message_end()

            if (g_szSound[0])
                emit_sound(pid, CHAN_STATIC, g_szSound, 0.4, ATTN_NORM, 0, PITCH_NORM)
        }
        else if (onGround && g_fFuel[pid] < 100.0)
        {
            g_fFuel[pid] += regen
            if (g_fFuel[pid] > 100.0)
                g_fFuel[pid] = 100.0
        }

        showFuel(pid)
    }
}

showFuel(id)
{
    /* only bother while flying or when the tank is not full */
    if (!g_bThrust[id] && g_fFuel[id] >= 100.0)
        return

    new pct = floatround(g_fFuel[id])
    new bar[11], filled = pct / 10

    for (new i = 0; i < 10; i++)
        bar[i] = (i < filled) ? '|' : '.'
    bar[10] = 0

    set_hudmessage(0, 180, 255, 0.02, 0.85, 0, 0.0, 0.3, 0.0, 0.0, -1)
    ShowSyncHudMsg(id, g_iSyncHud, "Jetpack [%s] %d%%", bar, pct)
}