/* * CSB Base Builder * Copyright (C) 2026 counter-strike-boost.com * * Base Builder core. Each round opens with a build phase in which the builder * team can grab, carry, rotate and lock map props: /grab pins whatever brush * prop your crosshair is on in front of you (moved every frame in * PlayerPreThink), /rotate spins it, /lock freezes it in place, /drop releases * it. Each builder is limited to a number of locked props. When the build timer * expires the fight phase starts, every prop is frozen and the attacking team * must break in. * * Inspired by Base Builder (ConnorMcLeod / Kreedz community). Independent GPL * re-implementation. * * 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 new const PLUGIN[] = "CSB Base Builder" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define PHASE_BUILD 0 #define PHASE_FIGHT 1 new g_pEnabled, g_pBuildTime, g_pBuilderTeam, g_pPropLimit new g_iPhase new g_iGrab[33] new Float:g_fGrabDist[33] new Float:g_fGrabYaw[33] new g_iLockedCount[33] new g_iHudSync public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_bb_enabled", "1") g_pBuildTime = register_cvar("csb_bb_buildtime", "45") g_pBuilderTeam = register_cvar("csb_bb_builderteam", "2") /* 1=T 2=CT */ g_pPropLimit = register_cvar("csb_bb_proplimit", "6") register_clcmd("say /grab", "cmdGrab") register_clcmd("say /drop", "cmdDrop") register_clcmd("say /rotate", "cmdRotate") register_clcmd("say /lock", "cmdLock") register_forward(FM_PlayerPreThink, "fwPreThink") register_logevent("eventRoundStart", 2, "1=Round_Start") g_iHudSync = CreateHudSyncObj() set_task(1.0, "taskHud", 0, _, _, "b") } public client_putinserver(id) { g_iGrab[id] = 0 g_iLockedCount[id] = 0 } public client_disconnected(id) { g_iGrab[id] = 0 } public eventRoundStart() { if (!get_pcvar_num(g_pEnabled)) return g_iPhase = PHASE_BUILD for (new id = 1; id <= 32; id++) { g_iGrab[id] = 0 g_iLockedCount[id] = 0 } client_print(0, print_chat, "[CSB] BUILD PHASE - %d seconds. Builders: /grab /rotate /lock /drop", get_pcvar_num(g_pBuildTime)) set_task(float(get_pcvar_num(g_pBuildTime)), "taskFightPhase", 9911) } public taskFightPhase() { g_iPhase = PHASE_FIGHT /* drop and freeze everything */ for (new id = 1; id <= 32; id++) { if (g_iGrab[id] > 0) { freezeProp(g_iGrab[id]) g_iGrab[id] = 0 } } client_print(0, print_chat, "[CSB] FIGHT PHASE - break into the base!") } bool:isBuilder(id) { return get_user_team(id) == get_pcvar_num(g_pBuilderTeam) } bool:isGrabbable(ent) { if (ent <= 32 || !pev_valid(ent)) return false static cls[32] pev(ent, pev_classname, cls, charsmax(cls)) if (equal(cls, "worldspawn") || equal(cls, "player")) return false /* brush props and pushables only */ if (equal(cls, "func_pushable") || equal(cls, "func_breakable") || equal(cls, "func_wall") || equal(cls, "func_door") || containi(cls, "func_") == 0) return true return false } public cmdGrab(id) { if (!get_pcvar_num(g_pEnabled) || g_iPhase != PHASE_BUILD) { client_print(id, print_chat, "[CSB] You can only build during the build phase.") return PLUGIN_HANDLED } if (!isBuilder(id) || !is_user_alive(id)) return PLUGIN_HANDLED if (g_iGrab[id] > 0) { client_print(id, print_chat, "[CSB] You are already carrying a prop. /drop or /lock first.") return PLUGIN_HANDLED } new ent, body get_user_aiming(id, ent, body, 700) if (!isGrabbable(ent)) { client_print(id, print_chat, "[CSB] No movable prop in your crosshair.") return PLUGIN_HANDLED } static Float:fMe[3], Float:fProp[3] pev(id, pev_origin, fMe) pev(ent, pev_origin, fProp) g_iGrab[id] = ent g_fGrabDist[id] = vector_distance(fMe, fProp) if (g_fGrabDist[id] > 200.0) g_fGrabDist[id] = 200.0 else if (g_fGrabDist[id] < 80.0) g_fGrabDist[id] = 80.0 static Float:fAng[3] pev(ent, pev_angles, fAng) g_fGrabYaw[id] = fAng[1] /* make it float freely while carried */ set_pev(ent, pev_movetype, MOVETYPE_NOCLIP) client_print(id, print_chat, "[CSB] Prop grabbed. /rotate to spin, /lock to place.") return PLUGIN_HANDLED } public cmdDrop(id) { if (g_iGrab[id] > 0) { set_pev(g_iGrab[id], pev_movetype, MOVETYPE_TOSS) g_iGrab[id] = 0 client_print(id, print_chat, "[CSB] Prop dropped.") } return PLUGIN_HANDLED } public cmdRotate(id) { if (g_iGrab[id] > 0) { g_fGrabYaw[id] += 45.0 if (g_fGrabYaw[id] >= 360.0) g_fGrabYaw[id] -= 360.0 client_print(id, print_chat, "[CSB] Rotated to %d degrees.", floatround(g_fGrabYaw[id])) } return PLUGIN_HANDLED } public cmdLock(id) { if (g_iGrab[id] <= 0) return PLUGIN_HANDLED if (g_iLockedCount[id] >= get_pcvar_num(g_pPropLimit)) { client_print(id, print_chat, "[CSB] You reached your prop limit (%d).", get_pcvar_num(g_pPropLimit)) return PLUGIN_HANDLED } new ent = g_iGrab[id] freezeProp(ent) set_pev(ent, pev_owner, id) g_iGrab[id] = 0 g_iLockedCount[id]++ client_print(id, print_chat, "[CSB] Prop locked in place (%d/%d).", g_iLockedCount[id], get_pcvar_num(g_pPropLimit)) return PLUGIN_HANDLED } freezeProp(ent) { if (!pev_valid(ent)) return static Float:fZero[3] set_pev(ent, pev_velocity, fZero) set_pev(ent, pev_movetype, MOVETYPE_PUSHSTEP) } public fwPreThink(id) { new ent = g_iGrab[id] if (ent <= 0) return if (!is_user_alive(id) || !pev_valid(ent)) { g_iGrab[id] = 0 return } static Float:fEye[3], Float:fOfs[3], Float:fAng[3], Float:fFwd[3], Float:fDest[3] pev(id, pev_origin, fEye) pev(id, pev_view_ofs, fOfs) fEye[0] += fOfs[0] fEye[1] += fOfs[1] fEye[2] += fOfs[2] pev(id, pev_v_angle, fAng) angle_vector(fAng, ANGLEVECTOR_FORWARD, fFwd) fDest[0] = fEye[0] + fFwd[0] * g_fGrabDist[id] fDest[1] = fEye[1] + fFwd[1] * g_fGrabDist[id] fDest[2] = fEye[2] + fFwd[2] * g_fGrabDist[id] static Float:fZero[3] set_pev(ent, pev_velocity, fZero) engfunc(EngFunc_SetOrigin, ent, fDest) static Float:fSet[3] fSet[0] = 0.0 fSet[1] = g_fGrabYaw[id] fSet[2] = 0.0 set_pev(ent, pev_angles, fSet) } public taskHud() { if (!get_pcvar_num(g_pEnabled)) return new players[32], num get_players(players, num, "ch") for (new i = 0; i < num; i++) { new id = players[i] set_hudmessage(255, 180, 0, 0.02, 0.12, 0, 0.0, 1.1, 0.0, 0.0, -1) if (g_iPhase == PHASE_BUILD && isBuilder(id)) ShowSyncHudMsg(id, g_iHudSync, "BUILD PHASE | props %d/%d", g_iLockedCount[id], get_pcvar_num(g_pPropLimit)) else if (g_iPhase == PHASE_BUILD) ShowSyncHudMsg(id, g_iHudSync, "BUILD PHASE | wait for the fight") else ShowSyncHudMsg(id, g_iHudSync, "FIGHT PHASE") } }