HLMOD.HU Forrás Megtekintés - www.hlmod.hu
  1.  
  2. // Thanks a lot to 3volution for helping me iron out some
  3. // bugs and for giving me some helpful suggestions.
  4. //
  5. // Thanks a lot to raa for helping me pinpoint the crash,
  6. // and discovering the respawn bug.
  7. //
  8. // Thanks a lot to VEN for being so smart.
  9. //
  10. // Thanks a lot to BAILOPAN for binary logging, and for
  11. // CSDM spawn files that I could leech off of.
  12. //
  13. // Thanks a lot to all of my supporters, predominantly:
  14. // 3volution, aligind4h0us3, arkshine, Curryking, Gunny,
  15. // IdiotSavant, Mordekay, polakpolak, raa, Silver Dragon,
  16. // and ToT | V!PER. (alphabetically)
  17. //
  18. // Thanks especially to all of the translators:
  19. // arkshine, b!orn, commonbullet, Curryking, Deviance,
  20. // D o o m, Fr3ak0ut, godlike, harbu, iggy_bus, jopmako,
  21. // KylixMynxAltoLAG, Morpheus759, SAMURAI16, TEG,
  22. // ToT | V!PER, Twilight Suzuka, and webpsiho. (alphabetically)
  23.  
  24. #include <amxmodx>
  25. #include <amxmisc>
  26. #include <fakemeta>
  27. #include <fakemeta_util>
  28. #include <cstrike>
  29.  
  30. // defines
  31. #define GG_VERSION "1.17b"
  32. #define TOP_PLAYERS 10 // for !top10
  33. #define MAX_SPAWNS 128 // for gg_dm_spawn_random
  34. #define COMMAND_ACCESS ADMIN_CVAR // for amx_gungame
  35. #define LANG_PLAYER_C -76 // for gungame_print (arbitrary number)
  36. #define MAX_WEAPON_ORDERS 10 // for random gg_weapon_order
  37. #define TEMP_SAVES 32 // for gg_save_temp
  38. #define TNAME_SAVE pev_noise3 // for blocking game_player_equip and player_weaponstrip
  39.  
  40. // gg_status_display
  41. enum
  42. {
  43. STATUS_LEADERWPN = 1,
  44. STATUS_YOURWPN,
  45. STATUS_KILLSLEFT,
  46. STATUS_KILLSDONE
  47. };
  48.  
  49. // toggle_gungame
  50. enum
  51. {
  52. TOGGLE_FORCE = -1,
  53. TOGGLE_DISABLE,
  54. TOGGLE_ENABLE
  55. };
  56.  
  57. // bombStatus[3]
  58. enum
  59. {
  60. BOMB_PICKEDUP = -1,
  61. BOMB_DROPPED,
  62. BOMB_PLANTED
  63. };
  64.  
  65. // cs_set_user_money
  66. #if cellbits == 32
  67. #define OFFSET_CSMONEY 115
  68. #else
  69. #define OFFSET_CSMONEY 140
  70. #endif
  71. #define OFFSET_LINUX 5
  72.  
  73. // task ids
  74. #define TASK_END_STAR 200
  75. #define TASK_RESPAWN 300
  76. #define TASK_CHECK_RESPAWN 400
  77. #define TASK_CHECK_RESPAWN2 1100
  78. #define TASK_CLEAR_SAVE 500
  79. #define TASK_CHECK_DEATHMATCH 600
  80. #define TASK_REMOVE_PROTECTION 700
  81. #define TASK_TOGGLE_GUNGAME 800
  82. #define TASK_WARMUP_CHECK 900
  83. #define TASK_VERIFY_WEAPON 1000
  84. #define TASK_DELAYED_SUICIDE 1100
  85. #define TASK_REFRESH_NADE 1200
  86.  
  87. // hud channels
  88. #define CHANNEL_STATUS 3
  89. #define CHANNEL_WARMUP 1
  90.  
  91. // animations
  92. #define USP_DRAWANIM 6
  93. #define M4A1_DRAWANIM 5
  94.  
  95. //
  96. // VARIABLE DEFINITIONS
  97. //
  98.  
  99. // pcvar holders
  100. new gg_enabled, gg_ff_auto, gg_vote_setting, gg_map_setup, gg_join_msg,
  101. gg_weapon_order, gg_max_lvl, gg_triple_on, gg_turbo, gg_knife_pro,
  102. gg_worldspawn_suicide, gg_bomb_defuse_lvl, gg_handicap_on, gg_top10_handicap,
  103. gg_warmup_timer_setting, gg_knife_warmup, gg_nade_glock, gg_nade_smoke,
  104. gg_nade_flash, gg_sound_levelup, gg_sound_leveldown, gg_sound_nade,
  105. gg_sound_knife, gg_sound_welcome, gg_sound_triple, gg_sound_winner,
  106. gg_kills_per_lvl, gg_give_armor, gg_give_helmet, gg_vote_custom,
  107. gg_changelevel_custom, gg_ammo_amount, gg_dm, gg_dm_sp_time, gg_dm_sp_mode,
  108. gg_dm_spawn_random, gg_dm_spawn_delay, gg_stats_file, gg_stats_prune,
  109. gg_refill_on_kill, gg_colored_messages, gg_tk_penalty, gg_dm_corpses, gg_save_temp,
  110. gg_awp_oneshot, gg_host_touch_reward, gg_host_rescue_reward, gg_host_kill_reward,
  111. gg_dm_countdown, gg_status_display, gg_dm_spawn_afterplant, gg_block_objectives,
  112. gg_stats_mode, gg_pickup_others, gg_stats_winbonus, gg_map_iterations, gg_warmup_multi,
  113. gg_host_kill_penalty, gg_dm_start_random, gg_stats_ip, gg_extra_nades, gg_endmap_setup,
  114. gg_allow_changeteam, gg_autovote_rounds, gg_autovote_ratio, gg_autovote_delay,
  115. gg_autovote_time, gg_ignore_bots, gg_nade_refresh, gg_block_equips;
  116.  
  117. // max clip
  118. stock const maxClip[31] = { -1, 13, -1, 10, 1, 7, 1, 30, 30, 1, 30, 20, 25, 30, 35, 25, 12, 20,
  119. 10, 30, 100, 8, 30, 30, 20, 2, 7, 30, 30, -1, 50 };
  120.  
  121. // max bpammo
  122. stock const maxAmmo[31] = { -1, 52, -1, 90, -1, 32, -1, 100, 90, -1, 120, 100, 100, 90, 90, 90, 100, 100,
  123. 30, 120, 200, 32, 90, 120, 60, -1, 35, 90, 90, -1, 100 };
  124.  
  125. // weapon slot lookup table
  126. stock const weaponSlots[] = { 0, 2, 0, 1, 4, 1, 5, 1, 1, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1,
  127. 1, 4, 2, 1, 1, 3, 1 };
  128.  
  129. // misc
  130. new scores_menu, level_menu, bombMap, hostageMap, warmup = -1, len, voted, won, trailSpr, roundEnded,
  131. weaponOrder[416], menuText[512], dummy[2], tempSave[TEMP_SAVES][27], c4planter, czero, bombStatus[4], maxPlayers,
  132. gameStarted, mapIteration = 1, Float:spawns[MAX_SPAWNS][9], spawnCount, csdmSpawnCount, cfgDir[32],
  133. top10[TOP_PLAYERS][81], csrespawnEnabled, modName[12], autovoted, autovotes[2], roundsElapsed,
  134. gameCommenced, cycleNum = -1;
  135.  
  136. // stats file stuff
  137. new sfFile[64], sfAuthid[24], sfWins[6], sfPoints[8], sfName[32], sfTimestamp[12], sfLineData[81];
  138.  
  139. // event ids
  140. new gmsgSayText, gmsgCurWeapon, gmsgScenario, gmsgBombDrop, gmsgBombPickup, gmsgHideWeapon, gmsgCrosshair;
  141.  
  142. // player values
  143. new level[33], levelsThisRound[33], score[33], weapon[33][24], star[33], welcomed[33],
  144. spawnProtected[33], blockResetHUD[33], page[33], blockCorpse[33], Float:lastDeathMsg[33], hosties[33][2],
  145. respawn_timeleft[33], Float:spawnTime[33], silenced[33], spawnSounds[33], oldTeam[33];
  146.  
  147. //
  148. // INITIATION FUNCTIONS
  149. //
  150.  
  151. native cs_respawn(index);
  152.  
  153. // plugin load
  154. public plugin_init()
  155. {
  156. register_plugin("GunGame AMXX",GG_VERSION,"Avalanche");
  157. register_cvar("gg_version",GG_VERSION,FCVAR_SERVER);
  158. set_cvar_string("gg_version",GG_VERSION);
  159.  
  160. // mehrsprachige unterstützung (nein, spreche ich nicht Deutsches)
  161. register_dictionary("gungame.txt");
  162. register_dictionary("common.txt");
  163. register_dictionary("adminvote.txt");
  164.  
  165. // event ids
  166. gmsgSayText = get_user_msgid("SayText");
  167. gmsgCurWeapon = get_user_msgid("CurWeapon");
  168. gmsgScenario = get_user_msgid("Scenario");
  169. gmsgBombDrop = get_user_msgid("BombDrop");
  170. gmsgBombPickup = get_user_msgid("BombPickup");
  171. gmsgHideWeapon = get_user_msgid("HideWeapon");
  172. gmsgCrosshair = get_user_msgid("Crosshair");
  173.  
  174. // forwards
  175. register_forward(FM_SetModel,"fw_setmodel");
  176. register_forward(FM_Touch,"fw_touch");
  177. register_forward(FM_EmitSound,"fw_emitsound");
  178.  
  179. // events
  180. register_event("DeathMsg","event_deathmsg","a");
  181. register_event("ResetHUD","event_resethud","b");
  182. register_event("CurWeapon","event_curweapon","b","1=1");
  183. register_event("AmmoX","event_ammox","b");
  184. register_event("HLTV","event_new_round","a","1=0","2=0"); // VEN
  185. register_event("TextMsg","event_round_restart","a","2=#Game_Commencing","2=#Game_will_restart_in");
  186. register_event("30","event_intermission","a");
  187. register_event("23","event_bomb_detonation","a","1=17","6=-105","7=17"); // planted bomb exploded (before/after round end) event (discovered by Ryan)
  188. register_message(get_user_msgid("ClCorpse"),"message_clcorpse");
  189. register_message(get_user_msgid("Money"),"message_money");
  190. register_message(gmsgScenario,"message_scenario");
  191. register_message(gmsgBombDrop,"message_bombdrop");
  192. register_message(gmsgBombPickup,"message_bombpickup");
  193. register_message(get_user_msgid("WeapPickup"),"message_weappickup"); // for gg_block_objectives
  194. register_message(get_user_msgid("AmmoPickup"),"message_ammopickup"); // for gg_block_objectives
  195. register_message(get_user_msgid("TextMsg"),"message_textmsg"); // for gg_block_objectives
  196. register_message(get_user_msgid("HostagePos"),"message_hostagepos"); // for gg_block_objectives
  197.  
  198. // logevents
  199. register_logevent("event_bomb_detonation",6,"3=Target_Bombed"); // another bomb exploded event, for security (VEN)
  200. register_logevent("logevent_bomb_planted",3,"2=Planted_The_Bomb"); // bomb planted (VEN)
  201. register_logevent("logevent_bomb_defused",3,"2=Defused_The_Bomb"); // bomb defused (VEN)
  202. register_logevent("logevent_round_end",2,"1=Round_End"); // round ended (VEN)
  203. register_logevent("logevent_hostage_touched",3,"2=Touched_A_Hostage");
  204. register_logevent("logevent_hostage_rescued",3,"2=Rescued_A_Hostage");
  205. register_logevent("logevent_hostage_killed",3,"2=Killed_A_Hostage");
  206. register_logevent("logevent_team_join",3,"1=joined team");
  207.  
  208. // commands
  209. register_concmd("amx_gungame","cmd_gungame",ADMIN_CVAR,"<0|1> - toggles the functionality of GunGame");
  210. register_concmd("amx_gungame_level","cmd_gungame_level",ADMIN_BAN,"<target> <level> - sets target's level. use + or - for relative, otherwise it's absolute.");
  211. register_concmd("amx_gungame_vote","cmd_gungame_vote",ADMIN_VOTE,"- starts a vote to toggle GunGame");
  212. register_clcmd("fullupdate","cmd_fullupdate");
  213. register_clcmd("joinclass","cmd_joinclass"); // new menus
  214. register_menucmd(register_menuid("Terrorist_Select",1),511,"cmd_joinclass"); // old menus (thanks teame06)
  215. register_menucmd(register_menuid("CT_Select",1),511,"cmd_joinclass"); // old menus (thanks teame06)
  216. register_clcmd("say","cmd_say");
  217. register_clcmd("say_team","cmd_say");
  218.  
  219. // menus
  220. register_menucmd(register_menuid("autovote_menu"),MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,"autovote_menu_handler");
  221. register_menucmd(register_menuid("welcome_menu"),1023,"welcome_menu_handler");
  222. register_menucmd(register_menuid("restart_menu"),MENU_KEY_1|MENU_KEY_0,"restart_menu_handler");
  223. register_menucmd(register_menuid("weapons_menu"),MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,"weapons_menu_handler");
  224. register_menucmd(register_menuid("top10_menu"),MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,"top10_menu_handler");
  225. scores_menu = register_menuid("scores_menu");
  226. register_menucmd(scores_menu,MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,"scores_menu_handler");
  227. level_menu = register_menuid("level_menu");
  228. register_menucmd(level_menu,1023,"level_menu_handler");
  229.  
  230. // basic cvars
  231. gg_enabled = register_cvar("gg_enabled","1");
  232. gg_vote_setting = register_cvar("gg_vote_setting","1");
  233. gg_vote_custom = register_cvar("gg_vote_custom","");
  234. gg_changelevel_custom = register_cvar("gg_changelevel_custom","");
  235. gg_map_setup = register_cvar("gg_map_setup","mp_timelimit 45; mp_winlimit 0; sv_alltalk 0; mp_chattime 10; mp_c4timer 25");
  236. gg_endmap_setup = register_cvar("gg_endmap_setup","");
  237. gg_join_msg = register_cvar("gg_join_msg","1");
  238. gg_colored_messages = register_cvar("gg_colored_messages","1");
  239. gg_save_temp = register_cvar("gg_save_temp","300"); // = 5 * 60 = 5 minutes
  240. gg_status_display = register_cvar("gg_status_display","0");
  241. gg_map_iterations = register_cvar("gg_map_iterations","1");
  242. gg_ignore_bots = register_cvar("gg_ignore_bots","0");
  243. gg_block_equips = register_cvar("gg_block_equips","0");
  244.  
  245. // autovote cvars
  246. gg_autovote_rounds = register_cvar("gg_autovote_rounds","0");
  247. gg_autovote_delay = register_cvar("gg_autovote_delay","8.0");
  248. gg_autovote_ratio = register_cvar("gg_autovote_ratio","0.51");
  249. gg_autovote_time = register_cvar("gg_autovote_time","10.0");
  250.  
  251. // stats cvars
  252. gg_stats_file = register_cvar("gg_stats_file","gungame.stats");
  253. gg_stats_ip = register_cvar("gg_stats_ip","0");
  254. gg_stats_prune = register_cvar("gg_stats_prune","2592000"); // = 60 * 60 * 24 * 30 = 30 days
  255. gg_stats_mode = register_cvar("gg_stats_mode","1");
  256. gg_stats_winbonus = register_cvar("gg_stats_winbonus","1.5");
  257.  
  258. // deathmatch cvars
  259. gg_dm = register_cvar("gg_dm","0");
  260. gg_dm_sp_time = register_cvar("gg_dm_sp_time","1.0");
  261. gg_dm_sp_mode = register_cvar("gg_dm_sp_mode","1");
  262. gg_dm_spawn_random = register_cvar("gg_dm_spawn_random","0");
  263. gg_dm_start_random = register_cvar("gg_dm_start_random","0");
  264. gg_dm_spawn_delay = register_cvar("gg_dm_spawn_delay","1.5");
  265. gg_dm_spawn_afterplant = register_cvar("gg_dm_spawn_afterplant","1");
  266. gg_dm_corpses = register_cvar("gg_dm_corpses","1");
  267. gg_dm_countdown = register_cvar("gg_dm_countdown","0");
  268.  
  269. // objective cvars
  270. gg_block_objectives = register_cvar("gg_block_objectives","0");
  271. gg_bomb_defuse_lvl = register_cvar("gg_bomb_defuse_lvl","1");
  272. gg_host_touch_reward = register_cvar("gg_host_touch_reward","0");
  273. gg_host_rescue_reward = register_cvar("gg_host_rescue_reward","0");
  274. gg_host_kill_reward = register_cvar("gg_host_kill_reward","0");
  275. gg_host_kill_penalty = register_cvar("gg_host_kill_penalty","0");
  276.  
  277. // gameplay cvars
  278. gg_ff_auto = register_cvar("gg_ff_auto","1");
  279. gg_weapon_order = register_cvar("gg_weapon_order","glock18,usp,p228,deagle,fiveseven,elite,m3,xm1014,tmp,mac10,mp5navy,ump45,p90,galil,famas,ak47,scout,m4a1,sg552,aug,m249,hegrenade,knife");
  280. gg_max_lvl = register_cvar("gg_max_lvl","3");
  281. gg_triple_on = register_cvar("gg_triple_on","0");
  282. gg_turbo = register_cvar("gg_turbo","0");
  283. gg_knife_pro = register_cvar("gg_knife_pro","0");
  284. gg_worldspawn_suicide = register_cvar("gg_worldspawn_suicide","1");
  285. gg_allow_changeteam = register_cvar("gg_allow_changeteam","0");
  286. gg_pickup_others = register_cvar("gg_pickup_others","0");
  287. gg_handicap_on = register_cvar("gg_handicap_on","1");
  288. gg_top10_handicap = register_cvar("gg_top10_handicap","1");
  289. gg_warmup_timer_setting = register_cvar("gg_warmup_timer_setting","60");
  290. gg_knife_warmup = register_cvar("gg_knife_warmup","1");
  291. gg_warmup_multi = register_cvar("gg_warmup_multi","0");
  292. gg_nade_glock = register_cvar("gg_nade_glock","0");
  293. gg_nade_smoke = register_cvar("gg_nade_smoke","0");
  294. gg_nade_flash = register_cvar("gg_nade_flash","0");
  295. gg_extra_nades = register_cvar("gg_extra_nades","0");
  296. gg_nade_refresh = register_cvar("gg_nade_refresh","0.0");
  297. gg_kills_per_lvl = register_cvar("gg_kills_per_lvl","1");
  298. gg_give_armor = register_cvar("gg_give_armor","100");
  299. gg_give_helmet = register_cvar("gg_give_helmet","1");
  300. gg_ammo_amount = register_cvar("gg_ammo_amount","200");
  301. gg_refill_on_kill = register_cvar("gg_refill_on_kill","1");
  302. gg_tk_penalty = register_cvar("gg_tk_penalty","0");
  303. gg_awp_oneshot = register_cvar("gg_awp_oneshot","1");
  304.  
  305. // sound cvars
  306. gg_sound_levelup = register_cvar("gg_sound_levelup","gungame/smb3_powerup.wav");
  307. gg_sound_leveldown = register_cvar("gg_sound_leveldown","gungame/smb3_powerdown.wav");
  308. gg_sound_nade = register_cvar("gg_sound_nade","gungame/nade_level.wav");
  309. gg_sound_knife = register_cvar("gg_sound_knife","gungame/knife_level.wav");
  310. gg_sound_welcome = register_cvar("gg_sound_welcome","gungame/gungame2.wav");
  311. gg_sound_triple = register_cvar("gg_sound_triple","gungame/smb_star.wav");
  312. gg_sound_winner = register_cvar("gg_sound_winner","media/Half-Life08.mp3");
  313.  
  314. // random weapon order cvars
  315. new i, cvar[20];
  316. for(i=1;i<=MAX_WEAPON_ORDERS;i++)
  317. {
  318. formatex(cvar,19,"gg_weapon_order%i",i);
  319. register_cvar(cvar,"");
  320. }
  321.  
  322. // check for mini respawn module
  323. csrespawnEnabled = module_exists("csrespawn");
  324.  
  325. // make sure to setup amx_nextmap incase nextmap.amxx isn't running
  326. if(!cvar_exists("amx_nextmap")) register_cvar("amx_nextmap","",FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY);
  327.  
  328. // identify this as a bomb map
  329. if(fm_find_ent_by_class(1,"info_bomb_target") || fm_find_ent_by_class(1,"func_bomb_target"))
  330. bombMap = 1;
  331.  
  332. // identify this as a hostage map
  333. if(fm_find_ent_by_class(1,"hostage_entity"))
  334. hostageMap = 1;
  335.  
  336. get_modname(modName,11);
  337.  
  338. // remember if we are running czero or not
  339. if(equali(modName,"czero")) czero = 1;
  340.  
  341. maxPlayers = get_maxplayers();
  342.  
  343. // grab CSDM file
  344. new mapName[32], csdmFile[64];
  345. get_configsdir(cfgDir,31);
  346. get_mapname(mapName,31);
  347. formatex(csdmFile,63,"%s/csdm/%s.spawns.cfg",cfgDir,mapName);
  348.  
  349. // collect CSDM spawns
  350. if(file_exists(csdmFile))
  351. {
  352. new csdmData[10][6];
  353.  
  354. new file = fopen(csdmFile,"rt");
  355. while(file && !feof(file))
  356. {
  357. fgets(file,sfLineData,63);
  358.  
  359. // invalid spawn
  360. if(!sfLineData[0] || str_count(sfLineData,' ') < 2)
  361. continue;
  362.  
  363. // BREAK IT UP!
  364. parse(sfLineData,csdmData[0],5,csdmData[1],5,csdmData[2],5,csdmData[3],5,csdmData[4],5,csdmData[5],5,csdmData[6],5,csdmData[7],5,csdmData[8],5,csdmData[9],5);
  365.  
  366. // origin
  367. spawns[spawnCount][0] = floatstr(csdmData[0]);
  368. spawns[spawnCount][1] = floatstr(csdmData[1]);
  369. spawns[spawnCount][2] = floatstr(csdmData[2]);
  370.  
  371. // angles
  372. spawns[spawnCount][3] = floatstr(csdmData[3]);
  373. spawns[spawnCount][4] = floatstr(csdmData[4]);
  374. spawns[spawnCount][5] = floatstr(csdmData[5]);
  375.  
  376. // team, csdmData[6], unused
  377.  
  378. // vangles
  379. spawns[spawnCount][6] = floatstr(csdmData[7]);
  380. spawns[spawnCount][7] = floatstr(csdmData[8]);
  381. spawns[spawnCount][8] = floatstr(csdmData[9]);
  382.  
  383. spawnCount++;
  384. csdmSpawnCount++;
  385. if(spawnCount >= MAX_SPAWNS) break;
  386. }
  387. if(file) fclose(file);
  388. }
  389.  
  390. // collect regular, boring spawns
  391. else
  392. {
  393. new ent, Float:spawnData[3];
  394. while((ent = fm_find_ent_by_class(ent,"info_player_deathmatch")) != 0)
  395. {
  396. // origin
  397. pev(ent,pev_origin,spawnData);
  398. spawns[spawnCount][0] = spawnData[0];
  399. spawns[spawnCount][1] = spawnData[1];
  400. spawns[spawnCount][2] = spawnData[2];
  401.  
  402. // angles
  403. pev(ent,pev_angles,spawnData);
  404. spawns[spawnCount][3] = spawnData[0];
  405. spawns[spawnCount][4] = spawnData[1];
  406. spawns[spawnCount][5] = spawnData[2];
  407.  
  408. // vangles
  409. spawns[spawnCount][6] = spawnData[0];
  410. spawns[spawnCount][7] = spawnData[1];
  411. spawns[spawnCount][8] = spawnData[2];
  412.  
  413. spawnCount++;
  414. if(spawnCount >= MAX_SPAWNS) break;
  415. }
  416.  
  417. // yeah, I probably should've optimized this
  418.  
  419. ent = 0;
  420. while((ent = fm_find_ent_by_class(ent,"info_player_start")) != 0)
  421. {
  422. // origin
  423. pev(ent,pev_origin,spawnData);
  424. spawns[spawnCount][0] = spawnData[0];
  425. spawns[spawnCount][1] = spawnData[1];
  426. spawns[spawnCount][2] = spawnData[2];
  427.  
  428. // angles
  429. pev(ent,pev_angles,spawnData);
  430. spawns[spawnCount][3] = spawnData[0];
  431. spawns[spawnCount][4] = spawnData[1];
  432. spawns[spawnCount][5] = spawnData[2];
  433.  
  434. // vangles
  435. spawns[spawnCount][6] = spawnData[0];
  436. spawns[spawnCount][7] = spawnData[1];
  437. spawns[spawnCount][8] = spawnData[2];
  438.  
  439. spawnCount++;
  440. if(spawnCount >= MAX_SPAWNS) break;
  441. }
  442. }
  443.  
  444. // delay for server.cfg
  445. set_task(1.0,"toggle_gungame",TASK_TOGGLE_GUNGAME + TOGGLE_FORCE);
  446.  
  447. // manage pruning (longer delay for toggle_gungame)
  448. set_task(2.0,"manage_pruning");
  449. }
  450.  
  451. // plugin ends, prune stats file maybe
  452. public plugin_end()
  453. {
  454. // run endmap setup on plugin close
  455. if(get_pcvar_num(gg_enabled))
  456. {
  457. new setup[512];
  458. get_pcvar_string(gg_endmap_setup,setup,511);
  459. if(setup[0]) server_cmd(setup);
  460. }
  461. }
  462.  
  463. // setup native filter for cs_respawn
  464. public plugin_natives()
  465. {
  466. set_native_filter("native_filter");
  467. }
  468.  
  469. // don't throw error on cs_respawn if not running module
  470. public native_filter(const name[],index,trap)
  471. {
  472. if(equal(name,"cs_respawn"))
  473. return PLUGIN_HANDLED;
  474.  
  475. return PLUGIN_CONTINUE;
  476. }
  477.  
  478. // manage stats pruning
  479. public manage_pruning()
  480. {
  481. get_pcvar_string(gg_stats_file,sfFile,63);
  482.  
  483. // stats disabled/file doesn't exist/pruning disabled
  484. if(!sfFile[0] || !file_exists(sfFile) || !get_pcvar_num(gg_stats_prune)) return;
  485.  
  486. // get how many plugin ends more until we prune
  487. new prune_in_str[3], prune_in;
  488. get_localinfo("gg_prune_in",prune_in_str,2);
  489. prune_in = str_to_num(prune_in_str);
  490.  
  491. // localinfo not set yet
  492. if(!prune_in)
  493. {
  494. set_localinfo("gg_prune_in","9");
  495. return;
  496. }
  497.  
  498. // time to prune
  499. if(prune_in == 1)
  500. {
  501. // prune and log
  502. log_amx("%L",LANG_SERVER,"PRUNING",sfFile,stats_prune());
  503.  
  504. // reset our prune count
  505. set_localinfo("gg_prune_in","10");
  506. return;
  507. }
  508.  
  509. // decrement our count
  510. num_to_str(prune_in-1,prune_in_str,2);
  511. set_localinfo("gg_prune_in",prune_in_str);
  512. }
  513.  
  514. // manage warmup mode
  515. public warmup_check(taskid)
  516. {
  517. warmup--;
  518. set_hudmessage(255,255,255,-1.0,0.4,0,6.0,1.0,0.1,0.2,CHANNEL_WARMUP);
  519.  
  520. if(warmup <= 0)
  521. {
  522. warmup = -13;
  523.  
  524. show_hudmessage(0,"%L",LANG_PLAYER,"WARMUP_ROUND_OVER");
  525. set_cvar_num("sv_restartround",1);
  526. }
  527. else
  528. {
  529.  
  530. show_hudmessage(0,"%L",LANG_PLAYER,"WARMUP_ROUND_DISPLAY",warmup);
  531. set_task(1.0,"warmup_check",taskid);
  532. }
  533. }
  534.  
  535. // plugin precache
  536. public plugin_precache()
  537. {
  538. precache_sound_by_cvar("gg_sound_levelup","gungame/smb3_powerup.wav");
  539. precache_sound_by_cvar("gg_sound_leveldown","gungame/smb3_powerdown.wav");
  540. precache_sound_by_cvar("gg_sound_nade","gungame/nade_level.wav");
  541. precache_sound_by_cvar("gg_sound_knife","gungame/knife_level.wav");
  542. precache_sound_by_cvar("gg_sound_welcome","gungame/gungame2.wav");
  543. precache_sound_by_cvar("gg_sound_triple","gungame/smb_star.wav");
  544. precache_sound_by_cvar("gg_sound_winner","media/Half-Life08.mp3");
  545.  
  546. precache_sound("gungame/brass_bell_C.wav");
  547. precache_sound("buttons/bell1.wav");
  548. precache_sound("common/null.wav");
  549.  
  550. trailSpr = precache_model("sprites/laserbeam.spr");
  551. }
  552.  
  553. //
  554. // FORWARDS
  555. //
  556.  
  557. // client gets a steamid
  558. public client_authorized(id)
  559. {
  560. clear_values(id);
  561.  
  562. get_pcvar_string(gg_stats_file,sfFile,63);
  563.  
  564. static authid[24];
  565.  
  566. if(get_pcvar_num(gg_stats_ip)) get_user_ip(id,authid,23);
  567. else get_user_authid(id,authid,23);
  568.  
  569. // refresh timestamp if we should
  570. if(sfFile[0]) stats_refresh_timestamp(authid);
  571.  
  572. // load temporary save
  573. if(get_pcvar_num(gg_enabled) && get_pcvar_num(gg_save_temp))
  574. {
  575. new i, save = -1;
  576.  
  577. // find our possible temp save
  578. for(i=0;i<TEMP_SAVES;i++)
  579. {
  580. if(equal(authid,tempSave[i],23))
  581. {
  582. save = i;
  583. break;
  584. }
  585. }
  586.  
  587. // no temp save
  588. if(save == -1) return;
  589.  
  590. // load values
  591. level[id] = tempSave[save][24];
  592. score[id] = tempSave[save][25];
  593.  
  594. // clear it
  595. clear_save(TASK_CLEAR_SAVE+save);
  596.  
  597. // get the name (almost forgot!)
  598. get_weapon_name_by_level(level[id],weapon[id],23);
  599. }
  600. }
  601.  
  602. // client leaves, reset values
  603. public client_disconnect(id)
  604. {
  605. // remove certain tasks
  606. remove_task(TASK_RESPAWN+id);
  607. remove_task(TASK_CHECK_RESPAWN+id);
  608. remove_task(TASK_CHECK_RESPAWN2+id);
  609. remove_task(TASK_CHECK_DEATHMATCH+id);
  610. remove_task(TASK_REMOVE_PROTECTION+id);
  611. remove_task(TASK_VERIFY_WEAPON+id);
  612. remove_task(TASK_DELAYED_SUICIDE+id);
  613. remove_task(TASK_REFRESH_NADE+id);
  614.  
  615. // clear bomb planter
  616. if(c4planter == id) c4planter = 0;
  617.  
  618. // don't bother saving if in winning period
  619. if(!won)
  620. {
  621. new save_temp = get_pcvar_num(gg_save_temp);
  622.  
  623. // temporarily save values
  624. if(get_pcvar_num(gg_enabled) && save_temp && (level[id] > 1 || score[id] > 0))
  625. {
  626. new freeSave = -1, oldestSave = -1, i;
  627.  
  628. for(i=0;i<TEMP_SAVES;i++)
  629. {
  630. // we found a free one
  631. if(!tempSave[i][0])
  632. {
  633. freeSave = i;
  634. break;
  635. }
  636.  
  637. // keep track of one soonest to expire
  638. if(oldestSave == -1 || tempSave[i][26] < tempSave[oldestSave][26])
  639. oldestSave = i;
  640. }
  641.  
  642. // no free, use oldest
  643. if(freeSave == -1) freeSave = oldestSave;
  644.  
  645. if(get_pcvar_num(gg_stats_ip)) get_user_ip(id,tempSave[freeSave],23);
  646. else get_user_authid(id,tempSave[freeSave],23);
  647.  
  648. tempSave[freeSave][24] = level[id];
  649. tempSave[freeSave][25] = score[id];
  650. tempSave[freeSave][26] = floatround(get_gametime());
  651.  
  652. set_task(float(save_temp),"clear_save",TASK_CLEAR_SAVE+freeSave);
  653. }
  654. }
  655.  
  656. clear_values(id);
  657. }
  658.  
  659. // remove a save
  660. public clear_save(taskid)
  661. {
  662. remove_task(taskid);
  663. tempSave[taskid-TASK_CLEAR_SAVE][0] = 0;
  664. }
  665.  
  666. // clear all saved values
  667. stock clear_values(id,ignoreWelcome=0)
  668. {
  669. level[id] = 0;
  670. levelsThisRound[id] = 0;
  671. score[id] = 0;
  672. weapon[id][0] = 0;
  673. star[id] = 0;
  674. if(!ignoreWelcome) welcomed[id] = 0;
  675. spawnProtected[id] = 0;
  676. blockResetHUD[id] = 0;
  677. page[id] = 0;
  678. blockCorpse[id] = 0;
  679. respawn_timeleft[id] = 0;
  680. silenced[id] = 0;
  681. spawnSounds[id] = 1;
  682. oldTeam[id] = 0;
  683. }
  684.  
  685. // an entity is given a model, stop weapons from
  686. // dropping in DM mode so that it doesn't get clustered
  687. public fw_setmodel(ent,model[])
  688. {
  689. if(!get_pcvar_num(gg_enabled) || !pev_valid(ent) || !model[0])
  690. return FMRES_IGNORED;
  691.  
  692. new owner = pev(ent,pev_owner);
  693.  
  694. // no owner
  695. if(!is_user_connected(owner)) return FMRES_IGNORED;
  696.  
  697. static classname[24];
  698. pev(ent,pev_classname,classname,10);
  699.  
  700. // not a weapon
  701. // checks for weaponbox, weapon_shield
  702. if(classname[8] != 'x' && !(classname[6] == '_' && classname[7] == 's' && classname[8] == 'h'))
  703. return FMRES_IGNORED;
  704.  
  705. // makes sure we don't get memory access error,
  706. // but also helpful to narrow down matches
  707. new len = strlen(model);
  708.  
  709. // ignore weaponboxes whose models haven't been set to correspond with their weapon types yet
  710. // checks for models/w_weaponbox.mdl
  711. if(len == 22 && model[17] == 'x') return FMRES_IGNORED;
  712.  
  713. // C4 should always drop
  714. // checks for models/w_backpack.mdl
  715. if(len == 21 && model[9] == 'b') return FMRES_IGNORED;
  716.  
  717. // if owner is dead
  718. if(get_user_health(owner) <= 0)
  719. {
  720. // first, remember silenced or burst status
  721.  
  722. // checks for models/w_usp.mdl, usp, models/w_m4a1.mdl, m4a1
  723. if( (len == 16 && model[10] == 's' && weapon[owner][1] == 's')
  724. || (len == 17 && model[10] == '4' && weapon[owner][1] == '4') )
  725. {
  726. copyc(model,len-1,model[containi(model,"_")+1],'.'); // strips off models/w_ and .mdl
  727. formatex(classname,23,"weapon_%s",model);
  728.  
  729. new wEnt = fm_find_ent_by_owner(maxPlayers,classname,ent);
  730. if(pev_valid(wEnt)) silenced[owner] = cs_get_weapon_silen(wEnt);
  731. }
  732.  
  733. // checks for models/w_glock18.mdl, glock18, models/w_famas.mdl, famas
  734. else if( (len == 20 && model[15] == '8' && weapon[owner][6] == '8')
  735. || (len == 18 && model[9] == 'f' && model[10] == 'a' && weapon[owner][0] == 'f' && weapon[owner][1] == 'a') )
  736. {
  737. copyc(model,len-1,model[containi(model,"_")+1],'.'); // strips off models/w_ and .mdl
  738. formatex(classname,23,"weapon_%s",model);
  739.  
  740. new wEnt = fm_find_ent_by_owner(maxPlayers,classname,ent);
  741. if(pev_valid(wEnt)) silenced[owner] = cs_get_weapon_burst(wEnt);
  742. }
  743.  
  744. if(get_pcvar_num(gg_dm) && !get_pcvar_num(gg_pickup_others))
  745. {
  746. // then remove it
  747. dllfunc(DLLFunc_Think,ent);
  748. }
  749. }
  750.  
  751. return FMRES_IGNORED;
  752. }
  753.  
  754. // touchy touchy
  755. public fw_touch(touched,toucher)
  756. {
  757. // invalid entities involved or gungame disabled
  758. if(!get_pcvar_num(gg_enabled) || !pev_valid(touched) || !is_user_connected(toucher))
  759. return FMRES_IGNORED;
  760.  
  761. static classname[10];
  762. pev(touched,pev_classname,classname,9);
  763.  
  764. // not touching a weapon-giver
  765. // checks for weaponbox, weapon_*, armoury_*
  766. if(classname[8] != 'x'
  767. && !(classname[0] == 'w' && classname[1] == 'e' && classname[2] == 'a')
  768. && !(classname[0] == 'a' && classname[1] == 'r' && classname[2] == 'm'))
  769. return FMRES_IGNORED;
  770.  
  771. // removing starting pistols
  772. if(fm_halflife_time() - spawnTime[toucher] < 0.2)
  773. {
  774. dllfunc(DLLFunc_Think,touched);
  775. return FMRES_SUPERCEDE;
  776. }
  777.  
  778. static model[24];
  779. pev(touched,pev_model,model,23);
  780.  
  781. // not touching the kind of weaponbox that we like
  782. // checks for models/w_weaponbox.mdl
  783. if(model[17] == 'x') return FMRES_IGNORED;
  784.  
  785. // allow pickup of C4
  786. // checks for models/w_backpack.mdl
  787. if(model[9] == 'b') return FMRES_IGNORED;
  788.  
  789. // knife warmup, no weapons allowed
  790. if(warmup > 0 && get_pcvar_num(gg_knife_warmup))
  791. return FMRES_SUPERCEDE;
  792.  
  793. // we are allowed to pick up other weapons
  794. if(get_pcvar_num(gg_pickup_others))
  795. return FMRES_IGNORED;
  796.  
  797. // weapon is weapon_mp5navy, but model is w_mp5.mdl
  798. // checks for models/w_mp5.mdl
  799. if(model[10] == 'p' && model[11] == '5') model = "mp5navy";
  800.  
  801. // get the type of weapon based on model
  802. else
  803. {
  804. replace(model,23,"models/w_","");
  805. replace(model,23,".mdl","");
  806. }
  807.  
  808. // everyone is allowed to use knife
  809. // checks for knife
  810. if(model[0] == 'k') return FMRES_IGNORED;
  811.  
  812. // check hegrenade exceptions
  813. // checks for hegrenade
  814. if(weapon[toucher][0] == 'h')
  815. {
  816. if(model[6] == '8' && get_pcvar_num(gg_nade_glock)) return FMRES_IGNORED; // glock18
  817. if(model[0] == 's' && model[1] == 'm' && get_pcvar_num(gg_nade_smoke)) return FMRES_IGNORED; // smokegrenade
  818. if(model[0] == 'f' && model[1] == 'l' && get_pcvar_num(gg_nade_flash)) return FMRES_IGNORED; // flashbang
  819. }
  820.  
  821. // this is our weapon, don't mess with it
  822. if(equal(weapon[toucher],model)) return FMRES_IGNORED;
  823.  
  824. // otherwise, this is an item we're not allowed to have
  825. return FMRES_SUPERCEDE;
  826. }
  827.  
  828. // HELLO HELLo HELlo HEllo Hello hello
  829. public fw_emitsound(ent,channel,sample[],Float:volume,Float:atten,flags,pitch)
  830. {
  831. if(!get_pcvar_num(gg_enabled) || !is_user_connected(ent) || !get_pcvar_num(gg_dm) || spawnSounds[ent])
  832. return FMRES_IGNORED;
  833.  
  834. return FMRES_SUPERCEDE;
  835. }
  836.  
  837. //
  838. // EVENT HOOKS
  839. //
  840.  
  841. // respawnish
  842. public event_resethud(id)
  843. {
  844. if(!get_pcvar_num(gg_enabled) || !is_user_connected(id))
  845. return;
  846.  
  847. remove_task(TASK_CHECK_DEATHMATCH+id);
  848.  
  849. // ignore first ResetHUD after sv_restartround
  850. if(blockResetHUD[id])
  851. {
  852. set_task(0.1,"hide_money",id);
  853. blockResetHUD[id]--;
  854. return;
  855. }
  856.  
  857. // have not joined yet
  858. new CsTeams:team = cs_get_user_team(id);
  859. if(team != CS_TEAM_T && team != CS_TEAM_CT) return;
  860.  
  861. spawnTime[id] = fm_halflife_time();
  862.  
  863. status_display(id);
  864. set_task(0.1,"post_resethud",id);
  865. }
  866.  
  867. // our delay
  868. public post_resethud(id)
  869. {
  870. if(!is_user_connected(id) || pev(id,pev_iuser1)) return;
  871.  
  872. levelsThisRound[id] = 0;
  873.  
  874. // just joined
  875. if(!level[id])
  876. {
  877. // handicap
  878. new handicapMode = get_pcvar_num(gg_handicap_on);
  879. if(handicapMode)
  880. {
  881. new rcvHandicap = 1;
  882.  
  883. get_pcvar_string(gg_stats_file,sfFile,63);
  884.  
  885. // top10 doesn't receive handicap -- also make sure we are using top10
  886. if(!get_pcvar_num(gg_top10_handicap) && sfFile[0] && file_exists(sfFile) && get_pcvar_num(gg_stats_mode))
  887. {
  888. static authid[24];
  889.  
  890. if(get_pcvar_num(gg_stats_ip)) get_user_ip(id,authid,23);
  891. else get_user_authid(id,authid,23);
  892.  
  893. new i;
  894. for(i=0;i<TOP_PLAYERS;i++)
  895. {
  896. // blank
  897. if(!top10[i][0]) continue;
  898.  
  899. // isolate authid
  900. strtok(top10[i],sfAuthid,23,dummy,1,'^t');
  901.  
  902. // I'm in top10, don't give me handicap
  903. if(equal(authid,sfAuthid))
  904. {
  905. rcvHandicap = 0;
  906. break;
  907. }
  908. }
  909. }
  910.  
  911. if(rcvHandicap)
  912. {
  913. new players[32], num, i;
  914. get_players(players,num);
  915.  
  916. // find lowest level (don't use bots unless we have to)
  917. if(handicapMode == 2)
  918. {
  919. new isBot, myLevel, lowestLevel, lowestBotLevel;
  920. for(i=0;i<num;i++)
  921. {
  922. if(players[i] == id)
  923. continue;
  924.  
  925. isBot = is_user_bot(players[i]);
  926. myLevel = level[players[i]];
  927.  
  928. if(!myLevel) continue;
  929.  
  930. if(!isBot && (!lowestLevel || myLevel < lowestLevel))
  931. lowestLevel = myLevel;
  932. else if(isBot && (!lowestBotLevel || myLevel < lowestBotLevel))
  933. lowestBotLevel = myLevel;
  934. }
  935.  
  936. // CLAMP!
  937. if(!lowestLevel) lowestLevel = 1;
  938. if(!lowestBotLevel) lowestBotLevel = 1;
  939.  
  940. change_level(id,(lowestLevel > 1) ? lowestLevel : lowestBotLevel,1,0);
  941. }
  942.  
  943. // find average level
  944. else
  945. {
  946. new Float:average;
  947. for(i=0;i<num;i++)
  948. {
  949. if(players[i] != id)
  950. average += float(level[players[i]]);
  951. }
  952.  
  953. average /= float(num)-1;
  954. change_level(id,(average >= 0.5) ? floatround(average) : 1,1,0);
  955. }
  956. }
  957.  
  958. // not eligible for handicap (in top10 with gg_top10_handicap disabled)
  959. else change_level(id,1,1,0);
  960. }
  961.  
  962. // no handicap enabled
  963. else change_level(id,1,1,0);
  964.  
  965. give_level_weapon(id);
  966. }
  967.  
  968. // didn't just join
  969. else
  970. {
  971. if(star[id])
  972. {
  973. end_star(TASK_END_STAR+id);
  974. remove_task(TASK_END_STAR+id);
  975. }
  976.  
  977. get_weapon_name_by_level(level[id],weapon[id],23);
  978. give_level_weapon(id);
  979. refill_ammo(id);
  980. }
  981.  
  982. // show welcome message
  983. if(!welcomed[id] && get_pcvar_num(gg_join_msg))
  984. show_welcome(id);
  985.  
  986. // update bomb for DM
  987. if(cs_get_user_team(id) == CS_TEAM_T && !get_pcvar_num(gg_block_objectives) && get_pcvar_num(gg_dm))
  988. {
  989.  
  990. if(bombStatus[3] == BOMB_PICKEDUP)
  991. {
  992. message_begin(MSG_ONE,gmsgBombPickup,_,id);
  993. message_end();
  994. }
  995. else if(bombStatus[0] || bombStatus[1] || bombStatus[2])
  996. {
  997. message_begin(MSG_ONE,gmsgBombDrop,_,id);
  998. write_coord(bombStatus[0]);
  999. write_coord(bombStatus[1]);
  1000. write_coord(bombStatus[2]);
  1001. write_byte(bombStatus[3]);
  1002. message_end();
  1003. }
  1004. }
  1005.  
  1006. hide_money(id);
  1007. }
  1008.  
  1009. // hide someone's money display
  1010. public hide_money(id)
  1011. {
  1012. // hide money
  1013. message_begin(MSG_ONE,gmsgHideWeapon,_,id);
  1014. write_byte(1<<5);
  1015. message_end();
  1016.  
  1017. // hide crosshair that appears from hiding money
  1018. message_begin(MSG_ONE,gmsgCrosshair,_,id);
  1019. write_byte(0);
  1020. message_end();
  1021. }
  1022.  
  1023. // someone has been killed
  1024. public event_deathmsg()
  1025. {
  1026. if(!get_pcvar_num(gg_enabled)) return;
  1027.  
  1028. new killer = read_data(1);
  1029. new victim = read_data(2);
  1030.  
  1031. new Float:time = fm_halflife_time();
  1032.  
  1033. // a bug with valve's code (dvander said so!):
  1034. // sometimes, when using an item giving code
  1035. // (as that's where this can lead) within a message
  1036. // hook, the message hook can get called twice.
  1037. // so, if this player "dies" twice within X seconds,
  1038. // it's obviously a bugged message, so ignore.
  1039. if(time - lastDeathMsg[victim] < 0.2)
  1040. return;
  1041.  
  1042. lastDeathMsg[victim] = time;
  1043.  
  1044. remove_task(TASK_VERIFY_WEAPON+victim);
  1045.  
  1046. star[victim] = 0;
  1047. remove_task(TASK_END_STAR+victim);
  1048.  
  1049. // allow us to join in on deathmatch
  1050. if(!get_pcvar_num(gg_dm))
  1051. {
  1052. remove_task(TASK_CHECK_DEATHMATCH+victim);
  1053. set_task(10.0,"check_deathmatch",TASK_CHECK_DEATHMATCH+victim);
  1054. }
  1055.  
  1056. // respawn us
  1057. else
  1058. {
  1059. remove_task(TASK_RESPAWN+victim);
  1060. remove_task(TASK_CHECK_RESPAWN+victim);
  1061. remove_task(TASK_CHECK_RESPAWN2+victim);
  1062. remove_task(TASK_REMOVE_PROTECTION+victim);
  1063. set_task(0.1,"begin_respawn",victim);
  1064. fm_set_user_rendering(victim); // clear spawn protection
  1065. }
  1066.  
  1067. // stops defusal kits from dropping in deathmatch mode
  1068. if(bombMap && get_pcvar_num(gg_dm)) cs_set_user_defuse(victim,0);
  1069.  
  1070. // remember victim's silenced status
  1071. if(equal(weapon[victim],"usp") || equal(weapon[victim],"m4a1"))
  1072. {
  1073. new wEnt = get_weapon_ent(victim,_,weapon[victim]);
  1074. if(pev_valid(wEnt)) silenced[victim] = cs_get_weapon_silen(wEnt);
  1075. }
  1076.  
  1077. // or, remember burst status
  1078. else if(equal(weapon[victim],"glock18") || equal(weapon[victim],"famas"))
  1079. {
  1080. new wEnt = get_weapon_ent(victim,_,weapon[victim]);
  1081. if(pev_valid(wEnt)) silenced[victim] = cs_get_weapon_burst(wEnt);
  1082. }
  1083.  
  1084. // NOTE: simply calling fm_remove_entity on defusal kits after they are dropped
  1085. // has the potential to cause a crash. the crash was pinpointed with the help of
  1086. // raa, and the solution was offered by VEN.
  1087.  
  1088. static wpnName[24];
  1089. read_data(4,wpnName,23);
  1090.  
  1091. // deaths by hegrenade are reported as grenade, fix
  1092. if(wpnName[0] == 'g' && wpnName[1] == 'r' && wpnName[2] == 'e')
  1093. wpnName = "hegrenade";
  1094.  
  1095. // killed self with worldspawn
  1096. if(equal(wpnName,"worldspawn"))
  1097. {
  1098. if(get_pcvar_num(gg_worldspawn_suicide)) player_suicided(victim);
  1099. return;
  1100. }
  1101.  
  1102.  
  1103. // killed self not with worldspawn
  1104. if(killer == victim)
  1105. {
  1106. if(!roundEnded && get_pcvar_num(gg_allow_changeteam) && equal(wpnName,"world"))
  1107. {
  1108. oldTeam[victim] = get_user_team(victim);
  1109. set_task(0.1,"delayed_suicide",TASK_DELAYED_SUICIDE+victim);
  1110. }
  1111. else player_suicided(victim);
  1112.  
  1113. return;
  1114. }
  1115.  
  1116. // team kill
  1117. if(get_user_team(killer) == get_user_team(victim))
  1118. {
  1119. new penalty = get_pcvar_num(gg_tk_penalty);
  1120.  
  1121. if(penalty > 0)
  1122. {
  1123. new name[32];
  1124. get_user_name(killer,name,31);
  1125.  
  1126. if(score[killer] - penalty < 0)
  1127. gungame_print(0,killer,"%L",LANG_PLAYER_C,"TK_LEVEL_DOWN",name,(level[killer] > 1) ? level[killer]-1 : level[killer]);
  1128. else
  1129. gungame_print(0,killer,"%L",LANG_PLAYER_C,"TK_SCORE_DOWN",name,penalty);
  1130.  
  1131. change_score(killer,-penalty);
  1132. }
  1133.  
  1134. return;
  1135. }
  1136.  
  1137. // other player had spawn protection
  1138. if(spawnProtected[victim])
  1139. {
  1140. new name[32];
  1141. get_user_name(victim,name,31);
  1142.  
  1143. gungame_print(killer,victim,"%L",killer,"SPAWNPROTECTED_KILL",name,floatround(get_pcvar_float(gg_dm_sp_time)));
  1144. return;
  1145. }
  1146.  
  1147. new canLevel = 1, scored;
  1148.  
  1149. // already reached max levels this round
  1150. new max_lvl = get_pcvar_num(gg_max_lvl);
  1151. if(!get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[killer] >= max_lvl)
  1152. canLevel = 0;
  1153.  
  1154. // was it a knife kill, and does it matter?
  1155. if(equal(wpnName,"knife") && get_pcvar_num(gg_knife_pro) && !equal(weapon[killer],"knife"))
  1156. {
  1157. // knife warmup, don't bother leveling up
  1158. if(warmup > 0 && get_pcvar_num(gg_knife_warmup)) return;
  1159.  
  1160. static killerName[32], victimName[32];
  1161. get_user_name(killer,killerName,31);
  1162. get_user_name(victim,victimName,31);
  1163.  
  1164. gungame_print(0,killer,"%L",LANG_PLAYER_C,"STOLE_LEVEL",killerName,victimName);
  1165.  
  1166. if(canLevel && !equal(weapon[killer],"hegrenade"))
  1167. {
  1168. if(level[killer] < get_weapon_num()) change_level(killer,1);
  1169. }
  1170.  
  1171. if(level[victim] > 1) change_level(victim,-1);
  1172. }
  1173.  
  1174. // otherwise, if he killed with his appropiate weapon, give him a point
  1175. else if(canLevel && equal(weapon[killer],wpnName))
  1176. {
  1177. scored = 1;
  1178.  
  1179. // didn't level off of it
  1180. if(!change_score(killer,1)) show_required_kills(killer);
  1181. }
  1182.  
  1183. // award for killing hostage carrier
  1184. new host_kill_reward = get_pcvar_num(gg_host_kill_reward);
  1185.  
  1186. // note that this doesn't work with CZ hostages
  1187. if(hostageMap && !czero && host_kill_reward && !equal(weapon[killer],"hegrenade") && !equal(weapon[killer],"knife"))
  1188. {
  1189. // check for hostages following this player
  1190. new hostage;
  1191. while((hostage = fm_find_ent_by_class(hostage,"hostage_entity")) != 0)
  1192. {
  1193. if(cs_get_hostage_foll(hostage) == victim && pev(hostage,pev_deadflag) == DEAD_NO)
  1194. break;
  1195. }
  1196.  
  1197. // award bonus score if victim had hostages
  1198. if(hostage)
  1199. {
  1200. scored = 1;
  1201.  
  1202. if(!equali(weapon[killer],"hegrenade") && !equali(weapon[killer],"knife") && level[killer] < get_weapon_num())
  1203. {
  1204. // didn't level off of it
  1205. if(!change_score(killer,host_kill_reward) || score[killer])
  1206. show_required_kills(killer);
  1207. }
  1208. }
  1209. }
  1210.  
  1211. if(equal(weapon[killer],"hegrenade") && get_pcvar_num(gg_extra_nades) && !cs_get_user_bpammo(killer,CSW_HEGRENADE))
  1212. {
  1213. fm_give_item(killer,"weapon_hegrenade");
  1214. remove_task(TASK_REFRESH_NADE+killer);
  1215. }
  1216.  
  1217. if((!scored || !get_pcvar_num(gg_turbo)) && get_pcvar_num(gg_refill_on_kill))
  1218. refill_ammo(killer,1);
  1219. }
  1220.  
  1221. // task is set on a potential team change, and removed on an
  1222. // approved team change, so if we reach it, deduct level
  1223. public delayed_suicide(taskid)
  1224. {
  1225. new id = taskid-TASK_DELAYED_SUICIDE;
  1226.  
  1227. oldTeam[id] = 0;
  1228. if(is_user_connected(id)) player_suicided(id);
  1229. }
  1230.  
  1231. // someone changes weapons
  1232. public event_curweapon(id)
  1233. {
  1234. if(!get_pcvar_num(gg_enabled)) return;
  1235.  
  1236. // keep star speed
  1237. if(star[id]) fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)*1.5);
  1238.  
  1239. // have only 1 ammo in awp clip
  1240. if(get_pcvar_num(gg_awp_oneshot) && read_data(2) == CSW_AWP && read_data(3) > 1)
  1241. {
  1242. new wEnt = get_weapon_ent(id,CSW_AWP);
  1243. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,1);
  1244.  
  1245. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  1246. write_byte(1);
  1247. write_byte(CSW_AWP);
  1248. write_byte(1);
  1249. message_end();
  1250. }
  1251. }
  1252.  
  1253. // ammo amount changes
  1254. public event_ammox(id)
  1255. {
  1256. new type = read_data(1);
  1257.  
  1258. // not HE grenade ammo, or not on the grenade level
  1259. if(type != 12 || !equali(weapon[id],"hegrenade")) return;
  1260.  
  1261. new amount = read_data(2);
  1262.  
  1263. // still have some left, ignore
  1264. if(amount > 0)
  1265. {
  1266. remove_task(TASK_REFRESH_NADE+id);
  1267. return;
  1268. }
  1269.  
  1270. new Float:refresh = get_pcvar_float(gg_nade_refresh);
  1271.  
  1272. // refreshing is disabled, or we are already giving one out
  1273. if(refresh <= 0.0 || task_exists(TASK_REFRESH_NADE+id)) return;
  1274.  
  1275. // start the timer for the new grenade
  1276. set_task(refresh,"refresh_nade",TASK_REFRESH_NADE+id);
  1277. }
  1278.  
  1279. // a new round has begun
  1280. public event_new_round()
  1281. {
  1282. roundsElapsed++;
  1283.  
  1284. if(!autovoted)
  1285. {
  1286. new autovote_rounds = get_pcvar_num(gg_autovote_rounds);
  1287.  
  1288. if(autovote_rounds && gameCommenced && roundsElapsed >= autovote_rounds)
  1289. {
  1290. autovoted = 1;
  1291. set_task(get_pcvar_float(gg_autovote_delay),"autovote_start");
  1292. }
  1293. }
  1294.  
  1295. // game_player_equip
  1296. manage_equips();
  1297.  
  1298. if(!get_pcvar_num(gg_enabled)) return;
  1299.  
  1300. roundEnded = 0;
  1301. c4planter = 0;
  1302. bombStatus[3] = BOMB_PICKEDUP;
  1303.  
  1304. // block hostages
  1305. if(hostageMap && get_pcvar_num(gg_block_objectives))
  1306. set_task(0.1,"move_hostages");
  1307.  
  1308. new i;
  1309. for(i=0;i<33;i++)
  1310. {
  1311. hosties[i][0] = 0;
  1312. hosties[i][1] = 0;
  1313. }
  1314.  
  1315. new leader = get_leader(dummy[0]);
  1316.  
  1317. if(equal(weapon[leader],"hegrenade")) play_sound_by_cvar(0,gg_sound_nade);
  1318. else if(equal(weapon[leader],"knife")) play_sound_by_cvar(0,gg_sound_knife);
  1319.  
  1320. // start in random positions at round start
  1321. if(get_pcvar_num(gg_dm) && get_pcvar_num(gg_dm_start_random))
  1322. set_task(0.1,"randomly_place_everyone");
  1323. }
  1324.  
  1325. // what do you think??
  1326. public randomly_place_everyone()
  1327. {
  1328. new players[32], num, i, CsTeams:team;
  1329. get_players(players,num);
  1330.  
  1331. // count number of legitimate players
  1332. new validNum;
  1333. for(i=0;i<num;i++)
  1334. {
  1335. team = cs_get_user_team(players[i]);
  1336. if(team == CS_TEAM_T || team == CS_TEAM_CT) validNum++;
  1337. }
  1338.  
  1339. // not enough CSDM spawns for everyone
  1340. if(validNum > csdmSpawnCount)
  1341. return;
  1342.  
  1343. // now randomly place them
  1344. for(i=0;i<num;i++)
  1345. {
  1346. team = cs_get_user_team(players[i]);
  1347.  
  1348. // not spectator or unassigned
  1349. if(team == CS_TEAM_T || team == CS_TEAM_CT)
  1350. do_random_spawn(players[i],2);
  1351. }
  1352. }
  1353.  
  1354. // manage game_player_equip and player_weaponstrip entities
  1355. public manage_equips()
  1356. {
  1357. static classname[20], targetname[256];
  1358. new ent, i, block_equips = get_pcvar_num(gg_block_equips), enabled = get_pcvar_num(gg_enabled);
  1359.  
  1360. // go through both entities to monitor
  1361. for(i=0;i<2;i++)
  1362. {
  1363. // get classname for current iteration
  1364. switch(i)
  1365. {
  1366. case 0: classname = "game_player_equip";
  1367. default: classname = "player_weaponstrip";
  1368. }
  1369.  
  1370. // go through whatever entity
  1371. while((ent = fm_find_ent_by_class(ent,classname)) != 0)
  1372. {
  1373. pev(ent,pev_targetname,targetname,255);
  1374.  
  1375. // allowed to have this, reverse possible changes
  1376. if(!enabled || !block_equips || (i == 1 && block_equips < 2)) // player_weaponstrip switch
  1377. {
  1378. // this one was blocked
  1379. if(equali(targetname,"gg_block_equips"))
  1380. {
  1381. pev(ent,TNAME_SAVE,targetname,255);
  1382.  
  1383. set_pev(ent,pev_targetname,targetname);
  1384. set_pev(ent,TNAME_SAVE,"");
  1385. }
  1386. }
  1387.  
  1388. // not allowed to pickup others, make possible changes
  1389. else
  1390. {
  1391. pev(ent,pev_targetname,targetname,255);
  1392.  
  1393. // needs to be blocked, but hasn't been yet
  1394. if(targetname[0] && !equali(targetname,"gg_block_equips"))
  1395. {
  1396. set_pev(ent,TNAME_SAVE,targetname);
  1397. set_pev(ent,pev_targetname,"gg_block_equips");
  1398. }
  1399. }
  1400. }
  1401. }
  1402. }
  1403.  
  1404. // move the hostages so that CTs can't get to them
  1405. public move_hostages()
  1406. {
  1407. new ent;
  1408. while((ent = fm_find_ent_by_class(ent,"hostage_entity")) != 0)
  1409. set_pev(ent,pev_origin,Float:{8192.0,8192.0,8192.0});
  1410. }
  1411.  
  1412. // round is restarting (TAG: sv_restartround)
  1413. public event_round_restart()
  1414. {
  1415. static message[32];
  1416. read_data(2,message,31);
  1417.  
  1418. if(equal(message,"#Game_Commencing")) gameCommenced = 1;
  1419.  
  1420. if(!get_pcvar_num(gg_enabled)) return;
  1421.  
  1422. new block;
  1423.  
  1424. // block only on round restart, not game commencing
  1425. if(equal(message,"#Game_will_restart_in")) block = 1;
  1426.  
  1427. // don't reset values on game commencing,
  1428. // if it has already commenced once
  1429. else
  1430. {
  1431. if(gameStarted) return;
  1432. gameStarted = 1;
  1433. }
  1434.  
  1435. new players[32], num, i;
  1436. get_players(players,num);
  1437.  
  1438. for(i=0;i<num;i++)
  1439. {
  1440. clear_values(players[i],1);
  1441.  
  1442. // bots don't experience that ResetHUD on round restart
  1443. if(!is_user_bot(players[i]) && block) blockResetHUD[players[i]]++;
  1444. }
  1445. }
  1446.  
  1447. // map is changing
  1448. public event_intermission()
  1449. {
  1450. if(!get_pcvar_num(gg_enabled) || won) return;
  1451.  
  1452. // grab highest level
  1453. new leaderLevel;
  1454. get_leader(leaderLevel);
  1455.  
  1456. // grab player list
  1457. new players[32], pNum, winner, i;
  1458. get_players(players,pNum);
  1459.  
  1460. new topLevel[32], tlNum;
  1461.  
  1462. // get all of the highest level players
  1463. for(i=0;i<pNum;i++)
  1464. {
  1465. if(level[players[i]] == leaderLevel)
  1466. topLevel[tlNum++] = players[i];
  1467. }
  1468.  
  1469. // only one on top level
  1470. if(tlNum == 1) winner = topLevel[0];
  1471. else
  1472. {
  1473. new highestKills, frags;
  1474.  
  1475. // get the most kills
  1476. for(i=0;i<tlNum;i++)
  1477. {
  1478. frags = get_user_frags(topLevel[i]);
  1479.  
  1480. if(frags >= highestKills)
  1481. highestKills = frags;
  1482. }
  1483.  
  1484. new topKillers[32], tkNum;
  1485.  
  1486. // get all of the players with highest kills
  1487. for(i=0;i<tlNum;i++)
  1488. {
  1489. if(get_user_frags(topLevel[i]) == highestKills)
  1490. topKillers[tkNum++] = topLevel[i];
  1491. }
  1492.  
  1493. // only one on top kills
  1494. if(tkNum == 1) winner = topKillers[0];
  1495. else
  1496. {
  1497. new leastDeaths, deaths;
  1498.  
  1499. // get the least deaths
  1500. for(i=0;i<tkNum;i++)
  1501. {
  1502. deaths = cs_get_user_deaths(topKillers[i]);
  1503.  
  1504. if(deaths <= leastDeaths)
  1505. leastDeaths = deaths;
  1506. }
  1507.  
  1508. new leastDead[32], ldNum;
  1509.  
  1510. // get all of the players with lowest deaths
  1511. for(i=0;i<tkNum;i++)
  1512. {
  1513. if(cs_get_user_deaths(topKillers[i]) == leastDeaths)
  1514. leastDead[ldNum++] = topKillers[i];
  1515. }
  1516.  
  1517. leastDead[random_num(0,ldNum-1)];
  1518. }
  1519. }
  1520.  
  1521. // crown them
  1522. win(winner);
  1523. }
  1524.  
  1525. // the bomb explodes
  1526. public event_bomb_detonation()
  1527. {
  1528. if(!get_pcvar_num(gg_enabled) || get_pcvar_num(gg_bomb_defuse_lvl) != 2 || !c4planter)
  1529. return;
  1530.  
  1531. new id = c4planter;
  1532. c4planter = 0;
  1533.  
  1534. if(!is_user_connected(id)) return;
  1535.  
  1536. if(!equal(weapon[id],"hegrenade") && !equal(weapon[id],"knife") && level[id] < get_weapon_num())
  1537. {
  1538. change_level(id,1);
  1539. //score[id] = 0;
  1540. }
  1541. else if(is_user_alive(id)) refill_ammo(id);
  1542. }
  1543.  
  1544. // scenario changes
  1545. public message_scenario(msg_id,msg_dest,msg_entity)
  1546. {
  1547. // disabled
  1548. if(!get_pcvar_num(gg_enabled))
  1549. return PLUGIN_CONTINUE;
  1550.  
  1551. // don't override our custom display, if we have one
  1552. if(get_pcvar_num(gg_status_display))
  1553. return PLUGIN_HANDLED;
  1554.  
  1555. // block hostage display if we disabled objectives
  1556. else if(get_msg_args() > 1 && get_pcvar_num(gg_block_objectives))
  1557. {
  1558. new sprite[8];
  1559. get_msg_arg_string(2,sprite,7);
  1560.  
  1561. if(equal(sprite,"hostage"))
  1562. return PLUGIN_HANDLED;
  1563. }
  1564.  
  1565. return PLUGIN_CONTINUE;
  1566. }
  1567.  
  1568. // bomb is dropped, remember for DM
  1569. public message_bombdrop(msg_id,msg_dest,msg_entity)
  1570. {
  1571. if(get_pcvar_num(gg_enabled) && get_pcvar_num(gg_block_objectives))
  1572. return PLUGIN_HANDLED;
  1573.  
  1574. // you can't simply get_msg_arg_int the coords
  1575. bombStatus[0] = floatround(get_msg_arg_float(1));
  1576. bombStatus[1] = floatround(get_msg_arg_float(2));
  1577. bombStatus[2] = floatround(get_msg_arg_float(3));
  1578. bombStatus[3] = get_msg_arg_int(4);
  1579.  
  1580. return PLUGIN_CONTINUE;
  1581. }
  1582.  
  1583. // bomb is picked up, remember for DM
  1584. public message_bombpickup(msg_id,msg_dest,msg_entity)
  1585. {
  1586. bombStatus[3] = BOMB_PICKEDUP;
  1587. return PLUGIN_CONTINUE;
  1588. }
  1589.  
  1590. // money money money!
  1591. public message_money(msg_id,msg_dest,msg_entity)
  1592. {
  1593. if(!get_pcvar_num(gg_enabled) || !is_user_connected(msg_entity) || !is_user_alive(msg_entity))
  1594. return PLUGIN_CONTINUE;
  1595.  
  1596. // this now just changes the value of the message, passes it along,
  1597. // and then modifies the pdata, instead of calling another cs_set_user_money
  1598. // and sending out more messages than needed.
  1599.  
  1600. set_msg_arg_int(1,ARG_LONG,0); // money
  1601. set_msg_arg_int(2,ARG_BYTE,0); // flash
  1602.  
  1603. set_pdata_int(msg_entity,OFFSET_CSMONEY,0,OFFSET_LINUX);
  1604. return PLUGIN_CONTINUE;
  1605. }
  1606.  
  1607. // a corpse is to be set, stop player shells bug (thanks sawce)
  1608. public message_clcorpse(msg_id,msg_dest,msg_entity)
  1609. {
  1610. if(!get_pcvar_num(gg_enabled) || get_msg_args() < 12)
  1611. return PLUGIN_CONTINUE;
  1612.  
  1613. if((get_pcvar_num(gg_dm) && !get_pcvar_num(gg_dm_corpses)) || blockCorpse[get_msg_arg_int(12)])
  1614. return PLUGIN_HANDLED;
  1615.  
  1616. return PLUGIN_CONTINUE;
  1617. }
  1618.  
  1619. // remove c4 if we disabled objectives
  1620. public message_weappickup(msg_id,msg_dest,msg_entity)
  1621. {
  1622. if(!bombMap || !get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_block_objectives))
  1623. return PLUGIN_CONTINUE;
  1624.  
  1625. if(get_msg_arg_int(1) == CSW_C4)
  1626. {
  1627. set_task(0.1,"strip_c4",msg_entity);
  1628. return PLUGIN_HANDLED;
  1629. }
  1630.  
  1631. return PLUGIN_CONTINUE;
  1632. }
  1633.  
  1634. // delay, since weappickup is slightly before we actually get the weapon
  1635. public strip_c4(id)
  1636. {
  1637. fm_strip_user_gun(id,CSW_C4);
  1638. }
  1639.  
  1640. // block c4 ammo message if we disabled objectives
  1641. public message_ammopickup(msg_id,msg_dest,msg_entity)
  1642. {
  1643. if(!bombMap || !get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_block_objectives))
  1644. return PLUGIN_CONTINUE;
  1645.  
  1646. if(get_msg_arg_int(1) == 14) // C4
  1647. return PLUGIN_HANDLED;
  1648.  
  1649. return PLUGIN_CONTINUE;
  1650. }
  1651.  
  1652. // block dropped the bomb message if we disabled objectives
  1653. public message_textmsg(msg_id,msg_dest,msg_entity)
  1654. {
  1655. if(!bombMap || !get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_block_objectives))
  1656. return PLUGIN_CONTINUE;
  1657.  
  1658. static message[16];
  1659. get_msg_arg_string(2,message,15);
  1660.  
  1661. if(equal(message,"#Game_bomb_drop"))
  1662. return PLUGIN_HANDLED;
  1663.  
  1664. return PLUGIN_CONTINUE;
  1665. }
  1666.  
  1667. // block hostages from appearing on radar if we disabled objectives
  1668. public message_hostagepos(msg_id,msg_dest,msg_entity)
  1669. {
  1670. if(!get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_block_objectives))
  1671. return PLUGIN_CONTINUE;
  1672.  
  1673. return PLUGIN_HANDLED;
  1674. }
  1675.  
  1676. //
  1677. // LOG EVENT HOOKS
  1678. //
  1679.  
  1680. // someone planted the bomb
  1681. public logevent_bomb_planted()
  1682. {
  1683. if(!get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_bomb_defuse_lvl) || roundEnded)
  1684. return;
  1685.  
  1686. new id = get_loguser_index();
  1687. if(!is_user_connected(id)) return;
  1688.  
  1689. if(get_pcvar_num(gg_bomb_defuse_lvl) == 2) c4planter = id;
  1690. else
  1691. {
  1692. if(!equal(weapon[id],"hegrenade") && !equal(weapon[id],"knife") && level[id] < get_weapon_num())
  1693. {
  1694. change_level(id,1);
  1695. //score[id] = 0;
  1696. }
  1697. else refill_ammo(id);
  1698. }
  1699.  
  1700. }
  1701.  
  1702. // someone defused the bomb
  1703. public logevent_bomb_defused()
  1704. {
  1705. if(!get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_bomb_defuse_lvl))
  1706. return;
  1707.  
  1708. new id = get_loguser_index();
  1709. if(!is_user_connected(id)) return;
  1710.  
  1711. if(!equal(weapon[id],"hegrenade") && !equal(weapon[id],"knife") && level[id] < get_weapon_num())
  1712. {
  1713. change_level(id,1);
  1714. //score[id] = 0;
  1715. }
  1716. else refill_ammo(id);
  1717. }
  1718.  
  1719. // the round ends
  1720. public logevent_round_end()
  1721. {
  1722. roundEnded = 1;
  1723. }
  1724.  
  1725. // hostage is touched
  1726. public logevent_hostage_touched()
  1727. {
  1728. new reward = get_pcvar_num(gg_host_touch_reward);
  1729.  
  1730. if(!get_pcvar_num(gg_enabled) || !reward || roundEnded)
  1731. return;
  1732.  
  1733. new id = get_loguser_index();
  1734. if(!is_user_connected(id) || hosties[id][0] == -1) return;
  1735.  
  1736. hosties[id][0]++;
  1737.  
  1738. if(hosties[id][0] >= reward)
  1739. {
  1740. if(!equal(weapon[id],"hegrenade") && !equal(weapon[id],"knife") && level[id] < get_weapon_num())
  1741. {
  1742. // didn't level off of it
  1743. if(!change_score(id,1)) show_required_kills(id);
  1744. }
  1745.  
  1746. hosties[id][0] = -1;
  1747. }
  1748. }
  1749.  
  1750. // hostage is rescued
  1751. public logevent_hostage_rescued()
  1752. {
  1753. new reward = get_pcvar_num(gg_host_rescue_reward);
  1754.  
  1755. if(!get_pcvar_num(gg_enabled) || !reward || roundEnded)
  1756. return;
  1757.  
  1758. new id = get_loguser_index();
  1759. if(!is_user_connected(id) || hosties[id][1] == -1) return;
  1760.  
  1761. hosties[id][1]++;
  1762.  
  1763. if(hosties[id][1] >= reward)
  1764. {
  1765. if(!equal(weapon[id],"hegrenade") && !equal(weapon[id],"knife") && level[id] < get_weapon_num())
  1766. change_level(id,1);
  1767.  
  1768. hosties[id][1] = -1;
  1769. }
  1770. }
  1771.  
  1772. // hostage is killed
  1773. public logevent_hostage_killed()
  1774. {
  1775. new penalty = get_pcvar_num(gg_host_kill_penalty);
  1776.  
  1777. if(!get_pcvar_num(gg_enabled) || !penalty)
  1778. return;
  1779.  
  1780. new id = get_loguser_index();
  1781. if(!is_user_connected(id)) return;
  1782.  
  1783. new name[32];
  1784. get_user_name(id,name,31);
  1785.  
  1786. if(score[id] - penalty < 0)
  1787. gungame_print(0,id,"%L",LANG_PLAYER_C,"HK_LEVEL_DOWN",name,(level[id] > 1) ? level[id]-1 : level[id]);
  1788. else
  1789. gungame_print(0,id,"%L",LANG_PLAYER_C,"HK_SCORE_DOWN",name,penalty);
  1790.  
  1791. change_score(id,-penalty);
  1792. }
  1793.  
  1794. // someone joins a team
  1795. public logevent_team_join()
  1796. {
  1797. new id = get_loguser_index();
  1798. if(!is_user_connected(id) || (oldTeam[id] != 1 && oldTeam[id] != 2)) return;
  1799.  
  1800. static arg2[10];
  1801. read_logargv(2,arg2,9);
  1802.  
  1803. // get the new team
  1804. new newTeam;
  1805. if(equal(arg2,"TERRORIST")) newTeam = 1;
  1806. else if(equal(arg2,"CT")) newTeam = 2;
  1807.  
  1808. // didn't switch teams, too bad for you (suicide)
  1809. if(!newTeam || oldTeam[id] == newTeam)
  1810. return;
  1811.  
  1812. // check to see if the team change was beneficial
  1813. if(get_pcvar_num(gg_allow_changeteam) == 2)
  1814. {
  1815. new teamCount[2], i;
  1816. for(i=1;i<=maxPlayers;i++)
  1817. {
  1818. if(!is_user_connected(i))
  1819. continue;
  1820.  
  1821. switch(cs_get_user_team(i))
  1822. {
  1823. case CS_TEAM_T: teamCount[0]++;
  1824. case CS_TEAM_CT: teamCount[1]++;
  1825. }
  1826. }
  1827.  
  1828. if(teamCount[newTeam-1] <= teamCount[oldTeam[id]-1])
  1829. remove_task(TASK_DELAYED_SUICIDE+id);
  1830. }
  1831. else remove_task(TASK_DELAYED_SUICIDE+id);
  1832. }
  1833.  
  1834. //
  1835. // COMMAND HOOKS
  1836. //
  1837.  
  1838. // turning GunGame on or off
  1839. public cmd_gungame(id,level,cid)
  1840. {
  1841. // no access, or GunGame ending anyway
  1842. if(!cmd_access(id,level,cid,2) || won)
  1843. return PLUGIN_HANDLED;
  1844.  
  1845. // already working on toggling GunGame
  1846. if(task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_FORCE)
  1847. || task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_DISABLE)
  1848. || task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_ENABLE))
  1849. {
  1850. console_print(id,"[GunGame] GunGame is already being turned on or off");
  1851. return PLUGIN_HANDLED;
  1852. }
  1853.  
  1854. new arg[32], oldStatus = get_pcvar_num(gg_enabled), newStatus;
  1855. read_argv(1,arg,31);
  1856.  
  1857. if(equali(arg,"on") || str_to_num(arg))
  1858. newStatus = 1;
  1859.  
  1860. // no change
  1861. if((!oldStatus && !newStatus) || (oldStatus && newStatus))
  1862. {
  1863. console_print(id,"[GunGame] GunGame is already %s!",(newStatus) ? "on" : "off");
  1864. return PLUGIN_HANDLED;
  1865. }
  1866.  
  1867. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+newStatus);
  1868. set_cvar_num("sv_restartround",5);
  1869. if(!newStatus) set_pcvar_num(gg_enabled,0);
  1870.  
  1871. console_print(id,"[GunGame] Turned GunGame %s",(newStatus) ? "on" : "off");
  1872.  
  1873. return PLUGIN_HANDLED;
  1874. }
  1875.  
  1876. // voting for GunGame
  1877. public cmd_gungame_vote(id,lvl,cid)
  1878. {
  1879. if(!cmd_access(id,lvl,cid,1))
  1880. return PLUGIN_HANDLED;
  1881.  
  1882. autovote_start();
  1883. console_print(id,"[GunGame] Started a vote to play GunGame");
  1884.  
  1885. return PLUGIN_HANDLED;
  1886. }
  1887.  
  1888. // setting players levels
  1889. public cmd_gungame_level(id,lvl,cid)
  1890. {
  1891. if(!cmd_access(id,lvl,cid,3))
  1892. return PLUGIN_HANDLED;
  1893.  
  1894. new arg1[32], arg2[32], targets[32], name[32], tnum, i;
  1895. read_argv(1,arg1,31);
  1896. read_argv(2,arg2,31);
  1897.  
  1898. // get player list
  1899. if(equali(arg1,"*") || equali(arg1,"@ALL"))
  1900. {
  1901. get_players(targets,tnum);
  1902. name = "ALL PLAYERS";
  1903. }
  1904. else if(equali(arg1,"@TERRORIST") || equali(arg1,"@CT"))
  1905. {
  1906. new players[32], team[32], pnum;
  1907. get_players(players,pnum);
  1908.  
  1909. for(i=0;i<pnum;i++)
  1910. {
  1911. get_user_team(players[i],team,31);
  1912. if(equali(team,arg1[1])) targets[tnum++] = players[i];
  1913. }
  1914.  
  1915. formatex(name,31,"ALL %s",arg1[1]);
  1916. }
  1917. else
  1918. {
  1919. targets[tnum++] = cmd_target(id,arg1,2);
  1920. if(!targets[0]) return PLUGIN_HANDLED;
  1921.  
  1922. get_user_name(targets[0],name,31);
  1923. }
  1924.  
  1925. new intval = str_to_num(arg2);
  1926.  
  1927. // relative
  1928. if(arg2[0] == '+' || arg2[0] == '-')
  1929. for(i=0;i<tnum;i++) change_level(targets[i],intval,0,1,1);
  1930.  
  1931. // absolute
  1932. else
  1933. for(i=0;i<tnum;i++) change_level(targets[i],intval-level[targets[i]],0,1,1);
  1934.  
  1935. console_print(id,"[GunGame] Changed %s's level to %s",name,arg2);
  1936.  
  1937. return PLUGIN_HANDLED;
  1938. }
  1939.  
  1940. // block fullupdate
  1941. public cmd_fullupdate(id)
  1942. {
  1943. return PLUGIN_HANDLED;
  1944. }
  1945.  
  1946. // hook say
  1947. public cmd_say(id)
  1948. {
  1949. if(!get_pcvar_num(gg_enabled)) return PLUGIN_CONTINUE;
  1950.  
  1951. static message[256];
  1952. read_argv(1,message,255);
  1953.  
  1954. // doesn't begin with !, ignore
  1955. if(message[0] != '!') return PLUGIN_CONTINUE;
  1956.  
  1957. if(equali(message,"!rules") || equali(message,"!help"))
  1958. {
  1959. new num = 1, max_lvl = get_pcvar_num(gg_max_lvl), turbo = get_pcvar_num(gg_turbo);
  1960.  
  1961. console_print(id,"-----------------------------");
  1962. console_print(id,"-----------------------------");
  1963. console_print(id,"*** Avalanche's %L %s %L ***",id,"GUNGAME",GG_VERSION,id,"RULES");
  1964. console_print(id,"%L",id,"RULES_CONSOLE_LINE1",num++);
  1965. console_print(id,"%L",id,"RULES_CONSOLE_LINE2",num++);
  1966. if(get_pcvar_num(gg_bomb_defuse_lvl)) console_print(id,"%L",id,"RULES_CONSOLE_LINE3",num++);
  1967. console_print(id,"%L",id,"RULES_CONSOLE_LINE4",num++);
  1968. if(get_pcvar_num(gg_ff_auto)) console_print(id,"%L",id,"RULES_CONSOLE_LINE5",num++);
  1969. if(turbo || !max_lvl) console_print(id,"%L",id,"RULES_CONSOLE_LINE6A",num++);
  1970. else if(max_lvl == 1) console_print(id,"%L",id,"RULES_CONSOLE_LINE6B",num++);
  1971. else if(max_lvl > 1) console_print(id,"%L",id,"RULES_CONSOLE_LINE6C",num++,max_lvl);
  1972. console_print(id,"%L",id,"RULES_CONSOLE_LINE7",num++);
  1973. if(get_pcvar_num(gg_knife_pro)) console_print(id,"%L",id,"RULES_CONSOLE_LINE8",num++);
  1974. if(turbo) console_print(id,"%L",id,"RULES_CONSOLE_LINE9",num++);
  1975. if(get_pcvar_num(gg_dm) || get_cvar_num("csdm_active")) console_print(id,"%L",id,"RULES_CONSOLE_LINE10",num++);
  1976. console_print(id,"****************************************************************");
  1977. console_print(id,"%L",id,"RULES_CONSOLE_LINE11");
  1978. console_print(id,"%L",id,"RULES_CONSOLE_LINE12");
  1979. console_print(id,"%L",id,"RULES_CONSOLE_LINE13");
  1980. console_print(id,"%L",id,"RULES_CONSOLE_LINE14");
  1981. console_print(id,"%L",id,"RULES_CONSOLE_LINE15");
  1982. console_print(id,"-----------------------------");
  1983. console_print(id,"-----------------------------");
  1984.  
  1985. len = formatex(menuText,511,"%L^n",id,"RULES_MESSAGE_LINE1");
  1986. len += formatex(menuText[len],511-len,"\d----------\w^n");
  1987. len += formatex(menuText[len],511-len,"%L^n",id,"RULES_MESSAGE_LINE2");
  1988. len += formatex(menuText[len],511-len,"\d----------\w^n");
  1989. len += formatex(menuText[len],511-len,"%L^n",id,"RULES_MESSAGE_LINE3");
  1990. len += formatex(menuText[len],511-len,"\d----------\w^n%L",id,"PRESS_KEY_TO_CONTINUE");
  1991.  
  1992. show_menu(id,1023,menuText);
  1993.  
  1994. return PLUGIN_HANDLED;
  1995. }
  1996. else if(equali(message,"!weapons") || equali(message,"!guns"))
  1997. {
  1998. page[id] = 1;
  1999. show_weapons_menu(id);
  2000.  
  2001. return PLUGIN_HANDLED;
  2002. }
  2003. else if(equali(message,"!top10"))
  2004. {
  2005. get_pcvar_string(gg_stats_file,sfFile,63);
  2006.  
  2007. // stats disabled
  2008. if(!sfFile[0] || !get_pcvar_num(gg_stats_mode))
  2009. {
  2010. client_print(id,print_chat,"%L",id,"NO_WIN_LOGGING");
  2011. return PLUGIN_HANDLED;
  2012. }
  2013.  
  2014. page[id] = 1;
  2015. show_top10_menu(id);
  2016.  
  2017. return PLUGIN_HANDLED;
  2018. }
  2019. else if(equali(message,"!score") || equali(message,"!scores"))
  2020. {
  2021. page[id] = 1;
  2022. show_scores_menu(id);
  2023.  
  2024. return PLUGIN_HANDLED;
  2025. }
  2026. else if(equali(message,"!level"))
  2027. {
  2028. show_level_menu(id);
  2029.  
  2030. return PLUGIN_HANDLED;
  2031. }
  2032. else if(equali(message,"!restart") || equali(message,"!reset"))
  2033. {
  2034. if(level[id] <= 1)
  2035. {
  2036. client_print(id,print_chat,"%L",id,"STILL_LEVEL_ONE");
  2037. return PLUGIN_HANDLED;
  2038. }
  2039.  
  2040. len = formatex(menuText,511,"%L^n^n",id,"RESET_QUERY");
  2041. len += formatex(menuText[len],511-len,"1. %L^n",id,"YES");
  2042. len += formatex(menuText[len],511-len,"0. %L",id,"CANCEL");
  2043. show_menu(id,MENU_KEY_1|MENU_KEY_0,menuText,-1,"restart_menu");
  2044.  
  2045. return PLUGIN_HANDLED;
  2046. }
  2047.  
  2048. return PLUGIN_CONTINUE;
  2049. }
  2050.  
  2051. // joining a team
  2052. public cmd_joinclass(id)
  2053. {
  2054. if(!get_pcvar_num(gg_enabled))
  2055. return PLUGIN_CONTINUE;
  2056.  
  2057. // allow us to join in on deathmatch
  2058. if(!get_pcvar_num(gg_dm))
  2059. {
  2060. remove_task(TASK_CHECK_DEATHMATCH+id);
  2061. set_task(10.0,"check_deathmatch",TASK_CHECK_DEATHMATCH+id);
  2062. return PLUGIN_CONTINUE;
  2063. }
  2064.  
  2065. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  2066. return PLUGIN_CONTINUE;
  2067.  
  2068. set_task(2.0,"check_joinclass",id);
  2069. return PLUGIN_CONTINUE;
  2070. }
  2071.  
  2072. // wait a bit after joinclass to see if we should jump in
  2073. public check_joinclass(id)
  2074. {
  2075. if(!is_user_connected(id)) return;
  2076.  
  2077. // already respawning
  2078. if(task_exists(TASK_RESPAWN+id) || task_exists(TASK_CHECK_RESPAWN+id)
  2079. || task_exists(TASK_CHECK_RESPAWN2+id) || is_user_alive(id))
  2080. return;
  2081.  
  2082. // not on a valid team
  2083. new CsTeams:team = cs_get_user_team(id);
  2084. if(team == CS_TEAM_UNASSIGNED || team == CS_TEAM_SPECTATOR) return;
  2085.  
  2086. set_task(0.1,"respawn",TASK_RESPAWN+id);
  2087. }
  2088.  
  2089. //
  2090. // MENU FUNCTIONS
  2091. //
  2092.  
  2093. // toggle the status of gungame
  2094. public toggle_gungame(taskid)
  2095. {
  2096. new status = taskid-TASK_TOGGLE_GUNGAME, i;
  2097.  
  2098. // clear player tasks and values
  2099. for(i=1;i<=32;i++)
  2100. {
  2101. remove_task(TASK_RESPAWN+i);
  2102. remove_task(TASK_CHECK_RESPAWN+i);
  2103. remove_task(TASK_CHECK_RESPAWN2+i);
  2104. remove_task(TASK_CHECK_DEATHMATCH+i);
  2105. remove_task(TASK_REMOVE_PROTECTION+i);
  2106. clear_values(i);
  2107.  
  2108. }
  2109.  
  2110. // clear temp saves
  2111. for(i=0;i<TEMP_SAVES;i++) clear_save(TASK_CLEAR_SAVE+i);
  2112.  
  2113. if(status == TOGGLE_FORCE || status == TOGGLE_ENABLE)
  2114. {
  2115. new cfgFile[64];
  2116. get_gg_config_file(cfgFile,63);
  2117.  
  2118. // run the gungame config
  2119. if(cfgFile[0] && file_exists(cfgFile))
  2120. {
  2121. new command[512], file, i;
  2122.  
  2123. file = fopen(cfgFile,"rt");
  2124. while(file && !feof(file))
  2125. {
  2126. fgets(file,command,511);
  2127. trim(command);
  2128.  
  2129. // stop at a comment
  2130. for(i=0;i<strlen(command)-2;i++)
  2131. {
  2132. // only check config-style (;) comments as first character,
  2133. // since they could be used ie in gg_map_setup to separate
  2134. // commands. also check for coding-style (//) comments
  2135. if((i == 0 && command[i] == ';') || (command[i] == '/' && command[i+1] == '/'))
  2136. {
  2137. copy(command,i,command);
  2138. break;
  2139. }
  2140. }
  2141.  
  2142. // don't override our setting from amx_gungame
  2143. if(containi(command,"gg_enabled") != -1 && status == TOGGLE_ENABLE)
  2144. continue;
  2145.  
  2146. trim(command);
  2147. if(command[0]) server_cmd(command);
  2148. }
  2149. if(file) fclose(file);
  2150. }
  2151. }
  2152.  
  2153. // set to what we chose from amx_gungame
  2154. if(status != TOGGLE_FORCE) set_pcvar_num(gg_enabled,status);
  2155.  
  2156. // execute all of those cvars that we just set
  2157. server_exec();
  2158.  
  2159. // run appropiate cvars
  2160. map_start_cvars();
  2161.  
  2162. // reset some things
  2163. if(!get_pcvar_num(gg_enabled))
  2164. {
  2165. // clear HUD message
  2166. if(warmup > 0)
  2167. {
  2168. set_hudmessage(255,255,255,-1.0,0.4,0,6.0,1.0,0.1,0.2,CHANNEL_WARMUP);
  2169. show_hudmessage(0," ");
  2170. }
  2171.  
  2172. warmup = -1;
  2173. voted = 0;
  2174. won = 0;
  2175.  
  2176. remove_task(TASK_WARMUP_CHECK);
  2177. }
  2178.  
  2179. stats_get_top_players(TOP_PLAYERS,top10,80);
  2180.  
  2181. // game_player_equip
  2182. manage_equips();
  2183. }
  2184.  
  2185. // run cvars that should be run on map start
  2186. public map_start_cvars()
  2187. {
  2188. new setup[512];
  2189.  
  2190. // gungame is disabled, run endmap_setup
  2191. if(!get_pcvar_num(gg_enabled))
  2192. {
  2193. get_pcvar_string(gg_endmap_setup,setup,511);
  2194. if(setup[0]) server_cmd(setup);
  2195. }
  2196. else
  2197. {
  2198. // run map setup
  2199. get_pcvar_string(gg_map_setup,setup,511);
  2200. if(setup[0]) server_cmd(setup);
  2201.  
  2202. // warmup is -13 after its finished, this stops multiple warmups for multiple map iterations
  2203. new warmup_value = get_pcvar_num(gg_warmup_timer_setting);
  2204. if(warmup_value > 0 && warmup != -13)
  2205. {
  2206. warmup = warmup_value;
  2207. set_task(0.1,"warmup_check",TASK_WARMUP_CHECK);
  2208. }
  2209.  
  2210. // random weapon orders
  2211. do_rOrder();
  2212. }
  2213. }
  2214.  
  2215. // select a random weapon order
  2216. do_rOrder()
  2217. {
  2218. new i, maxRandom, cvar[20];
  2219. for(i=1;i<=MAX_WEAPON_ORDERS+1;i++) // +1 so we can detect final
  2220. {
  2221. formatex(cvar,19,"gg_weapon_order%i",i);
  2222. get_cvar_string(cvar,weaponOrder,415);
  2223. trim(weaponOrder);
  2224.  
  2225. // found a blank one, stop here
  2226. if(!weaponOrder[0])
  2227. {
  2228. maxRandom = i - 1;
  2229. break;
  2230. }
  2231. }
  2232.  
  2233. // we found some random ones
  2234. if(maxRandom)
  2235. {
  2236. new randomOrder[30], lastOIstr[6], lastOI, orderAmt;
  2237. get_localinfo("gg_rand_order",randomOrder,29);
  2238. get_localinfo("gg_last_oi",lastOIstr,5);
  2239. lastOI = str_to_num(lastOIstr);
  2240. orderAmt = get_rOrder_amount(randomOrder);
  2241.  
  2242. // no random order yet, or amount of random orders changed
  2243. if(!randomOrder[0] || orderAmt != maxRandom)
  2244. {
  2245. shuffle_rOrder(randomOrder,29,maxRandom);
  2246. lastOI = 0;
  2247. }
  2248.  
  2249. // reached the end, reshuffle while avoiding this one
  2250. else if(get_rOrder_index_val(orderAmt,randomOrder) == get_rOrder_index_val(lastOI,randomOrder))
  2251. {
  2252. shuffle_rOrder(randomOrder,29,maxRandom,lastOI);
  2253. lastOI = 0;
  2254. }
  2255.  
  2256. new choice = get_rOrder_index_val(lastOI+1,randomOrder);
  2257.  
  2258. // get its weapon order
  2259. formatex(cvar,19,"gg_weapon_order%i",choice);
  2260. get_cvar_string(cvar,weaponOrder,415);
  2261.  
  2262. // set as current
  2263. set_cvar_string("gg_weapon_order",weaponOrder);
  2264.  
  2265. // remember for next time
  2266. num_to_str(lastOI+1,lastOIstr,5);
  2267. set_localinfo("gg_last_oi",lastOIstr);
  2268. }
  2269. }
  2270.  
  2271. // get the value of an order index in an order string
  2272. get_rOrder_index_val(index,randomOrder[])
  2273. {
  2274. // only one listed
  2275. if(str_count(randomOrder,',') < 1)
  2276. return str_to_num(randomOrder);
  2277.  
  2278. // find preceding comma
  2279. new search = str_find_num(randomOrder,',',index-1);
  2280.  
  2281. // go until succeeding comma
  2282. new extract[6];
  2283. copyc(extract,5,randomOrder[search+1],',');
  2284.  
  2285. return str_to_num(extract);
  2286. }
  2287.  
  2288. // gets the amount of orders in an order string
  2289. get_rOrder_amount(randomOrder[])
  2290. {
  2291. return str_count(randomOrder,',')+1;
  2292. }
  2293.  
  2294. // shuffle up our random order
  2295. stock shuffle_rOrder(randomOrder[],len,maxRandom,avoid=-1)
  2296. {
  2297. randomOrder[0] = 0;
  2298.  
  2299. // fill up array with order indexes
  2300. new order[MAX_WEAPON_ORDERS], i;
  2301. for(i=0;i<maxRandom;i++) order[i] = i+1;
  2302.  
  2303. // shuffle it
  2304. SortCustom1D(order,maxRandom,"sort_shuffle");
  2305.  
  2306. // avoid a specific number as the starting number
  2307. while(avoid > 0 && order[0] == avoid)
  2308. SortCustom1D(order,maxRandom,"sort_shuffle");
  2309.  
  2310. // get them into a string
  2311. for(i=0;i<maxRandom;i++)
  2312. {
  2313. format(randomOrder,len,"%s%s%i",randomOrder,(i>0) ? "," : "",order[i]);
  2314. set_localinfo("gg_rand_order",randomOrder);
  2315. }
  2316. }
  2317.  
  2318. // shuffle an array
  2319. public sort_shuffle(elem1,elem2)
  2320. {
  2321. return random_num(-1,1);
  2322. }
  2323.  
  2324. // handle the welcome menu
  2325. public welcome_menu_handler(id,key)
  2326. {
  2327. // just save welcomed status and let menu close
  2328. welcomed[id] = 1;
  2329. return PLUGIN_HANDLED;
  2330. }
  2331.  
  2332. // this menu does nothing but display stuff
  2333. public level_menu_handler(id,key)
  2334. {
  2335. return PLUGIN_HANDLED;
  2336. }
  2337.  
  2338. // handle the reset level menu
  2339. public restart_menu_handler(id,key)
  2340. {
  2341. if(level[id] <= 1)
  2342. {
  2343. client_print(id,print_chat,"%L",id,"STILL_LEVEL_ONE");
  2344. return PLUGIN_HANDLED;
  2345. }
  2346.  
  2347. // 1. Yes
  2348. if(key == 0)
  2349. {
  2350. new name[32];
  2351. get_user_name(id,name,31);
  2352.  
  2353. change_level(id,-(level[id]-1)); // back to level 1
  2354. gungame_print(0,id,"%L",LANG_PLAYER_C,"PLAYER_RESET",name);
  2355. }
  2356.  
  2357. return PLUGIN_HANDLED;
  2358. }
  2359.  
  2360. // show the level display
  2361. show_level_menu(id)
  2362. {
  2363. new goal, tied, leaderNum, leaderList[128], name[32];
  2364. new bestLevel, bestPlayer = get_leader(bestLevel);
  2365. len = 0;
  2366.  
  2367. new players[32], num, i;
  2368. get_players(players,num);
  2369.  
  2370. if(bestPlayer == id)
  2371. {
  2372. // check for ties first
  2373. for(i=0;i<num;i++)
  2374. {
  2375. if(level[players[i]] == level[id] && players[i] != id)
  2376. {
  2377. tied = 1;
  2378. break;
  2379. }
  2380. }
  2381. }
  2382. else if(level[bestPlayer] == level[id]) tied = 1;
  2383.  
  2384. // check for multiple leaders
  2385. for(i=0;i<num;i++)
  2386. {
  2387. if(level[players[i]] == bestLevel)
  2388. {
  2389. if(++leaderNum == 5)
  2390. {
  2391. len += formatex(leaderList[len],127-len,", ...");
  2392. break;
  2393. }
  2394.  
  2395. if(leaderList[0]) len += formatex(leaderList[len],127-len,", ");
  2396. get_user_name(players[i],name,31);
  2397. len += formatex(leaderList[len],127-len,"%s",name);
  2398. }
  2399. }
  2400.  
  2401. goal = get_level_goal(level[id]);
  2402.  
  2403. new displayWeapon[16];
  2404. if(level[id]) formatex(displayWeapon,15,"%s",weapon[id]);
  2405. else formatex(displayWeapon,15,"%L",id,"NONE");
  2406.  
  2407. len = formatex(menuText,511,"%L %i (%s)^n",id,"ON_LEVEL",level[id],displayWeapon);
  2408. len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE1",score[id],goal);
  2409.  
  2410. if(bestPlayer == id && !tied) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE2A");
  2411. else if(tied) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE2B");
  2412. else len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE2C",bestLevel-level[id]);
  2413. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2414.  
  2415. new authid[24], wins, points;
  2416.  
  2417. if(get_pcvar_num(gg_stats_ip)) get_user_ip(id,authid,23);
  2418. else get_user_authid(id,authid,23);
  2419.  
  2420. stats_get_data(authid,wins,points,dummy,1,dummy[0]);
  2421.  
  2422. new stats_mode = get_pcvar_num(gg_stats_mode);
  2423.  
  2424. if(stats_mode)
  2425. {
  2426. if(stats_mode == 1) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE3A",wins);
  2427. else len += formatex(menuText[len],511-len,"%L (%i %L)^n",id,"LEVEL_MESSAGE_LINE3B",points,wins,id,"WINS");
  2428.  
  2429. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2430. }
  2431.  
  2432. if(leaderNum > 1) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE4A",leaderList);
  2433. else len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE4B",leaderList);
  2434.  
  2435. if(level[bestPlayer]) formatex(displayWeapon,15,"%s",weapon[bestPlayer]);
  2436. else formatex(displayWeapon,15,"%L",id,"NONE");
  2437.  
  2438. len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE5",bestLevel,displayWeapon);
  2439. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2440.  
  2441. len += formatex(menuText[len],511-len,"%L",id,"PRESS_KEY_TO_CONTINUE");
  2442. show_menu(id,1023,menuText,-1,"level_menu");
  2443. }
  2444.  
  2445. // show the top10 list menu
  2446. show_top10_menu(id)
  2447. {
  2448. new totalPlayers = TOP_PLAYERS, playersPerPage = 5, stats_mode = get_pcvar_num(gg_stats_mode);
  2449. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  2450.  
  2451. if(page[id] < 1) page[id] = 1;
  2452. if(page[id] > pageTotal) page[id] = pageTotal;
  2453.  
  2454. len = formatex(menuText,511-len,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"TOP_10",page[id],pageTotal);
  2455. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2456.  
  2457. static top10listing[81];
  2458. new start = (playersPerPage * (page[id]-1)), i;
  2459.  
  2460. for(i=start;i<start+playersPerPage;i++)
  2461. {
  2462. if(i > totalPlayers) break;
  2463.  
  2464. // blank
  2465. if(!top10[i][0])
  2466. {
  2467. len += formatex(menuText[len],511-len,"#%i \d%L\w^n",i+1,id,"NONE");
  2468. continue;
  2469. }
  2470.  
  2471. // assign it to a new variable so that strtok
  2472. // doesn't tear apart our constant top10 variable
  2473. top10listing = top10[i];
  2474.  
  2475. // get rid of authid
  2476. strtok(top10listing,sfAuthid,1,top10listing,80,'^t');
  2477.  
  2478. // isolate wins
  2479. strtok(top10listing,sfWins,5,top10listing,80,'^t');
  2480.  
  2481. // isolate name
  2482. strtok(top10listing,sfName,31,top10listing,80,'^t');
  2483.  
  2484. // break off timestamp and get points
  2485. strtok(top10listing,sfTimestamp,1,sfPoints,7,'^t');
  2486.  
  2487. if(stats_mode == 1)
  2488. len += formatex(menuText[len],511-len,"#%i %s (%s %L)^n",i+1,sfName,sfWins,id,"WINS");
  2489. else
  2490. len += formatex(menuText[len],511-len,"#%i %s (%i %L, %s %L)^n",i+1,sfName,str_to_num(sfPoints),id,"POINTS",sfWins,id,"WINS");
  2491. }
  2492.  
  2493. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2494.  
  2495. new keys = MENU_KEY_0;
  2496.  
  2497. if(page[id] > 1)
  2498. {
  2499. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  2500. keys |= MENU_KEY_1;
  2501. }
  2502. if(page[id] < pageTotal)
  2503. {
  2504. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  2505. keys |= MENU_KEY_2;
  2506. }
  2507. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  2508.  
  2509. show_menu(id,keys,menuText,-1,"top10_menu");
  2510. }
  2511.  
  2512. // someone pressed a key on the top10 list menu page
  2513. public top10_menu_handler(id,key)
  2514. {
  2515. new totalPlayers = TOP_PLAYERS, playersPerPage = 5;
  2516. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  2517.  
  2518. if(page[id] < 1 || page[id] > pageTotal) return;
  2519.  
  2520. // 1. Previous
  2521. if(key == 0)
  2522. {
  2523. page[id]--;
  2524. show_top10_menu(id);
  2525.  
  2526. return;
  2527. }
  2528.  
  2529. // 2. Next
  2530. else if(key == 1)
  2531. {
  2532. page[id]++;
  2533. show_top10_menu(id);
  2534.  
  2535. return;
  2536. }
  2537.  
  2538. // 0. Close
  2539. // do nothing, menu closes automatically
  2540. }
  2541.  
  2542. // show the weapon list menu
  2543. show_weapons_menu(id)
  2544. {
  2545. new totalWeapons = get_weapon_num(), wpnsPerPage = 10;
  2546. new pageTotal = floatround(float(totalWeapons) / float(wpnsPerPage),floatround_ceil);
  2547.  
  2548. if(page[id] < 1) page[id] = 1;
  2549. if(page[id] > pageTotal) page[id] = pageTotal;
  2550.  
  2551. len = formatex(menuText,511-len,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"WEAPONS",page[id],pageTotal);
  2552. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2553.  
  2554. new start = (wpnsPerPage * (page[id]-1)) + 1, i, wName[24];
  2555.  
  2556. // are there any custom kill requirements?
  2557. get_pcvar_string(gg_weapon_order,weaponOrder,415);
  2558. new customKills = (containi(weaponOrder,":") != -1);
  2559.  
  2560. for(i=start;i<start+wpnsPerPage;i++)
  2561. {
  2562. if(i > totalWeapons) break;
  2563.  
  2564. get_weapon_name_by_level(i,wName,23);
  2565.  
  2566. if(customKills)
  2567. len += formatex(menuText[len],511-len,"%L %i: %s (%i)^n",id,"LEVEL",i,wName,get_level_goal(i));
  2568. else
  2569. len += formatex(menuText[len],511-len,"%L %i: %s^n",id,"LEVEL",i,wName);
  2570. }
  2571.  
  2572. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2573.  
  2574. new keys = MENU_KEY_0;
  2575.  
  2576. if(page[id] > 1)
  2577. {
  2578. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  2579. keys |= MENU_KEY_1;
  2580. }
  2581. if(page[id] < pageTotal)
  2582. {
  2583. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  2584. keys |= MENU_KEY_2;
  2585. }
  2586. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  2587.  
  2588. show_menu(id,keys,menuText,-1,"weapons_menu");
  2589. }
  2590.  
  2591. // someone pressed a key on the weapon list menu page
  2592. public weapons_menu_handler(id,key)
  2593. {
  2594. new totalWeapons = get_weapon_num(), wpnsPerPage = 10;
  2595. new pageTotal = floatround(float(totalWeapons) / float(wpnsPerPage),floatround_ceil);
  2596.  
  2597. if(page[id] < 1 || page[id] > pageTotal) return;
  2598.  
  2599. // 1. Previous
  2600. if(key == 0)
  2601. {
  2602. page[id]--;
  2603. show_weapons_menu(id);
  2604. return;
  2605. }
  2606.  
  2607. // 2. Next
  2608. else if(key == 1)
  2609. {
  2610. page[id]++;
  2611. show_weapons_menu(id);
  2612. return;
  2613. }
  2614.  
  2615. // 0. Close
  2616. // do nothing, menu closes automatically
  2617. }
  2618.  
  2619. // show the score list menu
  2620. show_scores_menu(id)
  2621. {
  2622. new totalPlayers = get_playersnum(), playersPerPage = 5, stats_mode = get_pcvar_num(gg_stats_mode);
  2623. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  2624.  
  2625. if(page[id] < 1) page[id] = 1;
  2626. if(page[id] > pageTotal) page[id] = pageTotal;
  2627.  
  2628. new players[32], num;
  2629. get_players(players,num);
  2630.  
  2631. // order by highest level first
  2632. SortCustom1D(players,num,"score_custom_compare");
  2633.  
  2634. len = formatex(menuText,511,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"SCORES",page[id],pageTotal);
  2635. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2636.  
  2637. new start = (playersPerPage * (page[id]-1)), i, name[32], player, authid[24], wins, points;
  2638.  
  2639. // check for stats
  2640. get_pcvar_string(gg_stats_file,sfFile,63);
  2641.  
  2642. new stats_ip = get_pcvar_num(gg_stats_ip);
  2643.  
  2644. for(i=start;i<start+playersPerPage;i++)
  2645. {
  2646. if(i >= totalPlayers) break;
  2647.  
  2648. player = players[i];
  2649. get_user_name(player,name,31);
  2650.  
  2651. new displayWeapon[16];
  2652. if(level[player] && weapon[player][0]) formatex(displayWeapon,15,"%s",weapon[player]);
  2653. else formatex(displayWeapon,15,"%L",id,"NONE");
  2654.  
  2655. if(sfFile[0] && stats_mode)
  2656. {
  2657. if(stats_ip) get_user_ip(player,authid,23);
  2658. else get_user_authid(player,authid,23);
  2659.  
  2660. stats_get_data(authid,wins,points,dummy,1,dummy[0]);
  2661.  
  2662. len += formatex(menuText[len],511-len,"#%i %s, %L %i (%s), %i %L^n",i+1,name,id,"LEVEL",level[player],displayWeapon,(stats_mode == 1) ? wins : points,id,(stats_mode == 1) ? "WINS" : "POINTS");
  2663. }
  2664. else len += formatex(menuText[len],511-len,"#%i %s, %L %i (%s)^n",i+1,name,id,"LEVEL",level[player],displayWeapon);
  2665. }
  2666.  
  2667. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  2668.  
  2669. new keys = MENU_KEY_0;
  2670.  
  2671. if(page[id] > 1)
  2672. {
  2673. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  2674. keys |= MENU_KEY_1;
  2675. }
  2676. if(page[id] < pageTotal)
  2677. {
  2678. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  2679. keys |= MENU_KEY_2;
  2680. }
  2681. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  2682.  
  2683. show_menu(id,keys,menuText,-1,"scores_menu");
  2684. }
  2685.  
  2686. // sort list of players with their level first
  2687. public score_custom_compare(elem1,elem2)
  2688. {
  2689. // invalid players
  2690. if(elem1 < 1 || elem1 > 32 || elem2 < 1 || elem2 > 32)
  2691. return 0;
  2692.  
  2693. // tied levels, compare scores
  2694. if(level[elem1] == level[elem2])
  2695. {
  2696. if(score[elem1] > score[elem2]) return -1;
  2697. else if(score[elem1] < score[elem2]) return 1;
  2698. else return 0;
  2699. }
  2700.  
  2701. // compare levels
  2702. else if(level[elem1] > level[elem2]) return -1;
  2703. else if(level[elem1] < level[elem2]) return 1;
  2704.  
  2705. return 0; // equal
  2706. }
  2707.  
  2708. // someone pressed a key on the score list menu page
  2709. public scores_menu_handler(id,key)
  2710. {
  2711. new totalPlayers = get_playersnum(), playersPerPage = 5;
  2712. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  2713.  
  2714. if(page[id] < 1 || page[id] > pageTotal) return;
  2715.  
  2716. // 1. Previous
  2717. if(key == 0)
  2718. {
  2719. page[id]--;
  2720. show_scores_menu(id);
  2721. return;
  2722. }
  2723.  
  2724. // 2. Next
  2725. else if(key == 1)
  2726. {
  2727. page[id]++;
  2728. show_scores_menu(id);
  2729. return;
  2730. }
  2731.  
  2732. // 0. Close
  2733. // do nothing, menu closes automatically
  2734. }
  2735.  
  2736. //
  2737. // MAIN FUNCTIONS
  2738. //
  2739.  
  2740. // refresh a player's hegrenade stock
  2741. public refresh_nade(taskid)
  2742. {
  2743. new id = taskid-TASK_REFRESH_NADE;
  2744.  
  2745. // player left, player died, or GunGame turned off
  2746. if(!is_user_connected(id) || !is_user_alive(id) || !get_pcvar_num(gg_enabled)) return;
  2747.  
  2748. // not on the grenade level, or have one already
  2749. if(!equali(weapon[id],"hegrenade") || cs_get_user_bpammo(id,CSW_HEGRENADE))
  2750. return;
  2751.  
  2752. // give another hegrenade
  2753. fm_give_item(id,"weapon_hegrenade");
  2754. }
  2755.  
  2756. // keep checking if a player needs to rejoin
  2757. public check_deathmatch(taskid)
  2758. {
  2759. new id = taskid-TASK_CHECK_DEATHMATCH;
  2760.  
  2761. // left the game, or gungame is now disabled
  2762. if(!is_user_connected(id) || !get_pcvar_num(gg_enabled)) return;
  2763.  
  2764. // now on spectator
  2765. new CsTeams:team = cs_get_user_team(id);
  2766. if(team == CS_TEAM_UNASSIGNED || team == CS_TEAM_SPECTATOR) return;
  2767.  
  2768. // DM still not enabled, keep waiting
  2769. if(!get_pcvar_num(gg_dm))
  2770. {
  2771. set_task(10.0,"check_deathmatch",taskid);
  2772. return;
  2773. }
  2774.  
  2775. // DM is enabled, respawn
  2776. if(!is_user_alive(id)) set_task(0.1,"respawn",TASK_RESPAWN+id);
  2777. }
  2778.  
  2779. // show someone a welcome message
  2780. public show_welcome(id)
  2781. {
  2782. if(welcomed[id]) return;
  2783.  
  2784. new menuid, keys;
  2785. get_user_menu(id,menuid,keys);
  2786.  
  2787. // another old-school menu opened
  2788. if(menuid > 0)
  2789. {
  2790. // wait and try again
  2791. set_task(3.0,"show_welcome",id);
  2792. return;
  2793. }
  2794.  
  2795. play_sound_by_cvar(id,gg_sound_welcome);
  2796.  
  2797. len = formatex(menuText,511,"\y%L\w^n",id,"WELCOME_MESSAGE_LINE1",GG_VERSION);
  2798. len += formatex(menuText[len],511-len,"\d---------------\w^n");
  2799.  
  2800. new special;
  2801. if(get_pcvar_num(gg_knife_pro))
  2802. {
  2803. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE2");
  2804. special = 1;
  2805. }
  2806. if(get_pcvar_num(gg_turbo))
  2807. {
  2808. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE3");
  2809. special = 1;
  2810. }
  2811. if(get_pcvar_num(gg_dm) || get_cvar_num("csdm_active"))
  2812. {
  2813. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE4");
  2814. special = 1;
  2815. }
  2816.  
  2817. if(special) len += formatex(menuText[len],511-len,"\d---------------\w^n");
  2818. len += formatex(menuText[len],511-len,"%L",id,"WELCOME_MESSAGE_LINE5");
  2819. len += formatex(menuText[len],511-len,"\d---------------\w^n");
  2820. len += formatex(menuText[len],511-len,"%L",id,"PRESS_KEY_TO_CONTINUE");
  2821.  
  2822. show_menu(id,1023,menuText,-1,"welcome_menu");
  2823. }
  2824.  
  2825. // show the required kills message
  2826. show_required_kills(id)
  2827. {
  2828. gungame_hudmessage(id,3.0,"%L, %i/%i",id,"REQUIRED_KILLS",score[id],get_level_goal(level[id]));
  2829. }
  2830.  
  2831. // player killed himself
  2832. player_suicided(id)
  2833. {
  2834. // we still have protection (round ended, new one hasn't started yet)
  2835. if(roundEnded) return;
  2836.  
  2837. static name[32];
  2838. get_user_name(id,name,31);
  2839.  
  2840. gungame_print(0,id,"%L",LANG_PLAYER_C,"SUICIDE_LEVEL_DOWN",name);
  2841.  
  2842. // decrease level if we can
  2843. change_level(id,-1);
  2844. }
  2845.  
  2846. // player scored or lost a point
  2847. public change_score(id,value)
  2848. {
  2849. if(!can_score(id)) return 0;
  2850.  
  2851. new oldScore = score[id], goal = get_level_goal(level[id]);
  2852.  
  2853. // if this is going to level us
  2854. if(score[id] + value >= goal)
  2855. {
  2856. new max_lvl = get_pcvar_num(gg_max_lvl);
  2857.  
  2858. // already reached max levels this round
  2859. if(!get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[id] >= max_lvl)
  2860. {
  2861. // put it as high as we can without leveling
  2862. score[id] = goal - 1;
  2863. }
  2864. else score[id] += value;
  2865. }
  2866. else score[id] += value;
  2867.  
  2868. // check for level up
  2869. if(score[id] >= goal)
  2870. {
  2871. score[id] = 0;
  2872. change_level(id,1);
  2873.  
  2874. return 1;
  2875. }
  2876.  
  2877. // check for level down
  2878. if(score[id] < 0)
  2879. {
  2880. goal = get_level_goal(level[id] > 1 ? level[id]-1 : 1);
  2881.  
  2882. score[id] = (oldScore + value) + goal; // carry over points
  2883. if(score[id] < 0) score[id] = 0;
  2884.  
  2885. //if(level[id] > 1)
  2886. change_level(id,-1);
  2887.  
  2888. return -1;
  2889. }
  2890.  
  2891. // refresh menus
  2892. new menu;
  2893. get_user_menu(id,menu,dummy[0]);
  2894. if(menu == level_menu) show_level_menu(id);
  2895.  
  2896. new sdisplay = get_pcvar_num(gg_status_display);
  2897. if(sdisplay == STATUS_KILLSLEFT || sdisplay == STATUS_KILLSDONE)
  2898. status_display(id);
  2899.  
  2900. if(value < 0)
  2901. show_required_kills(id);
  2902. else
  2903. client_cmd(id,"speak ^"buttons/bell1.wav^"");
  2904.  
  2905. if(get_pcvar_num(gg_refill_on_kill)) refill_ammo(id);
  2906.  
  2907. return 0;
  2908. }
  2909.  
  2910. // player gained or lost a level
  2911. stock change_level(id,value,just_joined=0,show_message=1,always_score=0)
  2912. {
  2913. if(level[id] > 0 && !always_score && !can_score(id))
  2914. return;
  2915.  
  2916. // knife warmup, don't bother leveling up
  2917. if(level[id] > 0 && warmup > 0 && get_pcvar_num(gg_knife_warmup)) return;
  2918.  
  2919. // this will put us below level 1
  2920. if(level[id] + value < 1)
  2921. value = 1 - level[id]; // go down only to level 1
  2922.  
  2923. // going up
  2924. if(value > 0)
  2925. {
  2926. new max_lvl = get_pcvar_num(gg_max_lvl);
  2927.  
  2928. // already reached max levels for this round
  2929. if(!get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[id] >= max_lvl)
  2930. return;
  2931. }
  2932.  
  2933. level[id] += value;
  2934. levelsThisRound[id] += value;
  2935.  
  2936. // level up!
  2937. if(value > 0) play_sound_by_cvar(id,gg_sound_levelup);
  2938.  
  2939. // level down :(
  2940. else play_sound_by_cvar(id,gg_sound_leveldown);
  2941.  
  2942. // grab my name
  2943. static name[32];
  2944. get_user_name(id,name,31);
  2945.  
  2946. // win???
  2947. if(level[id] >= get_weapon_num()+1)
  2948. {
  2949. // still warming up (wow, this guy is good)
  2950. if(warmup > 0)
  2951. {
  2952. change_level(id,-value,just_joined);
  2953.  
  2954. client_print(id,print_chat,"%L",id,"SLOW_DOWN");
  2955. client_print(id,print_center,"%L",id,"SLOW_DOWN");
  2956.  
  2957. return;
  2958. }
  2959.  
  2960. // bot, and not allowed to win
  2961. if(is_user_bot(id) && get_pcvar_num(gg_ignore_bots) == 2 && !only_bots())
  2962. {
  2963. change_level(id,-value,just_joined);
  2964. return;
  2965. }
  2966.  
  2967. // crown the winner
  2968. if(!won) win(id);
  2969.  
  2970. return;
  2971. }
  2972.  
  2973. silenced[id] = 0; // for going to Glock->USP, for example
  2974.  
  2975. // set weapon based on it
  2976. get_weapon_name_by_level(level[id],weapon[id],23);
  2977.  
  2978. new players[32], num, i, menu;
  2979. get_players(players,num);
  2980.  
  2981. // refresh menus
  2982. for(i=0;i<num;i++)
  2983. {
  2984. get_user_menu(players[i],menu,dummy[0]);
  2985.  
  2986. if(menu == scores_menu) show_scores_menu(players[i]);
  2987. else if(menu == level_menu) show_level_menu(players[i]);
  2988. }
  2989.  
  2990. // make sure we don't have more than required now
  2991. new goal = get_level_goal(level[id]);
  2992. if(score[id] >= goal) score[id] = goal-1; // 1 under
  2993.  
  2994. // status display
  2995. new sdisplay = get_pcvar_num(gg_status_display);
  2996.  
  2997. if(sdisplay == STATUS_LEADERWPN) status_display(0); // to all
  2998. else if(sdisplay) status_display(id); // only to me
  2999.  
  3000. // give weapon right away?
  3001. new turbo = get_pcvar_num(gg_turbo);
  3002. if((turbo || just_joined) && is_user_alive(id)) set_task(0.1,"give_level_weapon_delay",id);
  3003.  
  3004. if(show_message) gungame_hudmessage(id,3.0,"%L %i (%s)",id,"NOW_ON_LEVEL",level[id],weapon[id]);
  3005.  
  3006. new vote_setting = get_pcvar_num(gg_vote_setting), map_iterations = get_pcvar_num(gg_map_iterations);
  3007.  
  3008. // the level to start a map vote on
  3009. if(!voted && warmup <= 0 && vote_setting > 0
  3010. && level[id] >= get_weapon_num() - (vote_setting - 1)
  3011. && mapIteration >= map_iterations && map_iterations > 0)
  3012. {
  3013. new mapCycleFile[64];
  3014. get_gg_mapcycle_file(mapCycleFile,63);
  3015.  
  3016. // start map vote?
  3017. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  3018. {
  3019. voted = 1;
  3020.  
  3021. // check for a custom vote
  3022. new custom[256];
  3023. get_pcvar_string(gg_vote_custom,custom,255);
  3024.  
  3025. if(custom[0]) server_cmd(custom);
  3026. else start_mapvote();
  3027. }
  3028. }
  3029.  
  3030. // only calculate position if we didn't just join
  3031. if(!just_joined)
  3032. {
  3033. new bestLevel, bestPlayer = get_leader(bestLevel);
  3034.  
  3035. // I'M THE BEST!!!!!!!
  3036. if(bestPlayer == id)
  3037. {
  3038. // check for ties first
  3039. new players[32], num, i, tied;
  3040. get_players(players,num);
  3041.  
  3042. for(i=0;i<num;i++)
  3043. {
  3044. if(level[players[i]] == level[id] && players[i] != id)
  3045. {
  3046. tied = 1;
  3047. break;
  3048. }
  3049. }
  3050.  
  3051. if(tied && level[id] > 1) gungame_print(0,id,"%L",LANG_PLAYER_C,"TIED_LEADER",name);
  3052. else if(level[id] > 1) gungame_print(0,id,"%L",LANG_PLAYER_C,"LEADING_ON_LEVEL",name,level[id],weapon[id]);
  3053. }
  3054.  
  3055. // maybe still??
  3056. else if(level[bestPlayer] == level[id])
  3057. {
  3058. if(level[id] > 1) gungame_print(0,id,"%L",LANG_PLAYER_C,"TIED_LEADER",name);
  3059. }
  3060.  
  3061. // awww...
  3062. else gungame_print(id,0,"%L",id,"LEVELS_BEHIND_LEADER",level[bestPlayer]-level[id]);
  3063.  
  3064. // triple bonus!
  3065. if(levelsThisRound[id] == 3 && get_pcvar_num(gg_triple_on) && !turbo)
  3066. {
  3067. star[id] = 1;
  3068.  
  3069. new sound[64];
  3070. get_pcvar_string(gg_sound_triple,sound,63);
  3071.  
  3072. fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)*1.5);
  3073. if(sound[0]) emit_sound(id,CHAN_VOICE,sound,VOL_NORM,ATTN_NORM,0,PITCH_NORM);
  3074. set_pev(id,pev_effects,pev(id,pev_effects) | EF_BRIGHTLIGHT);
  3075. fm_set_rendering(id,kRenderFxGlowShell,255,255,100,kRenderNormal,1);
  3076. fm_set_user_godmode(id,1);
  3077.  
  3078. message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
  3079. write_byte(22); // TE_BEAMFOLLOW
  3080. write_short(id); // entity
  3081. write_short(trailSpr); // sprite
  3082. write_byte(20); // life
  3083. write_byte(10); // width
  3084. write_byte(255); // r
  3085. write_byte(255); // g
  3086. write_byte(100); // b
  3087. write_byte(100); // brightness
  3088. message_end();
  3089.  
  3090. gungame_print(0,id,"%L",LANG_PLAYER_C,"TRIPLE_LEVELED",name);
  3091. set_task(10.0,"end_star",TASK_END_STAR+id);
  3092. }
  3093. }
  3094.  
  3095. new ff_auto = get_pcvar_num(gg_ff_auto), ff = get_cvar_num("mp_friendlyfire");
  3096.  
  3097. // turn on FF?
  3098. if(ff_auto && !ff && equal(weapon[id],"hegrenade"))
  3099. {
  3100. set_cvar_num("mp_friendlyfire",1);
  3101. gungame_print(0,0,"%L",LANG_PLAYER_C,"FRIENDLYFIRE_ON");
  3102.  
  3103. client_cmd(0,"speak ^"gungame/brass_bell_C.wav^"");
  3104. }
  3105.  
  3106. // turn off FF?
  3107. else if(ff_auto && ff)
  3108. {
  3109. new keepFF, i;
  3110.  
  3111. for(i=1;i<=maxPlayers;i++)
  3112. {
  3113. if(equal(weapon[i],"hegrenade") || equal(weapon[i],"knife"))
  3114. {
  3115. keepFF = 1;
  3116. break;
  3117. }
  3118. }
  3119.  
  3120. // no one is on nade or knife level anymore
  3121. if(!keepFF) set_cvar_num("mp_friendlyfire",0);
  3122. }
  3123. }
  3124.  
  3125. // delay before giving weapon after leveling. without this, the game
  3126. // crashes without error. note that you couldn't just set_task to
  3127. // give_level_weapon, because it has multiple parameters, and so
  3128. // set_task won't accept it.
  3129. public give_level_weapon_delay(id)
  3130. {
  3131. if(is_user_connected(id)) give_level_weapon(id,0);
  3132. }
  3133.  
  3134. // get rid of a player's star
  3135. public end_star(taskid)
  3136. {
  3137. new id = taskid - TASK_END_STAR;
  3138. if(!star[id]) return;
  3139.  
  3140. star[id] = 0;
  3141. //gungame_print(id,0,"Your star has run out!");
  3142.  
  3143. if(is_user_alive(id))
  3144. {
  3145. fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)/1.5);
  3146. emit_sound(id,CHAN_VOICE,"common/null.wav",VOL_NORM,ATTN_NORM,0,PITCH_NORM); // stop sound
  3147. set_pev(id,pev_effects,pev(id,pev_effects) & ~EF_BRIGHTLIGHT);
  3148. fm_set_rendering(id);
  3149. fm_set_user_godmode(id,0);
  3150.  
  3151. message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
  3152. write_byte(99); // TE_KILLBEAM
  3153. write_short(id); // entity
  3154. message_end();
  3155. }
  3156. }
  3157.  
  3158. // give a player a weapon based on his level
  3159. stock give_level_weapon(id,notify=1,verify=1)
  3160. {
  3161. if(!is_user_alive(id) || pev(id,pev_iuser1)) return;
  3162.  
  3163. give_essentials(id);
  3164.  
  3165. new oldWeapon = get_user_weapon(id,dummy[0],dummy[0]);
  3166.  
  3167. static wpnName[24];
  3168. new weapons[32], wpnid, alright, num, i;
  3169. get_user_weapons(id,weapons,num);
  3170.  
  3171. new hasMain, hasGlock, hasSmoke, hasFlash;
  3172.  
  3173. new ammo = get_pcvar_num(gg_ammo_amount);
  3174. new knife_warmup = get_pcvar_num(gg_knife_warmup);
  3175. new pickup_others = get_pcvar_num(gg_pickup_others);
  3176. new myCategory = get_weapon_category(_,weapon[id]);
  3177.  
  3178. new nade_glock = get_pcvar_num(gg_nade_glock);
  3179. new nade_smoke = get_pcvar_num(gg_nade_smoke);
  3180. new nade_flash = get_pcvar_num(gg_nade_flash);
  3181.  
  3182. // remove stuff first
  3183. for(i=0;i<num;i++)
  3184. {
  3185. wpnid = weapons[i];
  3186. if(!wpnid) continue;
  3187.  
  3188. // ignore knife and C4
  3189. if(wpnid == CSW_KNIFE || wpnid == CSW_C4)
  3190. continue;
  3191.  
  3192. alright = 0;
  3193.  
  3194. // if we shouldn't be doing knives only,
  3195. // check to see if we already have certain weapons
  3196. if(warmup <= 0 || !knife_warmup)
  3197. {
  3198. // check for special grenade allowances
  3199. if(equal(weapon[id],"hegrenade"))
  3200. {
  3201. if(wpnid == CSW_GLOCK18 && nade_glock)
  3202. {
  3203. alright = 1;
  3204. hasGlock = 1;
  3205. }
  3206. else if(wpnid == CSW_SMOKEGRENADE && nade_smoke)
  3207. {
  3208. alright = 1;
  3209. hasSmoke = 1;
  3210. }
  3211. else if(wpnid == CSW_FLASHBANG && nade_flash)
  3212. {
  3213. alright = 1;
  3214. hasFlash = 1;
  3215. }
  3216. }
  3217.  
  3218. // weapon id -> weapon name
  3219. get_weaponname(wpnid,wpnName,23);
  3220. replace(wpnName,23,"weapon_","");
  3221.  
  3222. // this is our designated weapon
  3223. if(equal(weapon[id],wpnName))
  3224. {
  3225. alright = 1;
  3226. hasMain = 1;
  3227. }
  3228. }
  3229.  
  3230. // was it alright?
  3231. if(alright)
  3232. {
  3233. // reset ammo
  3234. if(wpnid != CSW_HEGRENADE && wpnid != CSW_SMOKEGRENADE && wpnid != CSW_FLASHBANG)
  3235. {
  3236. if(equal(weapon[id],"hegrenade") && wpnid == CSW_GLOCK18)
  3237. cs_set_user_bpammo(id,wpnid,50);
  3238.  
  3239. else if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  3240. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  3241. }
  3242. else cs_set_user_bpammo(id,wpnid,1); // grenades
  3243. }
  3244.  
  3245. // only remove this if we aren't allowed to have any other weapons,
  3246. // or if it takes up the same category as the weapon that we need
  3247. else if(!pickup_others || get_weapon_category(wpnid) == myCategory)
  3248. {
  3249. // remove grenades by clearing bpammo
  3250. if(wpnid == CSW_HEGRENADE || wpnid == CSW_SMOKEGRENADE || wpnid == CSW_FLASHBANG)
  3251. {
  3252. user_has_weapon(id,wpnid,0); // remove form
  3253. cs_set_user_bpammo(id,wpnid,0); // remove function
  3254. }
  3255.  
  3256. // remove regular weapons with this
  3257. else fm_strip_user_gun(id,wpnid);
  3258. }
  3259. }
  3260.  
  3261. // give CTs defuse kits on bomb maps
  3262. if(bombMap && !get_pcvar_num(gg_block_objectives) && cs_get_user_team(id) == CS_TEAM_CT)
  3263. cs_set_user_defuse(id,1);
  3264.  
  3265. new armor = get_pcvar_num(gg_give_armor), helmet = get_pcvar_num(gg_give_helmet);
  3266.  
  3267. // giving armor and helmets away like candy
  3268. if(helmet) cs_set_user_armor(id,armor,CS_ARMOR_VESTHELM);
  3269. else cs_set_user_armor(id,armor,CS_ARMOR_KEVLAR);
  3270.  
  3271. // extras for grenade level
  3272. if((warmup <= 0 || !knife_warmup) && equal(weapon[id],"hegrenade"))
  3273. {
  3274. if(nade_glock && !hasGlock)
  3275. {
  3276. fm_give_item(id,"weapon_glock18");
  3277. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  3278. }
  3279. if(nade_smoke && !hasSmoke) fm_give_item(id,"weapon_smokegrenade");
  3280. if(nade_flash && !hasFlash) fm_give_item(id,"weapon_flashbang");
  3281. }
  3282.  
  3283. if(notify)
  3284. {
  3285. if(warmup > 0)
  3286. {
  3287. if(knife_warmup) gungame_print(id,-1,"%L -- %L",id,"WARMUP_ROUND",id,"KNIVES_ONLY");
  3288. else gungame_print(id,-1,"%L",id,"WARMUP_ROUND");
  3289. }
  3290. else if(level[id] <= get_weapon_num()) // didn't just win
  3291. {
  3292. new goal = get_level_goal(level[id]);
  3293.  
  3294. gungame_print(id,-1,"%L %%n%i%%e :: %%n%s%%e",id,"ON_LEVEL",level[id],weapon[id]);
  3295. gungame_print(id,-1,"%L",id,"PROGRESS_DISPLAY",goal-score[id],score[id],goal);
  3296. }
  3297.  
  3298. //[GunGame] You are on level 9  : :  tmp
  3299. //[GunGame] You need  2  kills to advance.  Score :  0 / 2
  3300. }
  3301.  
  3302. // don't give anything away if knife-only warmup
  3303. if((warmup > 0 && knife_warmup) || equal(weapon[id],"knife"))
  3304. {
  3305. // draw knife on knife warmup and knife level... this is so that
  3306. // the terrorist that spawns with the C4 won't be spawned with his
  3307. // C4 selected, but instead his knfe
  3308. client_cmd(id,"weapon_knife");
  3309. return;
  3310. }
  3311.  
  3312. if(weapon[id][0] && !hasMain)
  3313. {
  3314. // stop double grenades
  3315. if(equal(weapon[id],"hegrenade") && cs_get_user_bpammo(id,CSW_HEGRENADE))
  3316. return;
  3317.  
  3318. formatex(wpnName,23,"weapon_%s",weapon[id]);
  3319.  
  3320. // make sure player gets his weapon
  3321. for(i=0;i<3;i++)
  3322. {
  3323. if(fm_give_item(id,wpnName))
  3324. break;
  3325. }
  3326.  
  3327. remove_task(TASK_REFRESH_NADE+id);
  3328.  
  3329. if(!equal(weapon[id],"hegrenade"))
  3330. {
  3331. wpnid = get_weaponid(wpnName);
  3332.  
  3333. if(!wpnid) log_amx("INVALID WEAPON ID FOR ^"%s^"",weapon[id]);
  3334. else
  3335. {
  3336. if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  3337. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  3338. }
  3339. }
  3340. }
  3341.  
  3342. // switch back to knife if we had it out. also don't do this when called
  3343. // by the verification check, because their old weapon will obviously be
  3344. // a knife and they will want to use their new one.
  3345. if(verify && oldWeapon == CSW_KNIFE && !notify) client_cmd(id,"weapon_knife");
  3346.  
  3347. // otherwise, switch to our new weapon
  3348. else
  3349. {
  3350. // glock18 for nade level?
  3351. if(equal(weapon[id],"hegrenade") && gg_nade_glock)
  3352. wpnName = "weapon_glock18";
  3353. else
  3354. formatex(wpnName,23,"weapon_%s",weapon[id]);
  3355.  
  3356. client_cmd(id,wpnName);
  3357. }
  3358.  
  3359. // remember burst or silenced status
  3360. if(silenced[id])
  3361. {
  3362. if(equal(weapon[id],"usp") || equal(weapon[id],"m4a1"))
  3363. {
  3364. new wEnt = get_weapon_ent(id,_,weapon[id]);
  3365. if(pev_valid(wEnt))
  3366. {
  3367. cs_set_weapon_silen(wEnt,1,0);
  3368.  
  3369. // play draw with silencer animation
  3370. if(weapon[id][0] == 'u') set_pev(id,pev_weaponanim,USP_DRAWANIM);
  3371. else set_pev(id,pev_weaponanim,M4A1_DRAWANIM);
  3372. }
  3373. }
  3374. else if(equal(weapon[id],"glock18") || equal(weapon[id],"famas"))
  3375. {
  3376. new wEnt = get_weapon_ent(id,_,weapon[id]);
  3377. if(pev_valid(wEnt)) cs_set_weapon_burst(wEnt,1);
  3378. }
  3379.  
  3380. silenced[id] = 0;
  3381. }
  3382.  
  3383. // make sure that we get this...
  3384. if(verify)
  3385. {
  3386. remove_task(TASK_VERIFY_WEAPON+id);
  3387. set_task(1.0,"verify_weapon",TASK_VERIFY_WEAPON+id);
  3388. }
  3389. }
  3390.  
  3391. // verify that we have our stupid weapon
  3392. public verify_weapon(taskid)
  3393. {
  3394. new id = taskid-TASK_VERIFY_WEAPON;
  3395.  
  3396. if(!is_user_alive(id)) return;
  3397.  
  3398. static wpnName[24];
  3399. formatex(wpnName,23,"weapon_%s",weapon[id]);
  3400. new wpnid = get_weaponid(wpnName);
  3401.  
  3402. if(!wpnid) return;
  3403.  
  3404. // we don't have it, but we want it
  3405. if((wpnid != CSW_HEGRENADE && !user_has_weapon(id,wpnid))
  3406. || (wpnid == CSW_HEGRENADE && !cs_get_user_bpammo(id,CSW_HEGRENADE)))
  3407. give_level_weapon(id,0,0);
  3408. }
  3409.  
  3410. // bring someone back to life
  3411. public begin_respawn(id)
  3412. {
  3413. if(!get_pcvar_num(gg_enabled) || !get_pcvar_num(gg_dm) || !is_user_connected(id))
  3414. return;
  3415.  
  3416. // now on spectator
  3417. new CsTeams:team = cs_get_user_team(id);
  3418. if(team == CS_TEAM_UNASSIGNED || team == CS_TEAM_SPECTATOR) return;
  3419.  
  3420. // alive, and not in the broken sort of way
  3421. if(is_user_alive(id) && !pev(id,pev_iuser1)) return;
  3422.  
  3423. // round is over, or bomb is planted
  3424. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  3425. return;
  3426.  
  3427. new Float:delay = get_pcvar_float(gg_dm_spawn_delay);
  3428. if(delay < 0.1) delay = 0.1;
  3429.  
  3430. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  3431.  
  3432. if((dm_countdown & 1) || (dm_countdown & 2))
  3433. {
  3434. respawn_timeleft[id] = floatround(delay);
  3435. respawn_countdown(id);
  3436. }
  3437.  
  3438. remove_task(TASK_RESPAWN+id);
  3439. set_task(delay,"respawn",TASK_RESPAWN+id);
  3440. }
  3441.  
  3442. // show the respawn countdown to a player
  3443. public respawn_countdown(id)
  3444. {
  3445. if(!is_user_connected(id) || is_user_alive(id))
  3446. {
  3447. respawn_timeleft[id] = 0;
  3448. return;
  3449. }
  3450.  
  3451. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  3452.  
  3453. if(dm_countdown & 1)
  3454. client_print(id,print_center,"%L",id,"RESPAWN_COUNTDOWN",respawn_timeleft[id]);
  3455.  
  3456. if(dm_countdown & 2)
  3457. gungame_hudmessage(id,1.0,"%L",id,"RESPAWN_COUNTDOWN",respawn_timeleft[id]);
  3458.  
  3459. if(--respawn_timeleft[id] >= 1) set_task(1.0,"respawn_countdown",id);
  3460. }
  3461.  
  3462. // REALLY bring someone back to life
  3463. public respawn(taskid)
  3464. {
  3465. new id = taskid-TASK_RESPAWN;
  3466. if(!is_user_connected(id) || !get_pcvar_num(gg_enabled)) return;
  3467.  
  3468. // round is over, or bomb is planted
  3469. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  3470. return;
  3471.  
  3472. // now on spectator
  3473. new CsTeams:team = cs_get_user_team(id);
  3474. if(team == CS_TEAM_UNASSIGNED || team == CS_TEAM_SPECTATOR) return;
  3475.  
  3476. // clear countdown
  3477. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  3478. if(dm_countdown & 1) client_print(id,print_center," ");
  3479. if(dm_countdown & 2) gungame_hudmessage(id,1.0," ");
  3480.  
  3481. // alive, and not in the broken sort of way
  3482. if(is_user_alive(id) && !pev(id,pev_iuser1)) return;
  3483.  
  3484. // remove his dropped weapons from before
  3485. new ent;
  3486. static model[22];
  3487. while((ent = fm_find_ent_by_class(ent,"weaponbox")) != 0)
  3488. {
  3489. pev(ent,pev_model,model,21);
  3490.  
  3491. // don't remove the bomb!! (thanks ToT | V!PER)
  3492. if(equal(model,"models/w_c4.mdl",15) || equal(model,"models/w_backpack.mdl"))
  3493. continue;
  3494.  
  3495. // this is mine
  3496. if(pev(ent,pev_owner) == id)
  3497. dllfunc(DLLFunc_Think,ent);
  3498. }
  3499.  
  3500. new spawn_random = get_pcvar_num(gg_dm_spawn_random);
  3501. if(spawn_random) spawnSounds[id] = 0;
  3502.  
  3503. if(csrespawnEnabled)
  3504. cs_respawn(id);
  3505. else
  3506. {
  3507. // properly respawn
  3508. blockCorpse[id] = 1;
  3509. fm_cs_user_spawn(id);
  3510.  
  3511. // make sure they made it
  3512. remove_task(TASK_CHECK_RESPAWN+id);
  3513. remove_task(TASK_CHECK_RESPAWN2+id);
  3514. set_task(0.5,"check_respawn",TASK_CHECK_RESPAWN+id);
  3515. set_task(1.5,"check_respawn",TASK_CHECK_RESPAWN2+id);
  3516. }
  3517.  
  3518. if(spawn_random)
  3519. {
  3520. do_random_spawn(id,spawn_random);
  3521. spawnSounds[id] = 1;
  3522.  
  3523. // to be fair, play a spawn noise at new location
  3524. engfunc(EngFunc_EmitSound,id,CHAN_ITEM,"items/gunpickup2.wav",VOL_NORM,ATTN_NORM,0,PITCH_NORM);
  3525. }
  3526.  
  3527. new Float:time = get_pcvar_float(gg_dm_sp_time);
  3528. new mode = get_pcvar_num(gg_dm_sp_mode);
  3529.  
  3530. // spawn protection
  3531. if(time > 0.0 && mode)
  3532. {
  3533. spawnProtected[id] = 1;
  3534. if(mode == 2)
  3535. {
  3536. fm_set_user_godmode(id,1);
  3537. fm_set_rendering(id,kRenderFxGlowShell,200,200,100,kRenderNormal,1); // goldenish
  3538. }
  3539. else fm_set_rendering(id,kRenderFxGlowShell,100,100,100,kRenderNormal,1); // gray/white
  3540.  
  3541. set_task(time,"remove_spawn_protection",TASK_REMOVE_PROTECTION+id);
  3542. }
  3543. }
  3544.  
  3545. // place a user at a random spawn
  3546. do_random_spawn(id,spawn_random)
  3547. {
  3548. // not even alive, don't brother
  3549. if(!is_user_alive(id) || pev(id,pev_iuser1))
  3550. return;
  3551.  
  3552. // no spawns???
  3553. if(spawnCount <= 0) return;
  3554.  
  3555. // no CSDM spawns, mode 2
  3556. if(spawn_random == 2 && !csdmSpawnCount)
  3557. return;
  3558.  
  3559. static Float:vecHolder[3];
  3560. new sp_index = random_num(0,spawnCount-1);
  3561.  
  3562. // get origin for comparisons
  3563. vecHolder[0] = spawns[sp_index][0];
  3564. vecHolder[1] = spawns[sp_index][1];
  3565. vecHolder[2] = spawns[sp_index][2];
  3566.  
  3567. // this one is taken
  3568. if(!is_hull_vacant(vecHolder,HULL_HUMAN) && spawnCount > 1)
  3569. {
  3570. new i;
  3571. for(i=sp_index+1;i!=sp_index;i++)
  3572. {
  3573. // start over when we reach the end
  3574. if(i >= spawnCount) i = 0;
  3575.  
  3576. vecHolder[0] = spawns[i][0];
  3577. vecHolder[1] = spawns[i][1];
  3578. vecHolder[2] = spawns[i][2];
  3579.  
  3580. // free space! office space!
  3581. if(is_hull_vacant(vecHolder,HULL_HUMAN))
  3582. {
  3583. sp_index = i;
  3584. break;
  3585. }
  3586. }
  3587. }
  3588.  
  3589. // origin
  3590. vecHolder[0] = spawns[sp_index][0];
  3591. vecHolder[1] = spawns[sp_index][1];
  3592. vecHolder[2] = spawns[sp_index][2];
  3593. engfunc(EngFunc_SetOrigin,id,vecHolder);
  3594.  
  3595. // angles
  3596. vecHolder[0] = spawns[sp_index][3];
  3597. vecHolder[1] = spawns[sp_index][4];
  3598. vecHolder[2] = spawns[sp_index][5];
  3599. set_pev(id,pev_angles,vecHolder);
  3600.  
  3601. // vangles
  3602. vecHolder[0] = spawns[sp_index][6];
  3603. vecHolder[1] = spawns[sp_index][7];
  3604. vecHolder[2] = spawns[sp_index][8];
  3605. set_pev(id,pev_v_angle,vecHolder);
  3606.  
  3607. set_pev(id,pev_fixangle,1);
  3608. }
  3609.  
  3610. // make sure a user respawned alright
  3611. public check_respawn(taskid)
  3612. {
  3613. new id;
  3614. if(taskid > TASK_CHECK_RESPAWN2) id = taskid-TASK_CHECK_RESPAWN2;
  3615. else id = taskid-TASK_CHECK_RESPAWN;
  3616.  
  3617. blockCorpse[id] = 0;
  3618.  
  3619. if(!is_user_connected(id))
  3620. return;
  3621.  
  3622. // now on spectator
  3623. new CsTeams:team = cs_get_user_team(id);
  3624. if(team == CS_TEAM_UNASSIGNED || team == CS_TEAM_SPECTATOR) return;
  3625.  
  3626. // didn't respawn properly
  3627. if(pev(id,pev_iuser1) || !is_user_alive(id))
  3628. {
  3629. //blockResetHUD[id]++; // no longer needed, since post_resethud checks pev_iuser1 now
  3630. remove_task(TASK_CHECK_RESPAWN+id);
  3631. remove_task(TASK_CHECK_RESPAWN2+id);
  3632. respawn(TASK_RESPAWN+id); // respawn them again
  3633. }
  3634. else
  3635. {
  3636. // double guarantee
  3637. give_essentials(id);
  3638. set_task(0.1,"give_essentials",id);
  3639. }
  3640. }
  3641.  
  3642. // give a user a knife and HUD after
  3643. // spawning in case he doesn't get one regularly
  3644. public give_essentials(id)
  3645. {
  3646. if(!is_user_alive(id) || pev(id,pev_iuser1)) return;
  3647.  
  3648. fm_set_user_suit(id,true,false);
  3649. if(!user_has_weapon(id,CSW_KNIFE)) fm_give_item(id,"weapon_knife");
  3650. }
  3651.  
  3652. // get rid of the spawn protection effects
  3653. public remove_spawn_protection(taskid)
  3654. {
  3655. new id = taskid-TASK_REMOVE_PROTECTION;
  3656.  
  3657. if(!is_user_connected(id)) return;
  3658.  
  3659. spawnProtected[id] = 0;
  3660. if(get_pcvar_num(gg_dm_sp_mode) == 2) fm_set_user_godmode(id,0);
  3661.  
  3662. fm_set_rendering(id); // reset back to normal
  3663. }
  3664.  
  3665. // crown a winner
  3666. win(id)
  3667. {
  3668. if(won) return;
  3669.  
  3670. won = 1;
  3671. roundEnded = 1;
  3672.  
  3673. set_cvar_num("sv_alltalk",1);
  3674. play_sound_by_cvar(0,gg_sound_winner);
  3675.  
  3676. new map_iterations = get_pcvar_num(gg_map_iterations);
  3677.  
  3678. // final playthrough, get ready for next map
  3679. if(mapIteration >= map_iterations && map_iterations > 0)
  3680. {
  3681. set_nextmap();
  3682. set_task(10.0,"goto_nextmap");
  3683.  
  3684. // as of 1.16, we always send a non-emessage intermission, because
  3685. // other map changing plugins (as well as StatsMe) intercepting it
  3686. // was causing problems.
  3687.  
  3688. message_begin(MSG_ALL,SVC_INTERMISSION);
  3689. message_end();
  3690. }
  3691.  
  3692. // get ready to go again!!
  3693. else
  3694. {
  3695. client_cmd(0,"+showscores");
  3696.  
  3697. set_task(4.9,"restart_gungame",czero ? get_cvar_num("bot_stop") : 0);
  3698. set_task(10.0,"stop_win_sound");
  3699.  
  3700. set_cvar_num("sv_restartround",5);
  3701. if(czero) set_cvar_num("bot_stop",1); // freeze CZ bots
  3702. }
  3703.  
  3704. new players[32], num, i;
  3705. get_players(players,num);
  3706.  
  3707. // freeze and godmode everyone
  3708. for(i=0;i<num;i++)
  3709. {
  3710. set_pev(players[i],pev_flags,pev(players[i],pev_flags) | FL_FROZEN);
  3711. fm_set_user_godmode(players[i],1);
  3712. }
  3713.  
  3714. // we have an invalid winner here
  3715. if(!is_user_connected(id) || !can_score(id))
  3716. return;
  3717.  
  3718. new winnerName[32], myName[32], authid[24], team[10];
  3719. get_user_name(id,winnerName,31);
  3720.  
  3721. for(i=0;i<5;i++) gungame_print(0,id,"%%n%s%%e %L!",winnerName,LANG_PLAYER_C,"WON");
  3722. set_cvar_num("sv_alltalk",1);
  3723.  
  3724. get_pcvar_string(gg_stats_file,sfFile,63);
  3725.  
  3726. new stats_mode = get_pcvar_num(gg_stats_mode), stats_ip = get_pcvar_num(gg_stats_ip),
  3727. ignore_bots = get_pcvar_num(gg_ignore_bots);
  3728.  
  3729. // points system
  3730. if(sfFile[0] && stats_mode == 2)
  3731. {
  3732. new wins, Float:flPoints, iPoints, totalPoints, player;
  3733.  
  3734. for(i=0;i<num;i++)
  3735. {
  3736. player = players[i];
  3737.  
  3738. // calculate points and add
  3739. flPoints = float(level[player]) - 1.0;
  3740. wins = 0;
  3741.  
  3742. // winner gets bonus points plus a win
  3743. if(player == id)
  3744. {
  3745. flPoints *= get_pcvar_float(gg_stats_winbonus);
  3746. wins = 1;
  3747. }
  3748.  
  3749. // unnecessary
  3750. if(flPoints <= 0.0 && !wins) continue;
  3751.  
  3752. iPoints = floatround(flPoints);
  3753.  
  3754. // it's okay to add to stats
  3755. if(!ignore_bots || !is_user_bot(player))
  3756. stats_add_to_score(player,wins,iPoints,dummy[0],totalPoints);
  3757.  
  3758. // log it
  3759. get_user_name(player,myName,31);
  3760.  
  3761. if(stats_ip) get_user_ip(player,authid,23);
  3762. else get_user_authid(player,authid,23);
  3763.  
  3764. get_user_team(player,team,9);
  3765. log_message("^"%s<%i><%s><%s>^" triggered ^"GunGame_Points^" amount ^"%i^"",myName,get_user_userid(player),authid,team,iPoints);
  3766.  
  3767. // display it
  3768. gungame_print(player,0,"%L",player,"GAINED_POINTS",iPoints,totalPoints);
  3769. }
  3770. }
  3771.  
  3772. // regular wins, no points
  3773. else if(sfFile[0] && stats_mode && (!ignore_bots || !is_user_bot(id)))
  3774. stats_add_to_score(id,1,0,dummy[0],dummy[0]);
  3775.  
  3776. if(stats_ip) get_user_ip(id,authid,23);
  3777. else get_user_authid(id,authid,23);
  3778.  
  3779. get_user_team(id,team,9);
  3780.  
  3781. log_message("^"%s<%i><%s><%s>^" triggered ^"Won_GunGame^"",winnerName,get_user_userid(id),authid,team);
  3782. //"Avalanche<2><VALVE_ID_LOOPBACK><TERRORIST>" triggered "Killed_A_Hostage"
  3783. }
  3784.  
  3785. // restart gungame, for the next map iteration
  3786. public restart_gungame(old_bot_stop_value)
  3787. {
  3788. won = 0;
  3789. mapIteration++;
  3790.  
  3791. toggle_gungame(TASK_TOGGLE_GUNGAME + TOGGLE_ENABLE); // reset stuff
  3792. do_rOrder(); // pick the next weapon order
  3793.  
  3794. // remove cheesey scoreboard
  3795. client_cmd(0,"-showscores");
  3796.  
  3797. new players[32], num, i;
  3798. get_players(players,num);
  3799.  
  3800. // unfreeze and ungodmode everyone
  3801. for(i=0;i<num;i++)
  3802. {
  3803. set_pev(players[i],pev_flags,pev(players[i],pev_flags) & ~FL_FROZEN);
  3804. fm_set_user_godmode(players[i],0);
  3805. welcomed[players[i]] = 1; // also don't show welcome again
  3806. }
  3807. if(czero) set_cvar_num("bot_stop",old_bot_stop_value); // unfreeze CZ bots
  3808.  
  3809. // only have warmup once?
  3810. if(!get_pcvar_num(gg_warmup_multi)) warmup = -13; // -13 is the magical stop number
  3811. else warmup = -1; // -1 isn't magical at all... :(
  3812. }
  3813.  
  3814. // stop the winner sound (for multiple map iterations)
  3815. public stop_win_sound()
  3816. {
  3817. new winSound[64];
  3818. get_pcvar_string(gg_sound_winner,winSound,63);
  3819.  
  3820. // stop winning sound
  3821. if(containi(winSound,".mp3") != -1) client_cmd(0,"mp3 stop");
  3822. else client_cmd(0,"speak null");
  3823. }
  3824.  
  3825. //
  3826. // AUTOVOTE FUNCTIONS
  3827. //
  3828.  
  3829. // start the autovote
  3830. public autovote_start()
  3831. {
  3832. // vote in progress
  3833. if(autovotes[0] || autovotes[1]) return;
  3834.  
  3835. new Float:autovote_time = get_pcvar_float(gg_autovote_time);
  3836.  
  3837. format(menuText,511,"\y%L^n^n\w1. %L^n2. %L^n^n0. %L",LANG_PLAYER,"PLAY_GUNGAME",LANG_PLAYER,"YES",LANG_PLAYER,"NO",LANG_PLAYER,"CANCEL");
  3838.  
  3839. show_menu(0,MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,menuText,floatround(autovote_time),"autovote_menu");
  3840. set_task(autovote_time,"autovote_result");
  3841. }
  3842.  
  3843. // take in votes
  3844. public autovote_menu_handler(id,key)
  3845. {
  3846. switch(key)
  3847. {
  3848. case 0: autovotes[1]++;
  3849. case 1: autovotes[0]++;
  3850. //case 9: let menu close
  3851. }
  3852.  
  3853. return PLUGIN_HANDLED;
  3854. }
  3855.  
  3856. // calculate end of vote
  3857. public autovote_result()
  3858. {
  3859. new enable, enabled = get_pcvar_num(gg_enabled);
  3860.  
  3861. if(autovotes[0] || autovotes[1])
  3862. {
  3863. if(float(autovotes[1]) / float(autovotes[0] + autovotes[1]) >= get_pcvar_float(gg_autovote_ratio))
  3864. enable = 1;
  3865. }
  3866.  
  3867. gungame_print(0,-1,"%L (%L: %i, %L: %i)",LANG_PLAYER_C,(enable) ? "VOTING_SUCCESS" : "VOTING_FAILED",LANG_PLAYER_C,"YES",autovotes[1],LANG_PLAYER_C,"NO",autovotes[0]);
  3868.  
  3869. if(enable && !enabled)
  3870. {
  3871. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_ENABLE);
  3872. set_cvar_num("sv_restartround",5);
  3873. }
  3874. else if(!enable && enabled)
  3875. {
  3876. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_DISABLE);
  3877. set_cvar_num("sv_restartround",5);
  3878. set_pcvar_num(gg_enabled,0);
  3879. }
  3880.  
  3881. // reset votes
  3882. autovotes[0] = 0;
  3883. autovotes[1] = 0;
  3884. }
  3885.  
  3886. //
  3887. // STAT FUNCTIONS
  3888. //
  3889.  
  3890. // add to a player's wins
  3891. stats_add_to_score(id,wins,points,&newWins,&newPoints)
  3892. {
  3893. // stats disabled
  3894. if(!get_pcvar_num(gg_stats_mode)) return 0;
  3895.  
  3896. get_pcvar_string(gg_stats_file,sfFile,63);
  3897.  
  3898. // stats disabled
  3899. if(!sfFile[0]) return 0;
  3900.  
  3901. // get data
  3902. new authid[24], name[32];
  3903.  
  3904. if(get_pcvar_num(gg_stats_ip)) get_user_ip(id,authid,23);
  3905. else get_user_authid(id,authid,23);
  3906.  
  3907. get_user_name(id,name,31);
  3908.  
  3909. // clean up the name
  3910. trim(name);
  3911. replace_all(name,31,"^t"," ");
  3912.  
  3913. // replace it with new data
  3914. new oldWins, oldPoints, line;
  3915. line = stats_get_data(authid,oldWins,oldPoints,dummy,1,dummy[0]);
  3916.  
  3917. newWins = oldWins+wins;
  3918. newPoints = oldPoints+points;
  3919.  
  3920. return stats_set_data(authid,oldWins+wins,oldPoints+points,name,get_systime(),line);
  3921. }
  3922.  
  3923. // get a player's last used name and wins from save file
  3924. stock stats_get_data(authid[],&wins,&points,lastName[],nameLen,&timestamp,knownLine=-1)
  3925. {
  3926. wins = 0;
  3927. points = 0;
  3928. timestamp = 0;
  3929.  
  3930. // stats disabled
  3931. if(!get_pcvar_num(gg_stats_mode)) return -1;
  3932.  
  3933. get_pcvar_string(gg_stats_file,sfFile,63);
  3934.  
  3935. // stats disabled/file doesn't exist
  3936. if(!sfFile[0] || !file_exists(sfFile)) return -1;
  3937.  
  3938. // storage format:
  3939. // AUTHID WINS LAST_USED_NAME TIMESTAMP POINTS
  3940.  
  3941. // reset
  3942. sfLineData[0] = 0;
  3943.  
  3944. // open 'er up, boys!
  3945. new line, found, file = fopen(sfFile,"rt");
  3946. if(!file) return -1;
  3947.  
  3948. // go through it
  3949. while(!feof(file))
  3950. {
  3951. fgets(file,sfLineData,80);
  3952. line++;
  3953.  
  3954. // go to the line we know
  3955. if(knownLine > -1)
  3956. {
  3957. if(line-1 == knownLine)
  3958. {
  3959. found = 1;
  3960. break;
  3961. }
  3962. else continue;
  3963. }
  3964.  
  3965. // isolate authid
  3966. strtok(sfLineData,sfAuthid,23,dummy,1,'^t');
  3967.  
  3968. // this is it, stop now because our
  3969. // data is already stored in sfLineData
  3970. if(equal(authid,sfAuthid))
  3971. {
  3972. found = 1;
  3973. break;
  3974. }
  3975. }
  3976.  
  3977. // close 'er up, boys! (hmm....)
  3978. fclose(file);
  3979.  
  3980. // couldn't find
  3981. if(!found) return -1;
  3982.  
  3983. // isolate authid
  3984. strtok(sfLineData,sfAuthid,23,sfLineData,80,'^t');
  3985.  
  3986. // isolate wins
  3987. strtok(sfLineData,sfWins,5,sfLineData,80,'^t');
  3988. wins = str_to_num(sfWins);
  3989.  
  3990. // isolate name
  3991. strtok(sfLineData,lastName,nameLen,sfLineData,80,'^t');
  3992.  
  3993. // isolate timestamp
  3994. strtok(sfLineData,sfTimestamp,11,sfPoints,7,'^t');
  3995. timestamp = str_to_num(sfTimestamp);
  3996.  
  3997. // isolate points (only thing left)
  3998. points = str_to_num(sfPoints);
  3999.  
  4000. // return the line we got it on
  4001. if(knownLine > -1) return knownLine;
  4002.  
  4003. return line - 1;
  4004. }
  4005.  
  4006. // set a player's last used name and wins from save file
  4007. stock stats_set_data(authid[],wins,points,lastName[],timestamp,knownLine=-1)
  4008. {
  4009. // stats disabled
  4010. if(!get_pcvar_num(gg_stats_mode)) return 0;
  4011.  
  4012. get_pcvar_string(gg_stats_file,sfFile,63);
  4013.  
  4014. // stats disabled
  4015. if(!sfFile[0]) return 0;
  4016.  
  4017. // storage format:
  4018. // AUTHID WINS LAST_USED_NAME TIMESTAMP POINTS
  4019.  
  4020. new tempFileName[65], sfFile_rename[64], newFile_rename[65], file;
  4021. formatex(tempFileName,64,"%s2",sfFile); // our temp file, append 2
  4022.  
  4023. // rename_file backwards compatibility (thanks Mordekay)
  4024. formatex(sfFile_rename,63,"%s/%s",modName,sfFile);
  4025. formatex(newFile_rename,64,"%s/%s",modName,tempFileName);
  4026.  
  4027. // create stats file if it doesn't exist
  4028. if(!file_exists(sfFile))
  4029. {
  4030. file = fopen(sfFile,"wt");
  4031. fclose(file);
  4032. }
  4033.  
  4034. // copy over current stat file
  4035. rename_file(sfFile_rename,newFile_rename);
  4036.  
  4037. // rename failed?
  4038. if(!file_exists(tempFileName)) return 0;
  4039.  
  4040. new tempFile = fopen(tempFileName,"rt");
  4041. new line, goal;
  4042. file = fopen(sfFile,"wt");
  4043.  
  4044. // go through our old copy and rewrite entries
  4045. while(tempFile && file && !feof(tempFile))
  4046. {
  4047. fgets(tempFile,sfLineData,80);
  4048.  
  4049. if(!sfLineData[0])
  4050. {
  4051. line++;
  4052. continue;
  4053. }
  4054.  
  4055. // see if this is the line we are trying to overwrite
  4056. if(!goal)
  4057. {
  4058. if(knownLine > -1)
  4059. {
  4060. if(line == knownLine) goal = 1;
  4061. }
  4062. else
  4063. {
  4064. // isolate authid
  4065. strtok(sfLineData,sfAuthid,23,dummy,1,'^t');
  4066.  
  4067. // this is what we are looking for
  4068. if(equal(authid,sfAuthid)) goal = 1;
  4069. }
  4070. }
  4071.  
  4072. // overwrite with new values
  4073. if(goal == 1)
  4074. {
  4075. goal = -1;
  4076. fprintf(file,"%s^t%i^t%s^t%i^t%i",authid,wins,lastName,timestamp,points);
  4077. fputc(file,'^n');
  4078. }
  4079.  
  4080. // otherwise just copy it over as it was (newline is already included)
  4081. else fprintf(file,"%s",sfLineData);
  4082.  
  4083. line++;
  4084. }
  4085.  
  4086. // never found an existing entry, make a new one
  4087. if(!goal)
  4088. {
  4089. fprintf(file,"%s^t%i^t%s^t%i^t%i",authid,wins,lastName,timestamp,points);
  4090. fputc(file,'^n');
  4091. }
  4092.  
  4093. if(tempFile) fclose(tempFile);
  4094. if(file) fclose(file);
  4095.  
  4096. // remove our copy
  4097. delete_file(tempFileName);
  4098.  
  4099. return 1;
  4100. }
  4101.  
  4102. // update a user's timestamp
  4103. stats_refresh_timestamp(authid[])
  4104. {
  4105. new wins, points, lastName[32], timestamp;
  4106. new line = stats_get_data(authid,wins,points,lastName,31,timestamp);
  4107.  
  4108. if(line > -1) stats_set_data(authid,wins,points,lastName,get_systime(),line);
  4109. }
  4110.  
  4111. // gets the top X amount of players into an array
  4112. // of the format: storage[amount][storageLen]
  4113. stats_get_top_players(amount,storage[][],storageLen)
  4114. {
  4115. // stats disabled
  4116. if(!get_pcvar_num(gg_stats_mode)) return 0;
  4117.  
  4118. get_pcvar_string(gg_stats_file,sfFile,63);
  4119.  
  4120. // stats disabled/file doesn't exist
  4121. if(!sfFile[0] || !file_exists(sfFile)) return 0;
  4122.  
  4123. // storage format:
  4124. // AUTHID WINS LAST_USED_NAME TIMESTAMP POINTS
  4125.  
  4126. // not so much OMG OMG OMG OMG as of 1.16
  4127. static tempList[TOP_PLAYERS+1][82], tempLineData[81];
  4128.  
  4129. new count, stats_mode = get_pcvar_num(gg_stats_mode), score[10];
  4130.  
  4131. // open sesame
  4132. new file = fopen(sfFile,"rt");
  4133. if(!file) return 0;
  4134.  
  4135. // reading, reading, reading...
  4136. while(!feof(file))
  4137. {
  4138. fgets(file,sfLineData,80);
  4139.  
  4140. // empty line
  4141. if(!sfLineData[0]) continue;
  4142.  
  4143. // assign it to a new variable so that strtok
  4144. // doesn't tear apart our constant sfLineData variable
  4145. tempLineData = sfLineData;
  4146.  
  4147. // get rid of authid
  4148. strtok(tempLineData,dummy,1,tempLineData,80,'^t');
  4149.  
  4150. // sort by wins
  4151. if(stats_mode == 1)
  4152. {
  4153. strtok(tempLineData,score,9,tempLineData,1,'^t');
  4154. }
  4155.  
  4156. // sort by points
  4157. else
  4158. {
  4159. // break off wins
  4160. strtok(tempLineData,dummy,1,tempLineData,80,'^t');
  4161.  
  4162. // break off name
  4163. strtok(tempLineData,dummy,1,tempLineData,80,'^t');
  4164.  
  4165. // break off timestamp and get points
  4166. strtok(tempLineData,dummy,1,score,9,'^t');
  4167. }
  4168.  
  4169. // don't store more than 11
  4170. if(count >= amount) count = amount;
  4171.  
  4172. tempList[count][0] = str_to_num(score);
  4173. formatex(tempList[count][1],81,"%s",sfLineData);
  4174. count++;
  4175.  
  4176. // filled list with 11, sort
  4177. if(count > amount) SortCustom2D(tempList,count,"stats_custom_compare");
  4178. }
  4179.  
  4180. // nolisting
  4181. if(!count)
  4182. {
  4183. fclose(file);
  4184. return 0;
  4185. }
  4186.  
  4187. // not yet sorted (didn't reach 11 entries)
  4188. else if(count <= amount)
  4189. SortCustom2D(tempList,count,"stats_custom_compare");
  4190.  
  4191. new i;
  4192.  
  4193. // now that it's sorted, return it
  4194. for(i=0;i<amount&&i<count;i++)
  4195. formatex(storage[i],storageLen,"%s",tempList[i][1]);
  4196.  
  4197.  
  4198. // close
  4199. fclose(file);
  4200.  
  4201. return 1;
  4202. }
  4203.  
  4204. // our custom sorting function (check first dimension for score)
  4205. public stats_custom_compare(elem1[],elem2[])
  4206. {
  4207. if(elem1[0] > elem2[0]) return -1;
  4208. else if(elem1[0] < elem2[0]) return 1;
  4209.  
  4210. return 0;
  4211. }
  4212.  
  4213. // prune old entries
  4214. stock stats_prune(max_time=-1)
  4215. {
  4216. get_pcvar_string(gg_stats_file,sfFile,63);
  4217.  
  4218. // stats disabled/file doesn't exist
  4219. if(!sfFile[0] || !file_exists(sfFile)) return 0;
  4220.  
  4221. // -1 = use value from cvar
  4222. if(max_time == -1) max_time = get_pcvar_num(gg_stats_prune);
  4223.  
  4224. // 0 = no pruning
  4225. if(max_time == 0) return 0;
  4226.  
  4227. new tempFileName[65], sfFile_rename[64], newFile_rename[65];
  4228. formatex(tempFileName,64,"%s2",sfFile); // our temp file, append 2
  4229.  
  4230. // rename_file backwards compatibility (thanks Mordekay)
  4231. formatex(sfFile_rename,63,"%s/%s",modName,sfFile);
  4232. formatex(newFile_rename,64,"%s/%s",modName,tempFileName);
  4233.  
  4234. // copy over current stat file
  4235. rename_file(sfFile_rename,newFile_rename);
  4236.  
  4237. // rename failed?
  4238. if(!file_exists(tempFileName)) return 0;
  4239.  
  4240. new tempFile = fopen(tempFileName,"rt");
  4241. new file = fopen(sfFile,"wt");
  4242.  
  4243. // go through our old copy and rewrite valid entries into the new copy
  4244. new current_time = get_systime(), original[81], removed;
  4245. while(tempFile && file && !feof(tempFile))
  4246. {
  4247. fgets(tempFile,sfLineData,80);
  4248.  
  4249. if(!sfLineData[0]) continue;
  4250.  
  4251. // save original
  4252. original = sfLineData;
  4253.  
  4254. // break off authid
  4255. strtok(sfLineData,sfAuthid,1,sfLineData,80,'^t');
  4256.  
  4257. // break off wins
  4258. strtok(sfLineData,sfWins,1,sfLineData,80,'^t');
  4259.  
  4260. // break off name, and thus get timestamp
  4261. strtok(sfLineData,sfName,1,sfTimestamp,11,'^t');
  4262. copyc(sfTimestamp,11,sfTimestamp,'^t'); // cut off points
  4263.  
  4264. // not too old, write it to our new file
  4265. if(current_time - str_to_num(sfTimestamp) <= max_time)
  4266. fprintf(file,"%s",original); // newline is already included
  4267. else
  4268. removed++;
  4269. }
  4270.  
  4271. if(tempFile) fclose(tempFile);
  4272. if(file) fclose(file);
  4273.  
  4274. // remove our copy
  4275. delete_file(tempFileName);
  4276. return removed;
  4277. }
  4278.  
  4279. //
  4280. // SUPPORT FUNCTIONS
  4281. //
  4282.  
  4283. stock get_level_goal(level)
  4284. {
  4285. get_pcvar_string(gg_weapon_order,weaponOrder,415);
  4286.  
  4287. new comma = str_find_num(weaponOrder,',',level-1)+1;
  4288.  
  4289. static crop[32];
  4290. copyc(crop,31,weaponOrder[comma],',');
  4291.  
  4292. new colon = containi(crop,":");
  4293.  
  4294. // no custom goal
  4295. if(colon == -1)
  4296. {
  4297. if(equal(crop,"hegrenade") || equal(crop,"knife"))
  4298. return 1;
  4299. else
  4300. return get_pcvar_num(gg_kills_per_lvl);
  4301. }
  4302.  
  4303. static goal[4];
  4304. copyc(goal,3,crop[colon+1],',');
  4305.  
  4306. return str_to_num(goal);
  4307. }
  4308.  
  4309. // get the name of a weapon by level
  4310. stock get_weapon_name_by_level(theLevel,var[],varLen,includeGoal=0)
  4311. {
  4312. if(!theLevel)
  4313. {
  4314. formatex(var,varLen,"glock18");
  4315. return;
  4316. }
  4317. else if(theLevel > 32 || theLevel > get_weapon_num())
  4318. {
  4319. formatex(var,varLen,"knife");
  4320. return;
  4321. }
  4322.  
  4323. static weapons[32][24];
  4324. get_weapon_order(weapons);
  4325.  
  4326. if(!includeGoal && containi(var,":")) // strip off goal if we don't want it
  4327. copyc(var,varLen,weapons[theLevel-1],':');
  4328.  
  4329. else
  4330. formatex(var,varLen,"%s",weapons[theLevel-1]);
  4331.  
  4332. strtolower(var);
  4333. }
  4334.  
  4335. // get the weapons, in order
  4336. get_weapon_order(weapons[32][24])
  4337. {
  4338. get_pcvar_string(gg_weapon_order,weaponOrder,415);
  4339.  
  4340. new i;
  4341. for(i=0;i<32;i++)
  4342. {
  4343. // out of stuff
  4344. if(strlen(weaponOrder) <= 1) break;
  4345.  
  4346. // we still have a comma, go up to it
  4347. if(containi(weaponOrder,",") != -1)
  4348. {
  4349. strtok(weaponOrder,weapons[i],23,weaponOrder,415,',');
  4350. trim(weapons[i]);
  4351. }
  4352.  
  4353. // otherwise, finish up
  4354. else
  4355. {
  4356. formatex(weapons[i],23,"%s",weaponOrder);
  4357. trim(weapons[i]);
  4358. break;
  4359. }
  4360. }
  4361. }
  4362.  
  4363. // get the number of weapons to go through
  4364. get_weapon_num()
  4365. {
  4366. get_pcvar_string(gg_weapon_order,weaponOrder,415);
  4367. return str_count(weaponOrder,',') + 1;
  4368. }
  4369.  
  4370. // easy function to precache sound via cvar
  4371. precache_sound_by_cvar(cvar[],default_val[])
  4372. {
  4373. new value[64];
  4374. get_cvar_string(cvar,value,63);
  4375.  
  4376. // mp3s precache as generic (full filepath)
  4377. if(containi(value,".mp3") != -1 || (!value[0] && containi(default_val,".mp3") != -1))
  4378. {
  4379. if(!strlen(value) || !file_exists(value)) precache_generic(default_val);
  4380. else precache_generic(value);
  4381. }
  4382.  
  4383. // wavs precache as sound (in sound/ directory by default)
  4384. else
  4385. {
  4386. new filepath[64];
  4387. formatex(filepath,63,"sound/%s",value);
  4388.  
  4389. if(!strlen(value) || !file_exists(filepath)) precache_sound(default_val);
  4390. else precache_sound(value);
  4391. }
  4392. }
  4393.  
  4394. // figure out which gungame.cfg file to use
  4395. get_gg_config_file(filename[],len)
  4396. {
  4397. formatex(filename,len,"%s/gungame.cfg",cfgDir);
  4398.  
  4399. if(!file_exists(filename))
  4400. {
  4401. formatex(filename,len,"gungame.cfg");
  4402. if(!file_exists(filename)) filename[0] = 0;
  4403. }
  4404. }
  4405.  
  4406. // figure out which gungame_mapcycle file to use
  4407. get_gg_mapcycle_file(filename[],len)
  4408. {
  4409. static testFile[64];
  4410.  
  4411. // cstrike/addons/amxmodx/configs/gungame_mapcycle.cfg
  4412. formatex(testFile,63,"%s/gungame_mapcycle.cfg",cfgDir);
  4413. if(file_exists(testFile))
  4414. {
  4415. formatex(filename,len,"%s",testFile);
  4416. return 1;
  4417. }
  4418.  
  4419. // cstrike/addons/amxmodx/configs/gungame_mapcycle.txt
  4420. formatex(testFile,63,"%s/gungame_mapcycle.txt",cfgDir);
  4421. if(file_exists(testFile))
  4422. {
  4423. formatex(filename,len,"%s",testFile);
  4424. return 1;
  4425. }
  4426.  
  4427. // cstrike/gungame_mapcycle.cfg
  4428. testFile = "gungame_mapcycle.cfg";
  4429. if(file_exists(testFile))
  4430. {
  4431. formatex(filename,len,"%s",testFile);
  4432. return 1;
  4433. }
  4434.  
  4435. // cstrike/gungame_mapcycle.txt
  4436. testFile = "gungame_mapcycle.txt";
  4437. if(file_exists(testFile))
  4438. {
  4439. formatex(filename,len,"%s",testFile);
  4440. return 1;
  4441. }
  4442.  
  4443. return 0;
  4444. }
  4445.  
  4446. // another easy function to play sound via cvar
  4447. play_sound_by_cvar(id,cvar)
  4448. {
  4449. static value[64];
  4450. get_pcvar_string(cvar,value,63);
  4451.  
  4452. if(!value[0]) return;
  4453.  
  4454. if(containi(value,".mp3") != -1) client_cmd(id,"mp3 play ^"%s^"",value);
  4455. else client_cmd(id,"speak ^"%s^"",value);
  4456. }
  4457.  
  4458. // find the highest level player and his level
  4459. get_leader(&Rlevel)
  4460. {
  4461. new players[32], num, i, leader;
  4462. get_players(players,num);
  4463.  
  4464. // locate highest player
  4465. for(i=0;i<num;i++)
  4466. {
  4467. if(leader == 0 || level[players[i]] > level[leader])
  4468. leader = players[i];
  4469. }
  4470.  
  4471. Rlevel = level[leader];
  4472. return leader;
  4473. }
  4474.  
  4475. // a butchered version of teame06's CS Color Chat Function
  4476. gungame_print(id,custom,msg[],{Float,Sql,Result,_}:...)
  4477. {
  4478. new changeCount, num, i, j;
  4479. static newMsg[191], message[191], changed[5], players[32];
  4480.  
  4481. if(id)
  4482. {
  4483. players[0] = id;
  4484. num = 1;
  4485. }
  4486. else get_players(players,num);
  4487.  
  4488. new colored_messages = get_pcvar_num(gg_colored_messages);
  4489.  
  4490. for(i=0;i<num;i++)
  4491. {
  4492. changeCount = 0;
  4493.  
  4494. // we have to change LANG_PLAYER into
  4495. // a player-specific argument, because
  4496. // ML doesn't work well with SayText
  4497. for(j=3;j<numargs();j++)
  4498. {
  4499. if(getarg(j) == LANG_PLAYER_C)
  4500. {
  4501. setarg(j,0,players[i]);
  4502. changed[changeCount++] = j;
  4503. }
  4504. }
  4505.  
  4506. // do user formatting
  4507. vformat(newMsg,190,msg,4);
  4508.  
  4509. // and now we have to change what we changed
  4510. // back into LANG_PLAYER, so that the next
  4511. // player will be able to have it in his language
  4512. for(j=0;j<changeCount;j++)
  4513. {
  4514. setarg(changed[j],0,LANG_PLAYER_C);
  4515. }
  4516.  
  4517. // optimized color swapping
  4518. if(colored_messages)
  4519. {
  4520. replace_all(newMsg,190,"%n","^x03"); // %n = team color
  4521. replace_all(newMsg,190,"%g","^x04"); // %g = green
  4522. replace_all(newMsg,190,"%e","^x01"); // %e = regular
  4523. }
  4524. else
  4525. {
  4526. replace_all(newMsg,190,"%n","");
  4527. replace_all(newMsg,190,"%g","");
  4528. replace_all(newMsg,190,"%e","");
  4529. }
  4530.  
  4531. // now do our formatting (I used two variables because sharing one caused glitches)
  4532.  
  4533. if(custom == -1) formatex(message,190,"^x04[%L]^x01 %s",players[i],"GUNGAME",newMsg);
  4534. else formatex(message,190,"^x01%s",newMsg);
  4535.  
  4536. message_begin(MSG_ONE,gmsgSayText,_,players[i]);
  4537. write_byte((custom > 0) ? custom : players[i]);
  4538. write_string(message);
  4539. message_end();
  4540. }
  4541. }
  4542.  
  4543. // show a HUD message to a user
  4544. gungame_hudmessage(id,Float:holdTime,msg[],{Float,Sql,Result,_}:...)
  4545. {
  4546. // user formatting
  4547. static newMsg[191];
  4548. vformat(newMsg,190,msg,4);
  4549.  
  4550. // show it
  4551. set_hudmessage(255,255,255,-1.0,0.8,0,6.0,holdTime,0.1,0.5,CHANNEL_STATUS);
  4552. show_hudmessage(id,newMsg);
  4553. }
  4554.  
  4555. // start a map vote
  4556. start_mapvote()
  4557. {
  4558. new dmmName[32];
  4559.  
  4560. // AMXX Nextmap Chooser
  4561. if(find_plugin_byfile("mapchooser.amxx") != INVALID_PLUGIN_ID)
  4562. {
  4563. new oldWinLimit = get_cvar_num("mp_winlimit"), oldMaxRounds = get_cvar_num("mp_maxrounds");
  4564. set_cvar_num("mp_winlimit",0); // skip winlimit check
  4565. set_cvar_num("mp_maxrounds",-1); // trick plugin to think game is almost over
  4566.  
  4567. // call the vote
  4568. if(callfunc_begin("voteNextmap","mapchooser.amxx") == 1)
  4569. callfunc_end();
  4570.  
  4571. // set maxrounds back
  4572. set_cvar_num("mp_winlimit",oldWinLimit);
  4573. set_cvar_num("mp_maxrounds",oldMaxRounds);
  4574. }
  4575.  
  4576. // Deagles' Map Management 2.30b
  4577. else if(find_plugin_byfile("deagsmapmanage230b.amxx") != INVALID_PLUGIN_ID)
  4578. {
  4579. dmmName = "deagsmapmanage230b.amxx";
  4580. }
  4581.  
  4582. // Deagles' Map Management 2.40
  4583. else if(find_plugin_byfile("deagsmapmanager.amxx") != INVALID_PLUGIN_ID)
  4584. {
  4585. dmmName = "deagsmapmanager.amxx";
  4586. }
  4587.  
  4588. // Mapchooser4
  4589. else if(find_plugin_byfile("mapchooser4.amxx") != INVALID_PLUGIN_ID)
  4590. {
  4591. new oldWinLimit = get_cvar_num("mp_winlimit"), oldMaxRounds = get_cvar_num("mp_maxrounds");
  4592. set_cvar_num("mp_winlimit",0); // skip winlimit check
  4593. set_cvar_num("mp_maxrounds",1); // trick plugin to think game is almost over
  4594.  
  4595. // deactivate g_buyingtime variable
  4596. if(callfunc_begin("buyFinished","mapchooser4.amxx") == 1)
  4597. callfunc_end();
  4598.  
  4599. // call the vote
  4600. if(callfunc_begin("voteNextmap","mapchooser4.amxx") == 1)
  4601. {
  4602. callfunc_push_str("",false);
  4603. callfunc_end();
  4604. }
  4605.  
  4606. // set maxrounds back
  4607. set_cvar_num("mp_winlimit",oldWinLimit);
  4608. set_cvar_num("mp_maxrounds",oldMaxRounds);
  4609. }
  4610.  
  4611. // NOTHING?
  4612. else log_amx("Using gg_vote_setting without mapchooser.amxx, mapchooser4.amxx, deagsmapmanage230b.amxx, or deagsmapmanager.amxx: could not start a vote!");
  4613.  
  4614. // do DMM stuff
  4615. if(dmmName[0])
  4616. {
  4617. // allow voting
  4618. /*if(callfunc_begin("dmapvotemode",dmmName) == 1)
  4619. {
  4620. callfunc_push_int(0); // server
  4621. callfunc_end();
  4622. }*/
  4623.  
  4624. new oldWinLimit = get_cvar_num("mp_winlimit"), Float:oldTimeLimit = get_cvar_float("mp_timelimit");
  4625. set_cvar_num("mp_winlimit",99999); // don't allow extending
  4626. set_cvar_float("mp_timelimit",0.0); // don't wait for buying
  4627. set_cvar_num("enforce_timelimit",1); // don't change map after vote
  4628.  
  4629. // call the vote
  4630. if(callfunc_begin("startthevote",dmmName) == 1)
  4631. callfunc_end();
  4632.  
  4633. set_cvar_num("mp_winlimit",oldWinLimit);
  4634. set_cvar_float("mp_timelimit",oldTimeLimit);
  4635.  
  4636. // disallow further voting
  4637. /*if(callfunc_begin("dmapcyclemode",dmmName) == 1)
  4638. {
  4639. callfunc_push_int(0); // server
  4640. callfunc_end();
  4641. }*/
  4642. }
  4643. }
  4644.  
  4645. // set amx_nextmap to the next map
  4646. set_nextmap()
  4647. {
  4648. new mapCycleFile[64];
  4649. get_gg_mapcycle_file(mapCycleFile,63);
  4650.  
  4651. // no mapcycle, leave amx_nextmap alone
  4652. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  4653. {
  4654. set_localinfo("gg_cycle_num","0");
  4655. return;
  4656. }
  4657.  
  4658. new strVal[10];
  4659.  
  4660. // have not gotten cycleNum yet (only get it once, because
  4661. // set_nextmap is generally called at least twice per map, and we
  4662. // don't want to change it twice)
  4663. if(cycleNum == -1)
  4664. {
  4665. get_localinfo("gg_cycle_num",strVal,9);
  4666. cycleNum = str_to_num(strVal);
  4667. }
  4668.  
  4669. new firstMap[32], currentMap[32], lineData[32], i, line, foundMap;
  4670. get_mapname(currentMap,31);
  4671.  
  4672. new file = fopen(mapCycleFile,"rt");
  4673. while(file && !feof(file))
  4674. {
  4675. fgets(file,lineData,31);
  4676.  
  4677. trim(lineData);
  4678. replace(lineData,31,".bsp",""); // remove extension
  4679.  
  4680. // stop at a comment
  4681. for(i=0;i<strlen(lineData)-2;i++)
  4682. {
  4683. // supports config-style (;) and coding-style (//)
  4684. if(lineData[i] == ';' || (lineData[i] == '/' && lineData[i+1] == '/'))
  4685. {
  4686. copy(lineData,i,lineData);
  4687. break;
  4688. }
  4689. }
  4690.  
  4691. trim(lineData);
  4692. if(!lineData[0]) continue;
  4693.  
  4694. // save first map
  4695. if(!firstMap[0]) formatex(firstMap,31,"%s",lineData);
  4696.  
  4697. // we reached the line after our current map's line
  4698. if(line == cycleNum+1)
  4699. {
  4700. // remember so
  4701. foundMap = 1;
  4702.  
  4703. // get ready to change to it
  4704. set_cvar_string("amx_nextmap",lineData);
  4705.  
  4706. // remember this map's line for next time
  4707. num_to_str(line,strVal,9);
  4708. set_localinfo("gg_cycle_num",strVal);
  4709.  
  4710. break;
  4711. }
  4712.  
  4713. line++;
  4714. }
  4715. if(file) fclose(file);
  4716.  
  4717. // we didn't find next map
  4718. if(!foundMap)
  4719. {
  4720. // reset line number to first (it's zero-based)
  4721. set_localinfo("gg_cycle_num","0");
  4722.  
  4723. // no maps listed, go to current
  4724. if(!firstMap[0]) set_cvar_string("amx_nextmap",currentMap);
  4725.  
  4726. // go to first map listed
  4727. else set_cvar_string("amx_nextmap",firstMap);
  4728. }
  4729. }
  4730.  
  4731. // go to amx_nextmap
  4732. public goto_nextmap()
  4733. {
  4734. set_nextmap(); // for good measure
  4735.  
  4736. new mapCycleFile[64];
  4737. get_gg_mapcycle_file(mapCycleFile,63);
  4738.  
  4739. // no gungame mapcycle
  4740. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  4741. {
  4742. new custom[256];
  4743. get_pcvar_string(gg_changelevel_custom,custom,255);
  4744.  
  4745. // try custom changelevel command
  4746. if(custom[0])
  4747. {
  4748. server_cmd(custom);
  4749. return;
  4750. }
  4751. }
  4752.  
  4753. // otherwise, go to amx_nextmap
  4754. new nextMap[32];
  4755. get_cvar_string("amx_nextmap",nextMap,31);
  4756.  
  4757. server_cmd("changelevel %s",nextMap);
  4758. }
  4759.  
  4760. // weapon display
  4761. stock status_display(id,status=1)
  4762. {
  4763. new sdisplay;
  4764. sdisplay = get_pcvar_num(gg_status_display);
  4765.  
  4766. // display disabled
  4767. if(!sdisplay) return;
  4768.  
  4769. // dead
  4770. if(id && (!is_user_alive(id) || pev(id,pev_iuser1)))
  4771. return;
  4772.  
  4773. new dest;
  4774. static sprite[32];
  4775. if(!id) dest = MSG_BROADCAST;
  4776. else dest = MSG_ONE_UNRELIABLE;
  4777.  
  4778. // disable display if status is 0, or we are doing a knife warmup
  4779. if(!status || (warmup > 0 && get_pcvar_num(gg_knife_warmup)))
  4780. {
  4781. message_begin(dest,gmsgScenario,_,id);
  4782. write_byte(0);
  4783. message_end();
  4784.  
  4785. return;
  4786. }
  4787.  
  4788. // weapon display
  4789. if(sdisplay == STATUS_LEADERWPN || sdisplay == STATUS_YOURWPN)
  4790. {
  4791. if(sdisplay == STATUS_LEADERWPN)
  4792. {
  4793. new ldrLevel;
  4794. get_leader(ldrLevel);
  4795.  
  4796. // get leader's weapon
  4797. if(ldrLevel <= 0) return;
  4798. get_weapon_name_by_level(ldrLevel,sprite,31);
  4799. }
  4800. else
  4801. {
  4802. // get your weapon
  4803. if(level[id] <= 0) return;
  4804. formatex(sprite,31,"%s",weapon[id]);
  4805. }
  4806.  
  4807. strtolower(sprite);
  4808.  
  4809. // sprite is d_grenade, not d_hegrenade
  4810. if(sprite[0] == 'h') sprite = "grenade";
  4811.  
  4812. // get true sprite name
  4813. format(sprite,31,"d_%s",sprite);
  4814. }
  4815.  
  4816. // kill display
  4817. else if(sdisplay == STATUS_KILLSLEFT)
  4818. {
  4819. new goal = get_level_goal(level[id]);
  4820. formatex(sprite,31,"number_%i",goal-score[id]);
  4821. }
  4822. else if(sdisplay == STATUS_KILLSDONE)
  4823. {
  4824. formatex(sprite,31,"number_%i",score[id]);
  4825. }
  4826.  
  4827. // display it already!
  4828. message_begin(dest,gmsgScenario,_,id);
  4829. write_byte(1);
  4830. write_string(sprite);
  4831. write_byte(150);
  4832. message_end();
  4833. }
  4834.  
  4835. // refill a player's ammo
  4836. stock refill_ammo(id,current=0)
  4837. {
  4838. if(!is_user_alive(id) || pev(id,pev_iuser1)) return;
  4839.  
  4840. new armor = get_pcvar_num(gg_give_armor), helmet = get_pcvar_num(gg_give_helmet);
  4841.  
  4842. // giving armor and helmets away like candy
  4843. if(helmet) cs_set_user_armor(id,armor,CS_ARMOR_VESTHELM);
  4844. else cs_set_user_armor(id,armor,CS_ARMOR_KEVLAR);
  4845.  
  4846. // no ammo for knives only
  4847. if(warmup > 0 && get_pcvar_num(gg_knife_warmup)) return;
  4848.  
  4849. // get weapon name and index
  4850. new wpnid, curweapon = get_user_weapon(id,dummy[0],dummy[0]);
  4851.  
  4852. if(current && (curweapon != CSW_KNIFE || equal(weapon[id],"knife")))
  4853. {
  4854. wpnid = curweapon;
  4855. }
  4856. else
  4857. {
  4858. static fullName[24];
  4859. formatex(fullName,23,"weapon_%s",weapon[id]);
  4860. wpnid = get_weaponid(fullName);
  4861. }
  4862.  
  4863. if(!wpnid) return;
  4864.  
  4865. // no reason to refill a knife
  4866. if(wpnid == CSW_KNIFE) return;
  4867.  
  4868. new ammo, wEnt;
  4869. ammo = get_pcvar_num(gg_ammo_amount);
  4870.  
  4871. // don't give away hundreds of grenades
  4872. if(wpnid != CSW_HEGRENADE)
  4873. {
  4874. // set clip ammo
  4875. wEnt = get_weapon_ent(id,wpnid);
  4876. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,maxClip[wpnid]);
  4877.  
  4878. // set backpack ammo
  4879. if(equal(weapon[id],"hegrenade") && wpnid == CSW_GLOCK18)
  4880. cs_set_user_bpammo(id,wpnid,50);
  4881.  
  4882. else if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  4883. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  4884.  
  4885. // update display if we need to
  4886. if(curweapon == wpnid)
  4887. {
  4888. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  4889. write_byte(1);
  4890. write_byte(wpnid);
  4891. write_byte(maxClip[wpnid]);
  4892. message_end();
  4893. }
  4894. }
  4895.  
  4896. // now do stupid grenade stuff
  4897. else
  4898. {
  4899. if(get_pcvar_num(gg_nade_glock))
  4900. {
  4901. // set clip ammo
  4902. wEnt = get_weapon_ent(id,CSW_GLOCK18);
  4903. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,maxClip[CSW_GLOCK18]);
  4904.  
  4905. // set backpack ammo
  4906. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  4907.  
  4908. // update display if we need to
  4909. if(curweapon == CSW_GLOCK18)
  4910. {
  4911. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  4912. write_byte(1);
  4913. write_byte(CSW_GLOCK18);
  4914. write_byte(maxClip[CSW_GLOCK18]);
  4915. message_end();
  4916. }
  4917. }
  4918.  
  4919. if(get_pcvar_num(gg_nade_smoke) && !cs_get_user_bpammo(id,CSW_SMOKEGRENADE))
  4920. fm_give_item(id,"weapon_smokegrenade");
  4921.  
  4922. if(get_pcvar_num(gg_nade_flash) && !cs_get_user_bpammo(id,CSW_FLASHBANG))
  4923. fm_give_item(id,"weapon_flashbang");
  4924.  
  4925. if(!cs_get_user_bpammo(id,CSW_HEGRENADE))
  4926. {
  4927. fm_give_item(id,"weapon_hegrenade");
  4928. remove_task(TASK_REFRESH_NADE+id);
  4929. }
  4930. }
  4931.  
  4932. // keep knife out
  4933. if(curweapon == CSW_KNIFE) client_cmd(id,"weapon_knife");
  4934. }
  4935.  
  4936. // find a player's weapon entity
  4937. stock get_weapon_ent(id,wpnid=0,wpnName[]="")
  4938. {
  4939. // who knows what wpnName will be
  4940. static newName[32];
  4941.  
  4942. // need to find the name
  4943. if(wpnid) get_weaponname(wpnid,newName,31);
  4944.  
  4945. // go with what we were told
  4946. else formatex(newName,31,"%s",wpnName);
  4947.  
  4948. // prefix it if we need to
  4949. if(!equal(newName,"weapon_",7))
  4950. format(newName,31,"weapon_%s",newName);
  4951.  
  4952. return fm_find_ent_by_owner(0,newName,id);
  4953. }
  4954.  
  4955. // counts number of chars in a string, by (probably) Twilight Suzuka
  4956. stock str_count(str[],searchchar)
  4957. {
  4958. new i = 0;
  4959. new maxlen = strlen(str);
  4960. new count = 0;
  4961.  
  4962. for(i=0;i<=maxlen;i++)
  4963. {
  4964. if(str[i] == searchchar)
  4965. count++;
  4966. }
  4967. return count;
  4968. }
  4969.  
  4970. // find the nth occurance of a character in a string, based on str_count
  4971. stock str_find_num(str[],searchchar,number)
  4972. {
  4973. new i;
  4974. new maxlen = strlen(str);
  4975. new found = 0;
  4976.  
  4977. for(i=0;i<=maxlen;i++)
  4978. {
  4979. if(str[i] == searchchar)
  4980. {
  4981. if(++found == number)
  4982. return i;
  4983. }
  4984. }
  4985. return -1;
  4986. }
  4987.  
  4988. // gets a player id that triggered certain logevents, by VEN
  4989. stock get_loguser_index()
  4990. {
  4991. static loguser[80], name[32];
  4992. read_logargv(0,loguser,79);
  4993. parse_loguser(loguser,name,31);
  4994.  
  4995. return get_user_index(name);
  4996. }
  4997.  
  4998. // checks if a space is vacant, by VEN
  4999. stock bool:is_hull_vacant(const Float:origin[3],hull)
  5000. {
  5001. new tr = 0;
  5002. engfunc(EngFunc_TraceHull,origin,origin,0,hull,0,tr);
  5003.  
  5004. if(!get_tr2(tr,TR_StartSolid) && !get_tr2(tr,TR_AllSolid) && get_tr2(tr,TR_InOpen))
  5005. return true;
  5006.  
  5007. return false;
  5008. }
  5009.  
  5010. // gets a weapon's category, for Counter-Strike
  5011. stock get_weapon_category(id=0,name[]="")
  5012. {
  5013. if(name[0])
  5014. {
  5015. if(equal(name,"weapon_",7)) id = get_weaponid(name);
  5016. else
  5017. {
  5018. static newName[32];
  5019. formatex(newName,31,"weapon_%s",name);
  5020. id = get_weaponid(newName);
  5021. }
  5022. }
  5023.  
  5024. return weaponSlots[id];
  5025. }
  5026.  
  5027. // if a player is allowed to score (at least 1 player on opposite team)
  5028. can_score(id)
  5029. {
  5030. new CsTeams:team = cs_get_user_team(id);
  5031.  
  5032. // find opposite team
  5033. switch(team)
  5034. {
  5035. case CS_TEAM_T: team = CS_TEAM_CT;
  5036. case CS_TEAM_CT: team = CS_TEAM_T;
  5037. default: return 0; // spectator
  5038. }
  5039.  
  5040. new i;
  5041. for(i=1;i<=maxPlayers;i++)
  5042. {
  5043. if(is_user_connected(i) && cs_get_user_team(i) == team)
  5044. return 1;
  5045. }
  5046.  
  5047. // didn't find anyone on opposing team
  5048. return 0;
  5049. }
  5050.  
  5051. // returns 1 if there are only bots in the server, 0 if not
  5052. only_bots()
  5053. {
  5054. new i;
  5055. for(i=1;i<=maxPlayers;i++)
  5056. {
  5057. if(is_user_connected(i) && !is_user_bot(i))
  5058. return 0;
  5059. }
  5060.  
  5061. // didn't find any humans
  5062. return 1;
  5063. }
  5064.