/* * 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 for details. */ #include #include #include 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: */ 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])) }