Promote server
csb-weapon-models / addons / amxmodx / scripting / csb_weapon_models.sma
163 lines 4.5 KiB Pawn Raw Permalink History
/*
 * CSB Weapon Models
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * Replaces the view (v_) and world/weapon (p_) models per weapon from a simple
 * ini file. Models are precached at map start; on every CurWeapon the plugin
 * writes the custom model into pev_viewmodel2 / pev_weaponmodel2. Players can
 * toggle back to the default models for themselves.
 *
 * Inspired by "Weapon Model Replacement" by Emp`. 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>

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

#define MAX_WEAPONS 31
#define INI_FILE    "csb_weapon_models.ini"

new g_szView[MAX_WEAPONS + 1][64]
new g_szWorld[MAX_WEAPONS + 1][64]
new bool:g_bDefault[33]

new g_pEnabled

/* human-friendly names accepted in the ini, mapped to CSW_* ids */
new const g_szNames[][] =
{
    "knife", "usp", "glock", "glock18", "deagle", "p228", "elite",
    "fiveseven", "m4a1", "ak47", "awp", "scout", "aug", "sg552",
    "galil", "famas", "m3", "xm1014", "mp5", "mp5navy", "tmp", "mac10",
    "ump45", "p90", "m249", "sg550", "g3sg1"
}

new const g_iNameCsw[] =
{
    CSW_KNIFE, CSW_USP, CSW_GLOCK18, CSW_GLOCK18, CSW_DEAGLE, CSW_P228, CSW_ELITE,
    CSW_FIVESEVEN, CSW_M4A1, CSW_AK47, CSW_AWP, CSW_SCOUT, CSW_AUG, CSW_SG552,
    CSW_GALIL, CSW_FAMAS, CSW_M3, CSW_XM1014, CSW_MP5NAVY, CSW_MP5NAVY, CSW_TMP, CSW_MAC10,
    CSW_UMP45, CSW_P90, CSW_M249, CSW_SG550, CSW_G3SG1
}

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

    g_pEnabled = register_cvar("csb_wmodels_enabled", "1")

    register_clcmd("say /wmodels",      "cmdToggle")
    register_clcmd("say_team /wmodels", "cmdToggle")

    register_event("CurWeapon", "fwCurWeapon", "be", "1=1")
}

public plugin_precache()
{
    loadModels()
}

loadModels()
{
    new configsDir[128], path[192]
    get_configsdir(configsDir, charsmax(configsDir))
    formatex(path, charsmax(path), "%s/%s", configsDir, INI_FILE)

    if (!file_exists(path))
    {
        log_amx("[CSB Weapon Models] %s not found - no custom models loaded.", path)
        return
    }

    new line[192], name[32], vmodel[64], pmodel[64], lineNum = 0, loaded = 0, tlen

    while (read_file(path, lineNum++, line, charsmax(line), tlen))
    {
        trim(line)

        if (!line[0] || line[0] == ';' || line[0] == '/' || line[0] == '#')
            continue

        /* format: <weaponname> <v_model.mdl> <p_model.mdl> */
        new count = parse(line, name, charsmax(name), vmodel, charsmax(vmodel), pmodel, charsmax(pmodel))

        if (count < 2)
            continue

        new csw = nameToCsw(name)

        if (csw < 0)
            continue

        if (vmodel[0] && file_exists(vmodel))
        {
            precache_model(vmodel)
            copy(g_szView[csw], charsmax(g_szView[]), vmodel)
        }

        if (count >= 3 && pmodel[0] && file_exists(pmodel))
        {
            precache_model(pmodel)
            copy(g_szWorld[csw], charsmax(g_szWorld[]), pmodel)
        }

        loaded++
    }

    log_amx("[CSB Weapon Models] loaded %d weapon model entries.", loaded)
}

nameToCsw(const name[])
{
    for (new i = 0; i < sizeof(g_szNames); i++)
    {
        if (equali(name, g_szNames[i]))
            return g_iNameCsw[i]
    }

    return -1
}

public client_putinserver(id)
{
    g_bDefault[id] = false
}

public cmdToggle(id)
{
    g_bDefault[id] = !g_bDefault[id]

    client_print(id, print_chat, "[CSB] Custom weapon models are now %s for you.",
        g_bDefault[id] ? "OFF (default models)" : "ON")

    return PLUGIN_HANDLED
}

public fwCurWeapon(id)
{
    if (!get_pcvar_num(g_pEnabled) || g_bDefault[id] || !is_user_alive(id))
        return

    new csw = read_data(2)

    if (csw < 1 || csw > MAX_WEAPONS)
        return

    if (g_szView[csw][0])
        set_pev(id, pev_viewmodel2, engfunc(EngFunc_AllocString, g_szView[csw]))

    if (g_szWorld[csw][0])
        set_pev(id, pev_weaponmodel2, engfunc(EngFunc_AllocString, g_szWorld[csw]))
}