/* Formatright � 2009, ConnorMcLeod
c4 management 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.
This program 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 the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with c4 management; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <hamsandwich>
#define VERSION "0.2.7"
#define MAX_PLAYERS 32
enum _:BombSites_Datas {
iBsIndex,
szBsModel[5]
}
enum _:BombSites_States {
AllSites,
MainSite,
NoSite
}
#define StatusIconDontShow 0
#define StatusIconShow 1
new const func_bomb_target[] = "func_bomb_target"
new const info_bomb_target[] = "info_bomb_target"
new const classname[] = "classname"
#define FIND_ENT_BY_CLASSNAME(%1,%2) engfunc(EngFunc_FindEntityByString, %1, classname, %2)
#define XTRA_OFS_PLAYER 5
#define m_iTeam 114
#define cs_get_user_team_index(%1) get_pdata_int(%1, m_iTeam, XTRA_OFS_PLAYER)
#define CS_TEAM_CT 2
new g_iMaxPlayers
new g_pCvarMinCts, g_pCvarMidCts
new g_pCvarStartRoundText, g_pCvarPlanterText
new bool:g_bMainSiteSet
new szConfigFile[64], g_szMapName[32]
new g_mMainBombSite[BombSites_Datas]
new g_szBombSiteName[16]
new Array:g_aBombSites
new Float:g_flCountUntilGameTime
new bool:g_bCountNewSpawns
new g_iSyncHud
new mp_buytime
new gmsgStatusIcon
new g_iBombSites_State
new g_iC4Carrier
public plugin_init()
{
new iEnt, mDatas[BombSites_Datas]
while( (iEnt = FIND_ENT_BY_CLASSNAME(iEnt, func_bomb_target)) )
{
if( g_aBombSites == Invalid_Array )
{
g_aBombSites = ArrayCreate(BombSites_Datas)
}
mDatas[iBsIndex] = iEnt
pev(iEnt, pev_model, mDatas[szBsModel], charsmax(mDatas[szBsModel]))
ArrayPushString(g_aBombSites, mDatas)
}
while( (iEnt = FIND_ENT_BY_CLASSNAME(iEnt, info_bomb_target)) )
{
if( g_aBombSites == Invalid_Array )
{
g_aBombSites = ArrayCreate(BombSites_Datas)
}
mDatas[iBsIndex] = iEnt
pev(iEnt, pev_model, mDatas[szBsModel], charsmax(mDatas[szBsModel]))
ArrayPushString(g_aBombSites, mDatas)
}
if( g_aBombSites == Invalid_Array )
{
register_plugin("c4 management", "NotBombMap", "ConnorMcLeod")
pause("ad")
return
}
register_plugin("c4 management", VERSION, "ConnorMcLeod")
register_dictionary("c4management.txt")
g_pCvarMinCts = register_cvar("bm_minct", "0")
g_pCvarMidCts = register_cvar("bm_midct", "4")
g_pCvarStartRoundText = register_cvar("bm_roundstart_text", "1")
g_pCvarPlanterText = register_cvar("bm_planter_text", "1")
get_mapname(g_szMapName, charsmax(g_szMapName))
get_localinfo("amxx_configsdir", szConfigFile, charsmax(szConfigFile))
format(szConfigFile, charsmax(szConfigFile), "%s/bombsites.ini", szConfigFile)
if( !file_exists(szConfigFile) )
{
new iFile = fopen(szConfigFile, "at")
fprintf(iFile, "; c4 management configuration file^n")
fclose(iFile)
}
g_iMaxPlayers = get_maxplayers()
GetMainBombSiteByFile()
register_event("HLTV", "Event_HLTV_New_Round", "a", "1=0", "2=0")
register_logevent("LogEvent_RoundStart", 2, "1=Round_Start")
register_logevent("Logevent_Round_End", 2, "1=Round_End")
RegisterHam(Ham_Spawn, "player", "Player_Spawn_Post", 1)
register_event("WeapPickup", "Event_WeapPickup_c4", "be", "1=6")
register_message(get_user_msgid("StatusIcon"), "Message_StatusIcon")
register_event("BombDrop", "Event_BombDrop", "bc")
register_event("TextMsg", "Event_TextMsg_C4PlantAtBombSpot", "be", "1=4", "2=#C4_Plant_At_Bomb_Spot")
register_clcmd("bm_mark_bs", "AdminCommand_MarkBombSite", ADMIN_CFG, " <BombSite Name>")
g_iSyncHud = CreateHudSyncObj()
mp_buytime = get_cvar_pointer("mp_buytime")
gmsgStatusIcon = get_user_msgid("StatusIcon")
}
GetMainBombSiteByFile()
{
new iFile = fopen(szConfigFile, "rt")
if( iFile )
{
new szData[64], szMapname[32], szModel[5], szBombSiteName[16]
while( fgets(iFile, szData, charsmax(szData)) )
{
if( !szData[0] || szData[0] == '/' || szData[0] == ';' || szData[0] == '#' )
{
continue
}
trim(szData)
parse(szData, szMapname, charsmax(szMapname),
szModel, charsmax(szModel),
szBombSiteName, charsmax(szBombSiteName))
if( equali(szMapname, g_szMapName) )
{
new iEnt
// less efficient than engine but used only at map start
iEnt = FIND_ENT_BY_MODELNAME(g_iMaxPlayers, func_bomb_target, szModel)
if( !iEnt )
{
iEnt = FIND_ENT_BY_MODELNAME(g_iMaxPlayers, info_bomb_target, szModel)
}
if( iEnt )
{
g_mMainBombSite[iBsIndex] = iEnt
g_mMainBombSite[szBsModel] = szModel
remove_quotes(szBombSiteName)
g_szBombSiteName = szBombSiteName
g_bMainSiteSet = true
}
break
}
}
fclose(iFile)
}
}
public plugin_pause()
{
new iBombSiteNum = ArraySize(g_aBombSites)
new mBombSiteDatas[BombSites_Datas]
for(new i; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
SetBombSite(mBombSiteDatas[iBsIndex], true)
}
}
public plugin_end()
{
if( g_aBombSites != Invalid_Array )
{
ArrayDestroy(g_aBombSites)
}
}
public Event_HLTV_New_Round()
{
g_iC4Carrier = 0
g_bCountNewSpawns = false
g_iBombSites_State = AllSites
}
public Event_BombDrop()
{
g_iC4Carrier = 0
if( read_data(4) ) // Bomb Planted
{
g_bCountNewSpawns = false
}
}
public Logevent_Round_End()
{
g_bCountNewSpawns = false
}
public LogEvent_RoundStart()
{
g_bCountNewSpawns = true
g_flCountUntilGameTime = get_gametime() + get_pcvar_float(mp_buytime) * 60.0
if(!g_bMainSiteSet)
{
return
}
CountCounterTerrorists()
}
public AdminCommand_MarkBombSite(id, level, cid)
{
if( !cmd_access(id, level, cid, 2) )
{
return PLUGIN_HANDLED
}
if(g_bMainSiteSet)
{
print_color(id, "%L", id, "BM_ALREADY")
client_cmd(id, "spk buttons/latchlocked1")
return PLUGIN_HANDLED
}
new iBombSiteNum = ArraySize(g_aBombSites)
new mBombSiteDatas[BombSites_Datas], iEnt
new Float:fVecOrigin[3], Float:fVecAbsMin[3], Float:fVecAbsMax[3]
for(new i=0; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
iEnt = mBombSiteDatas[iBsIndex]
pev(id, pev_origin, fVecOrigin)
pev(iEnt, pev_absmin, fVecAbsMin)
pev(iEnt, pev_absmax, fVecAbsMax)
if( (fVecAbsMin[0] <= fVecOrigin[0] <= fVecAbsMax[0])
&& (fVecAbsMin[1] <= fVecOrigin[1] <= fVecAbsMax[1])
&& (-72.0 <= (((fVecAbsMax[2] + fVecAbsMin[2]) / 2.0) - fVecOrigin[2]) <= 72.0) )
{
read_argv(1, g_szBombSiteName, charsmax(g_szBombSiteName))
new iFile = fopen(szConfigFile, "at")
fprintf(iFile, "^n%s %s ^"%s^"", g_szMapName, mBombSiteDatas[szBsModel], g_szBombSiteName)
fclose(iFile)
g_mMainBombSite = mBombSiteDatas
g_bMainSiteSet = true
print_color(id, "%L", id, "BM_DEFINED")
client_cmd(id, "spk events/task_complete")
return PLUGIN_HANDLED
}
}
print_color(id, "%L", id, "BM_NOTBOMBSITE")
client_cmd(id, "spk events/friend_died")
return PLUGIN_HANDLED
}
public Event_WeapPickup_c4( id )
{
g_iC4Carrier = id
}
public Message_StatusIcon(/*iMsgId, iMsgDest, id*/)
{
if( g_iBombSites_State != AllSites && get_msg_arg_int(1) == StatusIconShow )
{
new szIcon[4]
get_msg_arg_string(2, szIcon, charsmax(szIcon))
if( get_msg_arg_string(2, szIcon, charsmax(szIcon)) == 2 // check "c4" length first
&& equal(szIcon, "c4") )
{
switch( g_iBombSites_State )
{
case NoSite:
{
set_msg_arg_int(1, ARG_BYTE, 0)
}
case MainSite:
{
set_msg_arg_int(3, ARG_BYTE, 200)
set_msg_arg_int(4, ARG_BYTE, 100)
}
}
}
}
}
public Event_TextMsg_C4PlantAtBombSpot(id)
{
if( !get_pcvar_num(g_pCvarPlanterText) )
{
return
}
new iBombSiteNum = ArraySize(g_aBombSites)
new mBombSiteDatas[BombSites_Datas], iEnt
new Float:fVecOrigin[3], Float:fVecAbsMin[3], Float:fVecAbsMax[3]
for(new i=0; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
iEnt = mBombSiteDatas[iBsIndex]
pev(id, pev_origin, fVecOrigin)
pev(iEnt, pev_absmin, fVecAbsMin)
pev(iEnt, pev_absmax, fVecAbsMax)
if( (fVecAbsMin[0] <= fVecOrigin[0] <= fVecAbsMax[0])
&& (fVecAbsMin[1] <= fVecOrigin[1] <= fVecAbsMax[1])
&& (-72.0 <= (((fVecAbsMax[2] + fVecAbsMin[2]) / 2.0) - fVecOrigin[2]) <= 72.0) )
{
switch( g_iBombSites_State )
{
case NoSite:
{
print_color(id, "%L", id, "BM_AD_NOPLANT", get_pcvar_num(g_pCvarMinCts))
}
case MainSite:
{
print_color(id, "%L", id, "BM_AD_ONLYMAIN",
get_pcvar_num(g_pCvarMidCts), g_szBombSiteName)
}
}
break
}
}
}
public Player_Spawn_Post(id)
{
if( g_bMainSiteSet
&& g_bCountNewSpawns
&& is_user_alive(id)
&& cs_get_user_team_index(id) == CS_TEAM_CT )
{
if( g_flCountUntilGameTime < get_gametime() )
{
g_bCountNewSpawns = false
return
}
CountCounterTerrorists()
}
}
CountCounterTerrorists()
{
new iPlayers[MAX_PLAYERS], iNum, iCtNum
get_players(iPlayers, iNum, "h")
for(new i; i<iNum; i++)
{
if( cs_get_user_team_index(iPlayers[i]) == CS_TEAM_CT )
{
iCtNum++
}
}
new iMinCts = get_pcvar_num(g_pCvarMinCts)
new iMidCts = get_pcvar_num(g_pCvarMidCts)
new const szTag[] = "C4 Management"
new iBombSiteNum = ArraySize(g_aBombSites)
new mBombSiteDatas[BombSites_Datas]
if( iCtNum < iMinCts)
{
switch( get_pcvar_num(g_pCvarStartRoundText) )
{
case 1:
{
print_color(0, "[%s] %L", szTag, LANG_PLAYER, "BM_AD_NOPLANT", iMinCts)
}
case 2:
{
set_hudmessage(200, 50, 50, -1.0, 0.15, .holdtime=8.0, .channel=-1)
ShowSyncHudMsg(0, g_iSyncHud, "%s : %L", szTag, LANG_PLAYER, "BM_AD_NOPLANT", iMinCts)
}
}
for(new i; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
SetBombSite(mBombSiteDatas[iBsIndex], false)
}
g_iBombSites_State = NoSite
if( g_iC4Carrier )
{
Send_StatusIcon_c4(g_iC4Carrier)
}
}
else if( iCtNum < iMidCts)
{
switch( get_pcvar_num(g_pCvarStartRoundText) )
{
case 1:
{
print_color(0, "[%s] %L", szTag, LANG_PLAYER, "BM_AD_ONLYMAIN", iMidCts, g_szBombSiteName)
}
case 2:
{
set_hudmessage(200, 100, 0, -1.0, 0.15, .holdtime=8.0, .channel=-1)
ShowSyncHudMsg(0, g_iSyncHud, "%s : %L", szTag, LANG_PLAYER, "BM_AD_ONLYMAIN", iMidCts, g_szBombSiteName)
}
}
new iEnt
for(new i; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
iEnt = mBombSiteDatas[iBsIndex]
SetBombSite(iEnt, iEnt == g_mMainBombSite[iBsIndex] ? true : false)
}
g_iBombSites_State = MainSite
if( g_iC4Carrier )
{
Send_StatusIcon_c4(g_iC4Carrier, StatusIconShow, 200, 100, 0)
}
}
else
{
switch( get_pcvar_num(g_pCvarStartRoundText) )
{
case 1:
{
print_color(0, "[%s] %L", szTag, LANG_PLAYER, "BM_AD_ALLSITES")
}
case 2:
{
set_hudmessage(50, 200, 50, -1.0, 0.15, .holdtime=8.0, .channel=-1)
ShowSyncHudMsg(0, g_iSyncHud, "%s : %L", szTag, LANG_PLAYER, "BM_AD_ALLSITES")
}
}
for(new i; i<iBombSiteNum; i++)
{
ArrayGetArray(g_aBombSites, i, mBombSiteDatas)
SetBombSite(mBombSiteDatas[iBsIndex], true)
}
g_iBombSites_State = AllSites
if( g_iC4Carrier )
{
Send_StatusIcon_c4(g_iC4Carrier, StatusIconShow, 0, 160, 0)
}
}
}
SetBombSite(iEnt, bool:bActive)
{
set_pev(iEnt, pev_solid, bActive ? SOLID_TRIGGER : SOLID_NOT)
}
Send_StatusIcon_c4(id, Mode=StatusIconDontShow, r=0, g=0, b=0)
{
message_begin(MSG_ONE_UNRELIABLE, gmsgStatusIcon, .player=id)
write_byte(Mode)
write_string("c4")
if( Mode )
{
write_byte(r)
write_byte(g)
write_byte(b)
}
message_end()
}
FIND_ENT_BY_MODELNAME(const iStartEnt, const szClassName[], const szModel[])
{
new iEnt = iStartEnt
new szMdl[72]
while( (iEnt = FIND_ENT_BY_CLASSNAME(iEnt, szClassName)) )
{
pev(iEnt, pev_model, szMdl, charsmax(szMdl))
if( equal(szMdl, szModel) )
{
return iEnt
}
}
return 0
}
stock print_color(const id, const input[], any:...)
{
new count = 1, players[32]
static msg[191]
vformat(msg, 190, input, 3)
replace_all(msg, 190, "!g", "^4")
replace_all(msg, 190, "!y", "^1")
replace_all(msg, 190, "!t", "^3")
if (id) players[0] = id; else get_players(players, count, "ch")
{
for (new i = 0; i < count; i++)
{
if (is_user_connected(players[i]))
{
message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("SayText"), _, players[i])
write_byte(players[i])
write_string(msg)
message_end()
}
}
}
return PLUGIN_HANDLED
}