Advertisement
Guest User

Untitled

a guest
Feb 5th, 2018
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 283.01 KB | None | 0 0
  1. /* Uncomment the below define to use SQL stats intead of flat-file stats. */
  2.  
  3. //#define SQL
  4.  
  5. /* Uncomment the below define to have a player's timestamp get refreshed right away as soon as they join, instead of only when they play to the end of a game.
  6. ** There is a slight overhead for flat-file stats, but it's fairly speedy. When using SQL stats, you might as well uncomment this -- it'll be speedy. */
  7.  
  8. //#define REFRESH_TIMESTAMP_ON_JOIN
  9.  
  10. // Thanks a lot to 3volution for helping me iron out some
  11. // bugs and for giving me some helpful suggestions.
  12. //
  13. // Thanks a lot to raa for helping me pinpoint the crash,
  14. // and discovering the respawn bug.
  15. //
  16. // Thanks a lot to BAILOPAN for binary logging, and for
  17. // CSDM spawn files that I could leech off of. Oh, and
  18. // also AMXX, etcetera.
  19. //
  20. // Thanks to VEN for Fakemeta Utilities to ease development.
  21. //
  22. // Thanks a lot to all of my supporters, but especially:
  23. // 3volution, aligind4h0us3, arkshine, bmp, Curryking,
  24. // Gunny, IdiotSavant, Mordekay, polakpolak, raa, Silver
  25. // Dragon, Smileypt, Tomek Kalkowski, ToT | V!PER, and Vm|Mayhem.
  26. //
  27. // Thanks especially to all of the translators:
  28. // arkshine, b!orn, commonbullet, Curryking, Deviance,
  29. // D o o m, eD., e-N-z, Fr3ak0ut, godlike, harbu, iggy_bus,
  30. // jopmako, jozzz, KylixMynxAltoLAG, MeRcyLeZZ, Min2liz,
  31. // Mordekay, Morpheus759, rpm, SAMURAI16, Simbad, TEG,
  32. // ToT | V!PER, trawiator, Twilight Suzuka, webpsiho, and
  33. // others that I surely forgot (sorry!).
  34. //
  35. // Thanks to SeNz0r for many of the new sounds!
  36. //
  37. // If I missed you, please yell at me.
  38.  
  39. #pragma dynamic 8192 // just a little bit extra, not too much
  40.  
  41. #include <amxmodx>
  42. #include <amxmisc>
  43. #include <fakemeta>
  44. #include <fakemeta_util>
  45. #include <cstrike>
  46. #include <hamsandwich>
  47.  
  48. // defines to be left alone
  49. new const GG_VERSION[] = "2.13c";
  50. #define LANG_PLAYER_C -76 // for gungame_print (arbitrary number)
  51. #define TNAME_SAVE pev_noise3 // for blocking game_player_equip and player_weaponstrip
  52. #define WINSOUNDS_SIZE (MAX_WINSOUNDS*MAX_WINSOUND_LEN)+1 // for gg_sound_winner
  53.  
  54. // more customizable-friendly defines
  55. #define TOP_PLAYERS 10 // for !top10
  56. #define MAX_WEAPONS 36 // for gg_weapon_order
  57. #define MAX_WINSOUNDS 12 // for gg_sound_winnner
  58. #define MAX_WINSOUND_LEN 48 // for gg_sound_winner
  59. #define TEMP_SAVES 32 // for gg_save_temp
  60. #define MAX_WEAPON_ORDERS 10 // for random gg_weapon_order
  61. #define LEADER_DISPLAY_RATE 10.0 // for gg_leader_display
  62. #define MAX_SPAWNS 128 // for gg_dm_spawn_random
  63. #define MAX_STATS_RANK 1000 // cap of 1000 = 0.0063495ish sec for longest stats_get_position, cap of 5000 = 0.0327655ish sec
  64.  
  65. // returns which of the two stats files we should be using currently (si stands for Stats Index)
  66. #define get_gg_si() (get_pcvar_num(gg_stats_split) && get_pcvar_num(gg_teamplay))
  67.  
  68. // cs_set_user_money
  69. #if cellbits == 32
  70. #define OFFSET_CSMONEY 115
  71. #else
  72. #define OFFSET_CSMONEY 140
  73. #endif
  74. #define OFFSET_LINUX 5
  75.  
  76. // animations
  77. #define USP_DRAWANIM 6
  78. #define M4A1_DRAWANIM 5
  79.  
  80. // saves memory???
  81. new const WEAPON_HEGRENADE[] = "weapon_hegrenade";
  82. new const WEAPON_KNIFE[] = "weapon_knife";
  83. new const WEAPON_GLOCK18[] = "weapon_glock18";
  84. new const HEGRENADE[] = "hegrenade";
  85. new const KNIFE[] = "knife";
  86. new const BRASS_BELL_SOUND[] = "gungame/gg_brass_bell.wav";
  87. new const KILL_DING_SOUND[] = "buttons/bell1.wav";
  88.  
  89. // toggle_gungame
  90. enum
  91. {
  92. TOGGLE_FORCE = -1,
  93. TOGGLE_DISABLE,
  94. TOGGLE_ENABLE
  95. };
  96.  
  97. // gg_status_display
  98. enum
  99. {
  100. STATUS_LEADERWPN = 1,
  101. STATUS_YOURWPN,
  102. STATUS_KILLSLEFT,
  103. STATUS_KILLSDONE
  104. };
  105.  
  106. // value of bombStatus[3]
  107. enum
  108. {
  109. BOMB_PICKEDUP = -1,
  110. BOMB_DROPPED,
  111. BOMB_PLANTED
  112. };
  113.  
  114. // for gg_messages
  115. #define MSGS_CLASSIC 2
  116. #define MSGS_NOCOLOR 4
  117. #define MSGS_HIDETEXT 8
  118. #define MSGS_HIDEHUD 16
  119.  
  120. // task ids
  121. #define TASK_END_STAR 200
  122. #define TASK_RESPAWN 300
  123. #define TASK_CLEAR_SAVE 500
  124. #define TASK_CHECK_DEATHMATCH 600
  125. #define TASK_REMOVE_PROTECTION 700
  126. #define TASK_TOGGLE_GUNGAME 800
  127. #define TASK_WARMUP_CHECK 900
  128. #define TASK_VERIFY_WEAPON 1000
  129. #define TASK_DELAYED_SUICIDE 1100
  130. #define TASK_REFRESH_NADE 1200
  131. #define TASK_LEADER_DISPLAY 1300
  132. #define TASK_PLAY_LEAD_SOUNDS 1400
  133. #define TASK_CHECK_JOINCLASS 1500
  134. #define TASK_AUTOVOTE_RESULT 1600
  135. #define TASK_GET_TOP_PLAYERS 1700
  136.  
  137. //**********************************************************************
  138. // VARIABLE DEFINITIONS
  139. //**********************************************************************
  140.  
  141. // pcvar holders
  142. new gg_enabled, gg_ff_auto, gg_vote_setting, gg_map_setup, gg_join_msg,
  143. gg_weapon_order, gg_max_lvl, gg_triple_on, gg_turbo, gg_knife_pro,
  144. gg_worldspawn_suicide, gg_handicap_on, gg_top10_handicap, gg_warmup_timer_setting,
  145. gg_warmup_weapon, gg_sound_levelup, gg_sound_leveldown, gg_sound_levelsteal,
  146. gg_sound_nade, gg_sound_knife, gg_sound_welcome, gg_sound_triple, gg_sound_winner,
  147. gg_kills_per_lvl, gg_vote_custom, gg_changelevel_custom, gg_ammo_amount,
  148. gg_stats_prune, gg_refill_on_kill, gg_messages, gg_tk_penalty,
  149. gg_save_temp, gg_stats_mode, gg_pickup_others, gg_stats_winbonus, gg_map_iterations,
  150. gg_warmup_multi, gg_stats_ip, gg_extra_nades, gg_endmap_setup, gg_autovote_rounds,
  151. gg_autovote_ratio, gg_autovote_delay, gg_autovote_time, gg_autovote_mode, gg_ignore_bots, gg_nade_refresh,
  152. gg_block_equips, gg_leader_display, gg_leader_display_x, gg_leader_display_y,
  153. gg_sound_takenlead, gg_sound_tiedlead, gg_sound_lostlead, gg_lead_sounds, gg_knife_elite,
  154. gg_teamplay, gg_teamplay_knife_mod, gg_teamplay_nade_mod, gg_suicide_penalty, gg_winner_motd,
  155. gg_bomb_defuse_lvl, gg_nade_glock, gg_nade_smoke, gg_nade_flash, gg_give_armor, gg_give_helmet,
  156. gg_dm, gg_dm_sp_time, gg_dm_sp_mode, gg_dm_spawn_random, gg_dm_spawn_delay, gg_dm_corpses, gg_awp_oneshot,
  157. gg_host_touch_reward, gg_host_rescue_reward, gg_host_kill_reward, gg_dm_countdown, gg_status_display,
  158. gg_dm_spawn_afterplant, gg_block_objectives, gg_host_kill_penalty, gg_dm_start_random, gg_allow_changeteam,
  159. gg_teamplay_timeratio, gg_disable_money, gg_kills_botmod, gg_bots_skipnade, gg_bots_knifeable,
  160. gg_afk_protection, gg_stats_split, gg_top10_ppp;
  161.  
  162. // weapon information
  163. new maxClip[31] = { -1, 13, -1, 10, 1, 7, -1, 30, 30, 1, 30, 20, 25, 30, 35, 25, 12, 20,
  164. 10, 30, 100, 8, 30, 30, 20, 2, 7, 30, 30, -1, 50 };
  165.  
  166. new maxAmmo[31] = { -1, 52, -1, 90, -1, 32, 1, 100, 90, -1, 120, 100, 100, 90, 90, 90, 100, 100,
  167. 30, 120, 200, 32, 90, 120, 60, -1, 35, 90, 90, -1, 100 };
  168.  
  169. new weaponSlots[31] = { -1, 2, -1, 1, 4, 1, 5, 1, 1, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1,
  170. 4, 2, 1, 1, 3, 1 };
  171.  
  172. enum statsData
  173. {
  174. sdAuthid[32],
  175. sdWins[2],
  176. sdName[32],
  177. sdTimestamp, // [1]
  178. sdPoints[2],
  179. sdStreak[2]
  180. }; // size = 71
  181.  
  182. enum saveData
  183. {
  184. svAuthid[32],
  185. svLevel, // [1]
  186. svScore, // [1]
  187. svStatsPosition[2],
  188. svTeamTimes[2],
  189. svTime // [1]
  190. }; // size = 39
  191.  
  192. // misc
  193. new weapons_menu, scores_menu, level_menu, warmup = -1, warmupWeapon[24], voted, won, trailSpr, roundEnded,
  194. menuText[512], dummy[2], tempSave[TEMP_SAVES][saveData], czero, maxPlayers, mapIteration = 1, cfgDir[32],
  195. autovoted, autovotes[3], autovote_mode, roundsElapsed, gameCommenced, cycleNum = -1, czbot_hams, mp_friendlyfire,
  196. winSounds[MAX_WINSOUNDS][MAX_WINSOUND_LEN+1], numWinSounds, currentWinSound, hudSyncWarmup, hudSyncReqKills,
  197. hudSyncLDisplay, shouldWarmup, ggActive, teamLevel[3], teamLvlWeapon[3][24], teamScore[3], bombMap, hostageMap,
  198. bombStatus[4], c4planter, Float:spawns[MAX_SPAWNS][9], spawnCount, csdmSpawnCount, hudSyncCountdown,
  199. weaponName[MAX_WEAPONS+1][24], Float:weaponGoal[MAX_WEAPONS+1], weaponNum, initTeamplayStr[32], initTeamplayInt = -1,
  200. bot_quota, spareName[32], sqlInit, galileoID = -1;
  201.  
  202. // stats file stuff
  203. new sfStatsStruct[statsData], lastStatsMode = -909;
  204.  
  205. // event ids
  206. new gmsgSayText, gmsgCurWeapon, gmsgStatusIcon, gmsgBombDrop, gmsgBombPickup, gmsgHideWeapon,
  207. gmsgCrosshair, gmsgScenario;
  208.  
  209. // player values
  210. new level[33], levelsThisRound[33], score[33], lvlWeapon[33][24], star[33], welcomed[33],
  211. page[33], lastKilled[33], hosties[33][2], silenced[33], respawn_timeleft[33], Float:lastSwitch[33], lastTeam[33],
  212. spawnSounds[33], spawnProtected[33], statsPosition[33][2], Float:teamTimes[33][2], pointsExtraction[33][5],
  213. Float:spawnOrigin[33][3], Float:spawnAngles[33][3], afkCheck[33], playerStats[33][statsData];
  214.  
  215. #if defined SQL
  216. #include <sqlx>
  217.  
  218. // flags for the "flags" field in the gg_sql_winmotd table
  219. #define WON 1
  220. #define LOST 2
  221. #define LASTKILL 4
  222. #define NEWRECORD 8
  223.  
  224. new gg_sql_host, gg_sql_user, gg_sql_pass, gg_sql_db, gg_sql_table, gg_sql_streak_table, gg_sql_winmotd_table,
  225. sqlTable[128], sqlStreakTable[128], sqlPlayersTable[128], serverip[64], Handle:tuple, Handle:db, Handle:query, safeName[64], mkQuery[1536];
  226. #else
  227. new gg_stats_file, gg_stats_streak_file;
  228.  
  229. new sfFile[64], sfLineData[112], sfAuthid[32], sfTimestamp[12], Array:statsArray, Array:statsPointers[2], statsSize[2];
  230. #endif
  231.  
  232. //**********************************************************************
  233. // INITIATION FUNCTIONS
  234. //**********************************************************************
  235.  
  236. // plugin load
  237. public plugin_init()
  238. {
  239. register_plugin("GunGame AMXX",GG_VERSION,"Marian");
  240. register_cvar("gg_version",GG_VERSION,FCVAR_SERVER);
  241. set_cvar_string("gg_version",GG_VERSION);
  242.  
  243. // mehrsprachige unterstützung (nein, spreche ich nicht Deutsches)
  244. register_dictionary("gungame.txt");
  245. register_dictionary("common.txt");
  246. register_dictionary("adminvote.txt");
  247.  
  248. // event ids
  249. gmsgSayText = get_user_msgid("SayText");
  250. gmsgCurWeapon = get_user_msgid("CurWeapon");
  251. gmsgStatusIcon = get_user_msgid("StatusIcon");
  252. gmsgScenario = get_user_msgid("Scenario");
  253. gmsgBombDrop = get_user_msgid("BombDrop");
  254. gmsgBombPickup = get_user_msgid("BombPickup");
  255. gmsgHideWeapon = get_user_msgid("HideWeapon");
  256. gmsgCrosshair = get_user_msgid("Crosshair");
  257.  
  258. // events
  259. register_event("ResetHUD","event_resethud","be");
  260. register_event("HLTV","event_new_round","a","1=0","2=0");
  261. register_event("CurWeapon","event_curweapon","be","1=1");
  262. register_event("AmmoX","event_ammox","be");
  263. register_event("30","event_intermission","a");
  264. register_event("TextMsg","event_round_restart","a","2=#Game_Commencing","2=#Game_will_restart_in");
  265. register_event("23","event_bomb_detonation","a","1=17","6=-105","7=17"); // planted bomb exploded
  266.  
  267. // forwards
  268. register_forward(FM_SetModel,"fw_setmodel");
  269. register_forward(FM_EmitSound,"fw_emitsound");
  270.  
  271. // logevents
  272. register_logevent("event_bomb_detonation",6,"3=Target_Bombed"); // another bomb exploded event, for security
  273. register_logevent("logevent_bomb_planted",3,"2=Planted_The_Bomb"); // bomb planted
  274. register_logevent("logevent_bomb_defused",3,"2=Defused_The_Bomb"); // bomb defused
  275. register_logevent("logevent_round_end",2,"1=Round_End"); // round ended
  276. register_logevent("logevent_hostage_touched",3,"2=Touched_A_Hostage");
  277. register_logevent("logevent_hostage_rescued",3,"2=Rescued_A_Hostage");
  278. register_logevent("logevent_hostage_killed",3,"2=Killed_A_Hostage");
  279. register_logevent("logevent_team_join",3,"1=joined team");
  280.  
  281. // messages
  282. register_message(gmsgScenario,"message_scenario");
  283. register_message(get_user_msgid("ClCorpse"),"message_clcorpse");
  284. register_message(get_user_msgid("Money"),"message_money");
  285. register_message(gmsgBombDrop,"message_bombdrop");
  286. register_message(gmsgBombPickup,"message_bombpickup");
  287. register_message(get_user_msgid("WeapPickup"),"message_weappickup"); // for gg_block_objectives
  288. register_message(get_user_msgid("AmmoPickup"),"message_ammopickup"); // for gg_block_objectives
  289. register_message(get_user_msgid("TextMsg"),"message_textmsg"); // for gg_block_objectives
  290. register_message(get_user_msgid("HostagePos"),"message_hostagepos"); // for gg_block_objectives
  291.  
  292. // hams
  293. RegisterHam(Ham_Touch,"weaponbox","ham_weapon_touch",0);
  294. RegisterHam(Ham_Touch,"armoury_entity","ham_weapon_touch",0);
  295. RegisterHam(Ham_Spawn,"player","ham_player_spawn",1);
  296. RegisterHam(Ham_Killed,"player","ham_player_killed_pre",0);
  297. RegisterHam(Ham_Killed,"player","ham_player_killed_post",1);
  298.  
  299. // commands
  300. register_clcmd("joinclass","cmd_joinclass"); // new menus
  301. register_menucmd(register_menuid("Terrorist_Select",1),511,"cmd_joinclass"); // old menus
  302. register_menucmd(register_menuid("CT_Select",1),511,"cmd_joinclass"); // old menus
  303. register_concmd("amx_gungame","cmd_gungame",ADMIN_CVAR,"<0|1> - toggles the functionality of GunGame.");
  304. register_concmd("amx_gungame_level","cmd_gungame_level",ADMIN_BAN,"<target> <level> - sets target's level. use + or - for relative, otherwise it's absolute.");
  305. register_concmd("amx_gungame_score","cmd_gungame_score",ADMIN_BAN,"<target> <score> [dont_refill] - sets target's score. use + or - for relative, otherwise it's absolute.");
  306. register_concmd("amx_gungame_vote","cmd_gungame_vote",ADMIN_VOTE,"[mode] - starts a vote to toggle GunGame.");
  307. register_concmd("amx_gungame_win","cmd_gungame_win",ADMIN_BAN,"[target] - if target, forces target to win. if no target, forces highest level player to win.");
  308. register_concmd("amx_gungame_teamplay","cmd_gungame_teamplay",ADMIN_BAN,"<0|1> [killsperlvl] [suicidepenalty] - toggles teamplay mode. optionally specify new cvar values.");
  309. register_concmd("amx_gungame_restart","cmd_gungame_restart",ADMIN_BAN,"[delay] [full] - restarts GunGame. optionally specify a delay, in seconds. if full, reloads config and everything.");
  310. register_srvcmd("gg_reloadweapons","cmd_reloadweapons",ADMIN_CVAR,"- reloads the weapon order and kills per level from cvars");
  311. register_clcmd("say","cmd_say");
  312. register_clcmd("say_team","cmd_say");
  313.  
  314. // menus
  315. register_menucmd(register_menuid("autovote_menu"),MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_0,"autovote_menu_handler");
  316. register_menucmd(register_menuid("welcome_menu"),1023,"welcome_menu_handler");
  317. register_menucmd(register_menuid("restart_menu"),MENU_KEY_1|MENU_KEY_0,"restart_menu_handler");
  318. weapons_menu = register_menuid("weapons_menu");
  319. register_menucmd(weapons_menu,MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_0,"weapons_menu_handler");
  320. register_menucmd(register_menuid("top10_menu"),MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_0,"top10_menu_handler");
  321. scores_menu = register_menuid("scores_menu");
  322. register_menucmd(scores_menu,MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_0,"scores_menu_handler");
  323. level_menu = register_menuid("level_menu");
  324. register_menucmd(level_menu,1023,"level_menu_handler");
  325.  
  326. // basic cvars
  327. gg_enabled = register_cvar("gg_enabled","1");
  328. gg_vote_setting = register_cvar("gg_vote_setting","2");
  329. gg_vote_custom = register_cvar("gg_vote_custom","");
  330. gg_changelevel_custom = register_cvar("gg_changelevel_custom","");
  331. gg_map_setup = register_cvar("gg_map_setup","mp_timelimit 45; mp_winlimit 0; sv_alltalk 0; mp_chattime 10; mp_c4timer 25");
  332. gg_endmap_setup = register_cvar("gg_endmap_setup","");
  333. gg_join_msg = register_cvar("gg_join_msg","1");
  334. gg_messages = register_cvar("gg_messages","1");
  335. gg_save_temp = register_cvar("gg_save_temp","300"); // = 5 * 60 = 5 minutes
  336. gg_status_display = register_cvar("gg_status_display","1");
  337. gg_map_iterations = register_cvar("gg_map_iterations","1");
  338. gg_ignore_bots = register_cvar("gg_ignore_bots","0");
  339. gg_block_equips = register_cvar("gg_block_equips","2");
  340. gg_leader_display = register_cvar("gg_leader_display","1");
  341. gg_leader_display_x = register_cvar("gg_leader_display_x","-1.0");
  342. gg_leader_display_y = register_cvar("gg_leader_display_y","0.0");
  343. gg_allow_changeteam = register_cvar("gg_allow_changeteam","2");
  344. gg_disable_money = register_cvar("gg_disable_money","1");
  345. gg_winner_motd = register_cvar("gg_winner_motd","1");
  346. gg_afk_protection = register_cvar("gg_afk_protection","0");
  347. gg_top10_ppp = register_cvar("gg_top10_ppp","8");
  348.  
  349. // autovote cvars
  350. gg_autovote_mode = register_cvar("gg_autovote_mode","0");
  351. gg_autovote_rounds = register_cvar("gg_autovote_rounds","1");
  352. gg_autovote_delay = register_cvar("gg_autovote_delay","8.0");
  353. gg_autovote_ratio = register_cvar("gg_autovote_ratio","0.51");
  354. gg_autovote_time = register_cvar("gg_autovote_time","10.0");
  355.  
  356. // stats cvars
  357. #if !defined SQL
  358. gg_stats_file = register_cvar("gg_stats_file","gungame.stats");
  359. gg_stats_streak_file = register_cvar("gg_stats_streak_file","gungame.streaks");
  360. #endif
  361. gg_stats_ip = register_cvar("gg_stats_ip","0");
  362. gg_stats_prune = register_cvar("gg_stats_prune","2592000"); // = 60 * 60 * 24 * 30 = 30 days
  363. gg_stats_mode = register_cvar("gg_stats_mode","2");
  364. gg_stats_split = register_cvar("gg_stats_split","0");
  365. gg_stats_winbonus = register_cvar("gg_stats_winbonus","1.5");
  366.  
  367. // deathmatch cvars
  368. gg_dm = register_cvar("gg_dm","1");
  369. gg_dm_sp_time = register_cvar("gg_dm_sp_time","1.0");
  370. gg_dm_sp_mode = register_cvar("gg_dm_sp_mode","1");
  371. gg_dm_spawn_random = register_cvar("gg_dm_spawn_random","2");
  372. gg_dm_start_random = register_cvar("gg_dm_start_random","1");
  373. gg_dm_spawn_delay = register_cvar("gg_dm_spawn_delay","3.0");
  374. gg_dm_spawn_afterplant = register_cvar("gg_dm_spawn_afterplant","1");
  375. gg_dm_corpses = register_cvar("gg_dm_corpses","1");
  376. gg_dm_countdown = register_cvar("gg_dm_countdown","2");
  377.  
  378. // objective cvars
  379. gg_block_objectives = register_cvar("gg_block_objectives","0");
  380. gg_bomb_defuse_lvl = register_cvar("gg_bomb_defuse_lvl","1");
  381. gg_host_touch_reward = register_cvar("gg_host_touch_reward","2");
  382. gg_host_rescue_reward = register_cvar("gg_host_rescue_reward","2");
  383. gg_host_kill_reward = register_cvar("gg_host_kill_reward","1");
  384. gg_host_kill_penalty = register_cvar("gg_host_kill_penalty","1");
  385.  
  386. // teamplay cvars
  387. gg_teamplay = register_cvar("gg_teamplay","0");
  388. gg_teamplay_knife_mod = register_cvar("gg_teamplay_knife_mod","0.33");
  389. gg_teamplay_nade_mod = register_cvar("gg_teamplay_nade_mod","0.50");
  390. gg_teamplay_timeratio = register_cvar("gg_teamplay_timeratio","1");
  391.  
  392. // gameplay cvars
  393. gg_ff_auto = register_cvar("gg_ff_auto","1");
  394. 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");
  395. gg_max_lvl = register_cvar("gg_max_lvl","3");
  396. gg_triple_on = register_cvar("gg_triple_on","0");
  397. gg_turbo = register_cvar("gg_turbo","1");
  398. gg_knife_pro = register_cvar("gg_knife_pro","1");
  399. gg_knife_elite = register_cvar("gg_knife_elite","0");
  400. gg_suicide_penalty = register_cvar("gg_suicide_penalty","1");
  401. gg_worldspawn_suicide = register_cvar("gg_worldspawn_suicide","1");
  402. gg_pickup_others = register_cvar("gg_pickup_others","0");
  403. gg_handicap_on = register_cvar("gg_handicap_on","1");
  404. gg_top10_handicap = register_cvar("gg_top10_handicap","1");
  405. gg_warmup_timer_setting = register_cvar("gg_warmup_timer_setting","60");
  406. gg_warmup_weapon = register_cvar("gg_warmup_weapon",KNIFE);
  407. gg_warmup_multi = register_cvar("gg_warmup_multi","0");
  408. gg_nade_glock = register_cvar("gg_nade_glock","1");
  409. gg_nade_smoke = register_cvar("gg_nade_smoke","0");
  410. gg_nade_flash = register_cvar("gg_nade_flash","0");
  411. gg_extra_nades = register_cvar("gg_extra_nades","1");
  412. gg_nade_refresh = register_cvar("gg_nade_refresh","5.0");
  413. gg_kills_per_lvl = register_cvar("gg_kills_per_lvl","2");
  414. gg_kills_botmod = register_cvar("gg_kills_botmod","1.0");
  415. gg_give_armor = register_cvar("gg_give_armor","100");
  416. gg_give_helmet = register_cvar("gg_give_helmet","1");
  417. gg_ammo_amount = register_cvar("gg_ammo_amount","200");
  418. gg_refill_on_kill = register_cvar("gg_refill_on_kill","1");
  419. gg_tk_penalty = register_cvar("gg_tk_penalty","1");
  420. gg_awp_oneshot = register_cvar("gg_awp_oneshot","1");
  421. gg_bots_skipnade = register_cvar("gg_bots_skipnade","0");
  422. gg_bots_knifeable = register_cvar("gg_bots_knifeable","1");
  423.  
  424. #if defined SQL
  425. // SQL cvars
  426. gg_sql_host = register_cvar("gg_sql_host","127.0.0.1",FCVAR_PROTECTED);
  427. gg_sql_user = register_cvar("gg_sql_user","root",FCVAR_PROTECTED);
  428. gg_sql_pass = register_cvar("gg_sql_pass","",FCVAR_PROTECTED);
  429. gg_sql_db = register_cvar("gg_sql_db","amx",FCVAR_PROTECTED);
  430. gg_sql_table = register_cvar("gg_sql_table","gg_stats",FCVAR_PROTECTED);
  431. gg_sql_streak_table = register_cvar("gg_sql_streak_table","gg_streaks",FCVAR_PROTECTED);
  432. gg_sql_winmotd_table = register_cvar("gg_sql_winmotd_table","gg_winmotd",FCVAR_PROTECTED);
  433.  
  434. get_user_ip(0,serverip,63,0); // with port
  435. #else
  436. sqlInit = 1;
  437. #endif
  438.  
  439. // sound cvars done in plugin_precache now
  440.  
  441. // random weapon order cvars
  442. new i, cvar[20];
  443. for(i=1;i<=MAX_WEAPON_ORDERS;i++)
  444. {
  445. formatex(cvar,19,"gg_weapon_order%i",i);
  446. register_cvar(cvar,"");
  447. }
  448.  
  449. // update status immediately
  450. ggActive = get_pcvar_num(gg_enabled);
  451.  
  452. // make sure to setup amx_nextmap incase nextmap.amxx isn't running
  453. if(!cvar_exists("amx_nextmap")) register_cvar("amx_nextmap","",FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY);
  454.  
  455. // make sure we have this to trick mapchooser.amxx into working
  456. if(!cvar_exists("mp_maxrounds")) register_cvar("mp_maxrounds","0",FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY);
  457.  
  458. // collect some other information that would be handy
  459. maxPlayers = get_maxplayers();
  460.  
  461. // create hud sync objects
  462. hudSyncWarmup = CreateHudSyncObj();
  463. hudSyncReqKills = CreateHudSyncObj();
  464. hudSyncLDisplay = CreateHudSyncObj();
  465. hudSyncCountdown = CreateHudSyncObj();
  466.  
  467. // remember the mod
  468. new modName[7];
  469. get_modname(modName,6);
  470. if(equal(modName,"czero"))
  471. {
  472. czero = 1;
  473. bot_quota = get_cvar_pointer("bot_quota");
  474. }
  475.  
  476. // identify this as a bomb map
  477. if(fm_find_ent_by_class(maxPlayers,"info_bomb_target") || fm_find_ent_by_class(1,"func_bomb_target"))
  478. bombMap = 1;
  479.  
  480. // identify this as a hostage map
  481. if(fm_find_ent_by_class(maxPlayers,"hostage_entity"))
  482. hostageMap = 1;
  483.  
  484. // get spawns for deathmatch
  485. init_spawns();
  486.  
  487. // delay for server.cfg
  488. set_task(1.0,"toggle_gungame",TASK_TOGGLE_GUNGAME + TOGGLE_FORCE);
  489.  
  490. // manage pruning (longer delay for toggle_gungame)
  491. set_task(2.0,"manage_pruning");
  492.  
  493. // map configs take 6.1 seconds to load
  494. set_task(6.2,"setup_weapon_order");
  495. set_task(6.2,"stats_get_top_players",TASK_GET_TOP_PLAYERS);
  496. }
  497.  
  498. // plugin precache
  499. public plugin_precache()
  500. {
  501. // used in precache_sounds_from_config()
  502. get_configsdir(cfgDir,31);
  503.  
  504. // sound cvars
  505. gg_sound_levelup = register_cvar("gg_sound_levelup","sound/gungame/gg_levelup.wav");
  506. gg_sound_leveldown = register_cvar("gg_sound_leveldown","sound/ambience/xtal_down1(e70)");
  507. gg_sound_levelsteal = register_cvar("gg_sound_levelsteal","sound/turret/tu_die.wav");
  508. gg_sound_nade = register_cvar("gg_sound_nade","sound/gungame/gg_nade_level.wav");
  509. gg_sound_knife = register_cvar("gg_sound_knife","sound/gungame/gg_knife_level.wav");
  510. gg_sound_welcome = register_cvar("gg_sound_welcome","sound/gungame/gg_welcome.wav");
  511. gg_sound_triple = register_cvar("gg_sound_triple","sound/gungame/gg_triple.wav");
  512. gg_sound_winner = register_cvar("gg_sound_winner","media/Half-Life03.mp3;media/Half-Life08.mp3;media/Half-Life11.mp3;media/Half-Life17.mp3");
  513. gg_sound_takenlead = register_cvar("gg_sound_takenlead","sound/gungame/gg_takenlead.wav");
  514. gg_sound_tiedlead = register_cvar("gg_sound_tiedlead","sound/gungame/gg_tiedlead.wav");
  515. gg_sound_lostlead = register_cvar("gg_sound_lostlead","sound/gungame/gg_lostlead.wav");
  516. gg_lead_sounds = register_cvar("gg_lead_sounds","0.9");
  517.  
  518. mp_friendlyfire = get_cvar_pointer("mp_friendlyfire");
  519.  
  520. // precache everything in the config (regular and teamplay) -- we might need them
  521. precache_sounds_from_config();
  522.  
  523. // also precache what we have now, in case the server doesn't have a GunGame config
  524. precache_sound_by_cvar(gg_sound_levelup);
  525. precache_sound_by_cvar(gg_sound_leveldown);
  526. precache_sound_by_cvar(gg_sound_levelsteal);
  527. precache_sound_by_cvar(gg_sound_nade);
  528. precache_sound_by_cvar(gg_sound_knife);
  529. precache_sound_by_cvar(gg_sound_welcome);
  530. precache_sound_by_cvar(gg_sound_triple);
  531. precache_sound_by_cvar(gg_sound_takenlead);
  532. precache_sound_by_cvar(gg_sound_tiedlead);
  533. precache_sound_by_cvar(gg_sound_lostlead);
  534.  
  535. get_pcvar_string(gg_sound_winner,dummy,1);
  536. if(dummy[0]) // win sounds enabled
  537. {
  538. // gg_sound_winner might contain multiple sounds
  539. new buffer[WINSOUNDS_SIZE], temp[MAX_WINSOUND_LEN+1], pos;
  540. get_pcvar_string(gg_sound_winner,buffer,WINSOUNDS_SIZE-1);
  541.  
  542. while(numWinSounds < MAX_WINSOUNDS)
  543. {
  544. pos = contain_char(buffer,';');
  545.  
  546. // no more after this, precache what we have left
  547. if(pos == -1)
  548. {
  549. if(buffer[0])
  550. {
  551. precache_sound_special(buffer);
  552. copy(winSounds[numWinSounds++],MAX_WINSOUND_LEN,buffer);
  553. }
  554. break;
  555. }
  556.  
  557. // copy up to the semicolon and precache that
  558. copy(temp,pos,buffer);
  559.  
  560. if(temp[0])
  561. {
  562. precache_sound_special(temp);
  563. copy(winSounds[numWinSounds++],MAX_WINSOUND_LEN,temp);
  564. }
  565.  
  566. // copy everything after the semicolon
  567. copy(buffer,WINSOUNDS_SIZE-1,buffer[pos+1]);
  568. }
  569. }
  570.  
  571. // some generic, non-changing things
  572. precache_sound(BRASS_BELL_SOUND);
  573. precache_sound(KILL_DING_SOUND);
  574. precache_sound("common/null.wav");
  575.  
  576. // for the star
  577. trailSpr = precache_model("sprites/laserbeam.spr");
  578. }
  579.  
  580. public plugin_cfg()
  581. {
  582. galileoID = is_plugin_loaded("Galileo");
  583. }
  584.  
  585. public plugin_end()
  586. {
  587. #if defined SQL
  588. sql_uninit();
  589. #endif
  590.  
  591. // run endmap setup on plugin close
  592. if(ggActive)
  593. {
  594. // reset random teamplay
  595. if(initTeamplayInt != -1) set_pcvar_string(gg_teamplay,initTeamplayStr);
  596.  
  597. new setup[512];
  598. get_pcvar_string(gg_endmap_setup,setup,511);
  599. if(setup[0]) server_cmd(setup);
  600. }
  601. }
  602.  
  603. //**********************************************************************
  604. // FORWARDS
  605. //**********************************************************************
  606.  
  607. // client gets a steamid
  608. public client_authorized(id)
  609. {
  610. clear_values(id);
  611.  
  612. static authid[32];
  613. get_gg_authid(id,authid,31);
  614.  
  615. // load temporary save
  616. if(ggActive && get_pcvar_num(gg_save_temp))
  617. {
  618. new i, save = -1;
  619.  
  620. // find our possible temp save
  621. for(i=0;i<TEMP_SAVES;i++)
  622. {
  623. if(equal(authid,tempSave[i][svAuthid],31))
  624. {
  625. save = i;
  626. break;
  627. }
  628. }
  629.  
  630. // we found a save
  631. if(save > -1)
  632. {
  633. if(!get_pcvar_num(gg_teamplay))
  634. {
  635. // these are solo-only
  636. level[id] = tempSave[save][svLevel];
  637. score[id] = tempSave[save][svScore];
  638. get_level_weapon(level[id],lvlWeapon[id],23);
  639. }
  640.  
  641. statsPosition[id][0] = tempSave[save][svStatsPosition][0];
  642. statsPosition[id][1] = tempSave[save][svStatsPosition][1];
  643. teamTimes[id][0] = Float:tempSave[save][svTeamTimes][0];
  644. teamTimes[id][1] = Float:tempSave[save][svTeamTimes][1];
  645.  
  646. // clear it
  647. clear_save(TASK_CLEAR_SAVE+save);
  648. }
  649. }
  650.  
  651. #if defined SQL
  652. if(!statsPosition[id][0]) stats_get_position(id,authid,0);
  653. if(!statsPosition[id][1]) stats_get_position(id,authid,1);
  654. #else
  655. // cache our position if we didn't get it from a save
  656. if(!statsPosition[id][0] || !statsPosition[id][1])
  657. {
  658. if(statsArray) // we've set up the stats array
  659. {
  660. recheck_stats_sorting(); // see if anything changed
  661.  
  662. // if nothing happened, get my position
  663. if(!statsPosition[id][0]) stats_get_position(id,authid,0);
  664. if(!statsPosition[id][1]) stats_get_position(id,authid,1);
  665. }
  666. }
  667. #endif
  668.  
  669. #if defined REFRESH_TIMESTAMP_ON_JOIN
  670. stats_refresh_timestamp(authid);
  671. #endif
  672. }
  673.  
  674. // client leaves, reset values
  675. public client_disconnect(id)
  676. {
  677. // remove certain tasks
  678. remove_task(TASK_VERIFY_WEAPON+id);
  679. remove_task(TASK_REFRESH_NADE+id);
  680. remove_task(TASK_RESPAWN+id);
  681. remove_task(TASK_CHECK_DEATHMATCH+id);
  682. remove_task(TASK_REMOVE_PROTECTION+id);
  683. remove_task(TASK_DELAYED_SUICIDE+id);
  684.  
  685. // don't bother saving if in winning period or warmup
  686. if(!won && warmup <= 0)
  687. {
  688. new save_temp = get_pcvar_num(gg_save_temp);
  689.  
  690. // temporarily save values
  691. if(ggActive && save_temp && (level[id] > 1 || score[id] > 0))
  692. {
  693. // keep track of times
  694. new team = get_user_team(id);
  695. if(team == 1 || team == 2) teamTimes[id][team-1] += get_gametime() - lastSwitch[id];
  696.  
  697. new freeSave = -1, oldestSave = -1, i;
  698.  
  699. for(i=0;i<TEMP_SAVES;i++)
  700. {
  701. // we found a free one
  702. if(!tempSave[i][svAuthid][0])
  703. {
  704. freeSave = i;
  705. break;
  706. }
  707.  
  708. // keep track of one soonest to expire
  709. if(oldestSave == -1 || tempSave[i][svTime] < tempSave[oldestSave][svTime])
  710. oldestSave = i;
  711. }
  712.  
  713. // no free, use oldest
  714. if(freeSave == -1) freeSave = oldestSave;
  715.  
  716. get_gg_authid(id,tempSave[freeSave][svAuthid],31);
  717.  
  718. tempSave[freeSave][svLevel] = level[id];
  719. tempSave[freeSave][svScore] = score[id];
  720. tempSave[freeSave][svStatsPosition][0] = statsPosition[id][0];
  721. tempSave[freeSave][svStatsPosition][1] = statsPosition[id][1];
  722. tempSave[freeSave][svTeamTimes][0] = _:teamTimes[id][0];
  723. tempSave[freeSave][svTeamTimes][1] = _:teamTimes[id][1];
  724. tempSave[freeSave][svTime] = _:get_gametime();
  725.  
  726. set_task(float(save_temp),"clear_save",TASK_CLEAR_SAVE+freeSave);
  727. }
  728. }
  729.  
  730. clear_values(id);
  731. statsPosition[id][0] = 0;
  732. statsPosition[id][1] = 0;
  733. stats_clear_struct(playerStats[id]);
  734. }
  735.  
  736. // someone joins, monitor ham hooks
  737. public client_putinserver(id)
  738. {
  739. if(czero && !czbot_hams && is_user_bot(id) && get_pcvar_num(bot_quota) > 0)
  740. set_task(0.1,"czbot_hook_ham",id);
  741.  
  742. // bots don't call joinclass
  743. if(is_user_bot(id)) cmd_joinclass(id);
  744. }
  745.  
  746. // delay for private data to initialize --
  747. // here is the problem: registering a ham hook for "player" won't
  748. // register it for CZ bots, for some reason. so we have to register
  749. // it by entity. so we do this ridiculous thing in order to do so.
  750. public czbot_hook_ham(id)
  751. {
  752. if(czbot_hams || !is_user_connected(id)) return;
  753.  
  754. // probably a czero bot
  755. if(is_user_bot(id) && get_pcvar_num(bot_quota) > 0)
  756. {
  757. RegisterHamFromEntity(Ham_Spawn,id,"ham_player_spawn",1);
  758. RegisterHamFromEntity(Ham_Killed,id,"ham_player_killed_pre",0);
  759. RegisterHamFromEntity(Ham_Killed,id,"ham_player_killed_post",1);
  760.  
  761. czbot_hams = 1;
  762.  
  763. // bug fix for mid-round spawning, thanks to MeRcyLeZZ
  764. if(is_user_alive(id)) ham_player_spawn(id);
  765. }
  766. }
  767.  
  768. // remove a save
  769. public clear_save(taskid)
  770. {
  771. remove_task(taskid);
  772. tempSave[taskid-TASK_CLEAR_SAVE][svAuthid][0] = 0;
  773. }
  774.  
  775. // my info... it's changed!
  776. public client_infochanged(id)
  777. {
  778. if(!ggActive || !is_user_connected(id))
  779. return PLUGIN_CONTINUE;
  780.  
  781. new oldTeam = lastTeam[id], newTeam = _:cs_get_user_team(id);
  782.  
  783. // this means it was caught by logevent_team_join, or wasn't a team change
  784. if(oldTeam == newTeam) return PLUGIN_CONTINUE;
  785.  
  786. player_teamchange(id,oldTeam,newTeam);
  787.  
  788. // invalid team
  789. if((newTeam != 1 && newTeam != 2) || !get_pcvar_num(gg_teamplay))
  790. return PLUGIN_CONTINUE;
  791.  
  792. // something is out of synch
  793. if(teamLevel[newTeam] && (level[id] != teamLevel[newTeam] || score[id] != teamScore[newTeam] || !equal(lvlWeapon[id],teamLvlWeapon[newTeam])))
  794. {
  795. // set them directly
  796. level[id] = teamLevel[newTeam];
  797. lvlWeapon[id] = teamLvlWeapon[newTeam];
  798. score[id] = teamScore[newTeam];
  799.  
  800. // gimme mah weapon!
  801. if(is_user_alive(id)) give_level_weapon(id);
  802. }
  803.  
  804. return PLUGIN_CONTINUE;
  805. }
  806.  
  807. //**********************************************************************
  808. // FORWARD HOOKS
  809. //**********************************************************************
  810.  
  811. // an entity is given a model, check for silenced/burst status
  812. public fw_setmodel(ent,model[])
  813. {
  814. if(!ggActive) return FMRES_IGNORED;
  815.  
  816. new owner = pev(ent,pev_owner);
  817.  
  818. // no owner
  819. if(!is_user_connected(owner)) return FMRES_IGNORED;
  820.  
  821. static classname[24]; // the extra space is used later
  822. pev(ent,pev_classname,classname,10);
  823.  
  824. // not a weapon
  825. // checks for weaponbox, weapon_shield
  826. if(classname[8] != 'x' && !(classname[6] == '_' && classname[7] == 's' && classname[8] == 'h'))
  827. return FMRES_IGNORED;
  828.  
  829. // makes sure we don't get memory access error,
  830. // but also helpful to narrow down matches
  831. new len = strlen(model);
  832.  
  833. // ignore weaponboxes whose models haven't been set to correspond with their weapon types yet
  834. // checks for models/w_weaponbox.mdl
  835. if(len == 22 && model[17] == 'x') return FMRES_IGNORED;
  836.  
  837. // ignore C4
  838. // checks for models/w_backpack.mdl
  839. if(len == 21 && model[9] == 'b') return FMRES_IGNORED;
  840.  
  841. // checks for models/w_usp.mdl, usp, models/w_m4a1.mdl, m4a1
  842. if((len == 16 && model[10] == 's' && lvlWeapon[owner][1] == 's')
  843. || (len == 17 && model[10] == '4' && lvlWeapon[owner][1] == '4') )
  844. {
  845. copyc(model,len-1,model[contain_char(model,'_')+1],'.'); // strips off models/w_ and .mdl
  846. formatex(classname,23,"weapon_%s",model);
  847.  
  848. // remember silenced status
  849. new wEnt = fm_find_ent_by_owner(maxPlayers,classname,ent);
  850. if(pev_valid(wEnt)) silenced[owner] = cs_get_weapon_silen(wEnt);
  851. }
  852.  
  853. // checks for models/w_glock18.mdl, glock18, models/w_famas.mdl, famas
  854. else if((len == 20 && model[15] == '8' && lvlWeapon[owner][6] == '8')
  855. || (len == 18 && model[9] == 'f' && model[10] == 'a' && lvlWeapon[owner][0] == 'f' && lvlWeapon[owner][1] == 'a') )
  856. {
  857. copyc(model,len-1,model[contain_char(model,'_')+1],'.'); // strips off models/w_ and .mdl
  858. formatex(classname,23,"weapon_%s",model);
  859.  
  860. // remember burst status
  861. new wEnt = fm_find_ent_by_owner(maxPlayers,classname,ent);
  862. if(pev_valid(wEnt)) silenced[owner] = cs_get_weapon_burst(wEnt);
  863. }
  864.  
  865. // if owner is dead, remove it if we need to
  866. if(get_user_health(owner) <= 0 && get_pcvar_num(gg_dm) && !get_pcvar_num(gg_pickup_others))
  867. {
  868. dllfunc(DLLFunc_Think,ent);
  869. return FMRES_SUPERCEDE;
  870. }
  871.  
  872. return FMRES_IGNORED;
  873. }
  874.  
  875. // HELLO HELLo HELlo HEllo Hello hello
  876. public fw_emitsound(ent,channel,sample[],Float:volume,Float:atten,flags,pitch)
  877. {
  878. if(!ggActive || !is_user_connected(ent) || !get_pcvar_num(gg_dm) || spawnSounds[ent])
  879. return FMRES_IGNORED;
  880.  
  881. // used to stop spawn sounds in deathmatch
  882. return FMRES_SUPERCEDE;
  883. }
  884.  
  885. //**********************************************************************
  886. // EVENT HOOKS
  887. //**********************************************************************
  888.  
  889. // our HUD gets reset (obviously)
  890. public event_resethud(id)
  891. {
  892. if(ggActive && is_user_connected(id))
  893. set_task(0.1,"reset_hud",id);
  894. }
  895.  
  896. // fix the leader display and hide money
  897. public reset_hud(id)
  898. {
  899. if(is_user_connected(id))
  900. {
  901. status_display(id);
  902. if(get_pcvar_num(gg_disable_money)) hide_money(id);
  903. }
  904. }
  905.  
  906. // someone changes weapons
  907. public event_curweapon(id)
  908. {
  909. if(!ggActive || !is_user_connected(id)) return;
  910.  
  911. // keep star speed
  912. if(star[id]) fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)*1.5);
  913.  
  914. // monitor weapon activity
  915. if(afkCheck[id] && is_user_alive(id)) afkCheck[id]++;
  916.  
  917. // have at least one bullet in AWP clip
  918. if(get_pcvar_num(gg_awp_oneshot) && read_data(2) == CSW_AWP && read_data(3) > 1)
  919. {
  920. new wEnt = get_weapon_ent(id,CSW_AWP);
  921. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,1);
  922.  
  923. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  924. write_byte(1); // current?
  925. write_byte(CSW_AWP); // weapon
  926. write_byte(1); // clip
  927. message_end();
  928. }
  929. }
  930.  
  931. // a new round has begun
  932. public event_new_round()
  933. {
  934. static armourysHidden = 0;
  935.  
  936. roundEnded = 0;
  937. roundsElapsed++;
  938.  
  939. c4planter = 0;
  940. bombStatus[3] = BOMB_PICKEDUP;
  941.  
  942. if(gameCommenced && !autovoted)
  943. {
  944. // don't check mode until vote starts, so map configs have chance to execute
  945. if(/*autovote_mode &&*/ roundsElapsed >= get_pcvar_num(gg_autovote_rounds))
  946. {
  947. autovoted = 1;
  948. autovote_mode = -1; // signal to check in autovote_start
  949. set_task(get_pcvar_float(gg_autovote_delay),"autovote_start");
  950. }
  951. }
  952.  
  953. // game_player_equip
  954. manage_equips();
  955.  
  956. if(!ggActive) return;
  957.  
  958. // we should probably warmup...
  959. // don't ask me where I'm getting this from.
  960. if(shouldWarmup)
  961. {
  962. shouldWarmup = 0;
  963. start_warmup();
  964. }
  965.  
  966. if(warmup <= 0)
  967. {
  968. new leader = get_leader();
  969.  
  970. if(equal(lvlWeapon[leader],HEGRENADE)) play_sound_by_cvar(0,gg_sound_nade);
  971. else if(equal(lvlWeapon[leader],KNIFE)) play_sound_by_cvar(0,gg_sound_knife);
  972. }
  973.  
  974. // reset leader display
  975. remove_task(TASK_LEADER_DISPLAY);
  976. set_task(0.5,"show_leader_display"); // wite to initialize levels
  977.  
  978. new pickup_others = get_pcvar_num(gg_pickup_others);
  979. if(!pickup_others /*&& !armourysHidden*/) // they show up again on new round
  980. {
  981. set_task(0.1,"hide_armory_entitys");
  982. armourysHidden = 1;
  983. }
  984. else if(pickup_others && armourysHidden)
  985. {
  986. set_task(0.1,"show_armory_entitys");
  987. armourysHidden = 0;
  988. }
  989.  
  990. // block hostages
  991. if(hostageMap)
  992. {
  993. // block hostages
  994. if(get_pcvar_num(gg_block_objectives))
  995. set_task(0.1,"move_hostages");
  996. else
  997. {
  998. // reset hostage info
  999. new i;
  1000. for(i=0;i<33;i++)
  1001. {
  1002. hosties[i][0] = 0;
  1003. hosties[i][1] = 0;
  1004. }
  1005. }
  1006. }
  1007.  
  1008. // start in random positions at round start
  1009. if(get_pcvar_num(gg_dm) && get_pcvar_num(gg_dm_start_random))
  1010. set_task(0.1,"randomly_place_everyone");
  1011. }
  1012.  
  1013. // hide the armoury_entity's so players cannot pick them up
  1014. public hide_armory_entitys()
  1015. {
  1016. new ent = maxPlayers;
  1017. while((ent = fm_find_ent_by_class(ent,"armoury_entity")))
  1018. {
  1019. set_pev(ent,pev_solid,SOLID_NOT);
  1020. fm_set_entity_visibility(ent,0);
  1021. }
  1022. }
  1023.  
  1024. // reveal the armoury_entity's so players CAN pick them up
  1025. public show_armory_entitys()
  1026. {
  1027. new ent = maxPlayers;
  1028. while((ent = fm_find_ent_by_class(ent,"armoury_entity")))
  1029. {
  1030. set_pev(ent,pev_solid,SOLID_TRIGGER);
  1031. fm_set_entity_visibility(ent,1);
  1032. }
  1033. }
  1034.  
  1035. // move the hostages so that CTs can't get to them
  1036. public move_hostages()
  1037. {
  1038. new ent = maxPlayers;
  1039. while((ent = fm_find_ent_by_class(ent,"hostage_entity")))
  1040. set_pev(ent,pev_origin,Float:{8192.0,8192.0,8192.0});
  1041. }
  1042.  
  1043. // round is restarting (TAG: sv_restartround)
  1044. public event_round_restart()
  1045. {
  1046. // re-entrancy fix
  1047. static Float:lastThis;
  1048. new Float:now = get_gametime();
  1049. if(now == lastThis) return;
  1050. lastThis = now;
  1051.  
  1052. static message[17];
  1053. read_data(2,message,16);
  1054.  
  1055. if(equal(message,"#Game_Commencing"))
  1056. {
  1057. // don't reset values on game commencing,
  1058. // if it has already commenced once
  1059. if(gameCommenced) return;
  1060. gameCommenced = 1;
  1061.  
  1062. // start warmup
  1063. if(ggActive)
  1064. {
  1065. clear_all_values();
  1066.  
  1067. shouldWarmup = 0;
  1068. start_warmup();
  1069.  
  1070. return;
  1071. }
  1072. }
  1073. /*else if(ggActive) // #Game_will_restart_in
  1074. {
  1075. read_data(3,message,4); // time to restart in
  1076. new Float:time = floatstr(message) - 0.1;
  1077. set_task((time < 0.1) ? 0.1 : time,"clear_all_values");
  1078. }*/
  1079. }
  1080.  
  1081. // a delayed clearing
  1082. public clear_all_values()
  1083. {
  1084. new player;
  1085. for(player=1;player<=maxPlayers;player++)
  1086. {
  1087. if(is_user_connected(player)) clear_values(player,1);
  1088. }
  1089.  
  1090. clear_team_values(1);
  1091. clear_team_values(2);
  1092. }
  1093.  
  1094. // the bomb explodes
  1095. public event_bomb_detonation()
  1096. {
  1097. if(!ggActive || get_pcvar_num(gg_bomb_defuse_lvl) != 2 || !c4planter)
  1098. return;
  1099.  
  1100. // re-entrancy fix
  1101. static Float:lastThis;
  1102. new Float:now = get_gametime();
  1103. if(now == lastThis) return;
  1104. lastThis = now;
  1105.  
  1106. new id = c4planter;
  1107. c4planter = 0;
  1108.  
  1109. if(!is_user_connected(id)) return;
  1110.  
  1111. if(!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE) && level[id] < weaponNum)
  1112. {
  1113. change_level(id,1);
  1114. //score[id] = 0;
  1115. }
  1116. else if(is_user_alive(id)) refill_ammo(id);
  1117. }
  1118.  
  1119. // ammo amount changes
  1120. public event_ammox(id)
  1121. {
  1122. new type = read_data(1);
  1123.  
  1124. // not HE grenade ammo, or not on the grenade level
  1125. if(type != 12 || !equal(lvlWeapon[id],HEGRENADE)) return;
  1126.  
  1127. new amount = read_data(2);
  1128.  
  1129. // still have some left, ignore
  1130. if(amount > 0)
  1131. {
  1132. remove_task(TASK_REFRESH_NADE+id);
  1133. return;
  1134. }
  1135.  
  1136. new Float:refresh = get_pcvar_float(gg_nade_refresh);
  1137.  
  1138. // refreshing is disabled, or we are already giving one out
  1139. if(refresh <= 0.0 || task_exists(TASK_REFRESH_NADE+id)) return;
  1140.  
  1141. // start the timer for the new grenade
  1142. set_task(refresh,"refresh_nade",TASK_REFRESH_NADE+id);
  1143. }
  1144.  
  1145. // map is changing
  1146. public event_intermission()
  1147. {
  1148. if(!ggActive) return;
  1149.  
  1150. if(won)
  1151. {
  1152. if(set_nextmap()) set_task(1.0,"goto_nextmap");
  1153. return;
  1154. }
  1155.  
  1156. new player, found;
  1157. for(player=1;player<=maxPlayers;player++)
  1158. {
  1159. if(is_user_connected(player) && on_valid_team(player))
  1160. {
  1161. found = 1;
  1162. break;
  1163. }
  1164. }
  1165.  
  1166. // did not find any players on a valid team, game over man
  1167. if(!found)
  1168. {
  1169. if(set_nextmap()) set_task(1.0,"goto_nextmap");
  1170. return;
  1171. }
  1172.  
  1173. // teamplay, easier to decide
  1174. if(get_pcvar_num(gg_teamplay))
  1175. {
  1176. new winner;
  1177.  
  1178. // clear winner
  1179. if(teamLevel[1] > teamLevel[2]) winner = 1;
  1180. else if(teamLevel[2] > teamLevel[1]) winner = 2;
  1181. else
  1182. {
  1183. // tied for level, check score
  1184. if(teamScore[1] > teamScore[2]) winner = 1;
  1185. else if(teamScore[2] > teamScore[1]) winner = 2;
  1186. else
  1187. {
  1188. // tied for level and score, pick random
  1189. winner = random_num(1,2);
  1190. }
  1191. }
  1192.  
  1193. // grab a player from the winning and losing teams
  1194. new plWinner, plLoser, team;
  1195. for(player=1;player<=maxPlayers;player++)
  1196. {
  1197. if(is_user_connected(player) && on_valid_team(player))
  1198. {
  1199. team = _:cs_get_user_team(player);
  1200.  
  1201. if(!plWinner && team == winner) plWinner = player;
  1202. else if(!plLoser && team != winner) plLoser = player;
  1203.  
  1204. if(plWinner && plLoser) break;
  1205. }
  1206. }
  1207.  
  1208. win(plWinner,plLoser);
  1209. if(set_nextmap()) set_task(1.0,"goto_nextmap");
  1210.  
  1211. return;
  1212. }
  1213.  
  1214. // grab highest level
  1215. new leaderLevel;
  1216. get_leader(leaderLevel);
  1217.  
  1218. // grab player list
  1219. new players[32], pNum, winner, i;
  1220. get_players(players,pNum);
  1221.  
  1222. // no one here
  1223. if(pNum <= 0)
  1224. {
  1225. if(set_nextmap()) set_task(1.0,"goto_nextmap");
  1226. return;
  1227. }
  1228.  
  1229. new topLevel[32], tlNum;
  1230.  
  1231. // get all of the highest level players
  1232. for(i=0;i<pNum;i++)
  1233. {
  1234. player = players[i];
  1235.  
  1236. if(level[player] == leaderLevel)
  1237. topLevel[tlNum++] = player;
  1238. }
  1239.  
  1240. // only one on top level
  1241. if(tlNum == 1) winner = topLevel[0];
  1242. else
  1243. {
  1244. new highestKills, frags;
  1245.  
  1246. // get the most kills
  1247. for(i=0;i<tlNum;i++)
  1248. {
  1249. frags = get_user_frags(topLevel[i]);
  1250.  
  1251. if(frags >= highestKills)
  1252. highestKills = frags;
  1253. }
  1254.  
  1255. new topKillers[32], tkNum;
  1256.  
  1257. // get all of the players with highest kills
  1258. for(i=0;i<tlNum;i++)
  1259. {
  1260. if(get_user_frags(topLevel[i]) == highestKills)
  1261. topKillers[tkNum++] = topLevel[i];
  1262. }
  1263.  
  1264. // only one on top kills
  1265. if(tkNum == 1) winner = topKillers[0];
  1266. else
  1267. {
  1268. new leastDeaths, deaths;
  1269.  
  1270. // get the least deaths
  1271. for(i=0;i<tkNum;i++)
  1272. {
  1273. deaths = cs_get_user_deaths(topKillers[i]);
  1274. if(deaths <= leastDeaths) leastDeaths = deaths;
  1275. }
  1276.  
  1277. new leastDead[32], ldNum;
  1278.  
  1279. // get all of the players with lowest deaths
  1280. for(i=0;i<tkNum;i++)
  1281. {
  1282. if(cs_get_user_deaths(topKillers[i]) == leastDeaths)
  1283. leastDead[ldNum++] = topKillers[i];
  1284. }
  1285.  
  1286. leastDead[random_num(0,ldNum-1)];
  1287. }
  1288. }
  1289.  
  1290. // crown them
  1291. win(winner,0);
  1292.  
  1293. // go to next map in cycle
  1294. if(set_nextmap()) set_task(1.0,"goto_nextmap");
  1295. }
  1296.  
  1297. //**********************************************************************
  1298. // MESSAGE HOOKS
  1299. //**********************************************************************
  1300.  
  1301. // bomb is dropped, remember for DM
  1302. public message_bombdrop(msg_id,msg_dest,msg_entity)
  1303. {
  1304. if(ggActive && get_pcvar_num(gg_block_objectives))
  1305. return PLUGIN_HANDLED;
  1306.  
  1307. // you can't simply get_msg_arg_int the coords
  1308. bombStatus[0] = floatround(get_msg_arg_float(1));
  1309. bombStatus[1] = floatround(get_msg_arg_float(2));
  1310. bombStatus[2] = floatround(get_msg_arg_float(3));
  1311. bombStatus[3] = get_msg_arg_int(4);
  1312.  
  1313. return PLUGIN_CONTINUE;
  1314. }
  1315.  
  1316. // bomb is picked up, remember for DM
  1317. public message_bombpickup(msg_id,msg_dest,msg_entity)
  1318. {
  1319. bombStatus[3] = BOMB_PICKEDUP;
  1320. return PLUGIN_CONTINUE;
  1321. }
  1322.  
  1323. // scenario changes
  1324. public message_scenario(msg_id,msg_dest,msg_entity)
  1325. {
  1326. // disabled
  1327. if(!ggActive) return PLUGIN_CONTINUE;
  1328.  
  1329. // don't override our custom display, if we have one
  1330. if(get_pcvar_num(gg_status_display))
  1331. return PLUGIN_HANDLED;
  1332.  
  1333. // block hostage display if we disabled objectives
  1334. else if(get_msg_args() > 1 && get_pcvar_num(gg_block_objectives))
  1335. {
  1336. new sprite[8];
  1337. get_msg_arg_string(2,sprite,7);
  1338.  
  1339. if(equal(sprite,"hostage"))
  1340. return PLUGIN_HANDLED;
  1341. }
  1342.  
  1343. return PLUGIN_CONTINUE;
  1344. }
  1345.  
  1346. // remove c4 if we disabled objectives
  1347. public message_weappickup(msg_id,msg_dest,msg_entity)
  1348. {
  1349. if(!bombMap || !ggActive || !get_pcvar_num(gg_block_objectives))
  1350. return PLUGIN_CONTINUE;
  1351.  
  1352. if(get_msg_arg_int(1) == CSW_C4)
  1353. {
  1354. set_task(0.1,"strip_c4",msg_entity);
  1355. return PLUGIN_HANDLED;
  1356. }
  1357.  
  1358. return PLUGIN_CONTINUE;
  1359. }
  1360.  
  1361. // delay, since weappickup is slightly before we actually get the weapon
  1362. public strip_c4(id)
  1363. {
  1364. if(!is_user_connected(id)) return;
  1365.  
  1366. ham_strip_weapon(id,"weapon_c4");
  1367.  
  1368. // remove it from HUD
  1369. message_begin(MSG_ONE,gmsgStatusIcon,_,id);
  1370. write_byte(0);
  1371. write_string("c4");
  1372. message_end();
  1373. }
  1374.  
  1375. // block c4 ammo message if we disabled objectives
  1376. public message_ammopickup(msg_id,msg_dest,msg_entity)
  1377. {
  1378. if(!bombMap || !ggActive || !get_pcvar_num(gg_block_objectives))
  1379. return PLUGIN_CONTINUE;
  1380.  
  1381. if(get_msg_arg_int(1) == 14) // C4
  1382. return PLUGIN_HANDLED;
  1383.  
  1384. return PLUGIN_CONTINUE;
  1385. }
  1386.  
  1387. // block dropped the bomb message if we disabled objectives
  1388. public message_textmsg(msg_id,msg_dest,msg_entity)
  1389. {
  1390. if(!bombMap || !ggActive || !get_pcvar_num(gg_block_objectives))
  1391. return PLUGIN_CONTINUE;
  1392.  
  1393. static message[16];
  1394. get_msg_arg_string(2,message,15);
  1395.  
  1396. if(equal(message,"#Game_bomb_drop"))
  1397. return PLUGIN_HANDLED;
  1398.  
  1399. return PLUGIN_CONTINUE;
  1400. }
  1401.  
  1402. // block hostages from appearing on radar if we disabled objectives
  1403. public message_hostagepos(msg_id,msg_dest,msg_entity)
  1404. {
  1405. if(!ggActive || !get_pcvar_num(gg_block_objectives))
  1406. return PLUGIN_CONTINUE;
  1407.  
  1408. return PLUGIN_HANDLED;
  1409. }
  1410.  
  1411. // a corpse is to be set, stop player shells bug (thanks sawce)
  1412. public message_clcorpse(msg_id,msg_dest,msg_entity)
  1413. {
  1414. if(!ggActive || get_msg_args() < 12)
  1415. return PLUGIN_CONTINUE;
  1416.  
  1417. if(get_pcvar_num(gg_dm) && !get_pcvar_num(gg_dm_corpses))
  1418. return PLUGIN_HANDLED;
  1419.  
  1420. return PLUGIN_CONTINUE;
  1421. }
  1422.  
  1423. // money money money!
  1424. public message_money(msg_id,msg_dest,msg_entity)
  1425. {
  1426. if(!ggActive || !is_user_connected(msg_entity) || !is_user_alive(msg_entity) || !get_pcvar_num(gg_disable_money))
  1427. return PLUGIN_CONTINUE;
  1428.  
  1429. // this now just changes the value of the message, passes it along,
  1430. // and then modifies the pdata, instead of calling another cs_set_user_money
  1431. // and sending out more messages than needed.
  1432.  
  1433. set_msg_arg_int(1,ARG_LONG,0); // money
  1434. set_msg_arg_int(2,ARG_BYTE,0); // flash
  1435.  
  1436. set_pdata_int(msg_entity,OFFSET_CSMONEY,0,OFFSET_LINUX);
  1437. return PLUGIN_CONTINUE;
  1438. }
  1439.  
  1440. //**********************************************************************
  1441. // LOG EVENT HOOKS
  1442. //**********************************************************************
  1443.  
  1444. // someone planted the bomb
  1445. public logevent_bomb_planted()
  1446. {
  1447. if(!ggActive || !get_pcvar_num(gg_bomb_defuse_lvl) || roundEnded)
  1448. return;
  1449.  
  1450. new id = get_loguser_index();
  1451. if(!is_user_connected(id)) return;
  1452.  
  1453. if(get_pcvar_num(gg_bomb_defuse_lvl) == 2) c4planter = id;
  1454. else
  1455. {
  1456. if(!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE) && level[id] < weaponNum)
  1457. {
  1458. change_level(id,1);
  1459. }
  1460. else refill_ammo(id);
  1461. }
  1462.  
  1463. }
  1464.  
  1465. // someone defused the bomb
  1466. public logevent_bomb_defused()
  1467. {
  1468. if(!ggActive || !get_pcvar_num(gg_bomb_defuse_lvl))
  1469. return;
  1470.  
  1471. new id = get_loguser_index();
  1472. if(!is_user_connected(id)) return;
  1473.  
  1474. if(!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE) && level[id] < weaponNum)
  1475. {
  1476. change_level(id,1);
  1477. }
  1478. else refill_ammo(id);
  1479. }
  1480.  
  1481. // the round ends
  1482. public logevent_round_end()
  1483. {
  1484. roundEnded = 1;
  1485. }
  1486.  
  1487. // hostage is touched
  1488. public logevent_hostage_touched()
  1489. {
  1490. new reward = get_pcvar_num(gg_host_touch_reward);
  1491.  
  1492. if(!ggActive || !reward || roundEnded)
  1493. return;
  1494.  
  1495. new id = get_loguser_index();
  1496. if(!is_user_connected(id) || hosties[id][0] == -1) return;
  1497.  
  1498. hosties[id][0]++;
  1499.  
  1500. if(hosties[id][0] >= reward)
  1501. {
  1502. if((!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE) && level[id] < weaponNum)
  1503. || score[id] + 1 < get_level_goal(level[id],id))
  1504. {
  1505. // didn't level off of it
  1506. if(!change_score(id,1)) show_required_kills(id);
  1507. }
  1508. else refill_ammo(id);
  1509.  
  1510. hosties[id][0] = -1;
  1511.  
  1512. if(get_pcvar_num(gg_teamplay))
  1513. {
  1514. new CsTeams:team = cs_get_user_team(id), i;
  1515. for(i=1;i<=maxPlayers;i++)
  1516. {
  1517. // one per team
  1518. if(is_user_connected(i) && cs_get_user_team(i) == team)
  1519. hosties[i][0] = -1;
  1520. }
  1521. }
  1522. }
  1523. }
  1524.  
  1525. // hostage is rescued
  1526. public logevent_hostage_rescued()
  1527. {
  1528. new reward = get_pcvar_num(gg_host_rescue_reward);
  1529.  
  1530. if(!ggActive || !reward || roundEnded)
  1531. return;
  1532.  
  1533. new id = get_loguser_index();
  1534. if(!is_user_connected(id) || hosties[id][1] == -1) return;
  1535.  
  1536. hosties[id][1]++;
  1537.  
  1538. if(hosties[id][1] >= reward)
  1539. {
  1540. if(!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE) && level[id] < weaponNum)
  1541. change_level(id,1);
  1542. else
  1543. refill_ammo(id);
  1544.  
  1545. hosties[id][1] = -1;
  1546.  
  1547. if(get_pcvar_num(gg_teamplay))
  1548. {
  1549. new CsTeams:team = cs_get_user_team(id), i;
  1550. for(i=1;i<=maxPlayers;i++)
  1551. {
  1552. // one per team
  1553. if(is_user_connected(i) && cs_get_user_team(i) == team)
  1554. hosties[i][1] = -1;
  1555. }
  1556. }
  1557. }
  1558. }
  1559.  
  1560. // hostage is killed
  1561. public logevent_hostage_killed()
  1562. {
  1563. new penalty = get_pcvar_num(gg_host_kill_penalty);
  1564.  
  1565. if(!ggActive || !penalty)
  1566. return;
  1567.  
  1568. new id = get_loguser_index();
  1569. if(!is_user_connected(id)) return;
  1570.  
  1571. new teamplay = get_pcvar_num(gg_teamplay), name[32];
  1572.  
  1573. if(teamplay) get_user_team(id,name,9);
  1574. else get_user_name(id,name,31);
  1575.  
  1576. if(score[id] - penalty < 0)
  1577. gungame_print(0,id,1,"%L",LANG_PLAYER_C,(teamplay) ? "HK_LEVEL_DOWN_TEAM" : "HK_LEVEL_DOWN",name,(level[id] > 1) ? level[id]-1 : level[id]);
  1578. else
  1579. gungame_print(0,id,1,"%L",LANG_PLAYER_C,(teamplay) ? "HK_SCORE_DOWN_TEAM" : "HK_SCORE_DOWN",name,penalty);
  1580.  
  1581. change_score(id,-penalty);
  1582. }
  1583.  
  1584. // someone joins a team
  1585. public logevent_team_join()
  1586. {
  1587. if(!ggActive) return;
  1588.  
  1589. new id = get_loguser_index();
  1590. if(!is_user_connected(id)) return;
  1591.  
  1592. new oldTeam = get_user_team(id), newTeam = _:cs_get_user_team(id);
  1593. player_teamchange(id,oldTeam,newTeam);
  1594.  
  1595. // teamplay, team switch allowed
  1596. if(get_pcvar_num(gg_teamplay))
  1597. {
  1598. remove_task(TASK_DELAYED_SUICIDE+id);
  1599.  
  1600. // I was the one who planted the bomb
  1601. if(c4planter == id)
  1602. {
  1603. // clear in case we don't find anyone
  1604. c4planter = 0;
  1605.  
  1606. new player;
  1607. for(player=1;player<=maxPlayers;player++)
  1608. {
  1609. if(player != id && is_user_connected(player) && cs_get_user_team(player) == CS_TEAM_T)
  1610. {
  1611. // assign it to someone else so terrorists get points
  1612. c4planter = player;
  1613. break;
  1614. }
  1615. }
  1616. }
  1617.  
  1618. return;
  1619. }
  1620.  
  1621. // no (valid) previous team or didn't switch teams, ignore (suicide)
  1622. if(oldTeam < 1 || oldTeam > 2 || newTeam < 1 || newTeam > 2 || oldTeam == newTeam)
  1623. return;
  1624.  
  1625. // check to see if the team change was beneficial
  1626. if(get_pcvar_num(gg_allow_changeteam) == 2)
  1627. {
  1628. new teamCount[2], i;
  1629. for(i=1;i<=maxPlayers;i++)
  1630. {
  1631. if(!is_user_connected(i))
  1632. continue;
  1633.  
  1634. switch(cs_get_user_team(i))
  1635. {
  1636. case CS_TEAM_T: teamCount[0]++;
  1637. case CS_TEAM_CT: teamCount[1]++;
  1638. }
  1639. }
  1640.  
  1641. if(teamCount[newTeam-1] <= teamCount[oldTeam-1])
  1642. remove_task(TASK_DELAYED_SUICIDE+id);
  1643. }
  1644. else remove_task(TASK_DELAYED_SUICIDE+id);
  1645. }
  1646.  
  1647. //**********************************************************************
  1648. // HAM HOOKS
  1649. //**********************************************************************
  1650.  
  1651. // a player respawned
  1652. public ham_player_spawn(id)
  1653. {
  1654. if(ggActive && is_user_alive(id) && cs_get_user_team(id)) // do team check here for bots
  1655. spawned(id);
  1656.  
  1657. return HAM_IGNORED;
  1658. }
  1659.  
  1660. // what do you think happened here?
  1661. public ham_player_killed_pre(victim,killer,gib)
  1662. {
  1663. if(!ggActive || won || !is_user_connected(victim)) return HAM_IGNORED;
  1664.  
  1665. // stops defusal kits from dropping in deathmatch mode
  1666. if(bombMap && get_pcvar_num(gg_dm)) cs_set_user_defuse(victim,0);
  1667.  
  1668. // remember victim's silenced status
  1669. if(equal(lvlWeapon[victim],"usp") || equal(lvlWeapon[victim],"m4a1"))
  1670. {
  1671. new wEnt = get_weapon_ent(victim,_,lvlWeapon[victim]);
  1672. if(pev_valid(wEnt)) silenced[victim] = cs_get_weapon_silen(wEnt);
  1673. }
  1674.  
  1675. // or, remember burst status
  1676. else if(equal(lvlWeapon[victim],"glock18") || equal(lvlWeapon[victim],"famas"))
  1677. {
  1678. new wEnt = get_weapon_ent(victim,_,lvlWeapon[victim]);
  1679. if(pev_valid(wEnt)) silenced[victim] = cs_get_weapon_burst(wEnt);
  1680. }
  1681.  
  1682. // some sort of death that we don't want to count
  1683. if(killer == victim || !is_user_connected(killer) || cs_get_user_team(killer) == cs_get_user_team(victim))
  1684. return HAM_IGNORED;
  1685.  
  1686. // award for killing hostage carrier
  1687. new host_kill_reward = get_pcvar_num(gg_host_kill_reward);
  1688.  
  1689. // note that this doesn't work with CZ hostages
  1690. if(hostageMap && !czero && host_kill_reward && !equal(lvlWeapon[killer],HEGRENADE) && !equal(lvlWeapon[killer],KNIFE))
  1691. {
  1692. // check for hostages following this player
  1693. new hostage = maxPlayers;
  1694. while((hostage = fm_find_ent_by_class(hostage,"hostage_entity")))
  1695. {
  1696. if(cs_get_hostage_foll(hostage) == victim && pev(hostage,pev_deadflag) == DEAD_NO)
  1697. break;
  1698. }
  1699.  
  1700. // award bonus score if victim had hostages
  1701. if(hostage)
  1702. {
  1703. if(!equal(lvlWeapon[killer],HEGRENADE) && !equal(lvlWeapon[killer],KNIFE) && level[killer] < weaponNum)
  1704. {
  1705. // didn't level off of it
  1706. if(!change_score(killer,host_kill_reward) || score[killer])
  1707. show_required_kills(killer);
  1708. }
  1709. }
  1710. }
  1711.  
  1712. return HAM_IGNORED;
  1713. }
  1714.  
  1715. // it's just that easy (multiplay_gamerules.cpp, ln 709)
  1716. public ham_player_killed_post(victim,killer,gib)
  1717. {
  1718. if(!ggActive || won) return HAM_IGNORED;
  1719.  
  1720. // log in bounds
  1721. if(killer > 0 && killer < 33 && victim > 0 && victim < 33)
  1722. lastKilled[killer] = victim;
  1723.  
  1724. if(!is_user_connected(victim)) return HAM_IGNORED;
  1725.  
  1726. // moved the below from killed_pre to killed_post because sometimes user is still alive in pre.
  1727. // don't know why this wasn't here before, but just in case I need to change it back... (thanks addam)
  1728.  
  1729. // allow us to join in on deathmatch
  1730. if(!get_pcvar_num(gg_dm))
  1731. {
  1732. remove_task(TASK_CHECK_DEATHMATCH+victim);
  1733. set_task(10.0,"check_deathmatch",TASK_CHECK_DEATHMATCH+victim);
  1734. }
  1735.  
  1736. // respawn us
  1737. else
  1738. {
  1739. remove_task(TASK_RESPAWN+victim);
  1740. remove_task(TASK_REMOVE_PROTECTION+victim);
  1741. begin_respawn(victim);
  1742. fm_set_user_rendering(victim); // clear spawn protection
  1743. }
  1744.  
  1745. remove_task(TASK_VERIFY_WEAPON+victim);
  1746.  
  1747. star[victim] = 0;
  1748. remove_task(TASK_END_STAR+victim);
  1749.  
  1750. static wpnName[24];
  1751. get_killer_weapon(killer,pev(victim,pev_dmg_inflictor),wpnName,23);
  1752.  
  1753. // grenade death
  1754. if(equal(wpnName,"grenade"))
  1755. {
  1756. new inflictor = pev(victim,pev_dmg_inflictor);
  1757.  
  1758. if(pev_valid(inflictor))
  1759. {
  1760. new Float:dmgtime;
  1761. pev(inflictor,pev_dmgtime,dmgtime);
  1762.  
  1763. // a C4 kill will be reported as hegrenade. however, C4 has no
  1764. // pev_dmgtime, while a real hegrenade does. so distinguish between hegrenade
  1765. // and C4, and ignore C4 kills. also note that we can't compare models,
  1766. // because at this stage both an hegrenade and C4 have no model.
  1767. if(!dmgtime)
  1768. {
  1769. afkCheck[victim] = 0;
  1770. return HAM_IGNORED;
  1771. }
  1772. }
  1773.  
  1774. // fix name
  1775. formatex(wpnName,23,HEGRENADE);
  1776. }
  1777.  
  1778. // killed self with world
  1779. if(killer == victim && equal(wpnName,"world") && is_user_connected(killer))
  1780. {
  1781. // this might be a valid team switch, wait it out
  1782. if(!roundEnded && get_pcvar_num(gg_allow_changeteam))
  1783. {
  1784. set_task(0.1,"delayed_suicide",TASK_DELAYED_SUICIDE+victim);
  1785. afkCheck[victim] = 0;
  1786.  
  1787. return HAM_IGNORED; // in the meantime, don't penalize the suicide
  1788. }
  1789.  
  1790. player_suicided(killer);
  1791. afkCheck[victim] = 0;
  1792.  
  1793. return HAM_IGNORED;
  1794. }
  1795.  
  1796. // afk checker
  1797. if(afkCheck[victim] && afkCheck[victim] < 3) // 0 = no afk check, 3+ = they did something with a weapon (it is set to 1, and it goes to 2 when they get their new weapon)
  1798. {
  1799. new Float:origin[3], Float:angles[3], afk;
  1800. pev(victim,pev_origin,origin);
  1801. pev(victim,pev_v_angle,angles);
  1802.  
  1803. if(get_pcvar_num(gg_afk_protection) == 2)
  1804. {
  1805. // this mode requires that your origin and angles be exactly as they were when you spawned,
  1806. // but it ignores the z-component because often players spawn a few units above ground
  1807. afk = (origin[0] == spawnOrigin[victim][0]) && (origin[1] == spawnOrigin[victim][1]) && (angles[0] == spawnAngles[victim][0]) && (angles[1] == spawnAngles[victim][1]) && (angles[2] == spawnAngles[victim][2]);
  1808. }
  1809. else
  1810. {
  1811. // this mode allows a slight XY shift due to pushback from getting shot by certain weapons,
  1812. // and also ignores the Y-component of the angle, because it sometimes inexplicably doesn't match up
  1813. origin[2] = spawnOrigin[victim][2]; // ignore Z-component, they fall
  1814. afk = (vector_distance(origin,spawnOrigin[victim]) < 28.0) && (angles[0] == spawnAngles[victim][0]) && (angles[2] == spawnAngles[victim][2]);
  1815. }
  1816.  
  1817. if(afk)
  1818. {
  1819. new name[32];
  1820. get_user_name(victim,name,31);
  1821.  
  1822. gungame_print(killer,victim,1,"%L",killer,"AFK_KILL",name);
  1823. afkCheck[victim] = 0;
  1824.  
  1825. return HAM_IGNORED;
  1826. }
  1827. }
  1828.  
  1829. afkCheck[victim] = 0;
  1830.  
  1831. // other player had spawn protection
  1832. if(spawnProtected[victim])
  1833. {
  1834. new name[32];
  1835. get_user_name(victim,name,31);
  1836. gungame_print(killer,victim,1,"%L",killer,"SPAWNPROTECTED_KILL",name,floatround(get_pcvar_float(gg_dm_sp_time)));
  1837.  
  1838. spawnProtected[victim] = 0;
  1839. return HAM_IGNORED;
  1840. }
  1841.  
  1842. // killed self with worldspawn (fall damage usually)
  1843. if(equal(wpnName,"worldspawn"))
  1844. {
  1845. if(get_pcvar_num(gg_worldspawn_suicide)) player_suicided(victim);
  1846. return HAM_IGNORED;
  1847. }
  1848.  
  1849. // killed self not with worldspawn
  1850. if(!killer || killer == victim)
  1851. {
  1852. player_suicided(victim);
  1853. return HAM_IGNORED;
  1854. }
  1855.  
  1856. // a non-player entity killed this man!
  1857. if(!is_user_connected(killer))
  1858. {
  1859. // not linked so return is hit either way
  1860. if(pev_valid(killer))
  1861. {
  1862. static classname[14];
  1863. pev(killer,pev_classname,classname,13);
  1864.  
  1865. // killed by a trigger_hurt, count as suicide
  1866. if(equal(classname,"trigger_hurt"))
  1867. player_suicided(victim);
  1868. }
  1869.  
  1870. return HAM_IGNORED;
  1871. }
  1872.  
  1873. new teamplay = get_pcvar_num(gg_teamplay), penalty = get_pcvar_num(gg_tk_penalty);
  1874.  
  1875. // team kill
  1876. if(is_user_connected(victim) && cs_get_user_team(killer) == cs_get_user_team(victim) && penalty >= 0)
  1877. {
  1878. if(penalty > 0)
  1879. {
  1880. new name[32];
  1881. if(teamplay) get_user_team(killer,name,9);
  1882. else get_user_name(killer,name,31);
  1883.  
  1884. if(warmup <= 0 || !warmupWeapon[0])
  1885. {
  1886. if(score[killer] - penalty < 0)
  1887. gungame_print(0,killer,1,"%L",LANG_PLAYER_C,(teamplay) ? "TK_LEVEL_DOWN_TEAM" : "TK_LEVEL_DOWN",name,(level[killer] > 1) ? level[killer]-1 : level[killer]);
  1888. else
  1889. gungame_print(0,killer,1,"%L",LANG_PLAYER_C,(teamplay) ? "TK_SCORE_DOWN_TEAM" : "TK_SCORE_DOWN",name,penalty);
  1890. }
  1891.  
  1892. change_score(killer,-penalty);
  1893. }
  1894.  
  1895. return HAM_IGNORED;
  1896. }
  1897.  
  1898. new canLevel = 1, scored;
  1899.  
  1900. // already reached max levels this round
  1901. new max_lvl = get_pcvar_num(gg_max_lvl);
  1902. if(!teamplay && !get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[killer] >= max_lvl) canLevel = 0;
  1903.  
  1904. new nade = equal(lvlWeapon[killer],HEGRENADE), knife_pro = get_pcvar_num(gg_knife_pro),
  1905. victimIsBot = is_user_bot(victim), knifeLevel = equal(lvlWeapon[killer],KNIFE), bots_knifeable = get_pcvar_num(gg_bots_knifeable);
  1906.  
  1907. // knife_pro:
  1908. // 0 - nothing
  1909. // 1 - killer +1 level, victim -1 level
  1910. // 2 - killer +1 level, victim stays
  1911. // 3 - killer +1 point, victim -1 level
  1912.  
  1913. // was it a melee kill, and does it matter?
  1914. if( !(victimIsBot && !bots_knifeable) && !knifeLevel && knife_pro && equal(wpnName,KNIFE))
  1915. {
  1916. static killerName[32], victimName[32], authid[24], teamName[10];
  1917. get_user_name(killer,killerName,31);
  1918. get_user_name(victim,victimName,31);
  1919. get_user_authid(killer,authid,23);
  1920. get_user_team(killer,teamName,9);
  1921.  
  1922. log_message("^"%s<%i><%s><%s>^" triggered ^"Stole_Level^"",killerName,get_user_userid(killer),authid,teamName);
  1923.  
  1924. new tpGainPoints, tpLosePoints, tpOverride;
  1925. if(teamplay)
  1926. {
  1927. tpGainPoints = (knife_pro == 3) ? 1 : get_level_goal(level[killer],0);
  1928. tpLosePoints = (knife_pro == 2) ? 0 : get_level_goal(level[victim],0);
  1929.  
  1930. if(warmup <= 0 || !warmupWeapon[0]) gungame_print(0,killer,1,"%L",LANG_PLAYER_C,"STOLE_LEVEL_TEAM",killerName,tpLosePoints,victimName,tpGainPoints);
  1931.  
  1932. // allow points awarded on nade or final level if it won't level us
  1933. tpOverride = (score[killer] + tpGainPoints < get_level_goal(level[killer],killer));
  1934. }
  1935. else // solo play
  1936. {
  1937. if(warmup <= 0 || !warmupWeapon[0]) gungame_print(0,killer,1,"%L",LANG_PLAYER_C,"STOLE_LEVEL",killerName,victimName); // not a knife warmup
  1938. if(nade && knife_pro == 3 && score[killer] + 1 < get_level_goal(level[killer],killer)) tpOverride = 1; // if I'm just getting 1 point and it won't level me, it's okay for the nade level
  1939. }
  1940.  
  1941. if(tpOverride || (canLevel && !nade))
  1942. {
  1943. if(tpOverride || level[killer] < weaponNum)
  1944. {
  1945. if(teamplay)
  1946. {
  1947. if(!change_score(killer,tpGainPoints,_,0)) show_required_kills(killer); // don't play sounds
  1948. }
  1949. else
  1950. {
  1951. if(knife_pro == 3)
  1952. {
  1953. if(!change_score(killer,1,_,0)) show_required_kills(killer); // don't play sounds
  1954. }
  1955. else
  1956. {
  1957. change_level(killer,1,_,_,_,0); // don't play sounds
  1958. }
  1959. }
  1960. }
  1961. }
  1962.  
  1963. play_sound_by_cvar(killer,gg_sound_levelsteal); // use this one instead!
  1964.  
  1965. // knife pro 2 = victim doesn't lose a level
  1966. if(knife_pro != 2 && (level[victim] > 1 || teamplay))
  1967. {
  1968. if(teamplay) change_score(victim,-tpLosePoints);
  1969. else change_level(victim,-1);
  1970. }
  1971. }
  1972.  
  1973. // otherwise, if he killed with his appropiate weapon, give him a point
  1974. else if( !(victimIsBot && !bots_knifeable && knifeLevel) && canLevel && equal(lvlWeapon[killer],wpnName))
  1975. {
  1976. scored = 1;
  1977.  
  1978. // didn't level off of it
  1979. if(!change_score(killer,1)) show_required_kills(killer);
  1980. }
  1981.  
  1982. // refresh grenades
  1983. if(nade && get_pcvar_num(gg_extra_nades))
  1984. {
  1985. remove_task(TASK_REFRESH_NADE+killer);
  1986.  
  1987. // instant refresh, and refresh_nade makes sure we don't already have a nade
  1988. refresh_nade(TASK_REFRESH_NADE+killer);
  1989. }
  1990.  
  1991. if((!scored || !get_pcvar_num(gg_turbo)) && get_pcvar_num(gg_refill_on_kill))
  1992. refill_ammo(killer,1);
  1993.  
  1994. return HAM_IGNORED;
  1995. }
  1996.  
  1997. // a player is touching a weaponbox or armoury_entity, possibly disallow
  1998. public ham_weapon_touch(weapon,other)
  1999. {
  2000. // gungame off and non-player or dead-player
  2001. if(!ggActive || !is_user_alive(other)) return HAM_IGNORED;
  2002.  
  2003. new knife_elite = get_pcvar_num(gg_knife_elite);
  2004.  
  2005. // pickup others enabled, and no conflict with knife elite, stop here
  2006. if(get_pcvar_num(gg_pickup_others) && (!knife_elite || !levelsThisRound[other])) return HAM_IGNORED;
  2007.  
  2008. static model[24];
  2009. pev(weapon,pev_model,model,23);
  2010.  
  2011. // strips off models/w_ and .mdl
  2012. copyc(model,23,model[contain_char(model,'_')+1],'.');
  2013.  
  2014. // weaponbox model is no good, but C4 is okay
  2015. // checks for weaponbox, backpack
  2016. if(model[8] == 'x' || model[0] == 'b') return HAM_IGNORED;
  2017.  
  2018. // now that we allowed C4, check for knife elite again
  2019. if(knife_elite && levelsThisRound[other]) return HAM_SUPERCEDE;
  2020.  
  2021. // weapon is weapon_mp5navy, but model is w_mp5.mdl
  2022. // checks for mp5
  2023. if(model[1] == 'p' && model[2] == '5') model = "mp5navy";
  2024.  
  2025. // check hegrenade exceptions
  2026. // checks for hegrenade
  2027. if(lvlWeapon[other][0] == 'h')
  2028. {
  2029. // checks for glock18, smokegrenade, flashbang
  2030. if((model[6] == '8' && get_pcvar_num(gg_nade_glock))
  2031. || (model[0] == 's' && model[1] == 'm' && get_pcvar_num(gg_nade_smoke))
  2032. || (model[0] == 'f' && model[1] == 'l' && get_pcvar_num(gg_nade_flash)))
  2033. return HAM_IGNORED;
  2034. }
  2035.  
  2036. // this is our weapon, don't mess with it
  2037. if(equal(lvlWeapon[other],model)) return HAM_IGNORED;
  2038.  
  2039. return HAM_SUPERCEDE;
  2040. }
  2041.  
  2042. //**********************************************************************
  2043. // COMMAND HOOKS
  2044. //**********************************************************************
  2045.  
  2046. // turning GunGame on or off
  2047. public cmd_gungame(id,level,cid)
  2048. {
  2049. // no access, or GunGame ending anyway
  2050. if(!cmd_access(id,level,cid,2) || won)
  2051. return PLUGIN_HANDLED;
  2052.  
  2053. // already working on toggling GunGame
  2054. if(task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_FORCE)
  2055. || task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_DISABLE)
  2056. || task_exists(TASK_TOGGLE_GUNGAME + TOGGLE_ENABLE))
  2057. {
  2058. console_print(id,"[GunGame] GunGame is already being turned on or off");
  2059. return PLUGIN_HANDLED;
  2060. }
  2061.  
  2062. new arg[32], oldStatus = ggActive, newStatus;
  2063. read_argv(1,arg,31);
  2064.  
  2065. if(equali(arg,"on") || str_to_num(arg))
  2066. newStatus = 1;
  2067.  
  2068. // no change
  2069. if((!oldStatus && !newStatus) || (oldStatus && newStatus))
  2070. {
  2071. console_print(id,"[GunGame] GunGame is already %s!",(newStatus) ? "on" : "off");
  2072. return PLUGIN_HANDLED;
  2073. }
  2074.  
  2075. restart_round(5);
  2076. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+newStatus);
  2077.  
  2078. if(!newStatus)
  2079. {
  2080. set_pcvar_num(gg_enabled,0);
  2081. ggActive = 0;
  2082. }
  2083.  
  2084. console_print(id,"[GunGame] Turned GunGame %s",(newStatus) ? "on" : "off");
  2085.  
  2086. return PLUGIN_HANDLED;
  2087. }
  2088.  
  2089. // voting for GunGame
  2090. public cmd_gungame_vote(id,lvl,cid)
  2091. {
  2092. if(!cmd_access(id,lvl,cid,1))
  2093. return PLUGIN_HANDLED;
  2094.  
  2095. if(autovotes[0] || autovotes[1] || autovotes[2] || task_exists(TASK_AUTOVOTE_RESULT))
  2096. {
  2097. console_print(id,"[GunGame] Could not start vote: another vote is already in progress!");
  2098. return PLUGIN_HANDLED;
  2099. }
  2100.  
  2101. new arg[8];
  2102. read_argv(1,arg,7);
  2103.  
  2104. // override our autovote mode, but default to our autovote setting, then to 1
  2105. autovote_mode = str_to_num(arg);
  2106. //if(autovote_mode < 1 || autovote_mode > 3) autovote_mode = get_pcvar_num(gg_autovote_mode); // won't work with autovote rotation, so forget it for now
  2107. if(autovote_mode < 1 || autovote_mode > 3) autovote_mode = 1;
  2108.  
  2109. console_print(id,"[GunGame] Started a vote to play GunGame (mode %i)",autovote_mode);
  2110. autovote_start();
  2111.  
  2112. return PLUGIN_HANDLED;
  2113. }
  2114.  
  2115. // setting players levels
  2116. public cmd_gungame_level(id,lvl,cid)
  2117. {
  2118. if(!cmd_access(id,lvl,cid,3))
  2119. return PLUGIN_HANDLED;
  2120.  
  2121. new arg1[32], arg2[8], targets[32], name[32], tnum, i;
  2122. read_argv(1,arg1,31);
  2123. read_argv(2,arg2,7);
  2124.  
  2125. if(equali(arg1,"@T")) arg1 = "@TERRORIST";
  2126.  
  2127. // get player list
  2128. if(equali(arg1,"*") || equali(arg1,"@ALL"))
  2129. {
  2130. get_players(targets,tnum);
  2131. name = "ALL PLAYERS";
  2132. }
  2133. else if(arg1[0] == '@')
  2134. {
  2135. new players[32], team[10], pnum;
  2136. get_players(players,pnum);
  2137.  
  2138. for(i=0;i<pnum;i++)
  2139. {
  2140. get_user_team(players[i],team,9);
  2141. if(equali(team,arg1[1])) targets[tnum++] = players[i];
  2142. }
  2143.  
  2144. formatex(name,31,"ALL %s",arg1[1]);
  2145. }
  2146. else
  2147. {
  2148. targets[tnum++] = cmd_target(id,arg1,2);
  2149. if(!targets[0]) return PLUGIN_HANDLED;
  2150.  
  2151. get_user_name(targets[0],name,31);
  2152. }
  2153.  
  2154. new intval = str_to_num(arg2);
  2155.  
  2156. // relative
  2157. if(arg2[0] == '+' || arg2[0] == '-')
  2158. for(i=0;i<tnum;i++) change_level(targets[i],intval,_,_,1); // always score
  2159.  
  2160. // absolute
  2161. else
  2162. for(i=0;i<tnum;i++) change_level(targets[i],intval-level[targets[i]],_,_,1); // always score
  2163.  
  2164. console_print(id,"[GunGame] Changed %s's level to %s",name,arg2);
  2165.  
  2166. return PLUGIN_HANDLED;
  2167. }
  2168.  
  2169. // setting players score
  2170. public cmd_gungame_score(id,lvl,cid)
  2171. {
  2172. if(!cmd_access(id,lvl,cid,3))
  2173. return PLUGIN_HANDLED;
  2174.  
  2175. new arg1[32], arg2[8], arg3[8], targets[32], name[32], tnum, i;
  2176. read_argv(1,arg1,31);
  2177. read_argv(2,arg2,7);
  2178. read_argv(3,arg3,7);
  2179.  
  2180. if(equali(arg1,"@T")) arg1 = "@TERRORIST";
  2181.  
  2182. // get player list
  2183. if(equali(arg1,"*") || equali(arg1,"@ALL"))
  2184. {
  2185. get_players(targets,tnum);
  2186. name = "ALL PLAYERS";
  2187. }
  2188. else if(arg1[0] == '@')
  2189. {
  2190. new players[32], team[10], pnum;
  2191. get_players(players,pnum);
  2192.  
  2193. for(i=0;i<pnum;i++)
  2194. {
  2195. get_user_team(players[i],team,9);
  2196. if(equali(team,arg1[1])) targets[tnum++] = players[i];
  2197. }
  2198.  
  2199. formatex(name,31,"ALL %s",arg1[1]);
  2200. }
  2201. else
  2202. {
  2203. targets[tnum++] = cmd_target(id,arg1,2);
  2204. if(!targets[0]) return PLUGIN_HANDLED;
  2205.  
  2206. get_user_name(targets[0],name,31);
  2207. }
  2208.  
  2209. new intval = str_to_num(arg2), dont_refill = str_to_num(arg3);
  2210.  
  2211. // relative
  2212. if(arg2[0] == '+' || arg2[0] == '-')
  2213. for(i=0;i<tnum;i++) change_score(targets[i],intval,!dont_refill,_,_,1); // always score
  2214.  
  2215. // absolute
  2216. else
  2217. for(i=0;i<tnum;i++) change_score(targets[i],intval-score[targets[i]],!dont_refill,_,_,1); // always score
  2218.  
  2219. console_print(id,"[GunGame] Changed %s's score to %s",name,arg2);
  2220.  
  2221. return PLUGIN_HANDLED;
  2222. }
  2223.  
  2224. // forcing a win
  2225. public cmd_gungame_win(id,lvl,cid)
  2226. {
  2227. if(!cmd_access(id,lvl,cid,1))
  2228. return PLUGIN_HANDLED;
  2229.  
  2230. new arg[32];
  2231. read_argv(1,arg,31);
  2232.  
  2233. // no target given, select best player
  2234. if(!arg[0])
  2235. {
  2236. console_print(id,"[GunGame] Forcing the best player to win...");
  2237. event_intermission();
  2238. return PLUGIN_HANDLED;
  2239. }
  2240.  
  2241. new target = cmd_target(id,arg,2);
  2242. if(!target) return PLUGIN_HANDLED;
  2243.  
  2244. new name[32];
  2245. get_user_name(target,name,31);
  2246. console_print(id,"[GunGame] Forcing %s to win (cheater)...",name);
  2247.  
  2248. // make our target win (oh, we're dirty!)
  2249. win(target,0);
  2250.  
  2251. return PLUGIN_HANDLED;
  2252. }
  2253.  
  2254. // turn teamplay on or off
  2255. public cmd_gungame_teamplay(id,lvl,cid)
  2256. {
  2257. if(!cmd_access(id,lvl,cid,2))
  2258. return PLUGIN_HANDLED;
  2259.  
  2260. new oldValue = get_pcvar_num(gg_teamplay);
  2261.  
  2262. new arg1[8], arg2[8], arg3[8];
  2263. read_argv(1,arg1,7);
  2264. read_argv(2,arg2,7);
  2265. read_argv(3,arg3,7);
  2266.  
  2267. new teamplay = str_to_num(arg1);
  2268. new Float:killsperlvl = floatstr(arg2);
  2269. new suicideloselvl = str_to_num(arg3);
  2270.  
  2271. if(teamplay != oldValue)
  2272. {
  2273. restart_round(1);
  2274.  
  2275. // rerun configs if teamplay changes, and don't allow toggling of GunGame on/off
  2276. exec_gg_config_file(0,0);
  2277. if(teamplay) exec_gg_config_file(1,0);
  2278.  
  2279. set_pcvar_num(gg_teamplay,teamplay);
  2280. map_start_cvars(1); // keepTeamplay
  2281. }
  2282.  
  2283. //server_cmd("gg_teamplay %i",teamplay);
  2284.  
  2285. new result[128];
  2286. new len = formatex(result,127,"[GunGame] Turned Teamplay Mode %s",(teamplay) ? "on" : "off");
  2287.  
  2288. // important to run these after the config above
  2289.  
  2290. if(killsperlvl > 0.0)
  2291. {
  2292. server_cmd("gg_kills_per_lvl %f",killsperlvl);
  2293. len += formatex(result[len],127-len,", set kills per level to %f",killsperlvl);
  2294. }
  2295. if(arg3[0])
  2296. {
  2297. server_cmd("gg_suicide_penalty %i",suicideloselvl);
  2298. len += formatex(result[len],127-len,", set suicide penalty to %i",suicideloselvl);
  2299. }
  2300.  
  2301. console_print(id,"%s",result);
  2302.  
  2303. return PLUGIN_HANDLED;
  2304. }
  2305.  
  2306. // restarts GunGame
  2307. public cmd_gungame_restart(id,lvl,cid)
  2308. {
  2309. if(!cmd_access(id,lvl,cid,1))
  2310. return PLUGIN_HANDLED;
  2311.  
  2312. new arg[8];
  2313. read_argv(1,arg,7);
  2314.  
  2315. new Float:time = floatstr(arg);
  2316. if(time < 0.2) time = 0.2;
  2317.  
  2318. restart_round(floatround(time,floatround_ceil));
  2319. console_print(id,"[GunGame] Restarting GunGame in %i seconds",floatround(time,floatround_ceil));
  2320.  
  2321. read_argv(2,arg,1);
  2322. if(str_to_num(arg)) set_task(time-0.1,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_ENABLE);
  2323.  
  2324. return PLUGIN_HANDLED;
  2325. }
  2326.  
  2327. // reload weapon order
  2328. public cmd_reloadweapons(id,lvl,cid)
  2329. {
  2330. if(!cmd_access(id,lvl,cid,1))
  2331. return PLUGIN_HANDLED;
  2332.  
  2333. setup_weapon_order();
  2334. console_print(id,"* Reloaded the weapon order");
  2335.  
  2336. return PLUGIN_HANDLED;
  2337. }
  2338.  
  2339. // hook say
  2340. public cmd_say(id)
  2341. {
  2342. if(!ggActive) return PLUGIN_CONTINUE;
  2343.  
  2344. static message[10];
  2345. read_argv(1,message,9);
  2346.  
  2347. // doesn't begin with !, ignore
  2348. if(message[0] != '!') return PLUGIN_CONTINUE;
  2349.  
  2350. if(equali(message,"!rules") || equali(message,"!help"))
  2351. {
  2352. new num = 1, max_lvl = get_pcvar_num(gg_max_lvl), turbo = get_pcvar_num(gg_turbo);
  2353.  
  2354. console_print(id,"-----------------------------");
  2355. console_print(id,"-----------------------------");
  2356. console_print(id,"*** Avalanche's %L %s %L ***",id,"GUNGAME",GG_VERSION,id,"RULES");
  2357. console_print(id,"%L",id,"RULES_CONSOLE_LINE1",num++);
  2358. console_print(id,"%L",id,"RULES_CONSOLE_LINE2",num++);
  2359. if(get_pcvar_num(gg_bomb_defuse_lvl)) console_print(id,"%L",id,"RULES_CONSOLE_LINE3",num++);
  2360. console_print(id,"%L",id,"RULES_CONSOLE_LINE4",num++);
  2361. if(get_pcvar_num(gg_ff_auto)) console_print(id,"%L",id,"RULES_CONSOLE_LINE5",num++);
  2362. if(turbo || !max_lvl) console_print(id,"%L",id,"RULES_CONSOLE_LINE6A",num++);
  2363. else if(max_lvl == 1) console_print(id,"%L",id,"RULES_CONSOLE_LINE6B",num++);
  2364. else if(max_lvl > 1) console_print(id,"%L",id,"RULES_CONSOLE_LINE6C",num++,max_lvl);
  2365. console_print(id,"%L",id,"RULES_CONSOLE_LINE7",num++);
  2366. if(get_pcvar_num(gg_knife_pro)) console_print(id,"%L",id,"RULES_CONSOLE_LINE8",num++);
  2367. if(turbo) console_print(id,"%L",id,"RULES_CONSOLE_LINE9",num++);
  2368. if(get_pcvar_num(gg_knife_elite)) console_print(id,"%L",id,"RULES_CONSOLE_LINE10",num++);
  2369. if(get_pcvar_num(gg_dm) || get_cvar_num("csdm_active")) console_print(id,"%L",id,"RULES_CONSOLE_LINE11",num++);
  2370. if(get_pcvar_num(gg_teamplay)) console_print(id,"%L",id,"RULES_CONSOLE_LINE12",num++);
  2371. console_print(id,"****************************************************************");
  2372. console_print(id,"%L",id,"RULES_CONSOLE_LINE13");
  2373. console_print(id,"%L",id,"RULES_CONSOLE_LINE14");
  2374. console_print(id,"%L",id,"RULES_CONSOLE_LINE15");
  2375. console_print(id,"%L",id,"RULES_CONSOLE_LINE16");
  2376. console_print(id,"%L",id,"RULES_CONSOLE_LINE17");
  2377. console_print(id,"-----------------------------");
  2378. console_print(id,"-----------------------------");
  2379.  
  2380. new len = formatex(menuText,511,"%L^n",id,"RULES_MESSAGE_LINE1");
  2381. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2382. len += formatex(menuText[len],511-len,"%L^n",id,"RULES_MESSAGE_LINE2");
  2383. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2384. len += formatex(menuText[len],511-len,"%L^n",id,"RULES_MESSAGE_LINE3");
  2385. len += formatex(menuText[len],511-len,"\d----------\w^n%L",id,"PRESS_KEY_TO_CONTINUE");
  2386.  
  2387. show_menu(id,1023,menuText);
  2388.  
  2389. return PLUGIN_HANDLED;
  2390. }
  2391. else if(equali(message,"!weapons") || equali(message,"!guns"))
  2392. {
  2393. page[id] = 1;
  2394. //show_weapons_menu(id);
  2395. weapons_menu_handler(id,2); // jump to me
  2396.  
  2397. return PLUGIN_HANDLED;
  2398. }
  2399. else if(equali(message,"!top",4) && !str_count(message,' ')) // !topANYTHING
  2400. {
  2401. if(!sqlInit || !get_pcvar_num(gg_stats_mode))
  2402. {
  2403. client_print(id,print_chat,"%L",id,"NO_WIN_LOGGING");
  2404. return PLUGIN_HANDLED;
  2405. }
  2406.  
  2407. page[id] = 1;
  2408.  
  2409. if(get_pcvar_num(gg_stats_split) && get_pcvar_num(gg_teamplay))
  2410. page[id] *= -1; // use negative page numbers to denote teamplay stats
  2411.  
  2412. show_top10_menu(id);
  2413. //top10_menu_handler(id,2); // jump to me
  2414.  
  2415. return PLUGIN_HANDLED;
  2416. }
  2417. else if(equali(message,"!score") || equali(message,"!scores"))
  2418. {
  2419. page[id] = 1;
  2420. //show_scores_menu(id);
  2421. scores_menu_handler(id,2); // jump to me
  2422.  
  2423. return PLUGIN_HANDLED;
  2424. }
  2425. else if(equali(message,"!level"))
  2426. {
  2427. show_level_menu(id);
  2428.  
  2429. return PLUGIN_HANDLED;
  2430. }
  2431. else if(equali(message,"!restart") || equali(message,"!reset"))
  2432. {
  2433. if(level[id] <= 1)
  2434. {
  2435. client_print(id,print_chat,"%L",id,"STILL_LEVEL_ONE");
  2436. return PLUGIN_HANDLED;
  2437. }
  2438.  
  2439. new len = formatex(menuText,511,"%L^n^n",id,"RESET_QUERY");
  2440. len += formatex(menuText[len],511-len,"1. %L^n",id,"YES");
  2441. len += formatex(menuText[len],511-len,"0. %L",id,"CANCEL");
  2442. show_menu(id,MENU_KEY_1|MENU_KEY_0,menuText,-1,"restart_menu");
  2443.  
  2444. return PLUGIN_HANDLED;
  2445. }
  2446.  
  2447. return PLUGIN_CONTINUE;
  2448. }
  2449.  
  2450. // joining a team
  2451. public cmd_joinclass(id)
  2452. {
  2453. if(!ggActive) return PLUGIN_CONTINUE;
  2454.  
  2455. // allow us to join in on deathmatch
  2456. if(!get_pcvar_num(gg_dm))
  2457. {
  2458. remove_task(TASK_CHECK_DEATHMATCH+id);
  2459. set_task(10.0,"check_deathmatch",TASK_CHECK_DEATHMATCH+id);
  2460. return PLUGIN_CONTINUE;
  2461. }
  2462.  
  2463. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  2464. return PLUGIN_CONTINUE;
  2465.  
  2466. set_task(5.0,"check_joinclass",TASK_CHECK_JOINCLASS+id);
  2467. return PLUGIN_CONTINUE;
  2468. }
  2469.  
  2470. // wait a bit after joinclass to see if we should jump in
  2471. public check_joinclass(taskid)
  2472. {
  2473. new id = taskid-TASK_CHECK_JOINCLASS;
  2474.  
  2475. if(!is_user_connected(id)) return;
  2476.  
  2477. // already respawning
  2478. if(task_exists(TASK_RESPAWN+id) || is_user_alive(id) || !on_valid_team(id))
  2479. return;
  2480.  
  2481. respawn(TASK_RESPAWN+id);
  2482. }
  2483.  
  2484. //**********************************************************************
  2485. // RESPAWN FUNCTIONS
  2486. //**********************************************************************
  2487.  
  2488. // get all of our spawns into their arrays
  2489. init_spawns()
  2490. {
  2491. // grab CSDM file
  2492. new mapName[32], csdmFile[64], lineData[64];
  2493. get_configsdir(cfgDir,31);
  2494. get_mapname(mapName,31);
  2495. formatex(csdmFile,63,"%s/csdm/%s.spawns.cfg",cfgDir,mapName);
  2496.  
  2497. // collect CSDM spawns
  2498. if(file_exists(csdmFile))
  2499. {
  2500. new csdmData[10][6];
  2501.  
  2502. new file = fopen(csdmFile,"rt");
  2503. while(file && !feof(file))
  2504. {
  2505. fgets(file,lineData,63);
  2506.  
  2507. // invalid spawn
  2508. if(!lineData[0] || str_count(lineData,' ') < 2)
  2509. continue;
  2510.  
  2511. // BREAK IT UP!
  2512. parse(lineData,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);
  2513.  
  2514. // origin
  2515. spawns[spawnCount][0] = floatstr(csdmData[0]);
  2516. spawns[spawnCount][1] = floatstr(csdmData[1]);
  2517. spawns[spawnCount][2] = floatstr(csdmData[2]);
  2518.  
  2519. // angles
  2520. spawns[spawnCount][3] = floatstr(csdmData[3]);
  2521. spawns[spawnCount][4] = floatstr(csdmData[4]);
  2522. spawns[spawnCount][5] = floatstr(csdmData[5]);
  2523.  
  2524. // team, csdmData[6], unused
  2525.  
  2526. // vangles
  2527. spawns[spawnCount][6] = floatstr(csdmData[7]);
  2528. spawns[spawnCount][7] = floatstr(csdmData[8]);
  2529. spawns[spawnCount][8] = floatstr(csdmData[9]);
  2530.  
  2531. spawnCount++;
  2532. csdmSpawnCount++;
  2533. if(spawnCount >= MAX_SPAWNS) break;
  2534. }
  2535. if(file) fclose(file);
  2536. }
  2537.  
  2538. // collect regular, boring spawns
  2539. else
  2540. {
  2541. collect_spawns("info_player_deathmatch");
  2542. collect_spawns("info_player_start");
  2543. }
  2544. }
  2545.  
  2546. // collect boring spawns into our spawn data
  2547. collect_spawns(classname[])
  2548. {
  2549. new ent = maxPlayers, Float:spawnData[3];
  2550. while((ent = fm_find_ent_by_class(ent,classname)))
  2551. {
  2552. // origin
  2553. pev(ent,pev_origin,spawnData);
  2554. spawns[spawnCount][0] = spawnData[0];
  2555. spawns[spawnCount][1] = spawnData[1];
  2556. spawns[spawnCount][2] = spawnData[2];
  2557.  
  2558. // angles
  2559. pev(ent,pev_angles,spawnData);
  2560. spawns[spawnCount][3] = spawnData[0];
  2561. spawns[spawnCount][4] = spawnData[1];
  2562. spawns[spawnCount][5] = spawnData[2];
  2563.  
  2564. // vangles
  2565. spawns[spawnCount][6] = spawnData[0];
  2566. spawns[spawnCount][7] = spawnData[1];
  2567. spawns[spawnCount][8] = spawnData[2];
  2568.  
  2569. spawnCount++;
  2570. if(spawnCount >= MAX_SPAWNS) break;
  2571. }
  2572. }
  2573.  
  2574. // bring someone back to life
  2575. public begin_respawn(id)
  2576. {
  2577. if(!ggActive || !get_pcvar_num(gg_dm) || !is_user_connected(id))
  2578. return;
  2579.  
  2580. // now on spectator
  2581. if(!on_valid_team(id)) return;
  2582.  
  2583. // alive, and not in the broken sort of way
  2584. if(is_user_alive(id) && !pev(id,pev_iuser1))
  2585. return;
  2586.  
  2587. // round is over, or bomb is planted
  2588. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  2589. return;
  2590.  
  2591. new Float:delay = get_pcvar_float(gg_dm_spawn_delay);
  2592. if(delay < 0.1) delay = 0.1;
  2593.  
  2594. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  2595.  
  2596. if((dm_countdown & 1) || (dm_countdown & 2))
  2597. {
  2598. respawn_timeleft[id] = floatround(delay);
  2599. respawn_countdown(id);
  2600. }
  2601.  
  2602. remove_task(TASK_RESPAWN+id);
  2603. set_task(delay,"respawn",TASK_RESPAWN+id);
  2604. }
  2605.  
  2606. // show the respawn countdown to a player
  2607. public respawn_countdown(id)
  2608. {
  2609. if(!is_user_connected(id) || is_user_alive(id))
  2610. {
  2611. respawn_timeleft[id] = 0;
  2612. return;
  2613. }
  2614.  
  2615. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  2616.  
  2617. if(dm_countdown & 1)
  2618. client_print(id,print_center,"%L",id,"RESPAWN_COUNTDOWN",respawn_timeleft[id]);
  2619.  
  2620. if(dm_countdown & 2)
  2621. {
  2622. set_hudmessage(255,255,255,-1.0,0.75,0,6.0,1.0,0.1,0.5);
  2623. ShowSyncHudMsg(id,hudSyncCountdown,"%L",id,"RESPAWN_COUNTDOWN",respawn_timeleft[id]);
  2624. }
  2625.  
  2626. if(--respawn_timeleft[id] >= 1) set_task(1.0,"respawn_countdown",id);
  2627. }
  2628.  
  2629. // REALLY bring someone back to life
  2630. public respawn(taskid)
  2631. {
  2632. new id = taskid-TASK_RESPAWN;
  2633. if(!is_user_connected(id) || !ggActive) return;
  2634.  
  2635. // round is over, or bomb is planted
  2636. if(roundEnded || (bombStatus[3] == BOMB_PLANTED && !get_pcvar_num(gg_dm_spawn_afterplant)))
  2637. return;
  2638.  
  2639. // now on spectator
  2640. if(!on_valid_team(id)) return;
  2641.  
  2642. // clear countdown
  2643. new dm_countdown = get_pcvar_num(gg_dm_countdown);
  2644. if(dm_countdown & 1) client_print(id,print_center," ");
  2645. if(dm_countdown & 2) ClearSyncHud(id,hudSyncCountdown);
  2646.  
  2647. // alive, and not in the broken sort of way
  2648. if(is_user_alive(id)) return;
  2649.  
  2650. static model[22];
  2651.  
  2652. // remove his dropped weapons from before
  2653. new ent = maxPlayers;
  2654. while((ent = fm_find_ent_by_class(ent,"weaponbox")))
  2655. {
  2656. pev(ent,pev_model,model,21);
  2657.  
  2658. // don't remove the bomb!! (thanks ToT | V!PER)
  2659. if(equal(model,"models/w_c4.mdl",15) || equal(model,"models/w_backpack.mdl"))
  2660. continue;
  2661.  
  2662. // this is mine
  2663. if(pev(ent,pev_owner) == id) dllfunc(DLLFunc_Think,ent);
  2664. }
  2665.  
  2666. new spawn_random = get_pcvar_num(gg_dm_spawn_random);
  2667. if(spawn_random) spawnSounds[id] = 0;
  2668.  
  2669. ExecuteHamB(Ham_CS_RoundRespawn,id); // note the B
  2670.  
  2671. if(spawn_random)
  2672. {
  2673. do_random_spawn(id,spawn_random);
  2674. spawnSounds[id] = 1;
  2675.  
  2676. // to be fair, play a spawn noise at new location
  2677. engfunc(EngFunc_EmitSound,id,CHAN_ITEM,"items/gunpickup2.wav",VOL_NORM,ATTN_NORM,0,PITCH_NORM);
  2678. }
  2679.  
  2680. new Float:time = get_pcvar_float(gg_dm_sp_time);
  2681. new mode = get_pcvar_num(gg_dm_sp_mode);
  2682.  
  2683. // spawn protection
  2684. if(time > 0.0 && mode)
  2685. {
  2686. spawnProtected[id] = 1;
  2687. if(mode == 2)
  2688. {
  2689. fm_set_user_godmode(id,1);
  2690. fm_set_rendering(id,kRenderFxGlowShell,200,200,100,kRenderNormal,8); // goldenish
  2691. }
  2692. else fm_set_rendering(id,kRenderFxGlowShell,100,100,100,kRenderNormal,8); // gray/white
  2693.  
  2694. set_task(time,"remove_spawn_protection",TASK_REMOVE_PROTECTION+id);
  2695. }
  2696. }
  2697.  
  2698. // place a user at a random spawn
  2699. do_random_spawn(id,spawn_random)
  2700. {
  2701. // not even alive, don't bother
  2702. if(!is_user_alive(id)) return;
  2703.  
  2704. // no spawns???
  2705. if(spawnCount <= 0) return;
  2706.  
  2707. // no CSDM spawns, mode 2
  2708. if(spawn_random == 2 && !csdmSpawnCount)
  2709. return;
  2710.  
  2711. static Float:vecHolder[3];
  2712. new sp_index = random_num(0,spawnCount-1);
  2713.  
  2714. // get origin for comparisons
  2715. vecHolder[0] = spawns[sp_index][0];
  2716. vecHolder[1] = spawns[sp_index][1];
  2717. vecHolder[2] = spawns[sp_index][2];
  2718.  
  2719. // this one is taken
  2720. if(!is_hull_vacant(vecHolder,HULL_HUMAN) && spawnCount > 1)
  2721. {
  2722. // attempt to pick another random one up to three times
  2723. new i;
  2724. for(i=0;i<3;i++)
  2725. {
  2726. sp_index = random_num(0,spawnCount-1);
  2727.  
  2728. vecHolder[0] = spawns[sp_index][0];
  2729. vecHolder[1] = spawns[sp_index][1];
  2730. vecHolder[2] = spawns[sp_index][2];
  2731.  
  2732. if(is_hull_vacant(vecHolder,HULL_HUMAN)) break;
  2733. }
  2734.  
  2735. // we made it through the entire loop, no free spaces
  2736. if(i == 3)
  2737. {
  2738. // just find the first available
  2739. for(i=sp_index+1;i!=sp_index;i++)
  2740. {
  2741. // start over when we reach the end
  2742. if(i >= spawnCount) i = 0;
  2743.  
  2744. vecHolder[0] = spawns[i][0];
  2745. vecHolder[1] = spawns[i][1];
  2746. vecHolder[2] = spawns[i][2];
  2747.  
  2748. // free space! office space!
  2749. if(is_hull_vacant(vecHolder,HULL_HUMAN))
  2750. {
  2751. sp_index = i;
  2752. break;
  2753. }
  2754. }
  2755. }
  2756. }
  2757.  
  2758. // origin
  2759. vecHolder[0] = spawns[sp_index][0];
  2760. vecHolder[1] = spawns[sp_index][1];
  2761. vecHolder[2] = spawns[sp_index][2];
  2762. engfunc(EngFunc_SetOrigin,id,vecHolder);
  2763.  
  2764. // angles
  2765. vecHolder[0] = spawns[sp_index][3];
  2766. vecHolder[1] = spawns[sp_index][4];
  2767. vecHolder[2] = spawns[sp_index][5];
  2768. set_pev(id,pev_angles,vecHolder);
  2769.  
  2770. // vangles
  2771. vecHolder[0] = spawns[sp_index][6];
  2772. vecHolder[1] = spawns[sp_index][7];
  2773. vecHolder[2] = spawns[sp_index][8];
  2774. set_pev(id,pev_v_angle,vecHolder);
  2775.  
  2776. set_pev(id,pev_fixangle,1);
  2777. }
  2778.  
  2779. // get rid of the spawn protection effects
  2780. public remove_spawn_protection(taskid)
  2781. {
  2782. new id = taskid-TASK_REMOVE_PROTECTION;
  2783. spawnProtected[id] = 0;
  2784.  
  2785. if(!is_user_connected(id)) return;
  2786.  
  2787. if(get_pcvar_num(gg_dm_sp_mode) == 2) fm_set_user_godmode(id,0);
  2788. fm_set_rendering(id); // reset back to normal
  2789. }
  2790.  
  2791. // keep checking if a player needs to rejoin
  2792. public check_deathmatch(taskid)
  2793. {
  2794. new id = taskid-TASK_CHECK_DEATHMATCH;
  2795.  
  2796. // left the game, or gungame is now disabled
  2797. if(!is_user_connected(id) || !ggActive) return;
  2798.  
  2799. // now on spectator, or spawned already
  2800. if(!on_valid_team(id) || is_user_alive(id)) return;
  2801.  
  2802. // DM still not enabled, keep waiting (or: we are still on choose-a-class screen)
  2803. if(!get_pcvar_num(gg_dm) || !pev(id,pev_iuser1))
  2804. {
  2805. set_task(10.0,"check_deathmatch",taskid);
  2806. return;
  2807. }
  2808.  
  2809. // DM is enabled, respawn
  2810. respawn(TASK_RESPAWN+id);
  2811. }
  2812.  
  2813. // what do you think??
  2814. public randomly_place_everyone()
  2815. {
  2816. // count number of legitimate players
  2817. new player, validNum;
  2818. for(player=1;player<=maxPlayers;player++)
  2819. {
  2820. if(is_user_connected(player) && on_valid_team(player))
  2821. validNum++;
  2822. }
  2823.  
  2824. // not enough CSDM spawns for everyone
  2825. if(validNum > csdmSpawnCount)
  2826. return;
  2827.  
  2828. // now randomly place them
  2829. for(player=1;player<=maxPlayers;player++)
  2830. {
  2831. // not spectator or unassigned
  2832. if(is_user_connected(player) && on_valid_team(player))
  2833. do_random_spawn(player,2);
  2834. }
  2835. }
  2836.  
  2837. //**********************************************************************
  2838. // MENU FUNCTIONS
  2839. //**********************************************************************
  2840.  
  2841. // handle the welcome menu
  2842. public welcome_menu_handler(id,key)
  2843. {
  2844. // just save welcomed status and let menu close
  2845. welcomed[id] = 1;
  2846. return PLUGIN_HANDLED;
  2847. }
  2848.  
  2849. // this menu does nothing but display stuff
  2850. public level_menu_handler(id,key)
  2851. {
  2852. return PLUGIN_HANDLED;
  2853. }
  2854.  
  2855. // handle the reset level menu
  2856. public restart_menu_handler(id,key)
  2857. {
  2858. if(get_pcvar_num(gg_teamplay))
  2859. {
  2860. client_print(id,print_chat,"%L",id,"RESET_NOT_ALLOWED");
  2861. return PLUGIN_HANDLED;
  2862. }
  2863.  
  2864. if(level[id] <= 1)
  2865. {
  2866. client_print(id,print_chat,"%L",id,"STILL_LEVEL_ONE");
  2867. return PLUGIN_HANDLED;
  2868. }
  2869.  
  2870. // 1. Yes
  2871. if(key == 0)
  2872. {
  2873. new name[32];
  2874. get_user_name(id,name,31);
  2875.  
  2876. change_level(id,-(level[id]-1),_,_,1); // back to level 1 -- always score
  2877. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"PLAYER_RESET",name);
  2878. }
  2879.  
  2880. return PLUGIN_HANDLED;
  2881. }
  2882.  
  2883. // show the level display
  2884. show_level_menu(id)
  2885. {
  2886. #if !defined SQL
  2887. recheck_stats_sorting();
  2888. #endif
  2889.  
  2890. new goal, tied, leaderNum, leaderList[128], name[32];
  2891.  
  2892. new leaderLevel, numLeaders, leader, runnerUp, len;
  2893. new teamplay = get_pcvar_num(gg_teamplay), team;
  2894.  
  2895. if(teamplay) leader = teamplay_get_lead_team(leaderLevel,numLeaders,runnerUp);
  2896. else leader = get_leader(leaderLevel,numLeaders,runnerUp);
  2897.  
  2898. if(numLeaders > 1) tied = 1;
  2899.  
  2900. if(teamplay)
  2901. {
  2902. team = _:cs_get_user_team(id);
  2903.  
  2904. if(numLeaders == 1)
  2905. {
  2906. new team1[10];
  2907. get_team_name(CsTeams:leader,team1,9);
  2908. len += formatex(leaderList[len],127-len,"%s %L",team1,id,"TEAM");
  2909. }
  2910. else
  2911. {
  2912. new team1[10], team2[10];
  2913. get_team_name(CS_TEAM_T,team1,9);
  2914. get_team_name(CS_TEAM_CT,team2,9);
  2915. len += formatex(leaderList[len],127-len,"%s %L, %s %L",team1,id,"TEAM",team2,id,"TEAM");
  2916. }
  2917. }
  2918. else
  2919. {
  2920. new players[32], num, i, player;
  2921. get_players(players,num);
  2922.  
  2923. // check for multiple leaders
  2924. for(i=0;i<num;i++)
  2925. {
  2926. player = players[i];
  2927.  
  2928. if(level[player] == leaderLevel)
  2929. {
  2930. if(++leaderNum == 5)
  2931. {
  2932. len += formatex(leaderList[len],127-len,", ...");
  2933. break;
  2934. }
  2935.  
  2936. if(leaderList[0]) len += formatex(leaderList[len],127-len,", ");
  2937. get_user_name(player,name,31);
  2938. len += formatex(leaderList[len],127-len,"%s",name);
  2939. }
  2940. }
  2941. }
  2942.  
  2943. goal = get_level_goal(level[id],id);
  2944.  
  2945. new displayWeapon[16];
  2946. if(level[id]) copy(displayWeapon,15,lvlWeapon[id]);
  2947. else formatex(displayWeapon,15,"%L",id,"NONE");
  2948.  
  2949. len = formatex(menuText,511,"%L %i (%s)^n",id,(teamplay) ? "ON_LEVEL_TEAM" : "ON_LEVEL",level[id],displayWeapon);
  2950. len += formatex(menuText[len],511-len,"%L^n",id,(teamplay) ? "LEVEL_MESSAGE_LINE1B" : "LEVEL_MESSAGE_LINE1A",score[id],goal);
  2951.  
  2952. // winning
  2953. if(!tied && ((teamplay && leader == team) || (!teamplay && leader == id)))
  2954. {
  2955. if(teamplay) len += formatex(menuText[len],511-len,"%L^n",id,"PROGRESS_DISPLAY_TEAM1",teamLevel[leader]-teamLevel[runnerUp]);
  2956. else len += formatex(menuText[len],511-len,"%L^n",id,"PROGRESS_DISPLAY1",level[id]-level[runnerUp]);
  2957. }
  2958.  
  2959. // tied
  2960. else if(tied)
  2961. {
  2962. if(teamplay) len += formatex(menuText[len],511-len,"%L^n",id,"PROGRESS_DISPLAY_TEAM2");
  2963. else len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE2B");
  2964. }
  2965.  
  2966. // losing
  2967. else
  2968. {
  2969. if(teamplay) len += formatex(menuText[len],511-len,"%L^n",id,"PROGRESS_DISPLAY_TEAM3",teamLevel[leader]-teamLevel[runnerUp]);
  2970. else len += formatex(menuText[len],511-len,"%L^n",id,"PROGRESS_DISPLAY4",leaderLevel-level[id]);
  2971. }
  2972.  
  2973. len += formatex(menuText[len],511-len,"\d----------\w^n");
  2974.  
  2975. new authid[32];
  2976. get_gg_authid(id,authid,31);
  2977.  
  2978. new stats_mode = get_pcvar_num(gg_stats_mode);
  2979.  
  2980. if(sqlInit && stats_mode)
  2981. {
  2982. new stats_split = get_pcvar_num(gg_stats_split);
  2983.  
  2984. // decide which sentences we should be using based on current split/teamplay settings
  2985. new keyLINE3A[25], keyLINE3B[25], keyLINE4[24]; // should I rename these? nah, too long
  2986. if(stats_split)
  2987. {
  2988. keyLINE3A = "LEVEL_MESSAGE_LINE3A_REG";
  2989. keyLINE3B = "LEVEL_MESSAGE_LINE3B_REG";
  2990. keyLINE4 = "LEVEL_MESSAGE_LINE4_REG";
  2991. }
  2992. else
  2993. {
  2994. keyLINE3A = "LEVEL_MESSAGE_LINE3A";
  2995. keyLINE3B = "LEVEL_MESSAGE_LINE3B";
  2996. keyLINE4 = "LEVEL_MESSAGE_LINE4";
  2997. }
  2998.  
  2999. stats_get_data(authid,playerStats[id],id);
  3000.  
  3001. if(statsPosition[id][0] > 0) // show rank
  3002. {
  3003. new statsSuffix[3];
  3004. get_number_suffix(statsPosition[id][0],statsSuffix,2);
  3005.  
  3006. if(stats_mode == 1) len += formatex(menuText[len],511-len,"%L (%i%s)^n",id,keyLINE3A,playerStats[id][sdWins][0],statsPosition[id][0],statsSuffix);
  3007. else len += formatex(menuText[len],511-len,"%L (%i%s)^n",id,keyLINE3B,playerStats[id][sdPoints][0],playerStats[id][sdWins][0],statsPosition[id][0],statsSuffix);
  3008. }
  3009. else // don't show rank
  3010. {
  3011. if(stats_mode == 1) len += formatex(menuText[len],511-len,"%L^n",id,keyLINE3A,playerStats[id][sdWins][0]);
  3012. else len += formatex(menuText[len],511-len,"%L^n",id,keyLINE3B,playerStats[id][sdPoints][0],playerStats[id][sdWins][0]);
  3013. }
  3014.  
  3015. len += formatex(menuText[len],511-len,"%L^n",id,keyLINE4,playerStats[id][sdStreak][0]);
  3016.  
  3017. // now show teamplay if we can/should
  3018. if(stats_split)
  3019. {
  3020. if(statsPosition[id][1] > 0) // show rank
  3021. {
  3022. new statsSuffix[3];
  3023. get_number_suffix(statsPosition[id][1],statsSuffix,2);
  3024.  
  3025. if(stats_mode == 1) len += formatex(menuText[len],511-len,"%L (%i%s)^n",id,"LEVEL_MESSAGE_LINE3A_TP",playerStats[id][sdWins][1],statsPosition[id][1],statsSuffix);
  3026. else len += formatex(menuText[len],511-len,"%L (%i%s)^n",id,"LEVEL_MESSAGE_LINE3B_TP",playerStats[id][sdPoints][1],playerStats[id][sdWins][1],statsPosition[id][1],statsSuffix);
  3027. }
  3028. else // don't show rank
  3029. {
  3030. if(stats_mode == 1) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE3A_TP",playerStats[id][sdWins][1]);
  3031. else len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE3B_TP",playerStats[id][sdPoints][1],playerStats[id][sdWins][1]);
  3032. }
  3033.  
  3034. len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE4_TP",playerStats[id][sdStreak][1]);
  3035. }
  3036.  
  3037. len += formatex(menuText[len],511-len,"\d----------\w^n");
  3038. }
  3039.  
  3040. if(leaderNum > 1) len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE5A",leaderList);
  3041. else len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE5B",leaderList);
  3042.  
  3043. if(teamplay)
  3044. {
  3045. if(teamLevel[leader]) copy(displayWeapon,15,teamLvlWeapon[leader]);
  3046. else formatex(displayWeapon,15,"%L",id,"NONE");
  3047. }
  3048. else
  3049. {
  3050. if(level[leader]) copy(displayWeapon,15,lvlWeapon[leader]);
  3051. else formatex(displayWeapon,15,"%L",id,"NONE");
  3052. }
  3053.  
  3054. len += formatex(menuText[len],511-len,"%L^n",id,"LEVEL_MESSAGE_LINE6",leaderLevel,displayWeapon);
  3055. len += formatex(menuText[len],511-len,"\d----------\w^n");
  3056.  
  3057. len += formatex(menuText[len],511-len,"%L",id,"PRESS_KEY_TO_CONTINUE");
  3058.  
  3059. show_menu(id,1023,menuText,-1,"level_menu");
  3060. }
  3061.  
  3062. // show the top10 list menu
  3063. show_top10_menu(id)
  3064. {
  3065. new pppString[74], len = get_pcvar_string(gg_top10_ppp,pppString,63);
  3066.  
  3067. // URL specified
  3068. if(pppString[0] && !isdigit(pppString[0]))
  3069. {
  3070. new header[32], lang[3];
  3071. formatex(header,31,"%L %L",id,"GUNGAME",id,"STATS");
  3072. get_user_info(id,"lang",lang,2);
  3073.  
  3074. formatex(pppString[len],73-len,"?i=%i&l=%s",id,lang);
  3075. show_motd(id,pppString,header);
  3076.  
  3077. return;
  3078. }
  3079.  
  3080. #if !defined SQL
  3081. recheck_stats_sorting();
  3082. #endif
  3083.  
  3084. new absPage = abs(page[id]), stats_split = get_pcvar_num(gg_stats_split), si = (page[id] < 0);
  3085.  
  3086. new playersPerPage = str_to_num(pppString), stats_mode = get_pcvar_num(gg_stats_mode);
  3087. //if(stats_split == 2) playersPerPage = 7;
  3088.  
  3089. #if defined SQL
  3090. new winsColumn[8], pointsColumn[10], streakColumn[10], totalPlayers, numRows;
  3091.  
  3092. if(si == 0)
  3093. {
  3094. winsColumn = "wins";
  3095. pointsColumn = "points";
  3096. streakColumn = "streak";
  3097. }
  3098. else
  3099. {
  3100. winsColumn = "wins_tp";
  3101. pointsColumn = "points_tp";
  3102. streakColumn = "streak_tp";
  3103. }
  3104.  
  3105. if(stats_mode == 2) query = SQL_PrepareQuery(db,"SELECT NULL FROM `%s` WHERE serverip='%s' AND (%s > 0 OR %s > 0);",sqlTable,serverip,winsColumn,pointsColumn);
  3106. else query = SQL_PrepareQuery(db,"SELECT NULL FROM `%s` WHERE serverip='%s' AND %s > 0;",sqlTable,serverip,winsColumn);
  3107.  
  3108. if(SQL_ExecuteAndLog(query))
  3109. {
  3110. numRows = SQL_NumRows(query);
  3111. totalPlayers = playersPerPage * floatround(float(numRows+1) / float(playersPerPage),floatround_ceil);
  3112. }
  3113.  
  3114. SQL_FreeHandle(query);
  3115. #else
  3116. new totalPlayers = playersPerPage * floatround(float(statsSize[si]+1) / float(playersPerPage),floatround_ceil); // +1 for streak display
  3117. #endif
  3118.  
  3119. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  3120.  
  3121. if(pageTotal < 1) pageTotal = 1;
  3122. if(totalPlayers < playersPerPage) totalPlayers = playersPerPage;
  3123.  
  3124. if(absPage > pageTotal)
  3125. {
  3126. new negative = (page[id] < 0);
  3127. page[id] = absPage = pageTotal;
  3128. if(negative) page[id] *= -1;
  3129. }
  3130.  
  3131. if(stats_split) len = formatex(menuText,511,"\y%L %L (%i/%i)^n",id,"GUNGAME",id,(page[id] < 0) ? "STATS_TEAMPLAY" : "STATS_REGULAR",absPage,pageTotal);
  3132. else len = formatex(menuText,511,"\y%L %L (%i/%i)^n",id,"GUNGAME",id,"STATS",absPage,pageTotal);
  3133.  
  3134. new start = (playersPerPage * (absPage-1)), i;
  3135.  
  3136. // show the top streak for the first page
  3137. new topStreak, champName[32], champAuthid[32];
  3138. if(absPage == 1)
  3139. {
  3140. #if defined SQL
  3141. query = SQL_PrepareQuery(db,"SELECT authid,streak,name FROM `%s` WHERE type='%iR' AND serverip='%s' LIMIT 1;",sqlStreakTable,si,serverip);
  3142. if(SQL_ExecuteAndLog(query) && SQL_NumResults(query))
  3143. {
  3144. SQL_ReadResult(query,0,champAuthid,31);
  3145. topStreak = SQL_ReadResult(query,1);
  3146. SQL_ReadResult(query,2,champName,31);
  3147. }
  3148. SQL_FreeHandle(query);
  3149. #else
  3150. new sfStreak[4], stats_streak_file[64];
  3151. get_pcvar_string(gg_stats_streak_file,stats_streak_file,63);
  3152.  
  3153. if(file_exists(stats_streak_file))
  3154. {
  3155. new file = fopen(stats_streak_file,"rt");
  3156. while(file && !feof(file))
  3157. {
  3158. fgets(file,sfLineData,82);
  3159.  
  3160. // blank, not for our stats mode, or not the record
  3161. if(!sfLineData[0] || str_to_num(sfLineData[0]) != si || sfLineData[1] != 'R') continue;
  3162.  
  3163. strtok(sfLineData[3],champAuthid,31,sfLineData,82,'^t'); // cut off prefix and authid from the left
  3164. strtok(sfLineData,sfStreak,3,champName,31,'^t'); // get our streak, and the name as well
  3165.  
  3166. new pos = contain_char(champName,'^t');
  3167. if(pos != -1) champName[pos] = 0; // cut off the name at the tab
  3168.  
  3169. topStreak = str_to_num(sfStreak);
  3170. }
  3171. if(file) fclose(file);
  3172. }
  3173. #endif
  3174.  
  3175. if(!champName[0]) formatex(champName,31,"%L",id,"NO_ONE");
  3176. }
  3177.  
  3178. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3179.  
  3180. new authid[32];
  3181. get_gg_authid(id,authid,31);
  3182.  
  3183. #if defined SQL
  3184. if(numRows)
  3185. {
  3186. // do this to account for the streak display in our LIMIT clause
  3187. if(absPage == 1) playersPerPage--;
  3188. else start--;
  3189.  
  3190. if(stats_mode == 2)
  3191. {
  3192. query = SQL_PrepareQuery(db,"SELECT authid,name,%s,%s,%s,(SELECT COUNT(*)+1 FROM `%s` y WHERE y.%s > x.%s AND serverip='%s' AND (y.%s > 0 OR y.%s > 0) LIMIT 1) AS ranking FROM `%s` x WHERE x.serverip='%s' AND (x.%s > 0 OR x.%s > 0) ORDER BY %s DESC, %s DESC LIMIT %i, %i;",
  3193. winsColumn,pointsColumn,streakColumn,sqlTable,pointsColumn,pointsColumn,serverip,winsColumn,pointsColumn,sqlTable,serverip,winsColumn,pointsColumn,pointsColumn,winsColumn,start,playersPerPage);
  3194. }
  3195. else
  3196. {
  3197. query = SQL_PrepareQuery(db,"SELECT authid,name,%s,%s,%s,(SELECT COUNT(*)+1 FROM `%s` y WHERE y.%s > x.%s AND serverip='%s' AND y.%s > 0 LIMIT 1) AS ranking FROM `%s` x WHERE x.serverip='%s' AND x.%s > 0 ORDER BY %s DESC LIMIT %i, %i;",
  3198. winsColumn,pointsColumn,streakColumn,sqlTable,winsColumn,winsColumn,serverip,winsColumn,sqlTable,serverip,winsColumn,winsColumn,start,playersPerPage);
  3199. }
  3200.  
  3201. // reverse changes made above for LIMIT
  3202. if(absPage == 1) playersPerPage++;
  3203. else start++;
  3204. }
  3205.  
  3206. if(!numRows || SQL_ExecuteAndLog(query))
  3207. {
  3208. new ranking, moreResults, lastRanking = start;
  3209. if(numRows) moreResults = SQL_MoreResults(query);
  3210.  
  3211. for(i=start;i<start+playersPerPage;i++)
  3212. {
  3213. if(i >= totalPlayers) break;
  3214.  
  3215. // use the first slot to display the record streak
  3216. if(i == 0)
  3217. {
  3218. len += formatex(menuText[len],511-len,"%s%L^n",(equal(authid,champAuthid)) ? "\r" : "\w",id,"RECORD_STREAK",champName,topStreak);
  3219. continue;
  3220. }
  3221.  
  3222. // all out of rows
  3223. if(!moreResults)
  3224. {
  3225. lastRanking++;
  3226. len += formatex(menuText[len],511-len,"\w#%i \d%L^n",lastRanking,id,"NONE");
  3227. continue;
  3228. }
  3229.  
  3230. SQL_ReadResult(query,0,sfStatsStruct[sdAuthid],31);
  3231. SQL_ReadResult(query,1,sfStatsStruct[sdName],31);
  3232. sfStatsStruct[sdWins][si] = SQL_ReadResult(query,2);
  3233. sfStatsStruct[sdPoints][si] = SQL_ReadResult(query,3);
  3234. sfStatsStruct[sdStreak][si] = SQL_ReadResult(query,4);
  3235. ranking = SQL_ReadResult(query,5);
  3236.  
  3237. if(stats_mode == 1)
  3238. {
  3239. if(sfStatsStruct[sdStreak][si] > 1) len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",ranking,sfStatsStruct[sdName],sfStatsStruct[sdWins][si],id,"WINS",id,"IN_A_ROW",sfStatsStruct[sdStreak][si]);
  3240. else len += formatex(menuText[len],511-len,"%s#%i %s (%i %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",ranking,sfStatsStruct[sdName],sfStatsStruct[sdWins][si],id,"WINS");
  3241. }
  3242. else
  3243. {
  3244. if(sfStatsStruct[sdStreak][si] > 1) len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %i %L, %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",ranking,sfStatsStruct[sdName],sfStatsStruct[sdPoints][si],id,"POINTS",sfStatsStruct[sdWins][si],id,"WINS",id,"IN_A_ROW",sfStatsStruct[sdStreak][si]);
  3245. else len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %i %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",ranking,sfStatsStruct[sdName],sfStatsStruct[sdPoints][si],id,"POINTS",sfStatsStruct[sdWins][si],id,"WINS");
  3246. }
  3247.  
  3248. SQL_NextRow(query);
  3249. moreResults = SQL_MoreResults(query);
  3250.  
  3251. lastRanking = ranking;
  3252. }
  3253. }
  3254.  
  3255. if(numRows) SQL_FreeHandle(query);
  3256. #else
  3257. for(i=start;i<start+playersPerPage;i++)
  3258. {
  3259. if(i >= totalPlayers) break;
  3260.  
  3261. // use the first slot to display the record streak
  3262. if(i == 0)
  3263. {
  3264. len += formatex(menuText[len],511-len,"%s%L^n",(equal(authid,champAuthid)) ? "\r" : "\w",id,"RECORD_STREAK",champName,topStreak);
  3265. continue;
  3266. }
  3267.  
  3268. // blank
  3269. if(i-1 >= statsSize[si])
  3270. {
  3271. len += formatex(menuText[len],511-len,"\w#%i \d%L^n",i/*+1-1*/,id,"NONE");
  3272. continue;
  3273. }
  3274.  
  3275. ArrayGetArray(statsArray,ArrayGetCell(statsPointers[si],i-1),sfStatsStruct);
  3276.  
  3277. if(stats_mode == 1)
  3278. {
  3279. if(sfStatsStruct[sdStreak][si] > 1) len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",i/*+1-1*/,sfStatsStruct[sdName],sfStatsStruct[sdWins][si],id,"WINS",id,"IN_A_ROW",sfStatsStruct[sdStreak][si]);
  3280. else len += formatex(menuText[len],511-len,"%s#%i %s (%i %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",i/*+1-1*/,sfStatsStruct[sdName],sfStatsStruct[sdWins][si],id,"WINS");
  3281. }
  3282. else
  3283. {
  3284. if(sfStatsStruct[sdStreak][si] > 1) len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %i %L, %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",i/*+1-1*/,sfStatsStruct[sdName],sfStatsStruct[sdPoints][si],id,"POINTS",sfStatsStruct[sdWins][si],id,"WINS",id,"IN_A_ROW",sfStatsStruct[sdStreak][si]);
  3285. else len += formatex(menuText[len],511-len,"%s#%i %s (%i %L, %i %L)^n",(equal(authid,sfStatsStruct[sdAuthid])) ? "\r" : "\w",i/*+1-1*/,sfStatsStruct[sdName],sfStatsStruct[sdPoints][si],id,"POINTS",sfStatsStruct[sdWins][si],id,"WINS");
  3286. }
  3287. }
  3288. #endif
  3289.  
  3290. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3291.  
  3292. new keys = MENU_KEY_0;
  3293.  
  3294. if(absPage > 1)
  3295. {
  3296. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  3297. keys |= MENU_KEY_1;
  3298. }
  3299. if(absPage < pageTotal)
  3300. {
  3301. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  3302. keys |= MENU_KEY_2;
  3303. }
  3304. if(statsPosition[id][si] > 0)
  3305. {
  3306. len += formatex(menuText[len],511-len,"3. %L^n",id,"JUMP_TO_ME");
  3307. keys |= MENU_KEY_3;
  3308. }
  3309. if(stats_split)
  3310. {
  3311. len += formatex(menuText[len],511-len,"4. %L^n",id,(page[id] < 0) ? "STATS_REGULAR" : "STATS_TEAMPLAY");
  3312. keys |= MENU_KEY_4;
  3313. }
  3314. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  3315.  
  3316. show_menu(id,keys,menuText,-1,"top10_menu");
  3317. }
  3318.  
  3319. // someone pressed a key on the top10 list menu page
  3320. public top10_menu_handler(id,key)
  3321. {
  3322. #if !defined SQL
  3323. recheck_stats_sorting();
  3324. #endif
  3325.  
  3326. new si = (page[id] < 0);
  3327.  
  3328. new playersPerPage = get_pcvar_num(gg_top10_ppp);
  3329. //if(get_pcvar_num(gg_stats_split) == 2) playersPerPage = 7;
  3330.  
  3331. #if defined SQL
  3332. new winsColumn[8], pointsColumn[10], totalPlayers, stats_mode = get_pcvar_num(gg_stats_mode);
  3333.  
  3334. if(si == 0)
  3335. {
  3336. winsColumn = "wins";
  3337. pointsColumn = "points";
  3338. }
  3339. else
  3340. {
  3341. winsColumn = "wins_tp";
  3342. pointsColumn = "points_tp";
  3343. }
  3344.  
  3345. if(stats_mode == 2) query = SQL_PrepareQuery(db,"SELECT NULL FROM `%s` WHERE serverip='%s' AND (%s > 0 OR %s > 0);",sqlTable,serverip,winsColumn,pointsColumn);
  3346. else query = SQL_PrepareQuery(db,"SELECT NULL FROM `%s` WHERE serverip='%s' AND %s > 0;",sqlTable,serverip,winsColumn);
  3347.  
  3348. if(SQL_ExecuteAndLog(query)) totalPlayers = playersPerPage * floatround(float(SQL_NumRows(query)+1) / float(playersPerPage),floatround_ceil);
  3349. SQL_FreeHandle(query);
  3350. #else
  3351. new totalPlayers = playersPerPage * floatround(float(statsSize[si]+1) / float(playersPerPage),floatround_ceil); // +1 for streak display
  3352. #endif
  3353.  
  3354. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  3355. if(pageTotal < 1) pageTotal = 1;
  3356.  
  3357. if(!page[id] || page[id] > pageTotal) return;
  3358.  
  3359. // 1. Previous
  3360. if(key == 0)
  3361. {
  3362. if(page[id] < 0) page[id]++;
  3363. else page[id]--;
  3364.  
  3365. show_top10_menu(id);
  3366. }
  3367.  
  3368. // 2. Next
  3369. else if(key == 1)
  3370. {
  3371. if(page[id] < 0) page[id]--;
  3372. else page[id]++;
  3373.  
  3374. show_top10_menu(id);
  3375. }
  3376.  
  3377. // 3. Jump to me
  3378. else if(key == 2)
  3379. {
  3380. #if defined SQL
  3381. if(statsPosition[id][si] > 0)
  3382. {
  3383. // using SQL stats, players can have tied rankings (ie: 1st, 1st, 3rd). so, if we know a player's ranking, we don't necessarily know
  3384. // what page they're on (they could be the last of 20 players all tied for 1st, for example). however, we do know what position (and
  3385. // therefore also the page) that their ranking starts on. then we can select everyone with an equal score, and process the results
  3386. // until we find their authid, to see how many positions off they are from the start of their ranking. then find the page for that.
  3387.  
  3388. new authid[32], myPoints;
  3389. get_gg_authid(id,authid,31);
  3390.  
  3391. stats_get_data(authid,playerStats[id],id);
  3392.  
  3393. if(stats_mode == 2)
  3394. {
  3395. myPoints = playerStats[id][sdPoints][si];
  3396. query = SQL_PrepareQuery(db,"SELECT authid FROM `%s` WHERE %s='%i' AND serverip='%s' ORDER BY %s, %s DESC;",sqlTable,pointsColumn,myPoints,serverip,pointsColumn,winsColumn);
  3397. }
  3398. else
  3399. {
  3400. myPoints = playerStats[id][sdWins][si];
  3401. query = SQL_PrepareQuery(db,"SELECT authid FROM `%s` WHERE %s='%i' AND serverip='%s' ORDER BY %s DESC;",sqlTable,winsColumn,myPoints,serverip,winsColumn);
  3402. }
  3403.  
  3404. if(SQL_ExecuteAndLog(query))
  3405. {
  3406. new position = statsPosition[id][si]; // start at my position
  3407.  
  3408. if(SQL_NumRows(query) > 1) // if I'm the only one with my score, no searching is necessary
  3409. {
  3410. new rowAuthid[32];
  3411. while(SQL_MoreResults(query))
  3412. {
  3413. SQL_ReadResult(query,0,rowAuthid,31);
  3414. if(equal(authid,rowAuthid)) break;
  3415.  
  3416. position++;
  3417. SQL_NextRow(query);
  3418. }
  3419. }
  3420.  
  3421. new negative = (page[id] < 0);
  3422. page[id] = floatround(float(position) / float(playersPerPage),floatround_floor) + 1;
  3423. if(negative) page[id] *= -1;
  3424. }
  3425.  
  3426. SQL_FreeHandle(query);
  3427. }
  3428. #else
  3429. if(statsPosition[id][si] > 0)
  3430. {
  3431. // this method of finding the page is slightly different from the weapons and scores menu because
  3432. // this listing is 0-based, because we use the 0th index to display the record win streak. also,
  3433. // because we use negative numbers for the teamplay stats index.
  3434.  
  3435. new negative = (page[id] < 0);
  3436. page[id] = floatround(float(statsPosition[id][si]) / float(playersPerPage),floatround_floor) + 1;
  3437. if(negative) page[id] *= -1;
  3438. }
  3439. #endif
  3440. show_top10_menu(id);
  3441. }
  3442.  
  3443. // 4. Regular Stats / Teamplay Stats
  3444. else if(key == 3)
  3445. {
  3446. page[id] *= -1;
  3447. show_top10_menu(id);
  3448. }
  3449.  
  3450. // 0. Close
  3451. // do nothing, menu closes automatically
  3452. }
  3453.  
  3454. // show the weapon list menu
  3455. show_weapons_menu(id)
  3456. {
  3457. new totalWeapons = weaponNum, wpnsPerPage = 10;
  3458. new pageTotal = floatround(float(totalWeapons) / float(wpnsPerPage),floatround_ceil);
  3459.  
  3460. if(page[id] < 1) page[id] = 1;
  3461. if(page[id] > pageTotal) page[id] = pageTotal;
  3462.  
  3463. new len = formatex(menuText,511,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"WEAPONS",page[id],pageTotal);
  3464. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3465.  
  3466. new start = (wpnsPerPage * (page[id]-1)) + 1, i;
  3467.  
  3468. // are there any custom kill requirements?
  3469. new customKills, Float:expected, Float:killsperlvl = get_pcvar_float(gg_kills_per_lvl);
  3470. for(i=0;i<weaponNum;i++)
  3471. {
  3472. if(equal(weaponName[i],KNIFE) || equal(weaponName[i],HEGRENADE)) expected = 1.0;
  3473. else expected = killsperlvl;
  3474.  
  3475. if(weaponGoal[i] != expected)
  3476. {
  3477. customKills = 1;
  3478. break;
  3479. }
  3480. }
  3481.  
  3482. for(i=start;i<start+wpnsPerPage;i++)
  3483. {
  3484. if(i > totalWeapons) break;
  3485.  
  3486. if(customKills)
  3487. len += formatex(menuText[len],511-len,"%s%L %i: %s (%i)^n",(i == level[id]) ? "\r" : "\w",id,"LEVEL",i,weaponName[i-1],get_level_goal(i));
  3488. else
  3489. len += formatex(menuText[len],511-len,"%s%L %i: %s^n",(i == level[id]) ? "\r" : "\w",id,"LEVEL",i,weaponName[i-1]);
  3490. }
  3491.  
  3492. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3493.  
  3494. new keys = MENU_KEY_0;
  3495.  
  3496. if(page[id] > 1)
  3497. {
  3498. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  3499. keys |= MENU_KEY_1;
  3500. }
  3501. if(page[id] < pageTotal)
  3502. {
  3503. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  3504. keys |= MENU_KEY_2;
  3505. }
  3506.  
  3507. len += formatex(menuText[len],511-len,"3. %L^n",id,"JUMP_TO_ME");
  3508. keys |= MENU_KEY_3;
  3509.  
  3510. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  3511.  
  3512. show_menu(id,keys,menuText,-1,"weapons_menu");
  3513. }
  3514.  
  3515. // someone pressed a key on the weapon list menu page
  3516. public weapons_menu_handler(id,key)
  3517. {
  3518. new wpnsPerPage = 10, pageTotal = floatround(float(weaponNum) / float(wpnsPerPage),floatround_ceil);
  3519.  
  3520. if(page[id] < 1 || page[id] > pageTotal) return;
  3521.  
  3522. // 1. Previous
  3523. if(key == 0)
  3524. {
  3525. page[id]--;
  3526. show_weapons_menu(id);
  3527. return;
  3528. }
  3529.  
  3530. // 2. Next
  3531. else if(key == 1)
  3532. {
  3533. page[id]++;
  3534. show_weapons_menu(id);
  3535. return;
  3536. }
  3537.  
  3538. // 3. Jump to me
  3539. else if(key == 2)
  3540. {
  3541. page[id] = clamp(floatround(float(level[id]) / float(wpnsPerPage),floatround_ceil),1,pageTotal);
  3542. show_weapons_menu(id);
  3543. }
  3544.  
  3545. // 0. Close
  3546. // do nothing, menu closes automatically
  3547. }
  3548.  
  3549. // show the score list menu
  3550. show_scores_menu(id)
  3551. {
  3552. #if !defined SQL
  3553. recheck_stats_sorting();
  3554. #endif
  3555.  
  3556. new keys, len, teamplay = get_pcvar_num(gg_teamplay);
  3557.  
  3558. if(teamplay)
  3559. {
  3560. if(page[id] != 1) page[id] = 1;
  3561.  
  3562. new leader = teamplay_get_lead_team(), otherTeam = (leader == 1) ? 2 : 1;
  3563. new displayWeapon[24], teamName[10];
  3564.  
  3565. len = formatex(menuText,511,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"SCORES",page[id],1);
  3566.  
  3567. new team, myTeam = _:cs_get_user_team(id);
  3568. for(team=leader;team>0;team=otherTeam)
  3569. {
  3570. if(teamLevel[team] && teamLvlWeapon[team][0]) copy(displayWeapon,23,teamLvlWeapon[team]);
  3571. else formatex(displayWeapon,23,"%L",id,"NONE");
  3572.  
  3573. get_team_name(CsTeams:team,teamName,9);
  3574. len += formatex(menuText[len],511-len,"%s#%i %s %L, %L %i (%s) %i/%i^n",(team == myTeam) ? "\r" : "\w",(team == leader) ? 1 : 2,teamName,id,"TEAM",id,"LEVEL",teamLevel[team],displayWeapon,teamScore[team],teamplay_get_team_goal(team));
  3575.  
  3576. // finished
  3577. if(team == otherTeam) break;
  3578. }
  3579.  
  3580. // nice separator!
  3581. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3582.  
  3583. keys = MENU_KEY_0;
  3584. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  3585. }
  3586. else
  3587. {
  3588. new totalPlayers = get_playersnum(), playersPerPage = 7, stats_mode = get_pcvar_num(gg_stats_mode);
  3589. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  3590.  
  3591. if(page[id] < 1) page[id] = 1;
  3592. if(page[id] > pageTotal) page[id] = pageTotal;
  3593.  
  3594. new players[32], num;
  3595. get_players(players,num);
  3596.  
  3597. // order by highest level first
  3598. SortCustom1D(players,num,"score_custom_compare");
  3599.  
  3600. if(get_pcvar_num(gg_stats_split)) len = formatex(menuText,511,"\y%L %L (%i/%i) %L\w^n",id,"GUNGAME",id,"SCORES",page[id],pageTotal,id,"STATS_REGULAR");
  3601. else len = formatex(menuText,511,"\y%L %L (%i/%i)\w^n",id,"GUNGAME",id,"SCORES",page[id],pageTotal);
  3602. //len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3603.  
  3604. new start = (playersPerPage * (page[id]-1)), i, name[32], player, authid[32];
  3605. new stats_ip = get_pcvar_num(gg_stats_ip), displayWeapon[24], statsSuffix[3];
  3606. new si = get_gg_si();
  3607.  
  3608. for(i=start;i<start+playersPerPage;i++)
  3609. {
  3610. if(i >= totalPlayers) break;
  3611.  
  3612. player = players[i];
  3613. get_user_name(player,name,31);
  3614.  
  3615. if(level[player] && lvlWeapon[player][0]) copy(displayWeapon,23,lvlWeapon[player]);
  3616. else formatex(displayWeapon,23,"%L",id,"NONE");
  3617.  
  3618. if(sqlInit && stats_mode)
  3619. {
  3620. get_gg_authid(player,authid,31,stats_ip);
  3621. stats_get_data(authid,playerStats[player],player);
  3622.  
  3623. if(statsPosition[player][si] > 0)
  3624. {
  3625. get_number_suffix(statsPosition[player][si],statsSuffix,2);
  3626. len += formatex(menuText[len],511-len,"%s#%i %s, %L %i (%s) %i/%i, %i %L (%i%s)^n",(player == id) ? "\r" : "\w",i+1,name,id,"LEVEL",level[player],displayWeapon,score[player],get_level_goal(level[player],player),(stats_mode == 1) ? playerStats[player][sdWins][si] : playerStats[player][sdPoints][si],id,(stats_mode == 1) ? "WINS" : "POINTS_ABBR",statsPosition[player][si],statsSuffix);
  3627. }
  3628. else len += formatex(menuText[len],511-len,"%s#%i %s, %L %i (%s) %i/%i, %i %L^n",(player == id) ? "\r" : "\w",i+1,name,id,"LEVEL",level[player],displayWeapon,score[player],get_level_goal(level[player],player),(stats_mode == 1) ? playerStats[player][sdWins][si] : playerStats[player][sdPoints][si],id,(stats_mode == 1) ? "WINS" : "POINTS_ABBR");
  3629. }
  3630. else len += formatex(menuText[len],511-len,"#%i %s, %L %i (%s) %i/%i^n",i+1,name,id,"LEVEL",level[player],displayWeapon,score[player],get_level_goal(level[player],player));
  3631. }
  3632.  
  3633. len += formatex(menuText[len],511-len,"\d-----------\w^n");
  3634.  
  3635. keys = MENU_KEY_0;
  3636.  
  3637. if(page[id] > 1)
  3638. {
  3639. len += formatex(menuText[len],511-len,"1. %L^n",id,"PREVIOUS");
  3640. keys |= MENU_KEY_1;
  3641. }
  3642. if(page[id] < pageTotal)
  3643. {
  3644. len += formatex(menuText[len],511-len,"2. %L^n",id,"NEXT");
  3645. keys |= MENU_KEY_2;
  3646. }
  3647.  
  3648. len += formatex(menuText[len],511-len,"3. %L^n",id,"JUMP_TO_ME");
  3649. keys |= MENU_KEY_3;
  3650.  
  3651. len += formatex(menuText[len],511-len,"0. %L",id,"CLOSE");
  3652. }
  3653.  
  3654. show_menu(id,keys,menuText,-1,"scores_menu");
  3655. }
  3656.  
  3657. // sort list of players with their level first
  3658. public score_custom_compare(elem1,elem2)
  3659. {
  3660. // invalid players
  3661. if(elem1 < 1 || elem1 > 32 || elem2 < 1 || elem2 > 32)
  3662. return 0;
  3663.  
  3664. // tied levels, compare scores
  3665. if(level[elem1] == level[elem2])
  3666. {
  3667. if(score[elem1] > score[elem2]) return -1;
  3668. else if(score[elem1] < score[elem2]) return 1;
  3669. else return 0;
  3670. }
  3671.  
  3672. // compare levels
  3673. else if(level[elem1] > level[elem2]) return -1;
  3674. else if(level[elem1] < level[elem2]) return 1;
  3675.  
  3676. return 0; // equal
  3677. }
  3678.  
  3679. // someone pressed a key on the score list menu page
  3680. public scores_menu_handler(id,key)
  3681. {
  3682. new totalPlayers = get_playersnum(), playersPerPage = 7;
  3683. new pageTotal = floatround(float(totalPlayers) / float(playersPerPage),floatround_ceil);
  3684.  
  3685. if(page[id] < 1 || page[id] > pageTotal) return;
  3686.  
  3687. // 1. Previous
  3688. if(key == 0)
  3689. {
  3690. page[id]--;
  3691. show_scores_menu(id);
  3692. return;
  3693. }
  3694.  
  3695. // 2. Next
  3696. else if(key == 1)
  3697. {
  3698. page[id]++;
  3699. show_scores_menu(id);
  3700. return;
  3701. }
  3702.  
  3703. // 3. Jump to me
  3704. else if(key == 2)
  3705. {
  3706. new players[32], num, i;
  3707. get_players(players,num);
  3708. SortCustom1D(players,num,"score_custom_compare");
  3709.  
  3710. for(i=0;i<num;i++)
  3711. {
  3712. if(players[i] == id) break;
  3713. }
  3714.  
  3715. page[id] = floatround(float(i+1) / float(playersPerPage),floatround_ceil);
  3716. show_scores_menu(id);
  3717. }
  3718.  
  3719. // 0. Close
  3720. // do nothing, menu closes automatically
  3721. }
  3722.  
  3723. //**********************************************************************
  3724. // MAIN FUNCTIONS
  3725. //**********************************************************************
  3726.  
  3727. // toggle the status of gungame
  3728. public toggle_gungame(taskid)
  3729. {
  3730. new status = taskid-TASK_TOGGLE_GUNGAME, i;
  3731.  
  3732. // clear player tasks and values
  3733. for(i=1;i<=32;i++) clear_values(i);
  3734.  
  3735. clear_team_values(1);
  3736. clear_team_values(2);
  3737.  
  3738. // clear temp saves
  3739. for(i=0;i<TEMP_SAVES;i++) clear_save(TASK_CLEAR_SAVE+i);
  3740.  
  3741. if(status == TOGGLE_FORCE || status == TOGGLE_ENABLE)
  3742. {
  3743. // these allow toggling of GunGame on/off
  3744. exec_gg_config_file(0,1); // run the regular config file
  3745. if(get_pcvar_num(gg_teamplay)) exec_gg_config_file(1,1); // if teamplay, run the teamplay config file also
  3746. }
  3747.  
  3748. // set to what we chose from amx_gungame
  3749. if(status != TOGGLE_FORCE)
  3750. {
  3751. set_pcvar_num(gg_enabled,status);
  3752. ggActive = status;
  3753. }
  3754. else ggActive = get_pcvar_num(gg_enabled); // otherwise see what this is after the configs have been run
  3755.  
  3756. // run appropiate cvars
  3757. map_start_cvars(0); // this sets up weapon order
  3758.  
  3759. // reset some things
  3760. if(!ggActive)
  3761. {
  3762. // set armouries to be solid again
  3763. show_armory_entitys();
  3764.  
  3765. // clear HUD message
  3766. if(warmup > 0) ClearSyncHud(0,hudSyncWarmup);
  3767.  
  3768. warmup = -1;
  3769. warmupWeapon[0] = 0;
  3770. voted = 0;
  3771. won = 0;
  3772.  
  3773. remove_task(TASK_WARMUP_CHECK);
  3774. }
  3775.  
  3776. // we need to get these stats (GunGame is on, we don't have them, and we aren't in the process of getting them)
  3777. #if defined SQL
  3778. if(ggActive && !task_exists(TASK_GET_TOP_PLAYERS)) stats_get_top_players(); // there is no statsArray for SQL
  3779. #else
  3780. if(ggActive && !statsArray && !task_exists(TASK_GET_TOP_PLAYERS)) stats_get_top_players();
  3781. #endif
  3782.  
  3783. // game_player_equip
  3784. manage_equips();
  3785.  
  3786. // start (or stop) the leader display
  3787. remove_task(TASK_LEADER_DISPLAY);
  3788. show_leader_display();
  3789.  
  3790. // warmup weapon may've change
  3791. if(warmup > 0) get_pcvar_string(gg_warmup_weapon,warmupWeapon,23);
  3792.  
  3793. #if defined SQL
  3794. // fire up the engines!!
  3795. if(!sqlInit)
  3796. {
  3797. sql_init();
  3798.  
  3799. // because we can't refresh timestamps before SQL is initiated, refresh timestamps for people who joined before this
  3800. #if defined REFRESH_TIMESTAMP_ON_JOIN
  3801. new authid[32];
  3802. for(new i=1;i<=maxPlayers;i++)
  3803. {
  3804. if(is_user_connected(i))
  3805. {
  3806. get_gg_authid(i,authid,31);
  3807. stats_refresh_timestamp(authid);
  3808. }
  3809. }
  3810. #endif // REFRESH_TIMESTAMP_ON_JOIN
  3811. }
  3812. #endif // SQL
  3813. }
  3814.  
  3815. // run cvars that should be run on map start
  3816. //
  3817. // see declaration of d_rOrder for explanation of keepTeamplay
  3818. public map_start_cvars(keepTeamplay)
  3819. {
  3820. new setup[512];
  3821.  
  3822. // gungame is disabled, run endmap_setup
  3823. if(!ggActive)
  3824. {
  3825. get_pcvar_string(gg_endmap_setup,setup,511);
  3826. if(setup[0]) server_cmd(setup);
  3827. }
  3828. else
  3829. {
  3830. // run map setup
  3831. get_pcvar_string(gg_map_setup,setup,511);
  3832. if(setup[0]) server_cmd(setup);
  3833.  
  3834. do_rOrder(keepTeamplay); // also does random teamplay
  3835. setup_weapon_order();
  3836.  
  3837. // random win sounds
  3838. currentWinSound = do_rWinSound();
  3839. }
  3840. }
  3841.  
  3842. precache_sounds_from_config()
  3843. {
  3844. new cfgFile[64], command[WINSOUNDS_SIZE+32], cvar[32], value[WINSOUNDS_SIZE], file, i, pos, len;
  3845. for(i=0;i<2;i++)
  3846. {
  3847. get_gg_config_file(i,cfgFile,63);
  3848.  
  3849. if(cfgFile[0] && file_exists(cfgFile))
  3850. {
  3851. file = fopen(cfgFile,"rt");
  3852. while(file && !feof(file))
  3853. {
  3854. fgets(file,command,WINSOUNDS_SIZE+31);
  3855. len = strlen(command) - 2;
  3856.  
  3857. // stop at coding-style (//) comments
  3858. for(pos=0;pos<len;pos++)
  3859. {
  3860. if(command[pos] == '/' && command[pos+1] == '/')
  3861. {
  3862. copy(command,pos,command);
  3863. break;
  3864. }
  3865. }
  3866.  
  3867. // this is a sound
  3868. if(equal(command,"gg_sound_",9))
  3869. {
  3870. parse(command,cvar,31,value,WINSOUNDS_SIZE-1);
  3871.  
  3872. // gg_sound_winner might contain multiple sounds
  3873. if(command[9] == 'w' && command[10] == 'i' && value[0]) // check w AND i, thanks Tomek Kalkowski
  3874. {
  3875. new temp[MAX_WINSOUND_LEN+1];
  3876. while(numWinSounds < MAX_WINSOUNDS)
  3877. {
  3878. pos = contain_char(value,';');
  3879.  
  3880. // no more after this, precache what we have left
  3881. if(pos == -1)
  3882. {
  3883. if(value[0])
  3884. {
  3885. precache_sound_special(value);
  3886. copy(winSounds[numWinSounds++],MAX_WINSOUND_LEN,value);
  3887. }
  3888. break;
  3889. }
  3890.  
  3891. // copy up to the semicolon and precache that
  3892. copy(temp,pos,value);
  3893.  
  3894. if(temp[0])
  3895. {
  3896. precache_sound_special(temp);
  3897. copy(winSounds[numWinSounds++],MAX_WINSOUND_LEN,temp);
  3898. }
  3899.  
  3900. // copy everything after the semicolon
  3901. copy(value,WINSOUNDS_SIZE-1,value[pos+1]);
  3902. }
  3903. }
  3904. else precache_sound_special(value);
  3905. }
  3906. }
  3907. if(file) fclose(file);
  3908. }
  3909. }
  3910. }
  3911.  
  3912. // manage stats pruning
  3913. public manage_pruning()
  3914. {
  3915. // stats disabled/file doesn't exist/pruning disabled
  3916. if(!sqlInit || !get_pcvar_num(gg_stats_mode) || !get_pcvar_num(gg_stats_prune)) return;
  3917.  
  3918. #if !defined SQL
  3919. get_pcvar_string(gg_stats_file,sfFile,63);
  3920. if(!file_exists(sfFile)) return; // no existy
  3921. #endif
  3922.  
  3923. // get how many plugin loads more until we prune
  3924. new prune_in_str[3], prune_in;
  3925. get_localinfo("gg_prune_in",prune_in_str,2);
  3926. prune_in = str_to_num(prune_in_str);
  3927.  
  3928. // localinfo not set yet
  3929. if(prune_in <= 0)
  3930. {
  3931. set_localinfo("gg_prune_in","9");
  3932. return;
  3933. }
  3934.  
  3935. // time to prune
  3936. if(prune_in == 1)
  3937. {
  3938. // result is -1 for a threaded query, so wait for results until we display
  3939. new result = stats_prune();
  3940. if(result != -1)
  3941. {
  3942. #if defined SQL
  3943. log_amx("%L",LANG_SERVER,"PRUNING",sqlTable,result);
  3944. #else
  3945. log_amx("%L",LANG_SERVER,"PRUNING",sfFile,result);
  3946. #endif
  3947. }
  3948.  
  3949. set_localinfo("gg_prune_in","10"); // reset our prune count
  3950. return;
  3951. }
  3952.  
  3953. // decrement our count
  3954. num_to_str(prune_in-1,prune_in_str,2);
  3955. set_localinfo("gg_prune_in",prune_in_str);
  3956. }
  3957.  
  3958. // manage warmup mode
  3959. public warmup_check(taskid)
  3960. {
  3961. warmup--;
  3962. set_hudmessage(255,255,255,-1.0,0.4,0,6.0,1.0,0.1,0.2);
  3963.  
  3964. if(warmup <= 0)
  3965. {
  3966. warmup = -13;
  3967. warmupWeapon[0] = 0;
  3968.  
  3969. ShowSyncHudMsg(0,hudSyncWarmup,"%L",LANG_PLAYER,"WARMUP_ROUND_OVER");
  3970. restart_round(1);
  3971.  
  3972. return;
  3973. }
  3974.  
  3975. ShowSyncHudMsg(0,hudSyncWarmup,"%L",LANG_PLAYER,"WARMUP_ROUND_DISPLAY",warmup);
  3976. set_task(1.0,"warmup_check",taskid);
  3977. }
  3978.  
  3979. // show the leader display
  3980. public show_leader_display()
  3981. {
  3982. static Float:lastDisplay, lastLeader, lastLevel, leaderName[32], runnerUpName[32], runnerUp3Name[32];
  3983.  
  3984. if(!ggActive || !get_pcvar_num(gg_leader_display))
  3985. {
  3986. remove_task(TASK_LEADER_DISPLAY);
  3987. return 0;
  3988. }
  3989.  
  3990. // keep it going
  3991. if(!task_exists(TASK_LEADER_DISPLAY))
  3992. set_task(LEADER_DISPLAY_RATE,"show_leader_display",TASK_LEADER_DISPLAY,_,_,"b");
  3993.  
  3994. // don't show during warmup or game over
  3995. if(warmup > 0 || won) return 0;
  3996.  
  3997. new leaderLevel, numLeaders, leader,runnerUp, teamplay = get_pcvar_num(gg_teamplay),runnerUp3;
  3998.  
  3999. if(teamplay) leader = teamplay_get_lead_team(leaderLevel,numLeaders);
  4000. else leader = get_leader(leaderLevel,numLeaders,runnerUp,runnerUp3);
  4001.  
  4002. if(!leader || leaderLevel <= 0) return 0;
  4003.  
  4004. // we just displayed the same message, don't flood
  4005. new Float:now = get_gametime();
  4006. if(lastLevel == leaderLevel && lastLeader == leader && lastDisplay == now) return 0;
  4007.  
  4008. // remember for later
  4009. lastDisplay = now;
  4010. lastLeader = leader;
  4011. lastLevel = leaderLevel;
  4012.  
  4013. if(teamplay) get_team_name(CsTeams:leader,leaderName,9);
  4014. else get_user_name(leader,leaderName,31);
  4015. get_user_name(runnerUp,runnerUpName,31)
  4016. get_user_name(runnerUp3,runnerUp3Name,31)
  4017.  
  4018. set_hudmessage(200,200,200,get_pcvar_float(gg_leader_display_x),get_pcvar_float(gg_leader_display_y),_,_,LEADER_DISPLAY_RATE+0.5,0.0,0.0);
  4019. /*
  4020. if(numLeaders > 1)
  4021. {
  4022. if(teamplay)
  4023. {
  4024. static otherName[10];
  4025. get_team_name((leader == 1) ? CS_TEAM_CT : CS_TEAM_T,otherName,9);
  4026.  
  4027. ShowSyncHudMsg(0,hudSyncLDisplay,"%L: %s + %s (%i - %s)",LANG_PLAYER,"LEADER",leaderName,otherName,leaderLevel,teamLvlWeapon[leader])
  4028. }
  4029. else ShowSyncHudMsg(0,hudSyncLDisplay,"%L: %s +%i (%i - %s)",LANG_PLAYER,"LEADER",leaderName,numLeaders-1,leaderLevel,lvlWeapon[leader]);
  4030. }
  4031. else
  4032. */
  4033. ShowSyncHudMsg(0,hudSyncLDisplay,"1. %s - Level %i (%s)^n 2. %s - Level %i (%s)^n 3. %s - Level %i (%s)",leaderName,leaderLevel,(teamplay) ? teamLvlWeapon[leader] : lvlWeapon[leader],runnerUpName,level[runnerUp],(teamplay) ? teamLvlWeapon[runnerUp] : lvlWeapon[runnerUp],runnerUp3Name,level[runnerUp3],(teamplay) ? teamLvlWeapon[runnerUp3] : lvlWeapon[runnerUp3])
  4034.  
  4035. return 1;
  4036. }
  4037.  
  4038. // show the nice HUD progress display
  4039. show_progress_display(id)
  4040. {
  4041. static statusString[48];
  4042.  
  4043. // weapon-specific warmup
  4044. if(warmup > 0 && warmupWeapon[0]) return;
  4045.  
  4046. new teamplay = get_pcvar_num(gg_teamplay);
  4047.  
  4048. // old-school: sweet and simple
  4049. if((get_pcvar_num(gg_messages) & MSGS_CLASSIC))
  4050. {
  4051. new goal;
  4052. if(teamplay) goal = get_level_goal(teamLevel[_:cs_get_user_team(id)],id);
  4053. else goal = get_level_goal(level[id],id);
  4054.  
  4055. gungame_print(id,0,1,"%L %%n%i%%e :: %%n%s%%e",id,(teamplay) ? "ON_LEVEL_TEAM" : "ON_LEVEL",level[id],lvlWeapon[id]);
  4056. gungame_print(id,0,1,"%L",id,"PROGRESS_DISPLAY",goal-score[id],score[id],goal);
  4057.  
  4058. return;
  4059. }
  4060.  
  4061. if(teamplay)
  4062. {
  4063. new team = _:cs_get_user_team(id), otherTeam = (team == 1) ? 2 : 1;
  4064. if(team != 1 && team != 2) return;
  4065.  
  4066. new leaderLevel, numLeaders, leader = teamplay_get_lead_team(leaderLevel,numLeaders);
  4067.  
  4068. // tied
  4069. if(numLeaders > 1) formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY_TEAM2");
  4070.  
  4071. // leading
  4072. else if(leader == team) formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY_TEAM1",teamLevel[team]-teamLevel[otherTeam]);
  4073.  
  4074. // losing
  4075. else formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY_TEAM3",teamLevel[otherTeam]-teamLevel[team]);
  4076. }
  4077. else
  4078. {
  4079. new leaderLevel, numLeaders, runnerUp;
  4080. new leader = get_leader(leaderLevel,numLeaders,runnerUp);
  4081.  
  4082. if(level[id] == leaderLevel)
  4083. {
  4084. if(numLeaders == 1) formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY1",leaderLevel-level[runnerUp]);
  4085. else if(numLeaders == 2)
  4086. {
  4087. new otherLeader;
  4088. if(leader != id) otherLeader = leader;
  4089. else
  4090. {
  4091. new player;
  4092. for(player=1;player<=maxPlayers;player++)
  4093. {
  4094. if(is_user_connected(player) && level[player] == leaderLevel && player != id)
  4095. {
  4096. otherLeader = player;
  4097. break;
  4098. }
  4099. }
  4100. }
  4101.  
  4102. static otherName[32];
  4103. get_user_name(otherLeader,otherName,31);
  4104.  
  4105. formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY2",otherName);
  4106. }
  4107. else
  4108. {
  4109. static numWord[16], lang[3];
  4110.  
  4111. // if english, use words, otherwise use digits
  4112. get_user_info(id,"lang",lang,2);
  4113. if(equali(lang,"en"))
  4114. {
  4115. num_to_word(numLeaders-1,numWord,15);
  4116. trim(numWord);
  4117. }
  4118. else formatex(numWord,15,"%i",numLeaders-1);
  4119.  
  4120. formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY3",numWord);
  4121. }
  4122. }
  4123. else formatex(statusString,47,"%L",id,"PROGRESS_DISPLAY4",leaderLevel-level[id]);
  4124. }
  4125.  
  4126. gungame_hudmessage(id,5.0,"%L %i (%s)^n%s",id,(teamplay) ? "ON_LEVEL_TEAM" : "ON_LEVEL",level[id],lvlWeapon[id],statusString);
  4127. }
  4128.  
  4129. // play the taken/tied/lost lead sounds
  4130. public play_lead_sounds(id,oldLevel,Float:playDelay)
  4131. {
  4132. // id: the player whose level changed
  4133. // oldLevel: his level before it changed
  4134. // playDelay: how long to wait until we play id's sounds
  4135.  
  4136. if(get_pcvar_num(gg_teamplay))
  4137. {
  4138. // redirect to other function
  4139. teamplay_play_lead_sounds(id,oldLevel,Float:playDelay);
  4140. return;
  4141. }
  4142.  
  4143. // warmup or game over, no one cares
  4144. if(warmup > 0 || won) return;
  4145.  
  4146. // no level change
  4147. if(level[id] == oldLevel) return;
  4148.  
  4149. //
  4150. // monitor MY stuff first
  4151. //
  4152.  
  4153. new leaderLevel, numLeaders;
  4154. get_leader(leaderLevel,numLeaders);
  4155.  
  4156. // I'm now on the leader level
  4157. if(level[id] == leaderLevel)
  4158. {
  4159. // someone else here?
  4160. if(numLeaders > 1)
  4161. {
  4162. new params[2];
  4163. params[0] = id;
  4164. params[1] = gg_sound_tiedlead;
  4165.  
  4166. remove_task(TASK_PLAY_LEAD_SOUNDS+id);
  4167. set_task(playDelay,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+id,params,2);
  4168. }
  4169.  
  4170. // just me, I'm the winner!
  4171. else
  4172. {
  4173. // did I just pass someone?
  4174. if(level[id] > oldLevel && num_players_on_level(oldLevel))
  4175. {
  4176. new params[2];
  4177. params[0] = id;
  4178. params[1] = gg_sound_takenlead;
  4179.  
  4180. remove_task(TASK_PLAY_LEAD_SOUNDS+id);
  4181. set_task(playDelay,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+id,params,2);
  4182. }
  4183. }
  4184. }
  4185.  
  4186. // WAS I on the leader level?
  4187. else if(oldLevel == leaderLevel)
  4188. {
  4189. new params[2];
  4190. params[0] = id;
  4191. params[1] = gg_sound_lostlead;
  4192.  
  4193. remove_task(TASK_PLAY_LEAD_SOUNDS+id);
  4194. set_task(playDelay,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+id,params,2);
  4195.  
  4196. //return; // will not effect other players
  4197. }
  4198.  
  4199. // nothing of importance
  4200. else return; // will not effect other players
  4201.  
  4202. //
  4203. // now monitor other players.
  4204. // if we get this far, id is now in the lead level
  4205. //
  4206.  
  4207. new player;
  4208. for(player=1;player<=maxPlayers;player++)
  4209. {
  4210. if(!is_user_connected(player) || player == id) continue;
  4211.  
  4212. // PLAYER tied with ID
  4213. if(level[player] == level[id])
  4214. {
  4215. // don't tell him if he already got it from another player
  4216. if(num_players_on_level(level[id]) <= 2
  4217. || (oldLevel > level[id] && leaderLevel == level[id])) // dropped into tied position
  4218. {
  4219. new params[2];
  4220. params[0] = player;
  4221. params[1] = gg_sound_tiedlead;
  4222.  
  4223. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  4224. set_task(0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  4225. }
  4226.  
  4227. continue;
  4228. }
  4229.  
  4230. // PLAYER passed by ID
  4231. else if(level[id] > level[player] && level[player] == oldLevel)
  4232. {
  4233. // don't tell him if he already got it from another player
  4234. if(num_players_on_level(level[id]) <= 1)
  4235. {
  4236. new params[2];
  4237. params[0] = player;
  4238. params[1] = gg_sound_lostlead;
  4239.  
  4240. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  4241. set_task(0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  4242. }
  4243.  
  4244. continue;
  4245. }
  4246.  
  4247. // ID passed by PLAYER
  4248. else if(level[player] > level[id] && leaderLevel == level[player])
  4249. {
  4250. // I stand alone!
  4251. if(num_players_on_level(level[player]) <= 1)
  4252. {
  4253. new params[2];
  4254. params[0] = player;
  4255. params[1] = gg_sound_takenlead;
  4256.  
  4257. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  4258. set_task(0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  4259. }
  4260.  
  4261. continue;
  4262. }
  4263. }
  4264. }
  4265.  
  4266. // manage game_player_equip and player_weaponstrip entities
  4267. public manage_equips()
  4268. {
  4269. static classname[20], targetname[24];
  4270. new ent, i, block_equips = get_pcvar_num(gg_block_equips), enabled = ggActive;
  4271.  
  4272. // go through both entities to monitor
  4273. for(i=0;i<4;i++)
  4274. {
  4275. // get classname for current iteration
  4276. switch(i)
  4277. {
  4278. case 0: classname = "game_player_equip";
  4279. case 1: classname = "game_player_equip2";
  4280. case 2: classname = "player_weaponstrip";
  4281. default: classname = "player_weaponstrip2";
  4282. }
  4283.  
  4284. // go through whatever entity
  4285. ent = 0;
  4286. while((ent = fm_find_ent_by_class(ent,classname)))
  4287. {
  4288. // allowed to have this, reverse possible changes
  4289. if(!enabled || !block_equips || (i >= 2 && block_equips < 2)) // player_weaponstrip switch
  4290. {
  4291. pev(ent,pev_targetname,targetname,23);
  4292.  
  4293. // this one was blocked
  4294. if(equal(targetname,"gg_block_equips"))
  4295. {
  4296. pev(ent,TNAME_SAVE,targetname,23);
  4297.  
  4298. set_pev(ent,pev_targetname,targetname);
  4299. set_pev(ent,TNAME_SAVE,"");
  4300.  
  4301. switch(i)
  4302. {
  4303. case 0, 1: set_pev(ent,pev_classname,"game_player_equip");
  4304. default: set_pev(ent,pev_classname,"player_weaponstrip");
  4305. }
  4306. }
  4307. }
  4308.  
  4309. // not allowed to pickup others, make possible changes
  4310. else
  4311. {
  4312. pev(ent,pev_targetname,targetname,23);
  4313.  
  4314. // needs to be blocked, but hasn't been yet
  4315. if(targetname[0] && !equal(targetname,"gg_block_equips"))
  4316. {
  4317. set_pev(ent,TNAME_SAVE,targetname);
  4318. set_pev(ent,pev_targetname,"gg_block_equips");
  4319.  
  4320. // classname change is required sometimes for some reason
  4321. switch(i)
  4322. {
  4323. case 0, 1: set_pev(ent,pev_classname,"game_player_equip2");
  4324. default: set_pev(ent,pev_classname,"player_weaponstrip2");
  4325. }
  4326. }
  4327. }
  4328. }
  4329. }
  4330. }
  4331.  
  4332. // someone respawned
  4333. spawned(id)
  4334. {
  4335. // should be filtered in ham hook
  4336. if(/*!ggActive || !is_user_connected(id) ||*/ !on_valid_team(id))
  4337. return;
  4338.  
  4339. remove_task(TASK_CHECK_DEATHMATCH+id);
  4340.  
  4341. // should be frozen?
  4342. if(won)
  4343. {
  4344. new iterations = get_pcvar_num(gg_map_iterations);
  4345. if(mapIteration < iterations || !iterations)
  4346. {
  4347. // not done yet, just freeze players
  4348. set_pev(id,pev_flags,pev(id,pev_flags) | FL_FROZEN);
  4349. fm_set_user_godmode(id,1);
  4350. }
  4351.  
  4352. // done, make sure HUD is hidden
  4353. emessage_begin(MSG_ALL,gmsgHideWeapon);
  4354. ewrite_byte((1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5)|(1<<6)); // can't use (1<<2) or text disappears
  4355. emessage_end();
  4356.  
  4357. emessage_begin(MSG_ALL,gmsgCrosshair);
  4358. ewrite_byte(0); // hide
  4359. emessage_end();
  4360.  
  4361. return;
  4362. }
  4363.  
  4364. if(get_pcvar_num(gg_pickup_others)) strip_starting_pistols(id);
  4365.  
  4366. afkCheck[id] = 0;
  4367. levelsThisRound[id] = 0;
  4368.  
  4369. // just joined
  4370. if(!level[id])
  4371. {
  4372. new teamplay = get_pcvar_num(gg_teamplay);
  4373.  
  4374. // warming up
  4375. if(warmup > 0 && !teamplay)
  4376. {
  4377. change_level(id,1,1,_,1); // just joined, always score
  4378. }
  4379. else
  4380. {
  4381. // handicap
  4382. new handicapMode = get_pcvar_num(gg_handicap_on);
  4383. if(handicapMode && !teamplay)
  4384. {
  4385. new rcvHandicap = 1;
  4386.  
  4387. // top10 doesn't receive handicap -- also make sure we are using top10
  4388. if(sqlInit && !get_pcvar_num(gg_top10_handicap) && get_pcvar_num(gg_stats_mode))
  4389. {
  4390. static authid[32];
  4391. get_gg_authid(id,authid,31);
  4392.  
  4393. new si = get_gg_si();
  4394. #if defined SQL
  4395. if(!statsPosition[id][si]) statsPosition[id][si] = stats_get_position(id,authid,si);
  4396. if(0 < statsPosition[id][si] && statsPosition[id][si] <= TOP_PLAYERS) rcvHandicap = 0; // I'm in the top10
  4397. #else
  4398. for(new i=0;i<TOP_PLAYERS;i++)
  4399. {
  4400. if(i >= statsSize[si]) continue;
  4401. ArrayGetArray(statsArray,ArrayGetCell(statsPointers[si],i),sfStatsStruct);
  4402.  
  4403. // I'm in top10, don't give me handicap
  4404. if(equal(authid,sfStatsStruct[sdAuthid]))
  4405. {
  4406. rcvHandicap = 0;
  4407. break;
  4408. }
  4409. }
  4410. #endif
  4411. }
  4412.  
  4413. if(rcvHandicap)
  4414. {
  4415. new player;
  4416.  
  4417. // find lowest level (don't use bots unless we have to)
  4418. if(handicapMode == 2)
  4419. {
  4420. new isBot, myLevel, lowestLevel, lowestBotLevel;
  4421. for(player=1;player<=maxPlayers;player++)
  4422. {
  4423. if(!is_user_connected(player) || player == id)
  4424. continue;
  4425.  
  4426. isBot = is_user_bot(player);
  4427. myLevel = level[player];
  4428.  
  4429. if(!myLevel) continue;
  4430.  
  4431. if(!isBot && (!lowestLevel || myLevel < lowestLevel))
  4432. lowestLevel = myLevel;
  4433. else if(isBot && (!lowestBotLevel || myLevel < lowestBotLevel))
  4434. lowestBotLevel = myLevel;
  4435. }
  4436.  
  4437. // CLAMP!
  4438. if(!lowestLevel) lowestLevel = 1;
  4439. if(!lowestBotLevel) lowestBotLevel = 1;
  4440.  
  4441. change_level(id,(lowestLevel > 1) ? lowestLevel : lowestBotLevel,1,_,1); // just joined, always score
  4442. }
  4443.  
  4444. // find average level
  4445. else
  4446. {
  4447. new Float:average, num;
  4448. for(player=1;player<=maxPlayers;player++)
  4449. {
  4450. if(is_user_connected(player) && level[player])
  4451. {
  4452. average += float(level[player]);
  4453. num++;
  4454. }
  4455. }
  4456.  
  4457. average /= float(num);
  4458. change_level(id,(average >= 0.5) ? floatround(average) : 1,1,_,1); // just joined, always score
  4459. }
  4460. }
  4461.  
  4462. // not eligible for handicap (in top10 with gg_top10_handicap disabled)
  4463. else change_level(id,1,1,_,1); // just joined, always score
  4464. }
  4465.  
  4466. // no handicap enabled or playing teamplay
  4467. else
  4468. {
  4469. if(teamplay)
  4470. {
  4471. new team = _:cs_get_user_team(id);
  4472.  
  4473. if(team == 1 || team == 2)
  4474. {
  4475. // my team has a level already
  4476. if(teamLevel[team])
  4477. {
  4478. change_level(id,teamLevel[team],1,_,1,_,0); // just joined, always score, don't effect team
  4479. if(score[id] != teamScore[team]) change_score(id,teamScore[team]-score[id],_,_,0); // don't effect team
  4480. }
  4481.  
  4482. // my team just started
  4483. else
  4484. {
  4485. // initialize its values
  4486. teamplay_update_level(team,1,id);
  4487. teamplay_update_score(team,0,id);
  4488.  
  4489. change_level(id,teamLevel[team],1,_,1,_,0); // just joined, always score, don't effect team
  4490. }
  4491. }
  4492. }
  4493.  
  4494. // solo-play
  4495. else change_level(id,1,1,_,1); // just joined, always score
  4496. }
  4497. }
  4498. }
  4499.  
  4500. // didn't just join
  4501. else
  4502. {
  4503. if(star[id])
  4504. {
  4505. end_star(TASK_END_STAR+id);
  4506. remove_task(TASK_END_STAR+id);
  4507. }
  4508.  
  4509. if(get_pcvar_num(gg_teamplay))
  4510. {
  4511. new team = _:cs_get_user_team(id);
  4512.  
  4513. // my team just started
  4514. if((team == 1 || team == 2) && !teamLevel[team])
  4515. {
  4516. // initialize its values
  4517. teamplay_update_level(team,1,id);
  4518. teamplay_update_score(team,0,id);
  4519.  
  4520. change_level(id,teamLevel[team]-level[id],_,_,1,_,0); // always score, don't effect team
  4521. change_score(id,teamScore[team]-score[id],_,_,0); // don't effect team
  4522. }
  4523. }
  4524.  
  4525. give_level_weapon(id);
  4526. refill_ammo(id);
  4527. }
  4528.  
  4529. // show welcome message
  4530. if(!welcomed[id] && get_pcvar_num(gg_join_msg))
  4531. show_welcome(id);
  4532.  
  4533. // update bomb for DM
  4534. if(cs_get_user_team(id) == CS_TEAM_T && !get_pcvar_num(gg_block_objectives) && get_pcvar_num(gg_dm))
  4535. {
  4536. if(bombStatus[3] == BOMB_PICKEDUP)
  4537. {
  4538. message_begin(MSG_ONE,gmsgBombPickup,_,id);
  4539. message_end();
  4540. }
  4541. else if(bombStatus[0] || bombStatus[1] || bombStatus[2])
  4542. {
  4543. message_begin(MSG_ONE,gmsgBombDrop,_,id);
  4544. write_coord(bombStatus[0]);
  4545. write_coord(bombStatus[1]);
  4546. write_coord(bombStatus[2]);
  4547. write_byte(bombStatus[3]);
  4548. message_end();
  4549. }
  4550. }
  4551.  
  4552. if(get_pcvar_num(gg_disable_money)) hide_money(id);
  4553.  
  4554. // switch to our appropiate weapon, for those without the switch to new weapon option
  4555. if((warmup > 0 && warmupWeapon[0] && equal(warmupWeapon,KNIFE)) || equal(lvlWeapon[id],KNIFE) /* || (get_pcvar_num(gg_knife_elite) && levelsThisRound[id] > 0)*/)
  4556. {
  4557. engclient_cmd(id,WEAPON_KNIFE);
  4558. client_cmd(id,WEAPON_KNIFE);
  4559. }
  4560. else if(get_pcvar_num(gg_nade_glock) && equal(lvlWeapon[id],HEGRENADE))
  4561. {
  4562. engclient_cmd(id,WEAPON_GLOCK18);
  4563. client_cmd(id,WEAPON_GLOCK18);
  4564. }
  4565. else if(lvlWeapon[id][0])
  4566. {
  4567. static wpnName[24];
  4568. formatex(wpnName,23,"weapon_%s",lvlWeapon[id]);
  4569.  
  4570. engclient_cmd(id,wpnName);
  4571. client_cmd(id,wpnName);
  4572. }
  4573.  
  4574. // remember spawn info for AFK protection
  4575. if(get_pcvar_num(gg_afk_protection))
  4576. {
  4577. pev(id,pev_origin,spawnOrigin[id]);
  4578. pev(id,pev_v_angle,spawnAngles[id]);
  4579. afkCheck[id] = 1;
  4580. }
  4581. }
  4582.  
  4583. // player changed his team
  4584. player_teamchange(id,oldTeam,newTeam)
  4585. {
  4586. if(!ggActive) return 0;
  4587.  
  4588. // remember for crazy team switches
  4589. lastTeam[id] = newTeam;
  4590.  
  4591. // allow us to join in on deathmatch
  4592. if(oldTeam == 0 && (newTeam == 1 || newTeam == 2) && !roundEnded && get_pcvar_num(gg_dm) && !task_exists(TASK_CHECK_JOINCLASS+id))
  4593. {
  4594. remove_task(TASK_CHECK_DEATHMATCH+id);
  4595. set_task(5.0,"check_deathmatch",TASK_CHECK_DEATHMATCH+id);
  4596. }
  4597.  
  4598. // keep track of time
  4599. new Float:now = get_gametime();
  4600. if(oldTeam == 1 || oldTeam == 2) teamTimes[id][oldTeam-1] += now - lastSwitch[id];
  4601. lastSwitch[id] = now;
  4602.  
  4603. // we already have a level, set our values to our new team's
  4604. if(level[id] && get_pcvar_num(gg_teamplay) && (newTeam == 1 || newTeam == 2))
  4605. {
  4606. // set them directly
  4607. level[id] = teamLevel[newTeam];
  4608. lvlWeapon[id] = teamLvlWeapon[newTeam];
  4609. score[id] = teamScore[newTeam];
  4610. }
  4611.  
  4612. return 1;
  4613. }
  4614.  
  4615. // restart the round
  4616. public restart_round(delay)
  4617. {
  4618. // clear values
  4619. /*new player;
  4620. for(player=1;player<=maxPlayers;player++)
  4621. {
  4622. if(is_user_connected(player)) clear_values(player,1); // ignore welcome
  4623. }
  4624.  
  4625. // reset teams as well
  4626. clear_team_values(1);
  4627. clear_team_values(2);*/
  4628.  
  4629. if(delay < 1) delay = 1;
  4630.  
  4631. set_cvar_num("sv_restartround",delay);
  4632. set_task(float(delay)-0.1,"clear_all_values");
  4633. }
  4634.  
  4635. // select a random weapon order
  4636. //
  4637. // in cmd_gungame_teamplay we call map_start_cvars which leads to d_rOrder.
  4638. // when called this way we don't want to let it change teamplay or run teamplay
  4639. // configs, so we added the keepTeamplay parameter.
  4640. do_rOrder(keepTeamplay)
  4641. {
  4642. // manage random teamplay
  4643. if(initTeamplayInt == -1)
  4644. {
  4645. get_pcvar_string(gg_teamplay,initTeamplayStr,31);
  4646. initTeamplayInt = str_to_num(initTeamplayStr[0]);
  4647. }
  4648.  
  4649. new amount;
  4650.  
  4651. // if we are allowed to change teamplay, and our initial teamplay value was either a
  4652. // sequence, or it was just 2 (so select one randomly), then sort through it and pick a value
  4653. if(!keepTeamplay && ((amount = str_count(initTeamplayStr,',')+1) > 1 || initTeamplayInt == 2))
  4654. {
  4655. new info[6], rotation[32];
  4656. get_localinfo("gg_tp_iter",info,5);
  4657. copy(rotation,31,initTeamplayStr); // store initTeamplayStr in a variable that we can break apart, so on map end we can set gg_teamplay back to initTeamplayStr
  4658.  
  4659. new iter = str_to_num(info), teamplay;
  4660.  
  4661. if(iter <= 0 || iter > amount)
  4662. {
  4663. iter = 1;
  4664. set_localinfo("gg_tp_iter","1");
  4665. }
  4666.  
  4667. // no rotation, just use the given value
  4668. if(amount <= 1)
  4669. {
  4670. if(iter != 1) set_localinfo("gg_tp_iter","1");
  4671. // initTeamplayInt should still be set to the one we want to use
  4672. }
  4673. else
  4674. {
  4675. for(new i=1;i<=amount;i++)
  4676. {
  4677. if(contain(rotation,",") != -1)
  4678. {
  4679. strtok(rotation,info,5,rotation,31,',');
  4680. if(i == iter) // this is the one we're looking for
  4681. {
  4682. initTeamplayInt = str_to_num(info);
  4683. break;
  4684. }
  4685. }
  4686. else // we've stripped away everything else and are left with the last one, so use it
  4687. {
  4688. initTeamplayInt = str_to_num(rotation);
  4689. break;
  4690. }
  4691. }
  4692.  
  4693. iter++;
  4694. if(iter > amount) iter = 1;
  4695. num_to_str(iter,info,5);
  4696. set_localinfo("gg_tp_iter",info);
  4697. }
  4698.  
  4699. if(initTeamplayInt == 2) teamplay = random_num(0,1);
  4700. else teamplay = initTeamplayInt;
  4701.  
  4702. set_pcvar_num(gg_teamplay,teamplay);
  4703.  
  4704. // re-run config files based on teamplay, don't allow toggling
  4705. exec_gg_config_file(0,0);
  4706. if(teamplay) exec_gg_config_file(1,0);
  4707. }
  4708.  
  4709. new i, maxRandom, cvar[20], weaponOrder[(MAX_WEAPONS*16)+1];
  4710. for(i=1;i<=MAX_WEAPON_ORDERS+1;i++) // +1 so we can detect final
  4711. {
  4712. formatex(cvar,19,"gg_weapon_order%i",i);
  4713. get_cvar_string(cvar,weaponOrder,MAX_WEAPONS*16);
  4714. trim(weaponOrder);
  4715.  
  4716. // found a blank one, stop here
  4717. if(!weaponOrder[0])
  4718. {
  4719. maxRandom = i - 1;
  4720. break;
  4721. }
  4722. }
  4723.  
  4724. // there is just one
  4725. if(maxRandom == 1)
  4726. {
  4727. // get its weapon order and set as current
  4728. formatex(cvar,19,"gg_weapon_order1");
  4729. get_cvar_string(cvar,weaponOrder,MAX_WEAPONS*16);
  4730. set_pcvar_string(gg_weapon_order,weaponOrder);
  4731. return;
  4732. }
  4733.  
  4734. // we found some random ones
  4735. if(maxRandom)
  4736. {
  4737. new randomOrder[30], lastOIstr[6], lastOI, orderAmt;
  4738. get_localinfo("gg_rand_order",randomOrder,29);
  4739. get_localinfo("gg_last_oi",lastOIstr,5);
  4740. lastOI = str_to_num(lastOIstr);
  4741. orderAmt = get_rOrder_amount(randomOrder);
  4742.  
  4743. // no random order yet, or amount of random orders changed
  4744. if(!randomOrder[0] || orderAmt != maxRandom)
  4745. {
  4746. shuffle_rOrder(randomOrder,29,maxRandom);
  4747. lastOI = 0;
  4748. }
  4749.  
  4750. // reached the end, reshuffle while avoiding this one
  4751. else if(get_rOrder_index_val(orderAmt,randomOrder) == get_rOrder_index_val(lastOI,randomOrder))
  4752. {
  4753. shuffle_rOrder(randomOrder,29,maxRandom,lastOI);
  4754. lastOI = 0;
  4755. }
  4756.  
  4757. new choice = get_rOrder_index_val(lastOI+1,randomOrder);
  4758.  
  4759. // get its weapon order
  4760. formatex(cvar,19,"gg_weapon_order%i",choice);
  4761. get_cvar_string(cvar,weaponOrder,MAX_WEAPONS*16);
  4762.  
  4763. // set as current
  4764. set_pcvar_string(gg_weapon_order,weaponOrder);
  4765.  
  4766. // remember for next time
  4767. num_to_str(lastOI+1,lastOIstr,5);
  4768. set_localinfo("gg_last_oi",lastOIstr);
  4769. }
  4770. }
  4771.  
  4772. // get the value of an order index in an order string
  4773. get_rOrder_index_val(index,randomOrder[])
  4774. {
  4775. // only one listed
  4776. if(str_count(randomOrder,',') < 1)
  4777. return str_to_num(randomOrder);
  4778.  
  4779. // find preceding comma
  4780. new search = str_find_num(randomOrder,',',index-1);
  4781.  
  4782. // go until succeeding comma
  4783. new extract[6];
  4784. copyc(extract,5,randomOrder[search+1],',');
  4785.  
  4786. return str_to_num(extract);
  4787. }
  4788.  
  4789. // gets the amount of orders in an order string
  4790. get_rOrder_amount(randomOrder[])
  4791. {
  4792. return str_count(randomOrder,',')+1;
  4793. }
  4794.  
  4795. // shuffle up our random order
  4796. stock shuffle_rOrder(randomOrder[],len,maxRandom,avoid=-1)
  4797. {
  4798. randomOrder[0] = 0;
  4799.  
  4800. // fill up array with order indexes
  4801. new order[MAX_WEAPON_ORDERS], i;
  4802. for(i=0;i<maxRandom;i++) order[i] = i+1;
  4803.  
  4804. // shuffle it
  4805. SortCustom1D(order,maxRandom,"sort_shuffle");
  4806.  
  4807. // avoid a specific number as the starting number
  4808. while(avoid > 0 && order[0] == avoid)
  4809. SortCustom1D(order,maxRandom,"sort_shuffle");
  4810.  
  4811. // get them into a string
  4812. for(i=0;i<maxRandom;i++)
  4813. {
  4814. format(randomOrder,len,"%s%s%i",randomOrder,(i>0) ? "," : "",order[i]);
  4815. set_localinfo("gg_rand_order",randomOrder);
  4816. }
  4817. }
  4818.  
  4819. // play a random win sound
  4820. do_rWinSound()
  4821. {
  4822. // just one, no one cares
  4823. if(numWinSounds <= 1)
  4824. {
  4825. return 0; // 1 minus 1
  4826. }
  4827.  
  4828. new randomOrder[30], lastWSIstr[6], lastWSI, orderAmt;
  4829. get_localinfo("gg_winsound_order",randomOrder,29);
  4830. get_localinfo("gg_last_wsi",lastWSIstr,5);
  4831. lastWSI = str_to_num(lastWSIstr);
  4832. orderAmt = get_rWinSound_amount(randomOrder);
  4833.  
  4834. // no random order yet, or amount of random orders changed
  4835. if(!randomOrder[0] || orderAmt != numWinSounds)
  4836. {
  4837. shuffle_rWinSound(randomOrder,29);
  4838. lastWSI = 0;
  4839. }
  4840.  
  4841. // reached the end, reshuffle while avoiding this one
  4842. else if(get_rWinSound_index_val(orderAmt,randomOrder) == get_rWinSound_index_val(lastWSI,randomOrder))
  4843. {
  4844. shuffle_rWinSound(randomOrder,29,lastWSI);
  4845. lastWSI = 0;
  4846. }
  4847.  
  4848. new choice = get_rWinSound_index_val(lastWSI+1,randomOrder);
  4849.  
  4850. // remember for next time
  4851. num_to_str(lastWSI+1,lastWSIstr,5);
  4852. set_localinfo("gg_last_wsi",lastWSIstr);
  4853.  
  4854. return choice-1;
  4855. }
  4856.  
  4857. // get the value of an order index in an order string
  4858. get_rWinSound_index_val(index,randomOrder[])
  4859. {
  4860. // only one listed
  4861. if(str_count(randomOrder,',') < 1)
  4862. return str_to_num(randomOrder);
  4863.  
  4864. // find preceding comma
  4865. new search = str_find_num(randomOrder,',',index-1);
  4866.  
  4867. // go until succeeding comma
  4868. new extract[6];
  4869. copyc(extract,5,randomOrder[search+1],',');
  4870.  
  4871. return str_to_num(extract);
  4872. }
  4873.  
  4874. // gets the amount of orders in an order string
  4875. get_rWinSound_amount(randomOrder[])
  4876. {
  4877. return str_count(randomOrder,',')+1;
  4878. }
  4879.  
  4880. // shuffle up our random order
  4881. stock shuffle_rWinSound(randomOrder[],len,avoid=-1)
  4882. {
  4883. randomOrder[0] = 0;
  4884.  
  4885. // fill up array with order indexes
  4886. new order[MAX_WINSOUNDS], i;
  4887. for(i=0;i<numWinSounds;i++) order[i] = i+1;
  4888.  
  4889. // shuffle it
  4890. SortCustom1D(order,numWinSounds,"sort_shuffle");
  4891.  
  4892. // avoid a specific number as the starting number
  4893. while(avoid > 0 && order[0] == avoid)
  4894. SortCustom1D(order,numWinSounds,"sort_shuffle");
  4895.  
  4896. // get them into a string
  4897. for(i=0;i<numWinSounds;i++)
  4898. {
  4899. format(randomOrder,len,"%s%s%i",randomOrder,(i>0) ? "," : "",order[i]);
  4900. set_localinfo("gg_winsound_order",randomOrder);
  4901. }
  4902. }
  4903.  
  4904. // shuffle an array
  4905. public sort_shuffle(elem1,elem2)
  4906. {
  4907. return random_num(-1,1);
  4908. }
  4909.  
  4910. // clear all saved values
  4911. clear_values(id,ignoreWelcome=0)
  4912. {
  4913. level[id] = 0;
  4914. levelsThisRound[id] = 0;
  4915. score[id] = 0;
  4916. lvlWeapon[id][0] = 0;
  4917. star[id] = 0;
  4918. if(!ignoreWelcome) welcomed[id] = 0;
  4919. page[id] = 0;
  4920. lastKilled[id] = 0;
  4921. respawn_timeleft[id] = 0;
  4922. silenced[id] = 0;
  4923. spawnSounds[id] = 1;
  4924. spawnProtected[id] = 0;
  4925. teamTimes[id][0] = 0.0;
  4926. teamTimes[id][1] = 0.0;
  4927. lastSwitch[id] = get_gametime();
  4928. lastTeam[id] = 0;
  4929.  
  4930. if(c4planter == id) c4planter = 0;
  4931.  
  4932. remove_task(TASK_RESPAWN+id);
  4933. remove_task(TASK_CHECK_DEATHMATCH+id);
  4934. remove_task(TASK_REMOVE_PROTECTION+id);
  4935.  
  4936. if(is_user_connected(id)) fm_set_rendering(id);
  4937.  
  4938. return 1;
  4939. }
  4940.  
  4941. // clears a TEAM's values
  4942. clear_team_values(team)
  4943. {
  4944. if(team != 1 && team != 2) return;
  4945.  
  4946. teamLevel[team] = 0;
  4947. teamLvlWeapon[team][0] = 0;
  4948. teamScore[team] = 0;
  4949. }
  4950.  
  4951. // possibly start a warmup round
  4952. start_warmup()
  4953. {
  4954. new warmup_value = get_pcvar_num(gg_warmup_timer_setting);
  4955.  
  4956. // warmup is set to -13 after its finished if gg_warmup_multi is 0,
  4957. // so this stops multiple warmups for multiple map iterations
  4958. if(warmup_value > 0 && warmup != -13)
  4959. {
  4960. warmup = warmup_value;
  4961. get_pcvar_string(gg_warmup_weapon,warmupWeapon,23);
  4962. set_task(0.1,"warmup_check",TASK_WARMUP_CHECK);
  4963.  
  4964. // now that warmup is in effect, reset player weapons
  4965. new player;
  4966. for(player=1;player<=maxPlayers;player++)
  4967. {
  4968. if(is_user_connected(player))
  4969. {
  4970. // just joined for all intents and purposes
  4971. change_level(player,-MAX_WEAPONS,1,_,1,0,0); // just joined, always score, don't play sounds, don't effect team
  4972. }
  4973. }
  4974.  
  4975. // a single team update instead of for everyone
  4976. if(get_pcvar_num(gg_teamplay))
  4977. {
  4978. teamplay_update_score(1,0);
  4979. teamplay_update_score(2,0);
  4980. teamplay_update_level(1,1);
  4981. teamplay_update_level(2,1);
  4982. }
  4983.  
  4984. // clear leader display for warmup
  4985. if(warmup > 0) ClearSyncHud(0,hudSyncLDisplay);
  4986. }
  4987. }
  4988.  
  4989. // refresh a player's hegrenade stock
  4990. public refresh_nade(taskid)
  4991. {
  4992. new id = taskid-TASK_REFRESH_NADE;
  4993.  
  4994. // player left, player died, or GunGame turned off
  4995. if(!is_user_connected(id) || !is_user_alive(id) || !ggActive) return;
  4996.  
  4997. // on the grenade level, and lacking that aforementioned thing
  4998. if(equal(lvlWeapon[id],HEGRENADE) && !user_has_weapon(id,CSW_HEGRENADE))
  4999. ham_give_weapon(id,WEAPON_HEGRENADE);
  5000.  
  5001. // get bots to use the grenade (doesn't work very well)
  5002. if(is_user_bot(id))
  5003. {
  5004. engclient_cmd(id,WEAPON_HEGRENADE);
  5005. client_cmd(id,WEAPON_HEGRENADE);
  5006. }
  5007. }
  5008.  
  5009. // refill a player's ammo
  5010. stock refill_ammo(id,current=0)
  5011. {
  5012. if(!is_user_alive(id)) return 0;
  5013.  
  5014. // weapon-specific warmup, no ammo for knives only
  5015. if(warmup > 0 && warmupWeapon[0] && equal(warmupWeapon,KNIFE))
  5016. return 0;
  5017.  
  5018. // get weapon name and index
  5019. static fullName[24], curWpnName[24];
  5020. new wpnid, curWpnMelee, curweapon = get_user_weapon(id);
  5021.  
  5022. // re-init start of strings
  5023. fullName[0] = 0;
  5024. curWpnName[0] = 0;
  5025.  
  5026. // we have a valid current weapon (stupid runtime errors)
  5027. if(curweapon)
  5028. {
  5029. get_weaponname(curweapon,curWpnName,23);
  5030. curWpnMelee = equal(curWpnName,WEAPON_KNIFE);
  5031. }
  5032.  
  5033. // if we are refilling our current weapon instead of our level weapon,
  5034. // we actually have a current weapon, and this isn't a melee weapon or the
  5035. // other alternative, our level weapon, is a melee weapon
  5036. if(current && curweapon && (!curWpnMelee || equal(lvlWeapon[id],KNIFE)))
  5037. {
  5038. // refill our current weapon
  5039. get_weaponname(curweapon,fullName,23);
  5040. wpnid = curweapon;
  5041. }
  5042. else
  5043. {
  5044. // refill our level weapon
  5045. formatex(fullName,23,"weapon_%s",lvlWeapon[id]);
  5046. wpnid = get_weaponid(fullName);
  5047.  
  5048. // so that we know for sure
  5049. current = 0;
  5050. }
  5051.  
  5052. new armor = get_pcvar_num(gg_give_armor), helmet = get_pcvar_num(gg_give_helmet);
  5053.  
  5054. // giving armor and helmets away like candy
  5055. if(helmet) cs_set_user_armor(id,armor,CS_ARMOR_VESTHELM);
  5056. else cs_set_user_armor(id,armor,CS_ARMOR_KEVLAR);
  5057.  
  5058. // didn't find anything valid to refill somehow
  5059. if(wpnid < 1 || wpnid > 30 || !fullName[0])
  5060. return 0;
  5061.  
  5062. // no reason to refill a melee weapon, or a bomb.
  5063. // make use of our curWpnMelee cache here
  5064. if((current && curWpnMelee) || wpnid == CSW_KNIFE || wpnid == CSW_C4)
  5065. return 1;
  5066.  
  5067. new ammo, wEnt;
  5068. ammo = get_pcvar_num(gg_ammo_amount);
  5069.  
  5070. // don't give away hundreds of grenades
  5071. if(wpnid != CSW_HEGRENADE)
  5072. {
  5073. // set clip ammo
  5074. wEnt = get_weapon_ent(id,wpnid);
  5075. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,maxClip[wpnid]);
  5076.  
  5077. // glock on the nade level
  5078. if(wpnid == CSW_GLOCK18 && equal(lvlWeapon[id],HEGRENADE))
  5079. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  5080. else
  5081. {
  5082. // set backpack ammo
  5083. if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  5084. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  5085. }
  5086.  
  5087. // update display if we need to
  5088. if(curweapon == wpnid)
  5089. {
  5090. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  5091. write_byte(1);
  5092. write_byte(wpnid);
  5093. write_byte(maxClip[wpnid]);
  5094. message_end();
  5095. }
  5096. }
  5097.  
  5098. // now do stupid grenade stuff
  5099. else
  5100. {
  5101. // we don't have this nade yet
  5102. if(!user_has_weapon(id,wpnid))
  5103. {
  5104. ham_give_weapon(id,fullName);
  5105. remove_task(TASK_REFRESH_NADE+id);
  5106. }
  5107.  
  5108. if(get_pcvar_num(gg_nade_glock))
  5109. {
  5110. // set clip ammo
  5111. new wEnt = get_weapon_ent(id,CSW_GLOCK18);
  5112. if(pev_valid(wEnt)) cs_set_weapon_ammo(wEnt,20);
  5113.  
  5114. // set backpack ammo
  5115. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  5116.  
  5117. new curweapon = get_user_weapon(id);
  5118.  
  5119. // update display if we need to
  5120. if(curweapon == CSW_GLOCK18)
  5121. {
  5122. message_begin(MSG_ONE,gmsgCurWeapon,_,id);
  5123. write_byte(1);
  5124. write_byte(CSW_GLOCK18);
  5125. write_byte(20);
  5126. message_end();
  5127. }
  5128. }
  5129.  
  5130. if(get_pcvar_num(gg_nade_smoke) && !cs_get_user_bpammo(id,CSW_SMOKEGRENADE))
  5131. ham_give_weapon(id,"weapon_smokegrenade");
  5132.  
  5133. if(get_pcvar_num(gg_nade_flash) && !cs_get_user_bpammo(id,CSW_FLASHBANG))
  5134. ham_give_weapon(id,"weapon_flashbang");
  5135. }
  5136.  
  5137. // keep melee weapon out if we had it out
  5138. if(curweapon && curWpnMelee)
  5139. {
  5140. engclient_cmd(id,curWpnName);
  5141. client_cmd(id,curWpnName);
  5142. }
  5143.  
  5144. return 1;
  5145. }
  5146.  
  5147. // show someone a welcome message
  5148. public show_welcome(id)
  5149. {
  5150. if(welcomed[id]) return;
  5151.  
  5152. new menuid, keys;
  5153. get_user_menu(id,menuid,keys);
  5154.  
  5155. // another old-school menu opened
  5156. if(menuid > 0)
  5157. {
  5158. // wait and try again
  5159. set_task(3.0,"show_welcome",id);
  5160. return;
  5161. }
  5162.  
  5163. play_sound_by_cvar(id,gg_sound_welcome);
  5164.  
  5165. new len = formatex(menuText,511,"\y%L\w^n",id,"WELCOME_MESSAGE_LINE1",GG_VERSION);
  5166. len += formatex(menuText[len],511-len,"\d---------------\w^n");
  5167.  
  5168. new special;
  5169. if(get_pcvar_num(gg_knife_pro))
  5170. {
  5171. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE2");
  5172. special = 1;
  5173. }
  5174. if(get_pcvar_num(gg_turbo))
  5175. {
  5176. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE3");
  5177. special = 1;
  5178. }
  5179. if(get_pcvar_num(gg_knife_elite))
  5180. {
  5181. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE4");
  5182. special = 1;
  5183. }
  5184. if(get_pcvar_num(gg_dm) || get_cvar_num("csdm_active"))
  5185. {
  5186. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE5");
  5187. special = 1;
  5188. }
  5189. if(get_pcvar_num(gg_teamplay))
  5190. {
  5191. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE6");
  5192. special = 1;
  5193. }
  5194.  
  5195. if(special) len += formatex(menuText[len],511-len,"\d---------------\w^n");
  5196. len += formatex(menuText[len],511-len,"%L^n",id,"WELCOME_MESSAGE_LINE7",weaponNum);
  5197. len += formatex(menuText[len],511-len,"\d---------------\w^n");
  5198. len += formatex(menuText[len],511-len,"%L",id,"WELCOME_MESSAGE_LINE8");
  5199. len += formatex(menuText[len],511-len,"\d---------------\w^n");
  5200. len += formatex(menuText[len],511-len,"%L",id,"PRESS_KEY_TO_CONTINUE");
  5201.  
  5202. show_menu(id,1023,menuText,-1,"welcome_menu");
  5203. }
  5204.  
  5205. // show the required kills message
  5206. stock show_required_kills(id,always_individual=0)
  5207. {
  5208. // weapon-specific warmup, who cares
  5209. if(warmup > 0 && warmupWeapon[0]) return 0;
  5210.  
  5211. if(always_individual || !get_pcvar_num(gg_teamplay))
  5212. return gungame_hudmessage(id,3.0,"%L: %i / %i",id,"REQUIRED_KILLS",score[id],get_level_goal(level[id],id));
  5213.  
  5214. new player, myTeam = _:cs_get_user_team(id), goal = get_level_goal(teamLevel[myTeam],id);
  5215. for(player=1;player<=maxPlayers;player++)
  5216. {
  5217. if(player == id || (is_user_connected(player) && _:cs_get_user_team(player) == myTeam))
  5218. gungame_hudmessage(player,3.0,"%L: %i / %i",player,"REQUIRED_KILLS",teamScore[myTeam],goal);
  5219. }
  5220.  
  5221. return 1;
  5222. }
  5223.  
  5224. // player killed himself
  5225. player_suicided(id)
  5226. {
  5227. static name[32];
  5228.  
  5229. // we still have protection (round ended, new one hasn't started yet)
  5230. // or, suicide level downs are disabled
  5231. if(roundEnded || !get_pcvar_num(gg_suicide_penalty)) return 0;
  5232.  
  5233. // weapon-specific warmup, no one cares
  5234. if(warmup > 0 && warmupWeapon[0]) return 0;
  5235.  
  5236. if(!get_pcvar_num(gg_teamplay))
  5237. {
  5238. get_user_name(id,name,31);
  5239.  
  5240. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"SUICIDE_LEVEL_DOWN",name);
  5241.  
  5242. // this is going to start a respawn counter HUD message
  5243. if(get_pcvar_num(gg_dm) && (get_pcvar_num(gg_dm_countdown) & 2))
  5244. return change_level(id,-1,_,0,1); // don't show message, always score
  5245.  
  5246. // show with message
  5247. return change_level(id,-1,_,_,1); // always score
  5248. }
  5249. else
  5250. {
  5251. new team = _:cs_get_user_team(id);
  5252. if(team != 1 && team != 2) return 0;
  5253.  
  5254. new penalty = get_level_goal(teamLevel[team],0);
  5255. if(penalty > 0)
  5256. {
  5257. get_user_team(id,name,9);
  5258.  
  5259. if(teamScore[team] - penalty < 0)
  5260. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"SUICIDE_LEVEL_DOWN_TEAM",name,(teamLevel[team] > 1) ? teamLevel[team]-1 : teamLevel[team]);
  5261. else
  5262. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"SUICIDE_SCORE_DOWN_TEAM",name,penalty);
  5263.  
  5264. return change_score(id,-penalty);
  5265. }
  5266. }
  5267.  
  5268. return 0;
  5269. }
  5270.  
  5271. // player scored or lost a point
  5272. stock change_score(id,value,refill=1,play_sounds=1,effect_team=1,always_score=0)
  5273. {
  5274. // don't bother scoring up on weapon-specific warmup
  5275. if(warmup > 0 && warmupWeapon[0] && value > 0)
  5276. return 0;
  5277.  
  5278. // can't score!
  5279. if(!always_score && !can_score(id))
  5280. return 0;
  5281.  
  5282. // already won, isn't important
  5283. if(level[id] > weaponNum) return 0;
  5284.  
  5285. new oldScore = score[id], goal = get_level_goal(level[id],id);
  5286.  
  5287. new teamplay = get_pcvar_num(gg_teamplay), team;
  5288. if(teamplay) team = _:cs_get_user_team(id);
  5289.  
  5290. // if this is going to level us
  5291. if(score[id] + value >= goal)
  5292. {
  5293. new max_lvl = get_pcvar_num(gg_max_lvl);
  5294.  
  5295. // already reached max levels this round
  5296. if(!teamplay && !get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[id] >= max_lvl)
  5297. {
  5298. // put it as high as we can without leveling
  5299. score[id] = goal - 1;
  5300. }
  5301. else score[id] += value;
  5302. }
  5303. else score[id] += value;
  5304.  
  5305. // check for level up
  5306. if(score[id] >= goal)
  5307. {
  5308. score[id] = 0;
  5309.  
  5310. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5311. teamplay_update_score(team,score[id],id,1); // direct
  5312.  
  5313. change_level(id,1,_,_,always_score,play_sounds);
  5314. return 1;
  5315. }
  5316.  
  5317. // check for level down
  5318. if(score[id] < 0)
  5319. {
  5320. // can't go down below level 1
  5321. if(level[id] <= 1)
  5322. {
  5323. score[id] = 0;
  5324.  
  5325. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5326. teamplay_update_score(team,score[id],id,1); // direct
  5327.  
  5328. new sdisplay = get_pcvar_num(gg_status_display);
  5329. if(sdisplay == STATUS_KILLSLEFT || sdisplay == STATUS_KILLSDONE)
  5330. status_display(id);
  5331.  
  5332. if(value < 0) show_required_kills(id);
  5333. return 0;
  5334. }
  5335. else
  5336. {
  5337. goal = get_level_goal(level[id] > 1 ? level[id]-1 : 1,id);
  5338.  
  5339. score[id] = (oldScore + value) + goal; // carry over points
  5340. if(score[id] < 0) score[id] = 0;
  5341.  
  5342. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5343. teamplay_update_score(team,score[id],id,1); // direct
  5344.  
  5345. change_level(id,-1,_,_,always_score);
  5346. return -1;
  5347. }
  5348. }
  5349.  
  5350. // refresh menus
  5351. new menu;
  5352. get_user_menu(id,menu,dummy[0]);
  5353. if(menu == level_menu) show_level_menu(id);
  5354.  
  5355. if(refill && get_pcvar_num(gg_refill_on_kill)) refill_ammo(id);
  5356.  
  5357. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5358. teamplay_update_score(team,score[id],id,1); // direct
  5359.  
  5360. if(value < 0) show_required_kills(id);
  5361. else if(play_sounds) client_cmd(id,"spk ^"%s^"",KILL_DING_SOUND);
  5362.  
  5363. new sdisplay = get_pcvar_num(gg_status_display);
  5364. if(sdisplay == STATUS_KILLSLEFT || sdisplay == STATUS_KILLSDONE)
  5365. status_display(id);
  5366.  
  5367. return 0;
  5368. }
  5369.  
  5370. // player gained or lost a level
  5371. stock change_level(id,value,just_joined=0,show_message=1,always_score=0,play_sounds=1,effect_team=1)
  5372. {
  5373. // can't score
  5374. if(level[id] > 0 && !always_score && !can_score(id))
  5375. return 0;
  5376.  
  5377. // don't bother leveling up on weapon-specific warmup
  5378. if(level[id] > 0 && warmup > 0 && warmupWeapon[0] && value > 0)
  5379. return 0;
  5380.  
  5381. new oldLevel = level[id], oldValue = value;
  5382.  
  5383. new teamplay = get_pcvar_num(gg_teamplay), team;
  5384. if(teamplay) team = _:cs_get_user_team(id);
  5385.  
  5386. // teamplay, on a valid team
  5387. if(teamplay && (team == 1 || team == 2) && value != -MAX_WEAPONS) // ignore warmup reset
  5388. {
  5389. // not effecting team, but setting me to something that doesn't match team
  5390. // OR
  5391. // effecting team, and not even starting on same thing as team
  5392. if((!effect_team && level[id] + value != teamLevel[team]) || (effect_team && level[id] != teamLevel[team]))
  5393. {
  5394. log_amx("MISSYNCH -- id: %i, value: %i, just_joined: %i, show_message: %i, always_score: %i, play_sounds: %i, effect_team: %i, team: %i, level: %i, teamlevel: %i, usertime: %i, score: %i, teamscore: %i, lvlweapon: %s, teamlvlweapon: %s",
  5395. id,value,just_joined,show_message,always_score,play_sounds,effect_team,team,level[id],teamLevel[team],get_user_time(id,1),score[id],teamScore[team],lvlWeapon[id],teamLvlWeapon[team]);
  5396.  
  5397. log_message("MISSYNCH -- id: %i, value: %i, just_joined: %i, show_message: %i, always_score: %i, play_sounds: %i, effect_team: %i, team: %i, level: %i, teamlevel: %i, usertime: %i, score: %i, teamscore: %i, lvlweapon: %s, teamlvlweapon: %s",
  5398. id,value,just_joined,show_message,always_score,play_sounds,effect_team,team,level[id],teamLevel[team],get_user_time(id,1),score[id],teamScore[team],lvlWeapon[id],teamLvlWeapon[team]);
  5399. }
  5400. }
  5401.  
  5402. // this will put us below level 1
  5403. if(level[id] + value < 1)
  5404. {
  5405. value = 1 - level[id]; // go down only to level 1
  5406.  
  5407. // bottom out the score
  5408. score[id] = 0;
  5409.  
  5410. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5411. teamplay_update_score(team,score[id],id,1); // direct
  5412. }
  5413.  
  5414. // going up
  5415. if(value > 0)
  5416. {
  5417. new max_lvl = get_pcvar_num(gg_max_lvl);
  5418.  
  5419. // already reached max levels for this round
  5420. if(!teamplay && !get_pcvar_num(gg_turbo) && max_lvl > 0 && levelsThisRound[id] >= max_lvl)
  5421. return 0;
  5422. }
  5423.  
  5424. // can't win on the warmup round
  5425. if(level[id] + value > weaponNum && warmup > 0)
  5426. {
  5427. score[id] = get_level_goal(level[id],id) - 1;
  5428.  
  5429. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5430. teamplay_update_score(team,score[id],id,1); // direct
  5431.  
  5432. return 0;
  5433. }
  5434.  
  5435. level[id] += value;
  5436. if(!just_joined) levelsThisRound[id] += value;
  5437.  
  5438. silenced[id] = 0; // for going to Glock->USP, for example
  5439.  
  5440. // win???
  5441. if(level[id] > weaponNum)
  5442. {
  5443. // already won, ignore this
  5444. if(won) return 1;
  5445.  
  5446. // bot, and not allowed to win
  5447. if(is_user_bot(id) && get_pcvar_num(gg_ignore_bots) == 2 && !only_bots())
  5448. {
  5449. change_level(id,-value,just_joined,_,1); // always score
  5450. return 1;
  5451. }
  5452.  
  5453. // cap out score
  5454. score[id] = get_level_goal(level[id],id);
  5455.  
  5456. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5457. teamplay_update_score(team,score[id],id,1); // direct
  5458.  
  5459. if(teamplay && effect_team && (team == 1 || team == 2) && teamLevel[team] != level[id])
  5460. teamplay_update_level(team,level[id],id,1); // direct
  5461.  
  5462. // crown the winner
  5463. win(id,lastKilled[id]);
  5464.  
  5465. return 1;
  5466. }
  5467.  
  5468. // set weapon based on it
  5469. get_level_weapon(level[id],lvlWeapon[id],23);
  5470.  
  5471. // update the status display
  5472. new sdisplay = get_pcvar_num(gg_status_display);
  5473. if(sdisplay == STATUS_LEADERWPN) status_display(0); // to all
  5474. else if(sdisplay) status_display(id); // only to me
  5475.  
  5476. new nade = equal(lvlWeapon[id],HEGRENADE);
  5477.  
  5478. // I'm a leader!
  5479. if(warmup <= 0 && level[get_leader()] == level[id])
  5480. {
  5481. new sound_cvar;
  5482. if(nade) sound_cvar = gg_sound_nade;
  5483. else if(equal(lvlWeapon[id],KNIFE)) sound_cvar = gg_sound_knife;
  5484.  
  5485. if(sound_cvar)
  5486. {
  5487. // only play sound if we reached this level first
  5488. if(num_players_on_level(level[id]) == 1) play_sound_by_cvar(0,sound_cvar);
  5489. }
  5490. }
  5491.  
  5492. // NOW play level up sounds, so that they potentially
  5493. // override the global "Player is on X level" sounds
  5494.  
  5495. if(play_sounds)
  5496. {
  5497. // level up!
  5498. if(oldValue >= 0) play_sound_by_cvar(id,gg_sound_levelup);
  5499.  
  5500. // level down :(
  5501. else play_sound_by_cvar(id,gg_sound_leveldown);
  5502. }
  5503.  
  5504. // remember to modify changes
  5505. new oldTeamLevel;
  5506. if(team == 1 || team == 2) oldTeamLevel = teamLevel[team];
  5507.  
  5508. if(teamplay && effect_team && (team == 1 || team == 2) && teamLevel[team] != level[id])
  5509. teamplay_update_level(team,level[id],id);
  5510.  
  5511. // refresh menus
  5512. new player, menu;
  5513. for(player=1;player<=maxPlayers;player++)
  5514. {
  5515. if(!is_user_connected(player)) continue;
  5516. get_user_menu(player,menu,dummy[0]);
  5517.  
  5518. if(menu == scores_menu) show_scores_menu(player);
  5519. else if(menu == level_menu) show_level_menu(player);
  5520. else if(player == id && menu == weapons_menu) show_weapons_menu(player);
  5521. }
  5522.  
  5523. // make sure we don't have more than required now
  5524. new goal = get_level_goal(level[id],id);
  5525. if(score[id] >= goal)
  5526. {
  5527. score[id] = goal-1; // 1 under
  5528.  
  5529. if(teamplay && effect_team && (team == 1 || team == 2) && teamScore[team] != score[id])
  5530. teamplay_update_score(team,score[id],id,1); // direct
  5531. }
  5532.  
  5533. new turbo = get_pcvar_num(gg_turbo);
  5534.  
  5535. // give weapon right away?
  5536. if((turbo || just_joined) && is_user_alive(id)) give_level_weapon(id);
  5537. else show_progress_display(id); // still show display anyway
  5538.  
  5539. // update the leader display (cvar check done in that function)
  5540. if(!just_joined)
  5541. {
  5542. remove_task(TASK_LEADER_DISPLAY);
  5543. show_leader_display();
  5544.  
  5545. new Float:lead_sounds = get_pcvar_float(gg_lead_sounds);
  5546. if(lead_sounds > 0.0 && (!teamplay || effect_team)) play_lead_sounds(id,oldLevel,lead_sounds);
  5547. }
  5548.  
  5549. new vote_setting = get_pcvar_num(gg_vote_setting), map_iterations = get_pcvar_num(gg_map_iterations);
  5550.  
  5551. // the level to start a map vote on
  5552. if(!voted && warmup <= 0 && vote_setting > 0
  5553. && level[id] >= weaponNum - (vote_setting - 1)
  5554. && mapIteration >= map_iterations && map_iterations > 0)
  5555. {
  5556. new mapCycleFile[64];
  5557. get_gg_mapcycle_file(mapCycleFile,63);
  5558.  
  5559. // start map vote?
  5560. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  5561. {
  5562. voted = 1;
  5563.  
  5564. // check for a custom vote
  5565. new custom[256];
  5566. get_pcvar_string(gg_vote_custom,custom,255);
  5567.  
  5568. if(custom[0]) server_cmd(custom);
  5569. else start_mapvote();
  5570. }
  5571. }
  5572.  
  5573. // grab my name
  5574. static name[32];
  5575. if(!teamplay) get_user_name(id,name,31);
  5576.  
  5577. // only calculate position if we didn't just join
  5578. if(!just_joined && show_message)
  5579. {
  5580. if(teamplay)
  5581. {
  5582. // is the first call for this level change
  5583. if((team == 1 || team == 2) && teamLevel[team] != oldTeamLevel)
  5584. {
  5585. new leaderLevel, numLeaders, leader = teamplay_get_lead_team(leaderLevel,numLeaders);
  5586.  
  5587. // tied
  5588. if(numLeaders > 1) gungame_print(0,id,1,"%L",LANG_PLAYER_C,"TIED_LEADER_TEAM",leaderLevel,teamLvlWeapon[team]);
  5589.  
  5590. // leading
  5591. else if(leader == team)
  5592. {
  5593. get_user_team(id,name,9);
  5594. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"LEADING_ON_LEVEL_TEAM",name,leaderLevel,teamLvlWeapon[team]);
  5595. }
  5596.  
  5597. // trailing
  5598. else
  5599. {
  5600. get_user_team(id,name,9);
  5601. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"TRAILING_ON_LEVEL_TEAM",name,teamLevel[team],teamLvlWeapon[team]);
  5602. }
  5603. }
  5604. }
  5605. else
  5606. {
  5607. new leaderLevel, numLeaders, leader = get_leader(leaderLevel,numLeaders);
  5608.  
  5609. // tied
  5610. if(level[id] == leaderLevel && numLeaders > 1 && level[id] > 1)
  5611. {
  5612. if(numLeaders == 2)
  5613. {
  5614. new otherLeader;
  5615. if(leader != id) otherLeader = leader;
  5616. else
  5617. {
  5618. new player;
  5619. for(player=1;player<=maxPlayers;player++)
  5620. {
  5621. if(is_user_connected(player) && level[player] == leaderLevel && player != id)
  5622. {
  5623. otherLeader = player;
  5624. break;
  5625. }
  5626. }
  5627. }
  5628.  
  5629. static otherName[32];
  5630. get_user_name(otherLeader,otherName,31);
  5631.  
  5632. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"TIED_LEADER_ONE",name,leaderLevel,lvlWeapon[id],otherName);
  5633. }
  5634. else
  5635. {
  5636. static numWord[16], digiWord[3], lang[3];
  5637. num_to_word(numLeaders-1,numWord,15);
  5638. trim(numWord);
  5639. formatex(digiWord,2,"%i",numLeaders-1);
  5640.  
  5641. new player;
  5642. for(player=1;player<=maxPlayers;player++)
  5643. {
  5644. if(is_user_connected(player))
  5645. {
  5646. // use word for english, digit otherwise
  5647. get_user_info(player,"lang",lang,2);
  5648. gungame_print(player,id,1,"%L",player,"TIED_LEADER_MULTI",name,leaderLevel,lvlWeapon[id],equali(lang,"en") ? numWord : digiWord);
  5649. }
  5650. }
  5651. }
  5652. }
  5653.  
  5654. // I'M THE BEST!!!!!!!
  5655. else if(leader == id && level[id] > 1)
  5656. {
  5657. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"LEADING_ON_LEVEL",name,level[id],lvlWeapon[id]);
  5658. }
  5659. }
  5660. }
  5661.  
  5662. // teamplay, didn't grab name yet
  5663. if(teamplay) get_user_name(id,name,31);
  5664.  
  5665. // triple bonus!
  5666. if(levelsThisRound[id] == 3)
  5667. {
  5668. new triple_on = get_pcvar_num(gg_triple_on);
  5669.  
  5670. if(triple_on == 2 || (triple_on && !turbo))
  5671. {
  5672. star[id] = 1;
  5673.  
  5674. new sound[64];
  5675. get_pcvar_string(gg_sound_triple,sound,63);
  5676.  
  5677. fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)*1.5);
  5678.  
  5679. if(sound[0]) engfunc(EngFunc_EmitSound,id,CHAN_VOICE,sound[6],VOL_NORM,ATTN_NORM,0,PITCH_NORM); // ignore sound/ prefix
  5680. else engfunc(EngFunc_EmitSound,id,CHAN_VOICE,sound,VOL_NORM,ATTN_NORM,0,PITCH_NORM);
  5681.  
  5682. set_pev(id,pev_effects,pev(id,pev_effects) | EF_BRIGHTLIGHT);
  5683. fm_set_rendering(id,kRenderFxGlowShell,255,255,100,kRenderNormal,1);
  5684. fm_set_user_godmode(id,1);
  5685.  
  5686. message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
  5687. write_byte(22); // TE_BEAMFOLLOW
  5688. write_short(id); // entity
  5689. write_short(trailSpr); // sprite
  5690. write_byte(20); // life
  5691. write_byte(10); // width
  5692. write_byte(255); // r
  5693. write_byte(255); // g
  5694. write_byte(100); // b
  5695. write_byte(100); // brightness
  5696. message_end();
  5697.  
  5698. gungame_print(0,id,1,"%L",LANG_PLAYER_C,"TRIPLE_LEVELED",name);
  5699. set_task(10.0,"end_star",TASK_END_STAR+id);
  5700. }
  5701. }
  5702.  
  5703. new ff_auto = get_pcvar_num(gg_ff_auto), ff = get_pcvar_num(mp_friendlyfire);
  5704.  
  5705. // turn on FF?
  5706. if(ff_auto && !ff && nade)
  5707. {
  5708. server_cmd("mp_friendlyfire 1"); // so console is notified
  5709. set_pcvar_num(mp_friendlyfire,1); // so it changes instantly
  5710.  
  5711. gungame_print(0,0,1,"%L",LANG_PLAYER_C,"FRIENDLYFIRE_ON");
  5712.  
  5713. client_cmd(0,"spk ^"%s^"",BRASS_BELL_SOUND);
  5714. }
  5715.  
  5716. // turn off FF?
  5717. else if(ff_auto && ff)
  5718. {
  5719. new keepFF, player;
  5720.  
  5721. for(player=1;player<=maxPlayers;player++)
  5722. {
  5723. if(equal(lvlWeapon[player],HEGRENADE) || equal(lvlWeapon[player],KNIFE))
  5724. {
  5725. keepFF = 1;
  5726. break;
  5727. }
  5728. }
  5729.  
  5730. // no one is on nade or knife level anymore
  5731. if(!keepFF)
  5732. {
  5733. server_cmd("mp_friendlyfire 0"); // so console is notified
  5734. set_pcvar_num(mp_friendlyfire,0); // so it changes instantly
  5735. }
  5736. }
  5737.  
  5738. // some bots are actually allergic to the chemicals used in HE grenades
  5739. if(is_user_bot(id) && get_pcvar_num(gg_bots_skipnade) && !get_pcvar_num(gg_teamplay) && equal(lvlWeapon[id],HEGRENADE))
  5740. change_level(id,1);
  5741.  
  5742. return 1;
  5743. }
  5744.  
  5745. // forces a player to a level, skipping a lot of important stuff.
  5746. // it's assumed that this is used as a result of "id" being leveled
  5747. // up because his teammate leveled up in teamplay.
  5748. stock set_level_noifandsorbuts(id,newLevel,play_sounds=1)
  5749. {
  5750. // okay, this is our only but
  5751. if(!is_user_connected(id)) return 0;
  5752.  
  5753. new oldLevel = level[id];
  5754.  
  5755. level[id] = newLevel;
  5756. get_level_weapon(level[id],lvlWeapon[id],23);
  5757.  
  5758. if(play_sounds)
  5759. {
  5760. // level up!
  5761. if(newLevel >= oldLevel) play_sound_by_cvar(id,gg_sound_levelup);
  5762.  
  5763. // level down :(
  5764. else play_sound_by_cvar(id,gg_sound_leveldown);
  5765. }
  5766.  
  5767. // refresh menus
  5768. new player, menu;
  5769. for(player=1;player<=maxPlayers;player++)
  5770. {
  5771. if(!is_user_connected(player)) continue;
  5772. get_user_menu(player,menu,dummy[0]);
  5773.  
  5774. if(menu == scores_menu) show_scores_menu(player);
  5775. else if(menu == level_menu) show_level_menu(player);
  5776. }
  5777.  
  5778. // give weapon right away?
  5779. if(get_pcvar_num(gg_turbo) && is_user_alive(id)) give_level_weapon(id);
  5780. else show_progress_display(id); // still show display anyway
  5781.  
  5782. return 1;
  5783. }
  5784.  
  5785. // get rid of a player's star
  5786. public end_star(taskid)
  5787. {
  5788. new id = taskid - TASK_END_STAR;
  5789. if(!star[id]) return;
  5790.  
  5791. star[id] = 0;
  5792. //gungame_print(id,0,1,"Your star has run out!");
  5793.  
  5794. if(is_user_alive(id))
  5795. {
  5796. fm_set_user_maxspeed(id,fm_get_user_maxspeed(id)/1.5);
  5797. engfunc(EngFunc_EmitSound,id,CHAN_VOICE,"common/null.wav",VOL_NORM,ATTN_NORM,0,PITCH_NORM); // stop sound
  5798. set_pev(id,pev_effects,pev(id,pev_effects) & ~EF_BRIGHTLIGHT);
  5799. fm_set_rendering(id);
  5800. fm_set_user_godmode(id,0);
  5801.  
  5802. message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
  5803. write_byte(99); // TE_KILLBEAM
  5804. write_short(id); // entity
  5805. message_end();
  5806. }
  5807. }
  5808.  
  5809. // give a player a weapon based on his level
  5810. stock give_level_weapon(id,notify=1,verify=1)
  5811. {
  5812. if(!is_user_alive(id) || level[id] <= 0) return 0;
  5813.  
  5814. // not warming up, didn't just win
  5815. if(notify && warmup <= 0 && level[id] > 0 && level[id] <= weaponNum)
  5816. show_progress_display(id);
  5817.  
  5818. // stop attacks from bleeding over into the new weapon
  5819. //client_cmd(id,"-attack;-attack2");
  5820.  
  5821. // give CTs defuse kits on bomb maps
  5822. if(bombMap && !get_pcvar_num(gg_block_objectives) && cs_get_user_team(id) == CS_TEAM_CT)
  5823. cs_set_user_defuse(id,1);
  5824.  
  5825. new armor = get_pcvar_num(gg_give_armor), helmet = get_pcvar_num(gg_give_helmet);
  5826.  
  5827. // giving armor and helmets away like candy
  5828. if(helmet) cs_set_user_armor(id,armor,CS_ARMOR_VESTHELM);
  5829. else cs_set_user_armor(id,armor,CS_ARMOR_KEVLAR);
  5830.  
  5831. new oldWeapon = get_user_weapon(id);
  5832.  
  5833. static wpnName[24];
  5834. new weapons = pev(id,pev_weapons), wpnid, alright, myCategory, hasMain;
  5835.  
  5836. new ammo = get_pcvar_num(gg_ammo_amount),
  5837. knife_elite = get_pcvar_num(gg_knife_elite),
  5838. pickup_others = (get_pcvar_num(gg_pickup_others) && (!knife_elite || !levelsThisRound[id])),
  5839. mainCategory = get_weapon_category(_,lvlWeapon[id]);
  5840.  
  5841. new hasGlock, hasSmoke, hasFlash,
  5842. nade_level = (equal(lvlWeapon[id],HEGRENADE)),
  5843. nade_glock = get_pcvar_num(gg_nade_glock),
  5844. nade_smoke = get_pcvar_num(gg_nade_smoke),
  5845. nade_flash = get_pcvar_num(gg_nade_flash);
  5846.  
  5847. new melee_only = ((warmup > 0 && warmupWeapon[0] && equal(warmupWeapon,KNIFE)) || (knife_elite && levelsThisRound[id] > 0));
  5848.  
  5849. // remove stuff first
  5850. for(wpnid=1;wpnid<31;wpnid++)
  5851. {
  5852. // don't have this, or it's the C4
  5853. if(!(weapons & (1<<wpnid)) || wpnid == CSW_C4) continue;
  5854.  
  5855. alright = 0;
  5856. get_weaponname(wpnid,wpnName,23);
  5857.  
  5858. if(melee_only)
  5859. {
  5860. if(wpnid == CSW_KNIFE)
  5861. {
  5862. alright = 1;
  5863. hasMain = 1;
  5864. }
  5865. }
  5866. else
  5867. {
  5868. replace(wpnName,23,"weapon_","");
  5869.  
  5870. // this is our designated weapon
  5871. if(equal(lvlWeapon[id],wpnName))
  5872. {
  5873. alright = 1;
  5874. hasMain = 1;
  5875. }
  5876.  
  5877. // nade extras
  5878. else if(nade_level)
  5879. {
  5880. if(nade_glock && wpnid == CSW_GLOCK18)
  5881. {
  5882. alright = 1;
  5883. hasGlock = 1;
  5884. }
  5885. else if(nade_smoke && wpnid == CSW_SMOKEGRENADE)
  5886. {
  5887. alright = 1;
  5888. hasSmoke = 1;
  5889. }
  5890. else if(nade_flash && wpnid == CSW_FLASHBANG)
  5891. {
  5892. alright = 1;
  5893. hasFlash = 1;
  5894. }
  5895. }
  5896.  
  5897. // get the tag back on there
  5898. format(wpnName,23,"weapon_%s",wpnName);
  5899. }
  5900.  
  5901. // don't do anything about the knife
  5902. if(wpnid != CSW_KNIFE)
  5903. {
  5904. // was it alright?
  5905. if(alright)
  5906. {
  5907. // reset ammo
  5908. if(wpnid != CSW_HEGRENADE && wpnid != CSW_FLASHBANG && wpnid != CSW_SMOKEGRENADE)
  5909. {
  5910. if(nade_level && nade_glock && wpnid == CSW_GLOCK18)
  5911. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  5912. else
  5913. {
  5914. if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  5915. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  5916. }
  5917. }
  5918. else cs_set_user_bpammo(id,wpnid,1); // grenades
  5919. }
  5920.  
  5921. // we should probably remove this weapon
  5922. else
  5923. {
  5924. myCategory = get_weapon_category(wpnid);
  5925.  
  5926. // pistol in the way of glock, remove it
  5927. if(nade_level && nade_glock && myCategory == 2) ham_strip_weapon(id,wpnName);
  5928. else
  5929. {
  5930. // we aren't allowed to have any other weapons,
  5931. // or this is in the way of the weapon that I want.
  5932. if(!pickup_others || myCategory == mainCategory)
  5933. ham_strip_weapon(id,wpnName);
  5934. }
  5935. }/*not alright*/
  5936. }/*not a knife*/
  5937. }/*wpnid for-loop*/
  5938.  
  5939. // I should have a weapon but don't
  5940. if(lvlWeapon[id][0] && !hasMain)
  5941. {
  5942. formatex(wpnName,23,"weapon_%s",lvlWeapon[id]);
  5943.  
  5944. // give a player his weapon
  5945. ham_give_weapon(id,wpnName);
  5946.  
  5947. remove_task(TASK_REFRESH_NADE+id);
  5948.  
  5949. if(!equal(lvlWeapon[id],HEGRENADE) && !equal(lvlWeapon[id],KNIFE))
  5950. {
  5951. wpnid = get_weaponid(wpnName);
  5952.  
  5953. if(!wpnid) log_amx("INVALID WEAPON ID FOR ^"%s^"",lvlWeapon[id]);
  5954. else
  5955. {
  5956. if(ammo > 0) cs_set_user_bpammo(id,wpnid,ammo);
  5957. else cs_set_user_bpammo(id,wpnid,maxAmmo[wpnid]);
  5958. }
  5959. }
  5960. }
  5961.  
  5962. if(nade_level)
  5963. {
  5964. if(nade_glock && !hasGlock)
  5965. {
  5966. ham_give_weapon(id,WEAPON_GLOCK18);
  5967. cs_set_user_bpammo(id,CSW_GLOCK18,50);
  5968. }
  5969. if(nade_smoke && !hasSmoke) ham_give_weapon(id,"weapon_smokegrenade");
  5970. if(nade_flash && !hasFlash) ham_give_weapon(id,"weapon_flashbang");
  5971. }
  5972.  
  5973. new weapon = get_user_weapon(id);
  5974.  
  5975. // using a knife probably
  5976. if(melee_only || equal(lvlWeapon[id],KNIFE))
  5977. {
  5978. // draw knife on knife warmup and knife level... this is so that
  5979. // the terrorist that spawns with the C4 won't be spawned with his
  5980. // C4 selected, but instead his knife
  5981. engclient_cmd(id,WEAPON_KNIFE);
  5982. client_cmd(id,WEAPON_KNIFE);
  5983. }
  5984.  
  5985. // switch back to knife if we had it out. also don't do this when called
  5986. // by the verification check, because their old weapon will obviously be
  5987. // a knife and they will want to use their new one.
  5988. else if(verify /*&& !notify*/ && oldWeapon)
  5989. {
  5990. get_weaponname(oldWeapon,wpnName,23);
  5991. if(wpnName[0] && equal(wpnName,WEAPON_KNIFE))
  5992. {
  5993. engclient_cmd(id,wpnName);
  5994. client_cmd(id,wpnName);
  5995. }
  5996. else if(lvlWeapon[id][0])
  5997. {
  5998. formatex(wpnName,23,"weapon_%s",lvlWeapon[id]);
  5999. engclient_cmd(id,wpnName);
  6000. client_cmd(id,wpnName);
  6001. }
  6002. }
  6003.  
  6004. // switch to glock for nade level
  6005. else if(weapon != CSW_KNIFE && equal(lvlWeapon[id],HEGRENADE) && nade_glock)
  6006. {
  6007. engclient_cmd(id,WEAPON_GLOCK18);
  6008. client_cmd(id,WEAPON_GLOCK18);
  6009. }
  6010.  
  6011. // otherwise, switch to our new weapon
  6012. else if(lvlWeapon[id][0])
  6013. {
  6014. formatex(wpnName,23,"weapon_%s",lvlWeapon[id]);
  6015. engclient_cmd(id,wpnName);
  6016. client_cmd(id,wpnName);
  6017. }
  6018.  
  6019. // make sure that we get this...
  6020. if(verify)
  6021. {
  6022. remove_task(TASK_VERIFY_WEAPON+id);
  6023. set_task(1.0,"verify_weapon",TASK_VERIFY_WEAPON+id);
  6024. }
  6025.  
  6026. // remember burst or silenced status
  6027. if(silenced[id])
  6028. {
  6029. if(equal(lvlWeapon[id],"usp") || equal(lvlWeapon[id],"m4a1"))
  6030. {
  6031. new wEnt = get_weapon_ent(id,_,lvlWeapon[id]);
  6032. if(pev_valid(wEnt))
  6033. {
  6034. cs_set_weapon_silen(wEnt,1,0);
  6035.  
  6036. // play draw with silencer animation
  6037. if(lvlWeapon[id][0] == 'u') set_pev(id,pev_weaponanim,USP_DRAWANIM);
  6038. else set_pev(id,pev_weaponanim,M4A1_DRAWANIM);
  6039. }
  6040. }
  6041. else if(equal(lvlWeapon[id],"glock18") || equal(lvlWeapon[id],"famas"))
  6042. {
  6043. new wEnt = get_weapon_ent(id,_,lvlWeapon[id]);
  6044. if(pev_valid(wEnt)) cs_set_weapon_burst(wEnt,1);
  6045. }
  6046.  
  6047. silenced[id] = 0;
  6048. }
  6049.  
  6050. return 1;
  6051. }
  6052.  
  6053. // verify that we have our stupid weapon
  6054. public verify_weapon(taskid)
  6055. {
  6056. new id = taskid-TASK_VERIFY_WEAPON;
  6057.  
  6058. if(!is_user_alive(id)) return;
  6059.  
  6060. static wpnName[24];
  6061. formatex(wpnName,23,"weapon_%s",lvlWeapon[id]);
  6062. new wpnid = get_weaponid(wpnName);
  6063.  
  6064. if(!wpnid) return;
  6065.  
  6066. // we don't have it, but we want it
  6067. if(!user_has_weapon(id,wpnid)) give_level_weapon(id,0,0);
  6068. }
  6069.  
  6070. // crown a winner
  6071. win(winner,loser)
  6072. {
  6073. // we have an invalid winner here
  6074. if(won || !is_user_connected(winner) || !can_score(winner))
  6075. return;
  6076.  
  6077. won = 1;
  6078. roundEnded = 1;
  6079.  
  6080. server_cmd("sv_alltalk 1");
  6081. client_cmd(0,"stopsound;speak null;mp3 stop");
  6082. play_sound(0,winSounds[currentWinSound]);
  6083.  
  6084. new map_iterations = get_pcvar_num(gg_map_iterations), restart,
  6085. player, Float:chattime = get_cvar_float("mp_chattime");
  6086.  
  6087. // final playthrough, get ready for next map
  6088. if(mapIteration >= map_iterations && map_iterations > 0)
  6089. {
  6090. set_nextmap();
  6091. set_task(floatmax(chattime,2.5),"goto_nextmap");
  6092.  
  6093. // as of GG1.16, we always send a non-emessage intermission, because
  6094. // other map changing plugins (as well as StatsMe) intercepting it
  6095. // was causing problems.
  6096.  
  6097. // as of GG1.20, we no longer do this because it closes the MOTD.
  6098.  
  6099. // as of GG2.10, we use finale, which freezes players like the
  6100. // intermission but doesn't otherwise do any intermission stuff.
  6101. message_begin(MSG_ALL,SVC_FINALE);
  6102. write_string(""); // although you could put a nice typewrite-style centersay here
  6103. message_end();
  6104.  
  6105. // godmode everyone
  6106. new fullName[32];
  6107. for(player=1;player<=maxPlayers;player++)
  6108. {
  6109. if(!is_user_alive(player)) continue;
  6110.  
  6111. // finale won't stop players from shooting technically
  6112. formatex(fullName,31,"weapon_%s",lvlWeapon[player]);
  6113. ham_strip_weapon(player,fullName);
  6114.  
  6115. fm_set_user_godmode(player,1);
  6116. }
  6117. }
  6118.  
  6119. // get ready to go again!!
  6120. else
  6121. {
  6122. restart = 1;
  6123.  
  6124. // freeze and godmode everyone
  6125. for(player=1;player<=maxPlayers;player++)
  6126. {
  6127. if(!is_user_connected(player)) continue;
  6128.  
  6129. client_cmd(player,"-attack;-attack2");
  6130. set_pev(player,pev_flags,pev(player,pev_flags) | FL_FROZEN);
  6131. fm_set_user_godmode(player,1);
  6132. set_pev(player,pev_viewmodel2,"");
  6133. }
  6134. }
  6135.  
  6136. emessage_begin(MSG_ALL,gmsgHideWeapon);
  6137. ewrite_byte((1<<0)|(1<<1)|(1<<3)|(1<<4)|(1<<5)|(1<<6)); // can't use (1<<2) or text disappears
  6138. emessage_end();
  6139.  
  6140. emessage_begin(MSG_ALL,gmsgCrosshair);
  6141. ewrite_byte(0); // hide
  6142. emessage_end();
  6143.  
  6144. new winnerName[32], i, teamplay = get_pcvar_num(gg_teamplay);
  6145. if(teamplay) get_user_team(winner,winnerName,9);
  6146. else get_user_name(winner,winnerName,31);
  6147.  
  6148. // old-fashioned
  6149. for(i=0;i<5;i++)
  6150. {
  6151. if(teamplay) gungame_print(0,winner,1,"%L!!",LANG_PLAYER_C,"WON_TEAM",winnerName);
  6152. else gungame_print(0,winner,1,"%L!",LANG_PLAYER_C,"WON",winnerName);
  6153. }
  6154.  
  6155. // our new super function
  6156. stats_award_points(winner);
  6157.  
  6158. // finally show it off
  6159. new winner_motd[64];
  6160. get_pcvar_string(gg_winner_motd,winner_motd,63);
  6161. if(winner_motd[0] && winner_motd[0] != '0')
  6162. {
  6163. new params[66];
  6164. params[0] = winner;
  6165. params[1] = loser;
  6166. copy(params[2],63,winner_motd);
  6167. set_task(1.0,"show_win_screen",_,params,65);
  6168. }
  6169.  
  6170. // we can restart now (do it after calculations because points might get reset)
  6171. if(restart)
  6172. {
  6173. // delay it, because it will reset stuff
  6174. set_task(1.1,"restart_round",floatround(chattime-1.1));
  6175.  
  6176. set_task(floatmax(chattime-0.1,1.2),"restart_gungame",czero ? get_cvar_num("bot_stop") : 0);
  6177. set_task(floatmax(chattime+5.0,0.1),"stop_win_sound",currentWinSound);
  6178.  
  6179. if(czero) server_cmd("bot_stop 1"); // freeze CZ bots
  6180. }
  6181. }
  6182.  
  6183. // restart gungame, for the next map iteration
  6184. public restart_gungame(old_bot_stop_value)
  6185. {
  6186. won = 0;
  6187. mapIteration++;
  6188.  
  6189. /*new i;
  6190. for(i=0;i<sizeof teamLevel;i++)
  6191. clear_team_values(i);*/
  6192.  
  6193. // game already commenced, but we are restarting, allow us to warmup again
  6194. if(gameCommenced) shouldWarmup = 1;
  6195.  
  6196. stats_clear_all(); // clear out everything about our stats
  6197.  
  6198. toggle_gungame(TASK_TOGGLE_GUNGAME + TOGGLE_ENABLE); // reset stuff
  6199.  
  6200. // toggle_gungame calls map_start_cvars which calls do_rOrder, so we theoretically don't need to do it again here
  6201. //do_rOrder(0); // also does random teamplay
  6202.  
  6203. setup_weapon_order();
  6204. currentWinSound = do_rWinSound(); // pick the next win sound
  6205.  
  6206. // unfreeze and ungodmode everyone
  6207. for(new player=1;player<=maxPlayers;player++)
  6208. {
  6209. if(!is_user_connected(player)) continue;
  6210.  
  6211. set_pev(player,pev_flags,pev(player,pev_flags) & ~FL_FROZEN);
  6212. fm_set_user_godmode(player,0);
  6213. welcomed[player] = 1; // also don't show welcome again
  6214. }
  6215. if(czero) server_cmd("bot_stop %i",old_bot_stop_value); // unfreeze CZ bots
  6216.  
  6217. // only have warmup once?
  6218. if(!get_pcvar_num(gg_warmup_multi)) warmup = -13; // -13 is the magical stop number
  6219. else warmup = -1; // -1 isn't magical at all... :(
  6220.  
  6221. warmupWeapon[0] = 0;
  6222. }
  6223.  
  6224. // stop the winner sound (for multiple map iterations)
  6225. public stop_win_sound(winSound)
  6226. {
  6227. // stop winning sound
  6228. if(containi(winSounds[winSound],".mp3") != -1) client_cmd(0,"mp3 stop");
  6229. else client_cmd(0,"speak null");
  6230. }
  6231.  
  6232. // calculate the winner screen... severely cut down from before
  6233. public show_win_screen(params[66]) // [winner,loser,gg_win_motd[64]]
  6234. {
  6235. new winner = params[0], loser = params[1];
  6236. if(!is_user_connected(winner)) return 0;
  6237.  
  6238. new winner_motd[64];
  6239. copy(winner_motd,63,params[2]);
  6240.  
  6241. new motd[1536], len, header[32];
  6242.  
  6243. new teamplay = get_pcvar_num(gg_teamplay), stats_mode = get_pcvar_num(gg_stats_mode), stats_split = get_pcvar_num(gg_stats_split),
  6244. timeratio = get_pcvar_num(gg_teamplay_timeratio), iterations = get_pcvar_num(gg_map_iterations), roundsleft = iterations - mapIteration, nextmap[32],
  6245. loserDC = !is_user_connected(loser);
  6246.  
  6247. get_cvar_string("amx_nextmap",nextmap,31);
  6248.  
  6249. new winnerTeam[10], winnerName[32], winnerColor[8], winnerWinSuffix[3], winnerStreakSuffix[3], streakChampColor[8], myStreakSuffix[3],
  6250. winningTeam = _:cs_get_user_team(winner), losingTeam = _:(!(winningTeam-1)) + 1;
  6251.  
  6252. #if defined SQL
  6253. // abort if showing web page but could not initialize SQL
  6254. if(!isdigit(winner_motd[0]) && !sqlInit)
  6255. {
  6256. return 0;
  6257. }
  6258.  
  6259. // if web page or set to 2, update database
  6260. if((!isdigit(winner_motd[0]) || winner_motd[0] == '2') && sqlInit)
  6261. {
  6262. new systime = get_systime(), player, playerAuthid[32], playerName[32], playerSafeAuthid[64], playerSafeName[64], si = get_gg_si(), flags, team,
  6263. origLen = len = formatex(motd,1535,"DELETE FROM `%s`; INSERT INTO `%s` VALUES ('0','','%s','%i','%i','','%i','%i','%i','%i','%i','%i','%i','%i','%i','%i','%s'),",sqlPlayersTable,sqlPlayersTable,nextmap,stats_mode,stats_split,teamplay,timeratio,winner,loser,loserDC,winningTeam,losingTeam,iterations,roundsleft,systime,serverip);
  6264.  
  6265. for(player=1;player<=maxPlayers;player++)
  6266. {
  6267. if(!is_user_connected(player)) continue;
  6268.  
  6269. if(len >= 1200) // getting too close for comfort, cash in what we have and start a new query
  6270. {
  6271. motd[len] = ';';
  6272. motd[len+1] = 0;
  6273.  
  6274. // thread this to prevent weird connection errors??? only solution I could find
  6275. SQL_ThreadQuery(tuple,"sql_qhandler_dummy",motd);
  6276.  
  6277. len = origLen = formatex(motd,1535,"INSERT INTO `%s` VALUES ",sqlPlayersTable);
  6278. }
  6279.  
  6280. flags = 0;
  6281. team = _:cs_get_user_team(player);
  6282.  
  6283. if(team == winningTeam)
  6284. {
  6285. flags |= WON;
  6286. if(player == winner) flags |= LASTKILL;
  6287. }
  6288. else if(team > 0 && team < 3)
  6289. {
  6290. flags |= LOST;
  6291. if(player == loser) flags |= LASTKILL;
  6292. }
  6293.  
  6294. if(player == pointsExtraction[0][1]) flags |= NEWRECORD;
  6295.  
  6296. get_gg_authid(player,playerAuthid,31);
  6297. get_user_name(player,playerName,31);
  6298.  
  6299. // get new stats position
  6300. stats_clear_struct(playerStats[player]);
  6301. stats_get_position(player,playerAuthid,si);
  6302.  
  6303. SQL_QuoteString(db,playerSafeName,63,playerName);
  6304. SQL_QuoteString(db,playerSafeAuthid,63,playerAuthid);
  6305.  
  6306. len += formatex(motd[len],1535-len,"%s('%i','%s','%s','%i','%i','%s','%i','%i','%i','%i','%i','%i','%i','%i','%i','%i','%s')",(len != origLen) ? "," : "",
  6307. player,playerSafeAuthid,playerSafeName,team,level[player],lvlWeapon[player],flags,pointsExtraction[player][0],pointsExtraction[player][2],pointsExtraction[player][1],pointsExtraction[player][4],pointsExtraction[player][3],statsPosition[player][si],floatround(teamTimes[player][winningTeam-1]),floatround(teamTimes[player][losingTeam-1]),systime,serverip);
  6308. }
  6309.  
  6310. // if we actually added someone
  6311. if(len > origLen)
  6312. {
  6313. motd[len] = ';';
  6314. motd[len+1] = 0;
  6315.  
  6316. query = SQL_PrepareQuery(db,motd);
  6317. SQL_ExecuteAndLog(query);
  6318. SQL_FreeHandle(query);
  6319. }
  6320.  
  6321. // an actual web page
  6322. if(winner_motd[0] != '2')
  6323. {
  6324. new url[74], lang[3];
  6325. for(player=1;player<=maxPlayers;player++)
  6326. {
  6327. if(!is_user_connected(player)) continue;
  6328.  
  6329. get_user_info(player,"lang",lang,2);
  6330.  
  6331. formatex(header,31,"%L",player,"WIN_MOTD_LINE1",winnerName);
  6332. formatex(url,73,"%s?i=%i&l=%s",winner_motd,player,lang);
  6333.  
  6334. show_motd(player,url,header);
  6335. }
  6336.  
  6337. return 1;
  6338. }
  6339. }
  6340. #endif
  6341.  
  6342. if(sqlInit && stats_mode && is_user_connected(pointsExtraction[0][1]))
  6343. get_team_color(CsTeams:get_user_team(pointsExtraction[0][1]),streakChampColor,7);
  6344.  
  6345. get_user_team(winner,winnerTeam,9);
  6346. get_user_name(winner,winnerName,31);
  6347. get_team_color(CsTeams:winningTeam,winnerColor,7);
  6348. get_number_suffix(pointsExtraction[winner][0],winnerWinSuffix,2);
  6349. get_number_suffix(pointsExtraction[winner][3],winnerStreakSuffix,2);
  6350.  
  6351. // pointsExtraction[player][0] = total wins
  6352. // pointsExtraction[player][1] = points from this round
  6353. // pointsExtraction[player][2] = total points
  6354. // pointsExtraction[player][3] = current streak
  6355. // pointsExtraction[player][4] = previous record streak
  6356.  
  6357. // pointsExtraction[0][0] = old record (0 = no old record)
  6358. // pointsExtraction[0][1] = record holder (-1 = old guy)
  6359. // pointsExtraction[0][2] = new record (0 = no new record)
  6360.  
  6361. new loserName[32], loserColor[8];
  6362. if(!loserDC)
  6363. {
  6364. get_user_name(loser,loserName,31);
  6365. get_team_color(cs_get_user_team(loser),loserColor,7);
  6366. }
  6367. else loserColor = "gray";
  6368.  
  6369. // figure out which lines to use based on stats split stuff
  6370. new key_LINE5A[20], key_LINE5B[20], key_LINE5C[20], key_LINE7A[20], key_LINE7B[20], key_LINE7C[20],
  6371. key_STREAK1[21], key_STREAK2[21], key_STREAK3[21], key_STREAK4[21];
  6372.  
  6373. if(stats_split)
  6374. {
  6375. if(teamplay)
  6376. {
  6377. key_LINE5A = "WIN_MOTD_LINE5A_TP";
  6378. key_LINE5B = "WIN_MOTD_LINE5B_TP";
  6379. key_LINE5C = "WIN_MOTD_LINE5C_TP";
  6380. key_LINE7A = "WIN_MOTD_LINE7A_TP";
  6381. key_LINE7B = "WIN_MOTD_LINE7B_TP";
  6382. key_LINE7C = "WIN_MOTD_LINE7C_TP";
  6383. key_STREAK1 = "WIN_MOTD_STREAK1_TP";
  6384. key_STREAK2 = "WIN_MOTD_STREAK2_TP";
  6385. key_STREAK3 = "WIN_MOTD_STREAK3_TP";
  6386. key_STREAK4 = "WIN_MOTD_STREAK4_TP";
  6387. }
  6388. else
  6389. {
  6390. key_LINE5A = "WIN_MOTD_LINE5A_REG";
  6391. key_LINE5B = "WIN_MOTD_LINE5B_REG";
  6392. key_LINE5C = "WIN_MOTD_LINE5C_REG";
  6393. key_LINE7A = "WIN_MOTD_LINE7A_REG";
  6394. key_LINE7B = "WIN_MOTD_LINE7B_REG";
  6395. key_LINE7C = "WIN_MOTD_LINE7C_REG";
  6396. key_STREAK1 = "WIN_MOTD_STREAK1_REG";
  6397. key_STREAK2 = "WIN_MOTD_STREAK2_REG";
  6398. key_STREAK3 = "WIN_MOTD_STREAK3_REG";
  6399. key_STREAK4 = "WIN_MOTD_STREAK4_REG";
  6400. }
  6401. }
  6402. else
  6403. {
  6404. key_LINE5A = "WIN_MOTD_LINE5A";
  6405. key_LINE5B = "WIN_MOTD_LINE5B";
  6406. key_LINE5C = "WIN_MOTD_LINE5C";
  6407. key_LINE7A = "WIN_MOTD_LINE7A";
  6408. key_LINE7B = "WIN_MOTD_LINE7B";
  6409. key_LINE7C = "WIN_MOTD_LINE7C";
  6410. key_STREAK1 = "WIN_MOTD_STREAK1";
  6411. key_STREAK2 = "WIN_MOTD_STREAK2";
  6412. key_STREAK3 = "WIN_MOTD_STREAK3";
  6413. key_STREAK4 = "WIN_MOTD_STREAK4";
  6414. }
  6415.  
  6416. // format for each language
  6417. new player;
  6418. for(player=1;player<=maxPlayers;player++)
  6419. {
  6420. if(!is_user_connected(player)) continue;
  6421.  
  6422. if(loserDC) formatex(loserName,31,"%L",player,"NO_ONE");
  6423. formatex(header,31,"%L",player,"WIN_MOTD_LINE1",winnerName);
  6424.  
  6425. len = formatex(motd,1535,"<meta http-equiv=^"Content-Type^" content=^"text/html;charset=UTF-8^">");
  6426. len += formatex(motd[len],1535-len,"<body bgcolor=black style=line-height:1;color:white><center><font color=00CC00 size=7 face=Georgia>[GUNGAME] AMXX<p>");
  6427.  
  6428. len += formatex(motd[len],1535-len,"<font color=%s size=6 style=letter-spacing:2px>",winnerColor);
  6429. len += formatex(motd[len],1535-len,"<div style=height:1px;width:80%%;background-color:%s;overflow:hidden></div>",winnerColor);
  6430. if(teamplay) len += formatex(motd[len],1535-len,"%L",player,"WIN_MOTD_LINE2",winnerTeam); else len += formatex(motd[len],1535-len,"%s",winnerName);
  6431. len += formatex(motd[len],1535-len,"<div style=height:1px;width:80%%;background-color:%s;overflow:hidden></div>",winnerColor);
  6432. len += formatex(motd[len],1535-len,"<font size=4 color=white style=letter-spacing:1px>%L<p>",player,"WIN_MOTD_LINE3");
  6433.  
  6434. if(!teamplay) len += formatex(motd[len],1535-len,"<font size=3>%L</font>.<p>",player,"WIN_MOTD_LINE4A",lvlWeapon[winner],loserColor,loserName);
  6435. else len += formatex(motd[len],1535-len,"<font size=3>%L</font>.<p>",player,"WIN_MOTD_LINE4B",lvlWeapon[winner],loserColor,loserName,winnerColor,winnerName);
  6436.  
  6437. if(sqlInit && stats_mode == 1)
  6438. {
  6439. if(teamplay && timeratio)
  6440. {
  6441. // not enough for a win
  6442. if(teamTimes[winner][winningTeam-1]/(teamTimes[winner][winningTeam-1]+teamTimes[winner][losingTeam-1]) < 0.5)
  6443. len += formatex(motd[len],1535-len,"<p>");
  6444. else
  6445. len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE5A,winnerColor,winnerName,pointsExtraction[winner][0],winnerWinSuffix,pointsExtraction[winner][3],winnerStreakSuffix,pointsExtraction[winner][4]);
  6446.  
  6447. // no play time
  6448. if(teamTimes[player][winningTeam-1] < 1.0 && teamTimes[player][losingTeam-1] < 1.0)
  6449. len += formatex(motd[len],1535-len,"%L<br>",player,"WIN_MOTD_LINE6",0);
  6450. else
  6451. len += formatex(motd[len],1535-len,"%L<br>",player,"WIN_MOTD_LINE6",floatround(teamTimes[player][winningTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1])*100.0));
  6452. }
  6453. else len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE5A,winnerColor,winnerName,pointsExtraction[winner][0],winnerWinSuffix,pointsExtraction[winner][3],winnerStreakSuffix,pointsExtraction[winner][4]);
  6454.  
  6455. // we won somehow
  6456. if( (!teamplay && winner == player) || (teamplay && !timeratio && winningTeam == _:cs_get_user_team(player)) ||
  6457. (teamplay && timeratio && teamTimes[player][winningTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1]) >= 0.5) )
  6458. {
  6459. get_number_suffix(pointsExtraction[player][3],myStreakSuffix,2);
  6460. len += formatex(motd[len],1535-len,"%L<br>",player,key_LINE7A,pointsExtraction[player][0],pointsExtraction[player][3],myStreakSuffix,pointsExtraction[player][4]);
  6461. }
  6462.  
  6463. // we didn't get a win
  6464. else len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE7B,pointsExtraction[player][0]);
  6465.  
  6466. }
  6467. else if(sqlInit && stats_mode == 2)
  6468. {
  6469. if(teamplay && timeratio)
  6470. {
  6471. // winner didn't play enough to get a win
  6472. if(teamTimes[winner][winningTeam-1]/(teamTimes[winner][winningTeam-1]+teamTimes[winner][losingTeam-1]) < 0.5)
  6473. len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE5B,winnerColor,winnerName,pointsExtraction[winner][2]);
  6474. else
  6475. len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE5C,winnerColor,winnerName,pointsExtraction[winner][0],winnerWinSuffix,pointsExtraction[winner][2],pointsExtraction[winner][3],winnerStreakSuffix,pointsExtraction[winner][4]);
  6476.  
  6477. // no play time
  6478. if(teamTimes[player][winningTeam-1] < 1.0 && teamTimes[player][losingTeam-1] < 1.0)
  6479. len += formatex(motd[len],1535-len,"%L<br>",player,"WIN_MOTD_LINE6",0);
  6480. else
  6481. len += formatex(motd[len],1535-len,"%L<br>",player,"WIN_MOTD_LINE6",floatround(teamTimes[player][winningTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1])*100.0));
  6482. }
  6483. else len += formatex(motd[len],1535-len,"%L<p>",player,key_LINE5C,winnerColor,winnerName,pointsExtraction[winner][0],winnerWinSuffix,pointsExtraction[winner][2],pointsExtraction[winner][3],winnerStreakSuffix,pointsExtraction[winner][4]);
  6484.  
  6485. len += formatex(motd[len],1535-len,"%L<%s>",player,key_LINE7C,pointsExtraction[player][1],pointsExtraction[player][2],pointsExtraction[player][0],(pointsExtraction[player][3]) ? "p" : "p");
  6486.  
  6487. if(pointsExtraction[player][3])
  6488. {
  6489. get_number_suffix(pointsExtraction[player][3],myStreakSuffix,2);
  6490. len += formatex(motd[len],1535-len,"%L<br>",player,key_STREAK1,pointsExtraction[player][3],myStreakSuffix,pointsExtraction[player][4]);
  6491. }
  6492. }
  6493. else len += formatex(motd[len],1535-len,"<p>");
  6494.  
  6495. if(sqlInit && stats_mode)
  6496. {
  6497. if(!pointsExtraction[player][3] && pointsExtraction[player][4]) // I'm not on a streak, but I do have a record
  6498. {
  6499. len += formatex(motd[len],1535-len,"%L<br>",player,key_STREAK2,pointsExtraction[player][4]);
  6500. }
  6501.  
  6502. if(pointsExtraction[0][1] == -1) // champion is the previous record holder
  6503. {
  6504. // there actually was a previous record
  6505. if(pointsExtraction[0][0]) len += formatex(motd[len],1535-len,"%L<p>",player,key_STREAK3,pointsExtraction[0][0],spareName);
  6506. }
  6507. else len += formatex(motd[len],1535-len,"%L<p>",player,key_STREAK4,streakChampColor,spareName,pointsExtraction[0][2]);
  6508. }
  6509.  
  6510. if(iterations > 0)
  6511. {
  6512. if(roundsleft <= 0) len += formatex(motd[len],1535-len,"%L",player,"WIN_MOTD_LINE8A",nextmap);
  6513. else if(roundsleft == 1) len += formatex(motd[len],1535-len,"%L",player,"WIN_MOTD_LINE8B");
  6514. else len += formatex(motd[len],1535-len,"%L",player,"WIN_MOTD_LINE8C",roundsleft);
  6515. }
  6516.  
  6517. show_motd(player,motd,header);
  6518. }
  6519.  
  6520. return 1;
  6521. }
  6522.  
  6523. //**********************************************************************
  6524. // TEAMPLAY FUNCTIONS
  6525. //**********************************************************************
  6526.  
  6527. // change the score of a team
  6528. stock teamplay_update_score(team,newScore,exclude=0,direct=0)
  6529. {
  6530. if(team != 1 && team != 2) return;
  6531.  
  6532. teamScore[team] = newScore;
  6533.  
  6534. new player, sdisplay = get_pcvar_num(gg_status_display);
  6535. for(player=1;player<=maxPlayers;player++)
  6536. {
  6537. if(is_user_connected(player) && player != exclude && _:cs_get_user_team(player) == team)
  6538. {
  6539. if(direct)
  6540. {
  6541. score[player] = newScore;
  6542. if(sdisplay == STATUS_KILLSLEFT || sdisplay == STATUS_KILLSDONE)
  6543. status_display(player);
  6544. }
  6545. else change_score(player,newScore-score[player],0); // don't refill
  6546. }
  6547. }
  6548. }
  6549.  
  6550. // change the level of a team
  6551. stock teamplay_update_level(team,newLevel,exclude=0,direct=1)
  6552. {
  6553. if(team != 1 && team != 2) return;
  6554.  
  6555. teamLevel[team] = newLevel;
  6556. get_level_weapon(teamLevel[team],teamLvlWeapon[team],23);
  6557.  
  6558. new player;
  6559. for(player=1;player<=maxPlayers;player++)
  6560. {
  6561. if(is_user_connected(player) && player != exclude && _:cs_get_user_team(player) == team)
  6562. {
  6563. //if(direct) level[player] = newLevel;
  6564. if(direct) set_level_noifandsorbuts(player,newLevel);
  6565. else change_level(player,newLevel-level[player],_,_,1); // always score
  6566. }
  6567. }
  6568. }
  6569.  
  6570. // play the taken/tied/lost lead sounds
  6571. public teamplay_play_lead_sounds(id,oldLevel,Float:playDelay)
  6572. {
  6573. // both teams not initialized yet
  6574. if(!teamLevel[1] || !teamLevel[2]) return;
  6575.  
  6576. // id: the player whose level changed
  6577. // oldLevel: his level before it changed
  6578. // playDelay: how long to wait until we play id's sounds
  6579.  
  6580. // warmup or game over, no one cares
  6581. if(warmup > 0 || won) return;
  6582.  
  6583. // no level change
  6584. if(level[id] == oldLevel) return;
  6585.  
  6586. new team = _:cs_get_user_team(id), otherTeam = (team == 1) ? 2 : 1, thisTeam, player, params[2];
  6587. if(team != 1 && team != 2) return;
  6588.  
  6589. new leaderLevel, numLeaders, leader = teamplay_get_lead_team(leaderLevel,numLeaders);
  6590.  
  6591. // this team is leading
  6592. if(leader == team)
  6593. {
  6594. // the other team here?
  6595. if(numLeaders > 1)
  6596. {
  6597. params[1] = gg_sound_tiedlead;
  6598.  
  6599. // play to both teams
  6600. for(player=1;player<=maxPlayers;player++)
  6601. {
  6602. if(!is_user_connected(player)) continue;
  6603.  
  6604. thisTeam = _:cs_get_user_team(player);
  6605. if(thisTeam == team || thisTeam == otherTeam)
  6606. {
  6607. params[0] = player;
  6608. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  6609. set_task((thisTeam == team) ? playDelay : 0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  6610. }
  6611. }
  6612. }
  6613.  
  6614. // just us, we are the winners!
  6615. else
  6616. {
  6617. // did we just pass the other team?
  6618. if(level[id] > oldLevel && teamLevel[otherTeam] == oldLevel)
  6619. {
  6620. // play to both teams (conditional)
  6621. for(player=1;player<=maxPlayers;player++)
  6622. {
  6623. if(!is_user_connected(player)) continue;
  6624.  
  6625. thisTeam = _:cs_get_user_team(player);
  6626.  
  6627. if(thisTeam == team) params[1] = gg_sound_takenlead;
  6628. else if(thisTeam == otherTeam) params[1] = gg_sound_lostlead;
  6629. else continue;
  6630.  
  6631. params[0] = player;
  6632. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  6633. set_task((thisTeam == team) ? playDelay : 0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  6634. }
  6635. }
  6636. }
  6637. }
  6638.  
  6639. // WAS this team on the leader level?
  6640. else if(oldLevel == leaderLevel)
  6641. {
  6642. // play to entire team
  6643. for(player=1;player<=maxPlayers;player++)
  6644. {
  6645. if(!is_user_connected(player)) continue;
  6646.  
  6647. thisTeam = _:cs_get_user_team(player);
  6648.  
  6649. if(thisTeam == team) params[1] = gg_sound_lostlead;
  6650. else if(thisTeam == otherTeam) params[1] = gg_sound_takenlead;
  6651. else continue;
  6652.  
  6653. params[0] = player;
  6654. remove_task(TASK_PLAY_LEAD_SOUNDS+player);
  6655. set_task((thisTeam == team) ? playDelay : 0.1,"play_sound_by_cvar_task",TASK_PLAY_LEAD_SOUNDS+player,params,2);
  6656. }
  6657. }
  6658. }
  6659.  
  6660. // find the highest level team and such
  6661. stock teamplay_get_lead_team(&retLevel=0,&retNumLeaders=0,&retRunnerUp=0)
  6662. {
  6663. new leader, numLeaders, runnerUp;
  6664.  
  6665. if(teamLevel[1] >= teamLevel[2]) leader = 1;
  6666. else leader = 2;
  6667.  
  6668. if(teamLevel[1] == teamLevel[2]) numLeaders = 2;
  6669. else
  6670. {
  6671. numLeaders = 1;
  6672. runnerUp = (leader == 1) ? 2 : 1;
  6673. }
  6674.  
  6675. retLevel = teamLevel[leader];
  6676. retNumLeaders = numLeaders;
  6677. retRunnerUp = runnerUp;
  6678.  
  6679. return leader;
  6680. }
  6681.  
  6682. // gets the team's level goal without a player passed
  6683. teamplay_get_team_goal(team)
  6684. {
  6685. if(team != 1 && team != 2) return 0;
  6686.  
  6687. new player;
  6688. for(player=1;player<=maxPlayers;player++)
  6689. {
  6690. if(is_user_connected(player) && _:cs_get_user_team(player) == team)
  6691. return get_level_goal(teamLevel[team],player);
  6692. }
  6693.  
  6694. return 0;
  6695. }
  6696.  
  6697. //**********************************************************************
  6698. // AUTOVOTE FUNCTIONS
  6699. //**********************************************************************
  6700.  
  6701. // start the autovote
  6702. public autovote_start()
  6703. {
  6704. // vote in progress
  6705. if(autovotes[0] || autovotes[1] || autovotes[2] || task_exists(TASK_AUTOVOTE_RESULT)) return 0;
  6706.  
  6707. // if autovote_mode < 0, we haven't actually checked it yet
  6708. if(autovote_mode < 0)
  6709. {
  6710. new info[6];
  6711. get_localinfo("gg_av_iter",info,5);
  6712. new iter = str_to_num(info);
  6713.  
  6714. new rotation[32];
  6715. get_pcvar_string(gg_autovote_mode,rotation,31);
  6716. new amount = str_count(rotation,',')+1;
  6717.  
  6718. if(iter <= 0 || iter > amount)
  6719. {
  6720. iter = 1;
  6721. set_localinfo("gg_av_iter","1");
  6722. }
  6723.  
  6724. // no rotation, just use the given value
  6725. if(amount <= 1)
  6726. {
  6727. if(iter != 1) set_localinfo("gg_av_iter","1");
  6728. autovote_mode = str_to_num(rotation);
  6729. }
  6730. else
  6731. {
  6732. for(new i=1;i<=amount;i++)
  6733. {
  6734. if(contain(rotation,",") != -1)
  6735. {
  6736. strtok(rotation,info,5,rotation,31,',');
  6737. if(i == iter) // this is the one we're looking for
  6738. {
  6739. autovote_mode = str_to_num(info);
  6740. break;
  6741. }
  6742. }
  6743. else // we've stripped away everything else and are left with the last one, so use it
  6744. {
  6745. autovote_mode = str_to_num(rotation);
  6746. break;
  6747. }
  6748. }
  6749.  
  6750. iter++;
  6751. if(iter > amount) iter = 1;
  6752. num_to_str(iter,info,5);
  6753. set_localinfo("gg_av_iter",info);
  6754. }
  6755. }
  6756.  
  6757. // turns out it's disabled
  6758. if(autovote_mode <= 0) return 0;
  6759.  
  6760. new Float:autovote_time = get_pcvar_float(gg_autovote_time);
  6761.  
  6762. new i;
  6763. for(i=1;i<=maxPlayers;i++)
  6764. {
  6765. if(!is_user_connected(i)) continue;
  6766.  
  6767. switch(autovote_mode)
  6768. {
  6769. case 1:
  6770. {
  6771. formatex(menuText,511,"\y%L^n^n\w1. %L^n2. %L^n^n0. %L",i,"PLAY_GUNGAME",i,"YES",i,"NO",i,"CANCEL");
  6772. show_menu(i,MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,menuText,floatround(autovote_time),"autovote_menu");
  6773. }
  6774. case 2:
  6775. {
  6776. formatex(menuText,511,"\y%L^n^n\w1. %L^n2. %L^n^n0. %L",i,"PLAY_GUNGAME",i,"YES_TEAMPLAY",i,"YES_REGULAR",i,"CANCEL");
  6777. show_menu(i,MENU_KEY_1|MENU_KEY_2|MENU_KEY_0,menuText,floatround(autovote_time),"autovote_menu");
  6778. }
  6779. default:
  6780. {
  6781. formatex(menuText,511,"\y%L^n^n\w1. %L^n2. %L^n3. %L^n^n0. %L",i,"PLAY_GUNGAME",i,"YES_TEAMPLAY",i,"YES_REGULAR",i,"NO",i,"CANCEL");
  6782. show_menu(i,MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_0,menuText,floatround(autovote_time),"autovote_menu");
  6783. }
  6784. }
  6785. }
  6786.  
  6787. gungame_print(0,0,1,"%L",LANG_PLAYER_C,"VOTING_STARTED");
  6788. set_task(autovote_time,"autovote_result",TASK_AUTOVOTE_RESULT);
  6789.  
  6790. return 1;
  6791. }
  6792.  
  6793. // take in votes
  6794. public autovote_menu_handler(id,key)
  6795. {
  6796. switch(key)
  6797. {
  6798. case 0: // 1.
  6799. {
  6800. /* MODE 1- YES
  6801. MODE 2- YES_TEAMPLAY
  6802. MODE 3- YES_TEAMPLAY */
  6803.  
  6804. autovotes[0]++;
  6805. }
  6806. case 1: // 2.
  6807. {
  6808. /* MODE 1- NO
  6809. MODE 2- YES_REGULAR
  6810. MODE 3- YES_REGULAR */
  6811.  
  6812. if(autovote_mode == 1) autovotes[2]++;
  6813. else autovotes[1]++;
  6814. }
  6815. case 2: // 3.
  6816. {
  6817. /* MODE 1-
  6818. MODE 2-
  6819. MODE 3- NO */
  6820.  
  6821. autovotes[2]++;
  6822. }
  6823. //case 9: 0. /* ALL MODES- CANCEL */ let menu close
  6824. }
  6825.  
  6826. return PLUGIN_HANDLED;
  6827. }
  6828.  
  6829. // calculate end of vote, some of this was thanks to VEN
  6830. public autovote_result()
  6831. {
  6832. new vYes = autovotes[0] + autovotes[1], vNo = autovotes[2], vTotal = vYes + vNo, vSuccess, teamplay = get_pcvar_num(gg_teamplay), key[16];
  6833.  
  6834. switch(autovote_mode)
  6835. {
  6836. case 1: // this mode asks if they want to play GunGame, yes/no
  6837. {
  6838. if(vTotal)
  6839. {
  6840. if(float(vYes) / float(vTotal) >= get_pcvar_float(gg_autovote_ratio))
  6841. vSuccess = 1;
  6842.  
  6843. // the choice that changes the current game mode is the one that needs to meet the ratio. so if you are
  6844. // playing GunGame, at least however many people as defined by the ratio need to vote for it off to switch it,
  6845. // and vice-versa.
  6846. if( ( ggActive && (float(vNo) / float(vTotal)) < get_pcvar_float(gg_autovote_ratio))
  6847. || (!ggActive && (float(vYes) / float(vTotal)) >= get_pcvar_float(gg_autovote_ratio)) )
  6848. vSuccess = 1; // means that we will be playing GunGame
  6849. }
  6850. else if(ggActive) vSuccess = 1;
  6851.  
  6852. if(vSuccess && !ggActive)
  6853. {
  6854. restart_round(5);
  6855. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_ENABLE);
  6856. }
  6857. else if(!vSuccess && ggActive)
  6858. {
  6859. restart_round(5);
  6860. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_DISABLE);
  6861.  
  6862. set_pcvar_num(gg_enabled,0);
  6863. ggActive = 0;
  6864. }
  6865.  
  6866. if(vSuccess && teamplay) key = "AUTOVOTE_RES1";
  6867. else if(vSuccess && !teamplay) key = "AUTOVOTE_RES2";
  6868. else key = "AUTOVOTE_RES3";
  6869.  
  6870. gungame_print(0,0,1,"%L %i %L - %i %L - %L :: %L",LANG_PLAYER_C,"PLAY_GUNGAME",vYes,LANG_PLAYER_C,"YES",vNo,LANG_PLAYER_C,"NO",LANG_PLAYER_C,"THE_RESULT",LANG_PLAYER_C,key);
  6871. }
  6872. case 2: // this mode asks if they want to play teamplay, yes/no
  6873. {
  6874. if(!ggActive)
  6875. {
  6876. restart_round(5);
  6877. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_ENABLE);
  6878. }
  6879.  
  6880. if(vTotal)
  6881. {
  6882. // see above comment
  6883. if( ( teamplay && (float(autovotes[1]) / float(vTotal)) < get_pcvar_float(gg_autovote_ratio))
  6884. || (!teamplay && (float(autovotes[0]) / float(vTotal)) >= get_pcvar_float(gg_autovote_ratio)) )
  6885. vSuccess = 1; // means that we will be playing teamplay mode
  6886. }
  6887. else if(teamplay) vSuccess = 1;
  6888.  
  6889. if(vSuccess)
  6890. {
  6891. if(!teamplay)
  6892. {
  6893. set_pcvar_num(gg_teamplay,1);
  6894. if(ggActive && warmup <= 0) restart_round(3);
  6895.  
  6896. exec_gg_config_file(0,0);
  6897. exec_gg_config_file(1,0);
  6898. }
  6899.  
  6900. set_task(4.9,"force_teamplay",1);
  6901. }
  6902. else if(!vSuccess)
  6903. {
  6904. if(teamplay)
  6905. {
  6906. set_pcvar_num(gg_teamplay,0);
  6907. if(ggActive && warmup <= 0) restart_round(3);
  6908.  
  6909. exec_gg_config_file(0,0);
  6910. }
  6911.  
  6912. set_task(4.9,"force_teamplay",0);
  6913. }
  6914.  
  6915. if(vSuccess) key = "AUTOVOTE_RES1";
  6916. else key = "AUTOVOTE_RES2";
  6917.  
  6918. gungame_print(0,0,1,"%L %i %L - %i %L - %L :: %L",LANG_PLAYER_C,"PLAY_GUNGAME",autovotes[0],LANG_PLAYER_C,"YES_TEAMPLAY",autovotes[1],LANG_PLAYER_C,"YES_REGULAR",LANG_PLAYER_C,"THE_RESULT",LANG_PLAYER_C,key);
  6919. }
  6920. default: // this mode asks if they want to play, teamplay/regular/no
  6921. {
  6922. if(vTotal)
  6923. {
  6924. // see above comment
  6925. if( ( ggActive && (float(vNo) / float(vTotal)) < get_pcvar_float(gg_autovote_ratio))
  6926. || (!ggActive && (float(vYes) / float(vTotal)) >= get_pcvar_float(gg_autovote_ratio)) )
  6927. vSuccess = 1; // means that we will be playing GunGame
  6928. }
  6929. else if(ggActive) vSuccess = 1;
  6930.  
  6931. if(vSuccess)
  6932. {
  6933. if(!ggActive)
  6934. {
  6935. restart_round(5);
  6936. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_ENABLE);
  6937. }
  6938.  
  6939. // pick a random value for teamplay if we need it, then see if we should be using it.
  6940. // use it in the case that we have a tie, and we are using random teamplay mode.
  6941. new rand_val = random_num(0,1);
  6942. new use_rand = (autovotes[0] == autovotes[1] && (teamplay == 2 || initTeamplayInt == 2));
  6943.  
  6944. if(autovotes[0] > autovotes[1] || (use_rand && rand_val == 1)) // more votes for teamplay
  6945. {
  6946. if(!teamplay)
  6947. {
  6948. set_pcvar_num(gg_teamplay,1);
  6949. if(ggActive && warmup <= 0) restart_round(3);
  6950.  
  6951. exec_gg_config_file(0,0);
  6952. exec_gg_config_file(1,0);
  6953. }
  6954.  
  6955. key = "AUTOVOTE_RES1";
  6956. set_task(4.9,"force_teamplay",1);
  6957. }
  6958. else if(autovotes[0] < autovotes[1] || (use_rand && rand_val == 0)) // more votes for regular
  6959. {
  6960. if(teamplay)
  6961. {
  6962. set_pcvar_num(gg_teamplay,0);
  6963. if(ggActive && warmup <= 0) restart_round(3);
  6964.  
  6965. exec_gg_config_file(0,0);
  6966. }
  6967.  
  6968. key = "AUTOVOTE_RES2";
  6969. set_task(4.9,"force_teamplay",0);
  6970. }
  6971. else // if equal, leave it be
  6972. {
  6973. if(teamplay)
  6974. {
  6975. key = "AUTOVOTE_RES1";
  6976. set_task(4.9,"force_teamplay",1);
  6977. }
  6978. else
  6979. {
  6980. key = "AUTOVOTE_RES2";
  6981. set_task(4.9,"force_teamplay",0);
  6982. }
  6983. }
  6984. }
  6985. else if(!vSuccess && ggActive)
  6986. {
  6987. restart_round(5);
  6988. set_task(4.8,"toggle_gungame",TASK_TOGGLE_GUNGAME+TOGGLE_DISABLE);
  6989.  
  6990. set_pcvar_num(gg_enabled,0);
  6991. ggActive = 0;
  6992. }
  6993.  
  6994. if(!vSuccess) key = "AUTOVOTE_RES3";
  6995. gungame_print(0,0,1,"%L %i %L - %i %L - %i %L - %L :: %L",LANG_PLAYER_C,"PLAY_GUNGAME",autovotes[0],LANG_PLAYER_C,"YES_TEAMPLAY",autovotes[1],LANG_PLAYER_C,"YES_REGULAR",vNo,LANG_PLAYER_C,"NO",LANG_PLAYER_C,"THE_RESULT",LANG_PLAYER_C,key);
  6996. }
  6997. }
  6998.  
  6999. autovotes[0] = 0;
  7000. autovotes[1] = 0;
  7001. autovotes[2] = 0;
  7002. }
  7003.  
  7004. // force teamplay mode to what we want after a vote has been completed.
  7005. // otherwise, when switching from GunGame off to on, it will be overwritten by gungame.cfg.
  7006. public force_teamplay(teamplay)
  7007. {
  7008. set_pcvar_num(gg_teamplay,teamplay);
  7009.  
  7010. exec_gg_config_file(0,0);
  7011. if(teamplay) exec_gg_config_file(1,0);
  7012. }
  7013.  
  7014. //**********************************************************************
  7015. // STAT FUNCTIONS
  7016. //**********************************************************************
  7017.  
  7018. // clear out everything about our stats
  7019. stats_clear_all()
  7020. {
  7021. #if !defined SQL
  7022. // destroy large array
  7023. if(statsArray) ArrayDestroy(statsArray);
  7024.  
  7025. // destroy the two "pointer" arrays
  7026. if(statsPointers[0])
  7027. {
  7028. ArrayDestroy(statsPointers[0]);
  7029. statsSize[0] = 0;
  7030. }
  7031. if(statsPointers[1])
  7032. {
  7033. ArrayDestroy(statsPointers[1]);
  7034. statsSize[1] = 0;
  7035. }
  7036. #endif
  7037.  
  7038. // clear out saved stats data for the players
  7039. for(new i=1;i<=maxPlayers;i++)
  7040. {
  7041. statsPosition[i][0] = 0;
  7042. statsPosition[i][1] = 0;
  7043. stats_clear_struct(playerStats[i]);
  7044. }
  7045.  
  7046. // clear out saved stats data from the temp saves
  7047. for(new i=0;i<TEMP_SAVES;i++)
  7048. {
  7049. tempSave[i][svStatsPosition][0] = 0;
  7050. tempSave[i][svStatsPosition][1] = 0;
  7051. }
  7052. }
  7053.  
  7054. #if !defined SQL
  7055. // converts a stats string (as in gungame.stats) into a stats struct (by reference)
  7056. stats_str_to_struct(str[],struct[statsData])
  7057. {
  7058. // The format for str (as saved in gungame.stats):
  7059. //
  7060. // AUTHID WINS LAST_USED_NAME TIMESTAMP POINTS STREAK TPWINS TPPOINTS TPSTREAK
  7061.  
  7062. static piece[32], whole[112];
  7063. piece[0] = 0;
  7064. whole[0] = 0;
  7065.  
  7066. stats_clear_struct(struct);
  7067.  
  7068. strtok(str,piece,31,whole,111,'^t');
  7069. copy(struct[sdAuthid],31,piece);
  7070.  
  7071. strtok(whole,piece,5,whole,111,'^t');
  7072. struct[sdWins][0] = str_to_num(piece);
  7073.  
  7074. strtok(whole,piece,31,whole,111,'^t');
  7075. copy(struct[sdName],31,piece);
  7076.  
  7077. strtok(whole,piece,11,whole,111,'^t');
  7078. struct[sdTimestamp] = str_to_num(piece);
  7079.  
  7080. strtok(whole,piece,7,whole,111,'^t');
  7081. struct[sdPoints][0] = str_to_num(piece);
  7082.  
  7083. strtok(whole,piece,3,whole,111,'^t');
  7084. struct[sdStreak][0] = str_to_num(piece);
  7085.  
  7086. strtok(whole,piece,5,whole,111,'^t');
  7087. struct[sdWins][1] = str_to_num(piece);
  7088.  
  7089. strtok(whole,piece,7,whole,3,'^t');
  7090. struct[sdPoints][1] = str_to_num(piece);
  7091.  
  7092. //strtok(whole,piece,3,whole,1,'^t');
  7093. struct[sdStreak][1] = str_to_num(whole);
  7094. }
  7095. #endif
  7096.  
  7097. #if defined SQL
  7098. // sql version] much simpler.
  7099. stock stats_refresh_timestamp(authid[])
  7100. {
  7101. if(!sqlInit) return 0;
  7102.  
  7103. SQL_QuoteString(db,safeName,63,authid);
  7104. query = SQL_PrepareQuery(db,"UPDATE `%s` SET timestamp='%i' WHERE authid='%s' AND serverip='%s' LIMIT 1;",sqlTable,get_systime(),safeName,serverip);
  7105.  
  7106. SQL_ExecuteAndLog(query);
  7107. SQL_FreeHandle(query);
  7108.  
  7109. return 1;
  7110. }
  7111. #else
  7112. // IT'S BEEN REVIVED!
  7113. //
  7114. // This took me way too long to develop, but it actually is able to overwrite the
  7115. // old timestamp without having to copy over to a new file or anything. It should
  7116. // work until sometime in the year 2287 when Unix timestamps will be 11 digits.
  7117. //
  7118. // On my old 2.80 gHz Pentium IV, it takes less than a tenth of a second to read to
  7119. // the bottom of a 10,000 line stats file and then refresh the final player's timestamp.
  7120. stock stats_refresh_timestamp(authid[])
  7121. {
  7122. get_pcvar_string(gg_stats_file,sfFile,63);
  7123. if(!file_exists(sfFile)) return 0;
  7124.  
  7125. // Open in binary mode, because text mode can present issues regarding
  7126. // carriage returns and line feeds.
  7127. // (See http://support.microsoft.com/default.aspx?scid=kb;en-us;68337)
  7128. new file = fopen(sfFile,"rb+");
  7129. if(!file) return 0;
  7130.  
  7131. new readLen, authidLen = strlen(authid), q;
  7132. formatex(sfTimestamp,10,"%10i",get_systime());
  7133.  
  7134. while(!feof(file))
  7135. {
  7136. new start_of_line = ftell(file); // remember start of line position
  7137.  
  7138. readLen = fgets(file,sfLineData,111);
  7139.  
  7140. // check to see if this line starts with our authid
  7141. for(q=0;q<authidLen;q++)
  7142. {
  7143. if(sfLineData[q] != authid[q]) { q = 255; break; }
  7144. }
  7145.  
  7146. // if q == 255, we definitely did not have a match.
  7147. // else, if sfLineData[q] != '^t', our authid is probably
  7148. // a proper prefix for the authid on this line.
  7149. if(q == 255 || sfLineData[q] != '^t')
  7150. {
  7151. q = 255;
  7152. continue;
  7153. }
  7154.  
  7155. q++; // q was pointing to first tab, so skip over it
  7156. new tabsFound = 1;
  7157. while(sfLineData[q] != 0)
  7158. {
  7159. // keep going until we find the 3rd tab overall
  7160. if(sfLineData[q] == '^t' && ++tabsFound == 3) break;
  7161. q++;
  7162. }
  7163.  
  7164. // somehow we did not encounter the 3rd tab, abort
  7165. if(tabsFound != 3 || sfLineData[q] != '^t')
  7166. {
  7167. log_amx("Error in stats_refresh_timestamp -- stats file formatted incorrectly");
  7168. q = 255;
  7169. break;
  7170. }
  7171.  
  7172. q++; // q was the position of the tab before the timestamp, so skip over it
  7173.  
  7174. // Make sure we have room for the timestamp (though we might assume it).
  7175. // Minimum 12 characters: 10 for the timestamp, 1 for carriage return, 1 for newline.
  7176. if(readLen-q >= 12)
  7177. {
  7178. fseek(file,start_of_line+q,SEEK_SET);
  7179. fwrite_blocks(file,sfTimestamp,10,BLOCK_CHAR); // overwrite timestamp with current one
  7180. }
  7181.  
  7182. break;
  7183. }
  7184.  
  7185. fclose(file);
  7186.  
  7187. return (q != 255);
  7188. }
  7189. #endif
  7190.  
  7191. // we now have a super-duper function so that we only have to go through
  7192. // the stats file once, instead of rereading and rewriting it for every
  7193. // single player in a points match.
  7194. //
  7195. // also, timestamps are refreshed here, instead of every time you join.
  7196. public stats_award_points(winner)
  7197. {
  7198. new stats_mode = get_pcvar_num(gg_stats_mode);
  7199. if(!sqlInit || !stats_mode) return;
  7200.  
  7201. new teamplay = get_pcvar_num(gg_teamplay), winningTeam =_:cs_get_user_team(winner),
  7202. losingTeam = _:(!(winningTeam-1)) + 1, stats_ip = get_pcvar_num(gg_stats_ip),
  7203. timeratio = get_pcvar_num(gg_teamplay_timeratio), ignore_bots = get_pcvar_num(gg_ignore_bots);
  7204.  
  7205. new si = get_gg_si();
  7206.  
  7207. new player, playerWins[32], playerPoints[32], playerStreak[32], playerAuthid[32][32], playerName[32][32],
  7208. playerTotalPoints[32], players[32], intStreak, playerNum, i, team, Float:time = get_gametime(), systime = get_systime();
  7209.  
  7210. #if defined SQL
  7211. new playerSafeName[32][64], playerSafeAuthid[32][64];
  7212. #endif
  7213.  
  7214. //new botid;
  7215.  
  7216. get_players(players,playerNum);
  7217. for(i=0;i<playerNum;i++)
  7218. {
  7219. player = players[i];
  7220.  
  7221. // keep track of time
  7222. team = _:cs_get_user_team(player);
  7223. if(team == 1 || team == 2) teamTimes[player][team-1] += time - lastSwitch[player];
  7224. lastSwitch[player] = time;
  7225.  
  7226. get_gg_authid(player,playerAuthid[i],31,stats_ip);
  7227. get_user_name(player,playerName[i],31);
  7228.  
  7229. /*if(equal(playerAuthid[i],"BOT"))
  7230. {
  7231. botid++;
  7232. formatex(playerAuthid[i],31,"BOT_%i",botid);
  7233. }*/
  7234.  
  7235. #if defined SQL
  7236. SQL_QuoteString(db,playerSafeName[i],63,playerName[i]);
  7237. SQL_QuoteString(db,playerSafeAuthid[i],63,playerAuthid[i]);
  7238. #endif
  7239.  
  7240. // solo wins only
  7241. if(player == winner && stats_mode == 1 && !teamplay)
  7242. playerWins[i] = 1;
  7243. }
  7244.  
  7245. //
  7246. // COLLECT LIST OF PLAYERS AND THEIR INFORMATION
  7247. //
  7248.  
  7249. // points system
  7250. if(stats_mode == 2)
  7251. {
  7252. new wins, Float:flPoints, Float:winbonus = get_pcvar_float(gg_stats_winbonus), Float:percent;
  7253.  
  7254. for(i=0;i<playerNum;i++)
  7255. {
  7256. player = players[i];
  7257. if(!is_user_connected(player) || (ignore_bots && is_user_bot(player)))
  7258. continue;
  7259.  
  7260. wins = 0; // WHY DID I FORGET THIS BEFORE
  7261.  
  7262. // point ratio based on time played in teamplay
  7263. if(teamplay && timeratio)
  7264. {
  7265. // no play time
  7266. if(teamTimes[player][winningTeam-1] < 1.0 && teamTimes[player][losingTeam-1] < 1.0)
  7267. continue;
  7268.  
  7269. // give us points from losing team
  7270. flPoints = (float(teamLevel[losingTeam]) - 1.0) * teamTimes[player][losingTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1]);
  7271.  
  7272. // give us points from winning team
  7273. percent = teamTimes[player][winningTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1]);
  7274. flPoints += (float(teamLevel[winningTeam]) - 1.0) * percent;
  7275.  
  7276. // we played over half on winning team, give us a bonus and win
  7277. if(percent >= 0.5)
  7278. {
  7279. flPoints *= winbonus;
  7280. wins = 1;
  7281. }
  7282. }
  7283. else
  7284. {
  7285. flPoints = float(level[player]) - 1.0; // calculate points and add
  7286.  
  7287. // winner gets bonus points plus a win
  7288. if(player == winner || (teamplay && _:cs_get_user_team(player) == winningTeam))
  7289. {
  7290. flPoints *= winbonus;
  7291. wins = 1;
  7292. }
  7293. }
  7294.  
  7295. // unnecessary
  7296. if(flPoints < 0.5 && !wins) continue;
  7297.  
  7298. playerWins[i] = wins;
  7299. playerPoints[i] = floatround(flPoints);
  7300. if(playerPoints[i] < 0) playerPoints[i] = 0;
  7301. }
  7302. }
  7303.  
  7304. // regular wins teamplay (solo regular wins is above)
  7305. else if(teamplay)
  7306. {
  7307. for(i=0;i<playerNum;i++)
  7308. {
  7309. player = players[i];
  7310. if(_:cs_get_user_team(player) == winningTeam && (!ignore_bots || !is_user_bot(player)))
  7311. {
  7312. // no play time
  7313. if(teamTimes[player][winningTeam-1] < 1.0 && teamTimes[player][losingTeam-1] < 1.0)
  7314. continue;
  7315.  
  7316. // have to play at least half to get a win
  7317. if(!timeratio || teamTimes[player][winningTeam-1]/(teamTimes[player][winningTeam-1]+teamTimes[player][losingTeam-1]) >= 0.5)
  7318. playerWins[i] = 1;
  7319. }
  7320. }
  7321. }
  7322.  
  7323. //
  7324. // START MANAGING STREAKS
  7325. //
  7326.  
  7327. new streakToBeat = 0, streakChamp = -1;
  7328.  
  7329. #if defined SQL
  7330. new champRowExists;
  7331.  
  7332. // find current champion's info
  7333. query = SQL_PrepareQuery(db,"SELECT streak,name FROM `%s` WHERE type='%iR' AND serverip='%s' LIMIT 1;",sqlStreakTable,si,serverip);
  7334. if(SQL_ExecuteAndLog(query))
  7335. {
  7336. if(SQL_NumResults(query))
  7337. {
  7338. champRowExists = 1;
  7339. streakToBeat = SQL_ReadResult(query,0);
  7340. SQL_ReadResult(query,1,spareName,31);
  7341. }
  7342. }
  7343. SQL_FreeHandle(query);
  7344.  
  7345. pointsExtraction[0][0] = streakToBeat; // record old record
  7346. pointsExtraction[0][1] = -1; // record champion
  7347.  
  7348. new len, origLen;
  7349.  
  7350. // form query to delete players who did not win this round from the cache
  7351. origLen = len = formatex(mkQuery,1535,"DELETE FROM `%s` WHERE type='%iC' AND serverip='%s' AND authid NOT IN (",sqlStreakTable,si,serverip);
  7352. for(i=0;i<playerNum;i++)
  7353. {
  7354. if(playerWins[i]) len += formatex(mkQuery[len],1535-len,"%s'%s'",(len!=origLen) ? "," : "",playerSafeAuthid[i]);
  7355. }
  7356.  
  7357. if(len == origLen)
  7358. {
  7359. // no one was added, then add empty apostrophes to avoid SQL syntax error
  7360. len += formatex(mkQuery[len],1535-len,"''");
  7361. }
  7362.  
  7363. len += formatex(mkQuery[len],1535-len,");");
  7364.  
  7365. query = SQL_PrepareQuery(db,mkQuery);
  7366. SQL_ExecuteAndLog(query);
  7367. SQL_FreeHandle(query);
  7368.  
  7369. // use one query to get all current streaks, then process them in the loop and save to playerStreak array
  7370. new authid[64];
  7371. query = SQL_PrepareQuery(db,"SELECT authid,streak FROM `%s` WHERE type='%iC' AND serverip='%s';",sqlStreakTable,si,serverip);
  7372. if(SQL_ExecuteAndLog(query) && SQL_NumResults(query))
  7373. {
  7374. while(SQL_MoreResults(query))
  7375. {
  7376. SQL_ReadResult(query,0,authid,63);
  7377.  
  7378. for(i=0;i<playerNum;i++)
  7379. {
  7380. if(equal(authid,playerSafeAuthid[i]))
  7381. {
  7382. playerStreak[i] = SQL_ReadResult(query,1);
  7383. break;
  7384. }
  7385. }
  7386.  
  7387. SQL_NextRow(query);
  7388. }
  7389. }
  7390. SQL_FreeHandle(query);
  7391.  
  7392. len = origLen = formatex(mkQuery,1535,"INSERT INTO `%s` VALUES ",sqlStreakTable);
  7393.  
  7394. // now go through players, and make sure to start a streak for those who don't have one
  7395. for(i=0;i<playerNum;i++)
  7396. {
  7397. if(playerWins[i])
  7398. {
  7399. playerStreak[i]++; // if they won, they get one added to their streak
  7400.  
  7401. // am I the champion?? also, in the case of a tie, allow the winner of this round to be considered the champ
  7402. if(playerStreak[i] > streakToBeat || (streakChamp != -1 && playerStreak[i] == streakToBeat && players[i] == winner))
  7403. {
  7404. streakToBeat = playerStreak[i];
  7405. streakChamp = i;
  7406. }
  7407.  
  7408. // didn't find one with previous loop
  7409. if(playerStreak[i] == 1) // because of increment above, will be 1 at minimum
  7410. {
  7411. // insert a new row. note that the streak is inserted as 0 because it gets incremented below.
  7412. len += formatex(mkQuery[len],1535-len,"('%iC','%s','0','%s','%i','%s'),",si,playerSafeAuthid[i],playerSafeName[i],systime,serverip);
  7413.  
  7414. // cash in if we get too close
  7415. if(len >= 1200)
  7416. {
  7417. mkQuery[len-1] = ';';
  7418. mkQuery[len] = 0;
  7419.  
  7420. query = SQL_PrepareQuery(db,mkQuery);
  7421. SQL_ExecuteAndLog(query);
  7422. SQL_FreeHandle(query);
  7423.  
  7424. len = origLen = formatex(mkQuery,1535,"INSERT INTO `%s` VALUES ",sqlStreakTable);
  7425. }
  7426. }
  7427. }
  7428. }
  7429.  
  7430. // if we have some leftover query
  7431. if(len > origLen)
  7432. {
  7433. mkQuery[len-1] = ';';
  7434. mkQuery[len] = 0;
  7435.  
  7436. query = SQL_PrepareQuery(db,mkQuery);
  7437. SQL_ExecuteAndLog(query);
  7438. SQL_FreeHandle(query);
  7439. }
  7440.  
  7441. // update everyone's current streaks by +1
  7442. query = SQL_PrepareQuery(db,"UPDATE `%s` SET streak=streak+1 WHERE type='%iC' AND serverip='%s';",sqlStreakTable,si,serverip);
  7443. SQL_ExecuteAndLog(query);
  7444. SQL_FreeHandle(query);
  7445.  
  7446. // somebody beat the champion!
  7447. if(streakToBeat && streakChamp != -1)
  7448. {
  7449. if(champRowExists) query = SQL_PrepareQuery(db,"UPDATE `%s` SET authid='%s', streak='%i', name='%s', timestamp='%i' WHERE type='%iR' AND serverip='%s' LIMIT 1;",sqlStreakTable,playerSafeAuthid[streakChamp],streakToBeat,playerSafeName[streakChamp],systime,si,serverip);
  7450. else query = SQL_PrepareQuery(db,"INSERT INTO `%s` VALUES ('%iR','%s','%i','%s',%i,'%s');",sqlStreakTable,si,playerSafeAuthid[streakChamp],streakToBeat,playerSafeName[streakChamp],systime,serverip);
  7451.  
  7452. SQL_ExecuteAndLog(query);
  7453. SQL_FreeHandle(query);
  7454. }
  7455. #else
  7456. // go through and copy down the list of players who got a win last round
  7457. new sfStreak[2][4], tempFileName[65], streakRecord[53], streakFile, stats_streak_file[64];
  7458. get_pcvar_string(gg_stats_streak_file,stats_streak_file,63);
  7459.  
  7460. if(file_exists(stats_streak_file))
  7461. {
  7462. formatex(tempFileName,64,"%s2",stats_streak_file); // our temp file, append 2
  7463. rename_file(stats_streak_file,tempFileName,1); // copy it over to the temp name (relative flag)
  7464.  
  7465. // there are two basic types of lines:
  7466. // a record line, ie: 0R AUTHID STREAK NAME TIMESTAMP
  7467. // a "cache" line (a player with a running streak), ie: 0C AUTHID STREAK
  7468. // the first digit is the stats index (0 for regular, 1 for teamplay)
  7469.  
  7470. new streakTempFile = fopen(tempFileName,"rt");
  7471. streakFile = fopen(stats_streak_file,"wt");
  7472.  
  7473. // go through the old file, copy over unimportant lines, figure out the record, and distribute streaks
  7474. while(!feof(streakTempFile))
  7475. {
  7476. fgets(streakTempFile,sfLineData,82);
  7477. if(!sfLineData[0]) continue;
  7478.  
  7479. // not for our stats mode
  7480. if(str_to_num(sfLineData[0]) != si)
  7481. {
  7482. fprintf(streakFile,sfLineData); // just copy it over
  7483. continue;
  7484. }
  7485.  
  7486. // this is the record
  7487. if(sfLineData[1] == 'R')
  7488. {
  7489. copy(streakRecord,82,sfLineData); // just save it for now
  7490. continue;
  7491. }
  7492.  
  7493. // this is a cache (a player who got a win last game)
  7494. if(sfLineData[1] == 'C')
  7495. {
  7496. // use sfLineData[3] to skip characters "0C " (should be a tab)
  7497. strtok(sfLineData[3],sfAuthid,31,sfStreak[0],3,'^t'); // split them up
  7498.  
  7499. for(i=0;i<playerNum;i++)
  7500. {
  7501. // if we won, and we haven't read our streak yet, and this is our authid
  7502. if(playerWins[i] && !playerStreak[i] && equal(playerAuthid[i],sfAuthid))
  7503. {
  7504. playerStreak[i] = str_to_num(sfStreak[0]); // set our streak to our previous one
  7505. break; // in the case of duplicate authids, don't continually add to the streak
  7506. }
  7507. }
  7508.  
  7509. continue;
  7510. }
  7511.  
  7512. // don't copy over the rest, so it sort of auto-prunes
  7513. //fprintf(streakFile,sfLineData); // OLD COMMENT IGNORE ME: anything else, we might as well copy it
  7514. }
  7515.  
  7516. // get rid of the old copy
  7517. fclose(streakTempFile);
  7518. delete_file(tempFileName);
  7519. }
  7520. else if(stats_streak_file[0]) streakFile = fopen(stats_streak_file,"wt"); // did not exist, create it
  7521.  
  7522. //new streakToBeat = 0, streakChamp = -1;
  7523. if(streakRecord[0]) // if there was a record, figure it out
  7524. {
  7525. strtok(streakRecord[3],dummy,1,sfLineData,82,'^t'); // cut off prefix and authid from the left
  7526. strtok(sfLineData,sfStreak[0],3,spareName,31,'^t'); // get our streak, and the name as well
  7527.  
  7528. new pos = contain_char(spareName,'^t');
  7529. if(pos != -1) spareName[pos] = 0; // cut off the timestamp from the name
  7530.  
  7531. streakToBeat = str_to_num(sfStreak[0]);
  7532. }
  7533.  
  7534. pointsExtraction[0][0] = streakToBeat; // record old record
  7535. pointsExtraction[0][1] = -1; // record champion
  7536.  
  7537. // now go through current players, and rewrite them with their new streaks into the file
  7538. for(i=0;i<playerNum;i++)
  7539. {
  7540. if(playerWins[i])
  7541. {
  7542. playerStreak[i]++; // if they won, they get one added to their streak
  7543.  
  7544. // am I the champion?? also, in the case of a tie, allow the winner of this round to be considered the champ
  7545. if(playerStreak[i] > streakToBeat || (streakChamp != -1 && playerStreak[i] == streakToBeat && players[i] == winner))
  7546. {
  7547. streakToBeat = playerStreak[i];
  7548. streakChamp = i;
  7549. }
  7550.  
  7551. if(streakFile)
  7552. {
  7553. fprintf(streakFile,"%iC^t%s^t%i",si,playerAuthid[i],playerStreak[i]);
  7554. fputc(streakFile,'^n');
  7555. }
  7556. }
  7557. }
  7558.  
  7559. if(streakFile)
  7560. {
  7561. if(streakToBeat)
  7562. {
  7563. if(streakChamp == -1) fprintf(streakFile,"%s",streakRecord); // no one here beat the champ, reprint old champ
  7564. else // otherwise, give the new guy credit
  7565. {
  7566. fprintf(streakFile,"%iR^t%s^t%i^t%s^t%i",si,playerAuthid[streakChamp],playerStreak[streakChamp],playerName[streakChamp],systime);
  7567. fputc(streakFile,'^n');
  7568. }
  7569. }
  7570.  
  7571. fclose(streakFile);
  7572. }
  7573. #endif
  7574.  
  7575. // we have a new champion, record their stuff
  7576. if(streakChamp != -1)
  7577. {
  7578. pointsExtraction[0][1] = players[streakChamp]; // record champion
  7579. pointsExtraction[0][2] = playerStreak[streakChamp]; // record new record
  7580. copy(spareName,31,playerName[streakChamp]);
  7581. }
  7582.  
  7583. //
  7584. // NOW GO THROUGH THE FILE
  7585. //
  7586.  
  7587. #if defined SQL
  7588. new sfWins[2], sfPoints[2], sfStreak[2];
  7589.  
  7590. // do one query to grab all stats we need
  7591. len = formatex(mkQuery,1535,"SELECT authid,wins,points,streak,wins_tp,points_tp,streak_tp FROM `%s` WHERE serverip='%s' AND authid IN(",sqlTable,serverip);
  7592. for(i=0;i<playerNum;i++)
  7593. {
  7594. len += formatex(mkQuery[len],1535-len,"'%s'%s",playerSafeAuthid[i],(i==playerNum-1) ? "" : ",");
  7595. }
  7596. len += formatex(mkQuery[len],1535-len,");");
  7597.  
  7598. // go through results
  7599. new foundMe[33];
  7600.  
  7601. query = SQL_PrepareQuery(db,mkQuery);
  7602. if(SQL_ExecuteAndLog(query) && SQL_NumResults(query))
  7603. {
  7604. new Handle:query2;
  7605.  
  7606. while(SQL_MoreResults(query))
  7607. {
  7608. SQL_ReadResult(query,0,authid,63);
  7609.  
  7610. for(i=0;i<playerNum;i++)
  7611. {
  7612. if(foundMe[i] || !equal(authid,playerSafeAuthid[i])) continue;
  7613.  
  7614. // remember for later iterations
  7615. foundMe[i] = 1;
  7616.  
  7617. sfWins[0] = SQL_ReadResult(query,1);
  7618. sfPoints[0] = SQL_ReadResult(query,2);
  7619. sfStreak[0] = SQL_ReadResult(query,3);
  7620. sfWins[1] = SQL_ReadResult(query,4);
  7621. sfPoints[1] = SQL_ReadResult(query,5);
  7622. sfStreak[1] = SQL_ReadResult(query,6);
  7623.  
  7624. // if we set a new personal streak record, save it
  7625. intStreak = sfStreak[si];
  7626. pointsExtraction[players[i]][4] = intStreak; // show old record
  7627. if(playerStreak[i] > intStreak) intStreak = playerStreak[i];
  7628.  
  7629. // so we can reference this for the MOTD
  7630. playerTotalPoints[i] = playerPoints[i] + sfPoints[si];
  7631. pointsExtraction[players[i]][0] = sfWins[si] + playerWins[i];
  7632. pointsExtraction[players[i]][1] = playerPoints[i];
  7633. pointsExtraction[players[i]][2] = playerTotalPoints[i];
  7634. pointsExtraction[players[i]][3] = playerStreak[i];
  7635. //pointsExtraction[players[i]][4] = intStreak; // uncomment to show new record
  7636.  
  7637. // something worth updating
  7638. if(playerWins[i] || playerPoints[i])
  7639. {
  7640. if(si == 0) query2 = SQL_PrepareQuery(db,"UPDATE `%s` SET wins=wins+'%i',name='%s',timestamp='%i',points=points+'%i',streak='%i' WHERE authid='%s' AND serverip='%s' LIMIT 1;",sqlTable,playerWins[i],playerSafeName[i],systime,playerPoints[i],intStreak,playerSafeAuthid[i],serverip);
  7641. else query2 = SQL_PrepareQuery(db,"UPDATE `%s` SET wins_tp=wins_tp+'%i',name='%s',timestamp='%i',points_tp=points_tp+'%i',streak_tp='%i' WHERE authid='%s' AND serverip='%s' LIMIT 1;",sqlTable,playerWins[i],playerSafeName[i],systime,playerPoints[i],intStreak,playerSafeAuthid[i],serverip);
  7642.  
  7643. SQL_ExecuteAndLog(query2);
  7644. SQL_FreeHandle(query2);
  7645. }
  7646.  
  7647. break;
  7648. }
  7649.  
  7650. SQL_NextRow(query);
  7651. }
  7652. }
  7653. SQL_FreeHandle(query);
  7654.  
  7655. len = 0;
  7656.  
  7657. // go through again for people we didn't find
  7658. for(i=0;i<playerNum;i++)
  7659. {
  7660. // nothing worth reporting, still refresh timestamp
  7661. if(!playerWins[i] && !playerPoints[i])
  7662. {
  7663. stats_refresh_timestamp(playerAuthid[i]);
  7664. continue;
  7665. }
  7666.  
  7667. // already found me
  7668. if(foundMe[i]) continue;
  7669.  
  7670. // so we can reference this for the MOTD
  7671. playerTotalPoints[i] = playerPoints[i];
  7672. pointsExtraction[players[i]][0] = playerWins[i];
  7673. pointsExtraction[players[i]][1] = playerPoints[i];
  7674. pointsExtraction[players[i]][2] = playerTotalPoints[i];
  7675. pointsExtraction[players[i]][3] = playerStreak[i];
  7676. pointsExtraction[players[i]][4] = 0; // show old record
  7677.  
  7678. // haven't started yet
  7679. if(len == 0)
  7680. {
  7681. if(si == 0) len = origLen = formatex(mkQuery,1535,"INSERT INTO `%s` (authid,name,timestamp,wins,points,streak,serverip) VALUES ",sqlTable);
  7682. else len = origLen = formatex(mkQuery,1535,"INSERT INTO `%s` (authid,name,timestamp,wins_tp,points_tp,streak_tp,serverip) VALUES ",sqlTable);
  7683. }
  7684.  
  7685. len += formatex(mkQuery[len],1535-len,"('%s','%s','%i','%i','%i','%i','%s'),",playerSafeAuthid[i],playerSafeName[i],systime,playerWins[i],playerTotalPoints[i],playerStreak[i],serverip);
  7686.  
  7687. // cash in if we get too close
  7688. if(len >= 1200)
  7689. {
  7690. mkQuery[len-1] = ';';
  7691. mkQuery[len] = 0;
  7692.  
  7693. query = SQL_PrepareQuery(db,mkQuery);
  7694. SQL_ExecuteAndLog(query);
  7695. SQL_FreeHandle(query);
  7696.  
  7697. len = 0;
  7698. }
  7699. }
  7700.  
  7701. // if we have some leftover query
  7702. if(len && len > origLen)
  7703. {
  7704. mkQuery[len-1] = ';';
  7705. mkQuery[len] = 0;
  7706.  
  7707. query = SQL_PrepareQuery(db,mkQuery);
  7708. SQL_ExecuteAndLog(query);
  7709. SQL_FreeHandle(query);
  7710. }
  7711. #else
  7712. new file;
  7713. get_pcvar_string(gg_stats_file,sfFile,63);
  7714. formatex(tempFileName,64,"%s2",sfFile); // our temp file, append 2
  7715.  
  7716. // create file if it does not exist (thanks Min2liz)
  7717. if(!file_exists(sfFile))
  7718. {
  7719. file = fopen(sfFile,"wt");
  7720. fclose(file);
  7721. }
  7722.  
  7723. rename_file(sfFile,tempFileName,1); // copy over current stat file (relative flag)
  7724. if(!file_exists(tempFileName)) return; // rename failed?
  7725.  
  7726. new sfWins[2][6], sfPoints[2][8], set[32], setNum;
  7727.  
  7728. new tempFile = fopen(tempFileName,"rt"), lastSetNum;
  7729. file = fopen(sfFile,"wt");
  7730.  
  7731. // go through our old copy and rewrite entries
  7732. while(tempFile && file && !feof(tempFile))
  7733. {
  7734. fgets(tempFile,sfLineData,111);
  7735. if(!sfLineData[0]) continue;
  7736.  
  7737. // still have scores to add to
  7738. lastSetNum = setNum;
  7739. if(setNum < playerNum)
  7740. {
  7741. strtok(sfLineData,sfAuthid,31,sfLineData,111,'^t'); // isolate authid
  7742.  
  7743. // see if we need to change this one
  7744. for(i=0;i<playerNum;i++)
  7745. {
  7746. if(!set[i] && equal(playerAuthid[i],sfAuthid))
  7747. {
  7748. set[i] = 1;
  7749. setNum++;
  7750.  
  7751. strtok(sfLineData,sfWins[0],5,sfLineData,111,'^t'); // get wins
  7752. strtok(sfLineData,dummy,1,sfLineData,111,'^t'); // get name
  7753. strtok(sfLineData,dummy,1,sfLineData,111,'^t'); // get timestamp
  7754. strtok(sfLineData,sfPoints[0],7,sfLineData,111,'^t'); // get points
  7755. strtok(sfLineData,sfStreak[0],3,sfLineData,111,'^t'); // get streak
  7756.  
  7757. strtok(sfLineData,sfWins[1],5,sfLineData,111,'^t'); // get teamplay wins
  7758. strtok(sfLineData,sfPoints[1],7,sfStreak[1],3,'^t'); // get teamplay points and teamplay streak
  7759.  
  7760. // if we set a new personal streak record, save it
  7761. intStreak = str_to_num(sfStreak[si]);
  7762. pointsExtraction[players[i]][4] = intStreak; // show old record
  7763. if(playerStreak[i] > intStreak) intStreak = playerStreak[i];
  7764.  
  7765. playerTotalPoints[i] = playerPoints[i] + str_to_num(sfPoints[si]); // AUTHID WINS NAME TIMESTAMP POINTS STREAK TPWINS TPPOINTS TPSTREAK
  7766.  
  7767. if(si == 0) fprintf(file,"%s^t%i^t%s^t%i^t%i^t%i^t%i^t%i^t%i",sfAuthid,str_to_num(sfWins[0])+playerWins[i],playerName[i],systime,playerTotalPoints[i],intStreak,str_to_num(sfWins[1]),str_to_num(sfPoints[1]),str_to_num(sfStreak[1]));
  7768. else fprintf(file,"%s^t%i^t%s^t%i^t%i^t%i^t%i^t%i^t%i",sfAuthid,str_to_num(sfWins[0]),playerName[i],systime,str_to_num(sfPoints[0]),str_to_num(sfStreak[0]),str_to_num(sfWins[1])+playerWins[i],playerTotalPoints[i],intStreak);
  7769.  
  7770. fputc(file,'^n');
  7771.  
  7772. // so we can reference this for the MOTD
  7773. pointsExtraction[players[i]][0] = str_to_num(sfWins[si])+playerWins[i];
  7774. pointsExtraction[players[i]][1] = playerPoints[i];
  7775. pointsExtraction[players[i]][2] = playerTotalPoints[i];
  7776. pointsExtraction[players[i]][3] = playerStreak[i];
  7777. //pointsExtraction[players[i]][4] = intStreak; // uncomment to show new record
  7778.  
  7779. break;
  7780. }
  7781. }
  7782.  
  7783. // nothing to replace, just copy it over (newline is already included)
  7784. if(lastSetNum == setNum) fprintf(file,"%s^t%s",sfAuthid,sfLineData); // we cut authid earlier
  7785. }
  7786. else fprintf(file,"%s",sfLineData); // nothing to replace, just copy it over (newline is already included)
  7787. }
  7788.  
  7789. for(i=0;i<playerNum;i++)
  7790. {
  7791. // never found an existing entry, make a new one
  7792. if(!set[i] && (playerWins[i] || playerPoints[i]))
  7793. {
  7794. playerTotalPoints[i] = playerPoints[i]; // AUTHID WINS NAME TIMESTAMP POINTS STREAK TPWINS TPPOINTS TPSTREAK
  7795.  
  7796. if(si == 0) fprintf(file,"%s^t%i^t%s^t%i^t%i^t%i^t0^t0^t0",playerAuthid[i],playerWins[i],playerName[i],systime,playerTotalPoints[i],playerStreak[i]);
  7797. else fprintf(file,"%s^t0^t%s^t%i^t0^t0^t%i^t%i^t%i",playerAuthid[i],playerName[i],systime,playerWins[i],playerTotalPoints[i],playerStreak[i]);
  7798.  
  7799. fputc(file,'^n');
  7800.  
  7801. // so we can reference this for the MOTD
  7802. pointsExtraction[players[i]][0] = playerWins[i];
  7803. pointsExtraction[players[i]][1] = playerPoints[i];
  7804. pointsExtraction[players[i]][2] = playerTotalPoints[i];
  7805. pointsExtraction[players[i]][3] = playerStreak[i];
  7806. pointsExtraction[players[i]][4] = 0; // show old record
  7807. }
  7808. }
  7809.  
  7810. if(tempFile) fclose(tempFile);
  7811. if(file) fclose(file);
  7812.  
  7813. // remove our copy
  7814. delete_file(tempFileName);
  7815. #endif
  7816.  
  7817. new teamName[10], key_GAINED_POINTS[18];
  7818.  
  7819. // decide what to use based on split and such
  7820. if(get_pcvar_num(gg_stats_split))
  7821. {
  7822. if(teamplay) key_GAINED_POINTS = "GAINED_POINTS_TP";
  7823. else key_GAINED_POINTS = "GAINED_POINTS_REG";
  7824. }
  7825. else key_GAINED_POINTS = "GAINED_POINTS";
  7826.  
  7827. for(i=0;i<playerNum;i++)
  7828. {
  7829. get_user_team(players[i],teamName,9);
  7830.  
  7831. //if(players[i] == winner || (teamplay && _:cs_get_user_team(players[i]) == winningTeam))
  7832. if(playerWins[i]) log_message("^"%s<%i><%s><%s>^" triggered ^"Won_GunGame^"",playerName[i],get_user_userid(players[i]),playerAuthid[i],teamName);
  7833.  
  7834. if(stats_mode == 2 && playerPoints[i])
  7835. {
  7836. log_message("^"%s<%i><%s><%s>^" triggered ^"GunGame_Points^" amount ^"%i^"",playerName[i],get_user_userid(players[i]),playerAuthid[i],teamName,playerPoints[i]);
  7837. gungame_print(players[i],0,1,"%L",players[i],key_GAINED_POINTS,playerPoints[i],playerTotalPoints[i],pointsExtraction[players[i]][0]);
  7838. }
  7839. }
  7840. }
  7841.  
  7842. stock stats_clear_struct(struct[statsData],clearAuthid=1)
  7843. {
  7844. if(clearAuthid) struct[sdAuthid][0] = 0;
  7845. struct[sdWins][0] = 0;
  7846. struct[sdName][0] = 0;
  7847. struct[sdTimestamp] = 0;
  7848. struct[sdPoints][0] = 0;
  7849. struct[sdStreak][0] = 0;
  7850. struct[sdWins][1] = 0;
  7851. struct[sdPoints][1] = 0;
  7852. struct[sdStreak][1] = 0;
  7853. }
  7854.  
  7855. #if defined SQL
  7856. // sql version] get a player's last used name and wins from save file
  7857. stock stats_get_data(authid[],struct[statsData],id=0)
  7858. {
  7859. if(!sqlInit || !get_pcvar_num(gg_stats_mode))
  7860. {
  7861. stats_clear_struct(struct);
  7862. return 0;
  7863. }
  7864.  
  7865. if(id > 0 && playerStats[id][sdAuthid][0]) // already saved my stats
  7866. {
  7867. struct = playerStats[id];
  7868. return 1;
  7869. }
  7870.  
  7871. stats_clear_struct(struct);
  7872.  
  7873. SQL_QuoteString(db,safeName,63,authid);
  7874. query = SQL_PrepareQuery(db,"SELECT wins,name,points,streak,wins_tp,points_tp,streak_tp FROM `%s` WHERE authid='%s' AND serverip='%s' LIMIT 1;",sqlTable,safeName,serverip);
  7875.  
  7876. if(!SQL_ExecuteAndLog(query))
  7877. {
  7878. SQL_FreeHandle(query);
  7879. return 0;
  7880. }
  7881.  
  7882. copy(struct[sdAuthid],31,authid); // setting authid will cache it if this is playerStats
  7883.  
  7884. new found = SQL_NumResults(query);
  7885. if(found)
  7886. {
  7887. struct[sdWins][0] = SQL_ReadResult(query,0);
  7888. SQL_ReadResult(query,1,struct[sdName],31);
  7889. struct[sdPoints][0] = SQL_ReadResult(query,2);
  7890. struct[sdStreak][0] = SQL_ReadResult(query,3);
  7891. struct[sdWins][1] = SQL_ReadResult(query,4);
  7892. struct[sdPoints][1] = SQL_ReadResult(query,5);
  7893. struct[sdStreak][1] = SQL_ReadResult(query,6);
  7894. }
  7895.  
  7896. if(id > 0) playerStats[id] = struct; // if this is a connected player, save it
  7897.  
  7898. SQL_FreeHandle(query);
  7899. return found;
  7900. }
  7901. #else
  7902. // get a player's last used name and wins from save file
  7903. stock stats_get_data(authid[],struct[statsData],id=0)
  7904. {
  7905. if(!get_pcvar_num(gg_stats_mode))
  7906. {
  7907. stats_clear_struct(struct);
  7908. return 0;
  7909. }
  7910.  
  7911. get_pcvar_string(gg_stats_file,sfFile,63);
  7912. if(!file_exists(sfFile))
  7913. {
  7914. stats_clear_struct(struct);
  7915. return 0;
  7916. }
  7917.  
  7918. if(id > 0)
  7919. {
  7920. if(playerStats[id][sdAuthid][0]) // already saved my stats
  7921. {
  7922. struct = playerStats[id];
  7923. return 1;
  7924. }
  7925. else if(statsPosition[id][0] > 0) // check top regular players
  7926. {
  7927. ArrayGetArray(statsArray,ArrayGetCell(statsPointers[0],statsPosition[id][0]-1),playerStats[id]);
  7928. struct = playerStats[id];
  7929. return 1;
  7930. }
  7931. else if(statsPosition[id][1] > 0) // check top teamplay players
  7932. {
  7933. ArrayGetArray(statsArray,ArrayGetCell(statsPointers[1],statsPosition[id][1]-1),playerStats[id]);
  7934. struct = playerStats[id];
  7935. return 1;
  7936. }
  7937. }
  7938.  
  7939. stats_clear_struct(struct);
  7940.  
  7941. // now we have to go through the file
  7942.  
  7943. // open 'er up, boys!
  7944. new found, file = fopen(sfFile,"rt");
  7945. if(!file) return 0;
  7946.  
  7947. // go through it
  7948. while(!feof(file))
  7949. {
  7950. fgets(file,sfLineData,111);
  7951. strtok(sfLineData,sfAuthid,31,dummy,1,'^t'); // isolate authid
  7952.  
  7953. // this is it, stop now because our data is already stored in sfLineData
  7954. if(equal(authid,sfAuthid))
  7955. {
  7956. found = 1;
  7957. break;
  7958. }
  7959. }
  7960.  
  7961. // close 'er up, boys! (hmm....)
  7962. fclose(file);
  7963.  
  7964. copy(struct[sdAuthid],31,authid); // setting authid will cache it if this is playerStats
  7965.  
  7966. // couldn't find
  7967. if(found)
  7968. {
  7969. stats_str_to_struct(sfLineData,struct); // convert line from file to a struct
  7970. }
  7971.  
  7972. if(id > 0) playerStats[id] = struct; // if this is a connected player, save it
  7973.  
  7974. return found;
  7975. }
  7976. #endif
  7977.  
  7978. #if defined SQL
  7979. public stats_get_top_players()
  7980. {
  7981. if(!ggActive || !sqlInit) return 0;
  7982.  
  7983. lastStatsMode = get_pcvar_num(gg_stats_mode);
  7984. if(!lastStatsMode) return 0;
  7985.  
  7986. // assign stat position to players already in the game
  7987. new i, authid[32], stats_ip = get_pcvar_num(gg_stats_ip);
  7988. for(i=1;i<=maxPlayers;i++)
  7989. {
  7990. if(is_user_connected(i))
  7991. {
  7992. get_gg_authid(i,authid,31,stats_ip);
  7993. if(!statsPosition[i][0]) stats_get_position(i,authid,0);
  7994. if(!statsPosition[i][1]) stats_get_position(i,authid,1);
  7995. }
  7996. }
  7997.  
  7998. return 1;
  7999. }
  8000. #else
  8001. public stats_get_top_players()
  8002. {
  8003. if(!ggActive || !sqlInit) return 0;
  8004.  
  8005. lastStatsMode = get_pcvar_num(gg_stats_mode);
  8006. if(!lastStatsMode) return 0;
  8007.  
  8008. // we never made the array
  8009. if(!statsArray)
  8010. {
  8011. get_pcvar_string(gg_stats_file,sfFile,63);
  8012. if(!file_exists(sfFile)) return 0;
  8013.  
  8014. statsArray = ArrayCreate(statsData,100);
  8015. statsPointers[0] = ArrayCreate(1,100);
  8016. statsPointers[1] = ArrayCreate(1,100);
  8017.  
  8018. new file = fopen(sfFile,"rt");
  8019. if(file)
  8020. {
  8021. new entryNum;
  8022.  
  8023. while(!feof(file))
  8024. {
  8025. fgets(file,sfLineData,111);
  8026. if(!sfLineData[0]) continue;
  8027. stats_str_to_struct(sfLineData,sfStatsStruct);
  8028.  
  8029. // put all of our stats entries, with all of the info and stuff, into our big stats array
  8030. ArrayPushArray(statsArray,sfStatsStruct);
  8031.  
  8032. // and then put just their indexes into our "pointer" cell arrays
  8033. if(sfStatsStruct[sdWins][0] || sfStatsStruct[sdPoints][0])
  8034. {
  8035. ArrayPushCell(statsPointers[0],entryNum);
  8036. statsSize[0]++;
  8037. }
  8038. if(sfStatsStruct[sdWins][1] || sfStatsStruct[sdPoints][1])
  8039. {
  8040. ArrayPushCell(statsPointers[1],entryNum);
  8041. statsSize[1]++;
  8042. }
  8043.  
  8044. entryNum++;
  8045. }
  8046. fclose(file);
  8047.  
  8048. ArraySort(statsPointers[0],"stats_pointer_sort_reg");
  8049. ArraySort(statsPointers[1],"stats_pointer_sort_tp");
  8050.  
  8051. if(statsSize[0] > MAX_STATS_RANK) statsSize[0] = MAX_STATS_RANK;
  8052. if(statsSize[1] > MAX_STATS_RANK) statsSize[1] = MAX_STATS_RANK;
  8053. }
  8054. }
  8055.  
  8056. // if we were able to get anything put together
  8057. if(statsSize[0] || statsSize[1])
  8058. {
  8059. // assign stat position to players already in the game
  8060. new i, authid[32], stats_ip = get_pcvar_num(gg_stats_ip);
  8061. for(i=1;i<=maxPlayers;i++)
  8062. {
  8063. if(is_user_connected(i))
  8064. {
  8065. get_gg_authid(i,authid,31,stats_ip);
  8066. if(!statsPosition[i][0]) stats_get_position(i,authid,0); // these only work if statsSize[si] > 0
  8067. if(!statsPosition[i][1]) stats_get_position(i,authid,1);
  8068. }
  8069. }
  8070. }
  8071.  
  8072. return 1;
  8073. }
  8074.  
  8075. // seems to be slightly faster without passing in extra data, and this is how we used to do it, so we'll continue to use two functions to sort
  8076. public stats_pointer_sort_reg(Array:array,item1,item2)
  8077. {
  8078. static score[2];
  8079.  
  8080. if(lastStatsMode == 1) // sort by wins
  8081. {
  8082. ArrayGetArray(statsArray,ArrayGetCell(array,item1),sfStatsStruct);
  8083. score[0] = sfStatsStruct[sdWins][0];
  8084.  
  8085. ArrayGetArray(statsArray,ArrayGetCell(array,item2),sfStatsStruct);
  8086. score[1] = sfStatsStruct[sdWins][0];
  8087. }
  8088. else // sort by points
  8089. {
  8090. ArrayGetArray(statsArray,ArrayGetCell(array,item1),sfStatsStruct);
  8091. score[0] = sfStatsStruct[sdPoints][0];
  8092.  
  8093. ArrayGetArray(statsArray,ArrayGetCell(array,item2),sfStatsStruct);
  8094. score[1] = sfStatsStruct[sdPoints][0];
  8095. }
  8096.  
  8097. return score[1] - score[0];
  8098. }
  8099.  
  8100. // seems to be slightly faster without passing in extra data, and this is how we used to do it, so we'll continue to use two functions to sort
  8101. public stats_pointer_sort_tp(Array:array,item1,item2)
  8102. {
  8103. static score[2];
  8104.  
  8105. if(lastStatsMode == 1) // sort by wins
  8106. {
  8107. ArrayGetArray(statsArray,ArrayGetCell(array,item1),sfStatsStruct);
  8108. score[0] = sfStatsStruct[sdWins][1];
  8109.  
  8110. ArrayGetArray(statsArray,ArrayGetCell(array,item2),sfStatsStruct);
  8111. score[1] = sfStatsStruct[sdWins][1];
  8112. }
  8113. else // sort by points
  8114. {
  8115. ArrayGetArray(statsArray,ArrayGetCell(array,item1),sfStatsStruct);
  8116. score[0] = sfStatsStruct[sdPoints][1];
  8117.  
  8118. ArrayGetArray(statsArray,ArrayGetCell(array,item2),sfStatsStruct);
  8119. score[1] = sfStatsStruct[sdPoints][1];
  8120. }
  8121.  
  8122. return score[1] - score[0];
  8123. }
  8124. #endif
  8125.  
  8126. // gather up our players
  8127. /*public stats_get_top_players()
  8128. {
  8129. if(!ggActive) return 0;
  8130.  
  8131. glStatsMode = get_pcvar_num(gg_stats_mode);
  8132. if(!glStatsMode) return 0;
  8133.  
  8134. get_pcvar_string(gg_stats_file,sfFile,63);
  8135. if(!file_exists(sfFile)) return 0;
  8136.  
  8137. new buildMe[2], stats_split = get_pcvar_num(gg_stats_split);
  8138.  
  8139. // figure out if we need to build any of the arrays still
  8140. if(!statsArray[0])
  8141. {
  8142. statsArray[0] = ArrayCreate(statsData,100);
  8143. statsSize[0] = 0;
  8144. buildMe[0] = 1;
  8145. }
  8146. if(!statsArray[1] && stats_split)
  8147. {
  8148. statsArray[1] = ArrayCreate(statsData,100);
  8149. statsSize[1] = 0;
  8150. buildMe[1] = 1;
  8151. }
  8152.  
  8153. // if we do have an array or two to build
  8154. if(buildMe[0] || buildMe[1])
  8155. {
  8156. // storage format:
  8157. // AUTHID WINS LAST_USED_NAME TIMESTAMP POINTS STREAK TPWINS TPPOINTS TPSTREAK
  8158.  
  8159. new file = fopen(sfFile,"rt");
  8160. if(file)
  8161. {
  8162. while(!feof(file))
  8163. {
  8164. fgets(file,sfLineData,111);
  8165. if(!sfLineData[0]) continue;
  8166. stats_str_to_struct(sfLineData,sfStatsStruct);
  8167.  
  8168. // if we are working on this array, and we have some wins or points for it
  8169. if(buildMe[0] && (sfStatsStruct[sdWins][0] || sfStatsStruct[sdPoints][0]))
  8170. {
  8171. ArrayPushArray(statsArray[0],sfStatsStruct);
  8172. statsSize[0]++;
  8173. }
  8174. if(buildMe[1] && (sfStatsStruct[sdWins][1] || sfStatsStruct[sdPoints][1]))
  8175. {
  8176. ArrayPushArray(statsArray[1],sfStatsStruct);
  8177. statsSize[1]++;
  8178. }
  8179. }
  8180. fclose(file);
  8181.  
  8182. if(buildMe[0] && statsSize[0] > 1) // if we were working on this array and we have something to sort
  8183. {
  8184. ArraySort(statsArray[0],"stats_custom_compare_regular");
  8185. if(statsSize[0] > 1000) statsSize[0] = 1000; // arbitrarily limit because we have to look through this every time someone connects
  8186. }
  8187. if(buildMe[1] && statsSize[1] > 1)
  8188. {
  8189. ArraySort(statsArray[1],"stats_custom_compare_teamplay");
  8190. if(statsSize[1] > 1000) statsSize[1] = 1000;
  8191. }
  8192. }
  8193.  
  8194. // clear any saved stats positions out of the tempsaves, so no one rejoins with the wrong position
  8195. for(new i=0;i<TEMP_SAVES;i++)
  8196. {
  8197. tempSave[i][34] = 0;
  8198. tempSave[i][35] = 0;
  8199. }
  8200. }
  8201.  
  8202. // if we were able to get anything put together
  8203. if(statsSize[0] || statsSize[1])
  8204. {
  8205. // assign stat position to players already in the game
  8206. new i, authid[32], stats_ip = get_pcvar_num(gg_stats_ip);
  8207. for(i=1;i<=maxPlayers;i++)
  8208. {
  8209. if(is_user_connected(i))
  8210. {
  8211. get_gg_authid(i,authid,31,stats_ip);
  8212. if(!statsPosition[i][0]) stats_get_position(i,authid,0); // these will only do anything if we created the respective array above
  8213. if(!statsPosition[i][1]) stats_get_position(i,authid,1);
  8214. }
  8215. }
  8216. }
  8217.  
  8218. lastStatsMode = glStatsMode;
  8219. statsLastSplit = stats_split;
  8220.  
  8221. return 1;
  8222. }*/
  8223.  
  8224. // our custom sorting functions
  8225. /*public stats_custom_compare_regular(Array:array,item1,item2)
  8226. {
  8227. static score[2];
  8228.  
  8229. ArrayGetArray(array,item1,sfStatsStruct);
  8230. if(glStatsMode == 1) score[0] = sfStatsStruct[sdWins][0]; // sort by wins
  8231. else score[0] = sfStatsStruct[sdPoints][0]; // sort by wins
  8232.  
  8233. ArrayGetArray(array,item2,sfStatsStruct);
  8234. if(glStatsMode == 1) score[1] = sfStatsStruct[sdWins][0]; // sort by wins
  8235. else score[1] = sfStatsStruct[sdPoints][0]; // sort by wins
  8236.  
  8237. return score[1] - score[0];
  8238. }*/
  8239.  
  8240. /*public stats_custom_compare_teamplay(Array:array,item1,item2)
  8241. {
  8242. static score[2];
  8243.  
  8244. ArrayGetArray(array,item1,sfStatsStruct);
  8245. if(glStatsMode == 1) score[0] = sfStatsStruct[sdWins][1]; // sort by wins
  8246. else score[0] = sfStatsStruct[sdPoints][1]; // sort by wins
  8247.  
  8248. ArrayGetArray(array,item2,sfStatsStruct);
  8249. if(glStatsMode == 1) score[1] = sfStatsStruct[sdWins][1]; // sort by wins
  8250. else score[1] = sfStatsStruct[sdPoints][1]; // sort by wins
  8251.  
  8252. return score[1] - score[0];
  8253. }*/
  8254.  
  8255. #if defined SQL
  8256. // get a player's overall position
  8257. stats_get_position(id,authid[],si)
  8258. {
  8259. if(!sqlInit) return 0; // can't get position yet
  8260.  
  8261. statsPosition[id][si] = -1; // mark that we've at least attempted to find it
  8262.  
  8263. new stats_mode = get_pcvar_num(gg_stats_mode), myPoints;
  8264.  
  8265. // first, we need to get their current amount of wins/points. this allows us to make sure that they are really in the database
  8266. // (could cause problems with a sub-query returning 0 instead of NULL) and that they actually have wins/points for the current
  8267. // stats mode (could cause problems when they are in the database but you are looking at their stats index for which they have
  8268. // no points). then, we might as well use the result for our ranking query instead of using a sub-query.
  8269.  
  8270. // if we don't have the cached stats, we will have to do a query to get the wins/points. since we would be doing a query for it
  8271. // anyway, we might as well just get all of the stats at once.
  8272. stats_get_data(authid,playerStats[id],id); // stats_get_data should automatically manage cache
  8273.  
  8274. if(stats_mode == 2) myPoints = playerStats[id][sdPoints][si];
  8275. else myPoints = playerStats[id][sdWins][si];
  8276.  
  8277. if(myPoints <= 0 && (stats_mode != 2 || playerStats[id][sdWins][si] <= 0)) return -1;
  8278.  
  8279. new winsColumn[8], pointsColumn[10];
  8280.  
  8281. if(si == 0)
  8282. {
  8283. winsColumn = "wins";
  8284. pointsColumn = "points";
  8285. }
  8286. else
  8287. {
  8288. winsColumn = "wins_tp";
  8289. pointsColumn = "points_tp";
  8290. }
  8291.  
  8292. // select the number of people who have a score higher than I do, plus one. query from Giuseppe Maxia
  8293. if(stats_mode == 2)
  8294. {
  8295. query = SQL_PrepareQuery(db,"SELECT COUNT(*)+1 AS ranking FROM `%s` WHERE %s > %i AND serverip='%s' AND (%s > 0 OR %s > 0);",
  8296. sqlTable,pointsColumn,myPoints,serverip,winsColumn,pointsColumn);
  8297. }
  8298. else
  8299. {
  8300. query = SQL_PrepareQuery(db,"SELECT COUNT(*)+1 AS ranking FROM `%s` WHERE %s > %i AND serverip='%s';",
  8301. sqlTable,winsColumn,myPoints,serverip);
  8302. }
  8303.  
  8304. if(SQL_ExecuteAndLog(query))
  8305. {
  8306. new result = SQL_ReadResult(query,0);
  8307. SQL_FreeHandle(query);
  8308.  
  8309. statsPosition[id][si] = result;
  8310. return result;
  8311. }
  8312.  
  8313. SQL_FreeHandle(query);
  8314. return -1;
  8315. }
  8316. #else
  8317. // get a player's overall position
  8318. stats_get_position(id,authid[],si)
  8319. {
  8320. if(statsArray && statsPointers[si] && statsSize[si])
  8321. {
  8322. statsPosition[id][si] = -1; // mark that we've at least attempted to find it
  8323.  
  8324. for(new i=0;i<statsSize[si];i++)
  8325. {
  8326. ArrayGetArray(statsArray,ArrayGetCell(statsPointers[si],i),sfStatsStruct);
  8327. if(equal(authid,sfStatsStruct[sdAuthid]))
  8328. {
  8329. statsPosition[id][si] = i+1;
  8330. return i+1;
  8331. }
  8332. }
  8333.  
  8334. return -1;
  8335. }
  8336.  
  8337. return 0;
  8338. }
  8339. #endif
  8340.  
  8341. #if defined SQL
  8342. // prune old entries
  8343. stock stats_prune(max_time=-1)
  8344. {
  8345. if(!sqlInit) return 0;
  8346.  
  8347. if(max_time == -1) max_time = get_pcvar_num(gg_stats_prune); // -1 = use value from cvar
  8348. if(max_time == 0) return 0; // 0 = no pruning
  8349.  
  8350. // prune old entries
  8351. formatex(mkQuery,255,"DELETE FROM `%s` WHERE timestamp < %i AND serverip='%s';",sqlTable,get_systime() - max_time,serverip);
  8352. SQL_ThreadQuery(tuple,"sql_qhandler_prune",mkQuery);
  8353.  
  8354. // fix up all of our tables
  8355. formatex(mkQuery,255,"REPAIR TABLE `%s`;",sqlTable);
  8356. SQL_ThreadQuery(tuple,"sql_qhandler_dummy",mkQuery);
  8357.  
  8358. formatex(mkQuery,255,"OPTIMIZE TABLE `%s`;",sqlTable);
  8359. SQL_ThreadQuery(tuple,"sql_qhandler_dummy",mkQuery);
  8360.  
  8361. formatex(mkQuery,255,"REPAIR TABLE `%s`;",sqlStreakTable);
  8362. SQL_ThreadQuery(tuple,"sql_qhandler_dummy",mkQuery);
  8363.  
  8364. formatex(mkQuery,255,"OPTIMIZE TABLE `%s`;",sqlStreakTable);
  8365. SQL_ThreadQuery(tuple,"sql_qhandler_dummy",mkQuery);
  8366.  
  8367. return -1;
  8368. }
  8369. #else
  8370. // prune old entries
  8371. stock stats_prune(max_time=-1)
  8372. {
  8373. get_pcvar_string(gg_stats_file,sfFile,63);
  8374. if(!file_exists(sfFile)) return 0;
  8375.  
  8376. if(max_time == -1) max_time = get_pcvar_num(gg_stats_prune); // -1 = use value from cvar
  8377. if(max_time == 0) return 0; // 0 = no pruning
  8378.  
  8379. new tempFileName[33];
  8380. formatex(tempFileName,32,"%s2",sfFile); // our temp file, append 2
  8381.  
  8382. // copy over current stat file
  8383. rename_file(sfFile,tempFileName,1); // relative
  8384.  
  8385. // rename failed?
  8386. if(!file_exists(tempFileName)) return 0;
  8387.  
  8388. new tempFile = fopen(tempFileName,"rt");
  8389. new file = fopen(sfFile,"wt");
  8390.  
  8391. // go through our old copy and rewrite valid entries into the new copy
  8392. new systime = get_systime(), original[112], removed;
  8393. while(tempFile && file && !feof(tempFile))
  8394. {
  8395. fgets(tempFile,sfLineData,111);
  8396. if(!sfLineData[0]) continue;
  8397.  
  8398. // save original
  8399. original = sfLineData;
  8400.  
  8401. // break off authid
  8402. strtok(sfLineData,dummy,1,sfLineData,111,'^t');
  8403.  
  8404. // break off wins
  8405. strtok(sfLineData,dummy,1,sfLineData,111,'^t');
  8406.  
  8407. // break off name, and thus get timestamp
  8408. strtok(sfLineData,dummy,1,sfTimestamp,11,'^t');
  8409. copyc(sfTimestamp,11,sfTimestamp,'^t'); // cut off points
  8410.  
  8411. // not too old, write it to our new file
  8412. if(systime - str_to_num(sfTimestamp) <= max_time)
  8413. fprintf(file,"%s",original); // newline is already included
  8414. else
  8415. removed++;
  8416. }
  8417.  
  8418. if(tempFile) fclose(tempFile);
  8419. if(file) fclose(file);
  8420.  
  8421. // remove our copy
  8422. delete_file(tempFileName);
  8423. return removed;
  8424. }
  8425. #endif
  8426.  
  8427. //**********************************************************************
  8428. // SQL FUNCTIONS
  8429. //**********************************************************************
  8430.  
  8431. #if defined SQL
  8432.  
  8433. // opens the database
  8434. stock sql_init(creation_queries=1)
  8435. {
  8436. new host[128], user[128], pass[128], dbname[128];
  8437. get_pcvar_string(gg_sql_host,host,127);
  8438. get_pcvar_string(gg_sql_user,user,127);
  8439. get_pcvar_string(gg_sql_pass,pass,127);
  8440. get_pcvar_string(gg_sql_db,dbname,127);
  8441.  
  8442. new sqlErrorCode, sqlError[1024];
  8443.  
  8444. // free old stuff if reconnecting
  8445. if(tuple != Empty_Handle) SQL_FreeHandleAndClear(tuple);
  8446. if(db != Empty_Handle) SQL_FreeHandleAndClear(db);
  8447.  
  8448. tuple = SQL_MakeDbTuple(host,user,pass,dbname);
  8449.  
  8450. if(tuple == Empty_Handle)
  8451. {
  8452. log_amx("Could not create database tuple. Error #%i: %s",sqlErrorCode,sqlError);
  8453. return 0;
  8454. }
  8455.  
  8456. db = SQL_Connect(tuple,sqlErrorCode,sqlError,1023);
  8457.  
  8458. if(db == Empty_Handle)
  8459. {
  8460. log_amx("Could not connect to database. Error #%i: %s",sqlErrorCode,sqlError);
  8461. return 0;
  8462. }
  8463.  
  8464. if(creation_queries)
  8465. {
  8466. // set up the main table, unfortunately we have to split it up to avoid "input line too long" compile errors
  8467. get_pcvar_string(gg_sql_table,sqlTable,127);
  8468.  
  8469. new super_long_query[716],
  8470. len = formatex(super_long_query,715,"CREATE TABLE IF NOT EXISTS `%s`(`authid` VARCHAR(31) NOT NULL,`wins` SMALLINT(6) default '0',`name` VARCHAR(31) NOT NULL,`timestamp` INT(10) UNSIGNED default '0',`points` MEDIUMINT(9) default '0',`streak` SMALLINT(6) default '0',`wins_tp` SMALLINT(6) default '0',`points_tp` MEDIUMINT(9) default '0',",sqlTable);
  8471. formatex(super_long_query[len],715-len,"`streak_tp` SMALLINT(6) default '0',`serverip` VARCHAR(63) NOT NULL,PRIMARY KEY(`authid`,`serverip`),INDEX(`wins`),INDEX(`points`),INDEX(`wins_tp`), INDEX(`points_tp`));");
  8472.  
  8473. query = SQL_PrepareQuery(db,super_long_query);
  8474. if(!SQL_ExecuteAndLog(query))
  8475. {
  8476. SQL_FreeHandle(query);
  8477. return 0;
  8478. }
  8479.  
  8480. // set up the streaks table
  8481. get_pcvar_string(gg_sql_streak_table,sqlStreakTable,127);
  8482.  
  8483. query = SQL_PrepareQuery(db,"CREATE TABLE IF NOT EXISTS `%s`(`type` ENUM('0C','0R','1C','1R') default NULL,`authid` VARCHAR(31) NOT NULL,`streak` SMALLINT(6) default '0',`name` VARCHAR(31) NOT NULL,`timestamp` INT(10) UNSIGNED default '0',`serverip` VARCHAR(63) NOT NULL,INDEX(`authid`,`serverip`),INDEX(`type`));",sqlStreakTable);
  8484. if(!SQL_ExecuteAndLog(query))
  8485. {
  8486. SQL_FreeHandle(query);
  8487. return 0;
  8488. }
  8489.  
  8490. // set up the players table
  8491. get_pcvar_string(gg_sql_winmotd_table,sqlPlayersTable,127);
  8492.  
  8493. len = formatex(super_long_query,715,"CREATE TABLE IF NOT EXISTS `%s`(`id` tinyint(4) NOT NULL default '0',`authid` varchar(31) NOT NULL,`name` varchar(31) NOT NULL,`team` tinyint(4) default '0',`level` tinyint(4) default '0',`weapon` varchar(23) NOT NULL,`flags` tinyint(4) default '0',`wins` smallint(6) default '0',`points` mediumint(9) default '0',`new_points` mediumint(9) default '0',`record_streak` smallint(6) default '0',",sqlPlayersTable);
  8494. formatex(super_long_query[len],715-len,"`current_streak` smallint(6) default '0',`stats_position` smallint(6) unsigned default '0',`teamtime_winning` smallint(6) unsigned default '0',`teamtime_losing` smallint(6) unsigned default '0',`timestamp` int(10) unsigned default '0',`serverip` varchar(63) NOT NULL, PRIMARY KEY(`id`));");
  8495.  
  8496. query = SQL_PrepareQuery(db,super_long_query);
  8497. if(!SQL_ExecuteAndLog(query))
  8498. {
  8499. SQL_FreeHandle(query);
  8500. return 0;
  8501. }
  8502.  
  8503. SQL_FreeHandle(query);
  8504. }
  8505.  
  8506. sqlInit = 1;
  8507. return 1;
  8508. }
  8509.  
  8510. // closes the database
  8511. public sql_uninit()
  8512. {
  8513. if(sqlInit)
  8514. {
  8515. if(db != Empty_Handle) SQL_FreeHandleAndClear(db);
  8516. if(tuple != Empty_Handle) SQL_FreeHandleAndClear(tuple);
  8517. }
  8518. }
  8519.  
  8520. // frees a handle and resets its variable to empty
  8521. SQL_FreeHandleAndClear(&Handle:arg)
  8522. {
  8523. SQL_FreeHandle(arg);
  8524. arg = Empty_Handle;
  8525. }
  8526.  
  8527. // execute a query and log any errors that come up
  8528. stock SQL_ExecuteAndLog(&Handle:queryHandle,const queryStr[]="")
  8529. {
  8530. static preventLoopback = 0;
  8531.  
  8532. if(!SQL_Execute(queryHandle))
  8533. {
  8534. static error[256];
  8535. new errnum = SQL_QueryError(queryHandle,error,255);
  8536.  
  8537. if(queryStr[0]) log_amx("Could not execute query [%s] -- err #%i [%s]",queryStr,errnum,error);
  8538. else
  8539. {
  8540. SQL_GetQueryString(queryHandle,mkQuery,255);
  8541. log_amx("Could not execute query [%s] -- err #%i [%s]",mkQuery,errnum,error);
  8542. }
  8543.  
  8544. // fix thanks to 2inspyr
  8545. if(errnum == 2006 && !preventLoopback) // MySQL server has gone away
  8546. {
  8547. log_amx("Attempting to reconnect to server");
  8548.  
  8549. if(sql_init(0)) // no creation queries
  8550. {
  8551. log_amx("Successfully reconnected to server, executing query again");
  8552.  
  8553. SQL_GetQueryString(queryHandle,mkQuery,1535);
  8554. new Handle:newQuery = SQL_PrepareQuery(db,mkQuery);
  8555.  
  8556. preventLoopback = 1;
  8557. SQL_ExecuteAndLog(newQuery);
  8558.  
  8559. // transfer handles
  8560. SQL_FreeHandle(queryHandle);
  8561. queryHandle = newQuery;
  8562.  
  8563. preventLoopback = 0;
  8564. return 1;
  8565.  
  8566. //return SQL_Execute(queryHandle);
  8567. }
  8568. else
  8569. {
  8570. log_amx("Could not reconnect to server");
  8571.  
  8572. preventLoopback = 0;
  8573. return 0;
  8574. }
  8575. }
  8576.  
  8577. preventLoopback = 0;
  8578. return 0;
  8579. }
  8580.  
  8581. preventLoopback = 0;
  8582. return 1;
  8583. }
  8584.  
  8585. public sql_qhandler_prune(failstate,Handle:query,error[],errnum,data[],size,Float:queuetime)
  8586. {
  8587. if(error[0])
  8588. {
  8589. SQL_GetQueryString(query,mkQuery,255);
  8590. log_amx("Could not execute query [%s] -- err #%i [%s]",mkQuery,errnum,error);
  8591. }
  8592. else log_amx("%L",LANG_SERVER,"PRUNING",sqlTable,SQL_NumRows(query));
  8593. }
  8594.  
  8595. public sql_qhandler_dummy(failstate,Handle:query,error[],errnum,data[],size,Float:queuetime)
  8596. {
  8597. if(error[0])
  8598. {
  8599. SQL_GetQueryString(query,mkQuery,255);
  8600. log_amx("Could not execute query [%s] -- err #%i [%s]",mkQuery,errnum,error);
  8601. }
  8602. }
  8603.  
  8604. #endif
  8605.  
  8606. //**********************************************************************
  8607. // WHATEV
  8608. //**********************************************************************
  8609.  
  8610. #if !defined SQL
  8611. // monitor stats mode and resort if it changed
  8612. public recheck_stats_sorting()
  8613. {
  8614. new stats_mode = get_pcvar_num(gg_stats_mode);
  8615.  
  8616. if(stats_mode && stats_mode != lastStatsMode && lastStatsMode != -909) // set to -909 on init
  8617. {
  8618. lastStatsMode = stats_mode;
  8619.  
  8620. // we are judging by a different criteria, so we need to resort
  8621. if(statsPointers[0] && statsSize[0]) ArraySort(statsPointers[0],"stats_pointer_sort_reg");
  8622. if(statsPointers[1] && statsSize[1]) ArraySort(statsPointers[1],"stats_pointer_sort_tp");
  8623.  
  8624. // clear any saved stats positions out of the tempsaves, so no one rejoins with the wrong position
  8625. for(new i=0;i<TEMP_SAVES;i++)
  8626. {
  8627. tempSave[i][svStatsPosition][0] = 0;
  8628. tempSave[i][svStatsPosition][1] = 0;
  8629. }
  8630.  
  8631. // also make sure that everyone will get assigned new positions
  8632. for(new i=1;i<=maxPlayers;i++)
  8633. {
  8634. statsPosition[i][0] = 0;
  8635. statsPosition[i][1] = 0;
  8636. }
  8637.  
  8638. stats_get_top_players();
  8639. }
  8640.  
  8641. lastStatsMode = stats_mode;
  8642. }
  8643. #endif
  8644.  
  8645. // task is set on a potential team change, and removed on an
  8646. // approved team change, so if we reach it, deduct level
  8647. public delayed_suicide(taskid)
  8648. {
  8649. new id = taskid-TASK_DELAYED_SUICIDE;
  8650. if(is_user_connected(id)) player_suicided(id);
  8651. }
  8652.  
  8653. // remove those annoying pesky pistols, if they haven't been already
  8654. strip_starting_pistols(id)
  8655. {
  8656. if(!is_user_alive(id)) return;
  8657.  
  8658. switch(cs_get_user_team(id))
  8659. {
  8660. case CS_TEAM_T:
  8661. {
  8662. if(!equal(lvlWeapon[id],"glock18") && user_has_weapon(id,CSW_GLOCK18))
  8663. ham_strip_weapon(id,WEAPON_GLOCK18);
  8664. }
  8665. case CS_TEAM_CT:
  8666. {
  8667. if(!equal(lvlWeapon[id],"usp") && user_has_weapon(id,CSW_USP))
  8668. ham_strip_weapon(id,"weapon_usp");
  8669. }
  8670. }
  8671. }
  8672.  
  8673. // weapon display
  8674. stock status_display(id,status=1)
  8675. {
  8676. new sdisplay = get_pcvar_num(gg_status_display);
  8677.  
  8678. // display disabled
  8679. if(!sdisplay) return;
  8680.  
  8681. // dead
  8682. if(id && !is_user_alive(id)) return;
  8683.  
  8684. new dest;
  8685. static sprite[32];
  8686.  
  8687. if(!id) dest = MSG_BROADCAST;
  8688. else dest = MSG_ONE_UNRELIABLE;
  8689.  
  8690. // disable display if status is 0, or we are doing a warmup
  8691. if(!status || warmup > 0)
  8692. {
  8693. // don't send to bots
  8694. if(dest == MSG_BROADCAST || !is_user_bot(id))
  8695. {
  8696. message_begin(dest,gmsgScenario,_,id);
  8697. write_byte(0);
  8698. message_end();
  8699. }
  8700.  
  8701. return;
  8702. }
  8703.  
  8704. // weapon display
  8705. if(sdisplay == STATUS_LEADERWPN || sdisplay == STATUS_YOURWPN)
  8706. {
  8707. if(sdisplay == STATUS_LEADERWPN)
  8708. {
  8709. new ldrLevel;
  8710. get_leader(ldrLevel);
  8711.  
  8712. // get leader's weapon
  8713. if(ldrLevel <= 0) return;
  8714. copy(sprite,31,weaponName[ldrLevel-1]);
  8715. }
  8716. else
  8717. {
  8718. // get your weapon
  8719. if(level[id] <= 0) return;
  8720. copy(sprite,31,lvlWeapon[id]);
  8721. }
  8722.  
  8723. strtolower(sprite);
  8724.  
  8725. // sprite is d_grenade, not d_hegrenade
  8726. if(sprite[0] == 'h') sprite = "grenade";
  8727.  
  8728. // get true sprite name
  8729. format(sprite,31,"d_%s",sprite);
  8730. }
  8731.  
  8732. // kill display
  8733. else if(sdisplay == STATUS_KILLSLEFT)
  8734. {
  8735. new goal = get_level_goal(level[id],id);
  8736. formatex(sprite,31,"number_%i",goal-score[id]);
  8737. }
  8738. else if(sdisplay == STATUS_KILLSDONE)
  8739. {
  8740. formatex(sprite,31,"number_%i",score[id]);
  8741. }
  8742.  
  8743. // don't send to bots
  8744. if(!id || !is_user_bot(id))
  8745. {
  8746. message_begin(dest,gmsgScenario,_,id);
  8747. write_byte(1);
  8748. write_string(sprite);
  8749. write_byte(150);
  8750. message_end();
  8751. }
  8752. }
  8753.  
  8754. // hide someone's money display
  8755. public hide_money(id)
  8756. {
  8757. // hide money
  8758. emessage_begin(MSG_ONE,gmsgHideWeapon,_,id);
  8759. ewrite_byte(1<<5);
  8760. emessage_end();
  8761.  
  8762. // hide crosshair that appears from hiding money
  8763. emessage_begin(MSG_ONE,gmsgCrosshair,_,id);
  8764. ewrite_byte(0);
  8765. emessage_end();
  8766. }
  8767.  
  8768. //**********************************************************************
  8769. // SUPPORT FUNCTIONS
  8770. //**********************************************************************
  8771.  
  8772. // gets a players info, intended for other plugins to callfunc
  8773. public get_player_info(id,&rf_level,&rf_score,rf_lvlWeapon[],len,&rf_spawnProtected,rf_statsPosition[2])
  8774. {
  8775. rf_level = level[id];
  8776. rf_score = score[id];
  8777. copy(rf_lvlWeapon,len,lvlWeapon[id]);
  8778. rf_spawnProtected = spawnProtected[id];
  8779. rf_statsPosition = statsPosition[id];
  8780. return 1;
  8781. }
  8782.  
  8783. // analyzes the weapon order and saves it into our variables
  8784. public setup_weapon_order()
  8785. {
  8786. new weaponOrder[(MAX_WEAPONS*16)+1], temp[27];
  8787. get_pcvar_string(gg_weapon_order,weaponOrder,MAX_WEAPONS*16);
  8788.  
  8789. new Float:killsperlvl = get_pcvar_float(gg_kills_per_lvl), i, done, colon, goal[6];
  8790.  
  8791. // cut them apart
  8792. for(i=0;i<MAX_WEAPONS;i++)
  8793. {
  8794. // out of stuff
  8795. if(strlen(weaponOrder) <= 1)
  8796. {
  8797. i--; // for our count
  8798. break;
  8799. }
  8800.  
  8801. // we still have a comma, go up to it
  8802. if(contain_char(weaponOrder,',') != -1)
  8803. {
  8804. strtok(weaponOrder,temp,26,weaponOrder,MAX_WEAPONS*16,',');
  8805. trim(temp);
  8806. strtolower(temp);
  8807. }
  8808.  
  8809. // otherwise, finish up
  8810. else
  8811. {
  8812. copy(temp,26,weaponOrder);
  8813. trim(temp);
  8814. strtolower(temp);
  8815. done = 1; // flag for end of loop
  8816. }
  8817.  
  8818. colon = contain_char(temp,':');
  8819.  
  8820. // no custom requirement, easy
  8821. if(colon == -1)
  8822. {
  8823. copy(weaponName[i],23,temp);
  8824. if(equal(temp,KNIFE) || equal(temp,HEGRENADE)) weaponGoal[i] = (killsperlvl > 1.0) ? 1.0 : killsperlvl;
  8825. else weaponGoal[i] = killsperlvl;
  8826. }
  8827. else
  8828. {
  8829. copyc(weaponName[i],23,temp,':');
  8830. copy(goal,5,temp[colon+1]);
  8831. weaponGoal[i] = floatstr(goal);
  8832. }
  8833.  
  8834. if(done) break;
  8835. }
  8836.  
  8837. // we break to end our loop, so "i" will be where we left it. but it's 0-based.
  8838. weaponNum = i+1;
  8839. }
  8840.  
  8841. // gets the goal for a level, taking into account default and custom values
  8842. stock get_level_goal(level,id=0)
  8843. {
  8844. if(level < 1) return 1;
  8845.  
  8846. // no teamplay, return preset goal
  8847. if(!is_user_connected(id) || !get_pcvar_num(gg_teamplay))
  8848. {
  8849. if(is_user_bot(id)) return floatround(weaponGoal[level-1]*get_pcvar_float(gg_kills_botmod),floatround_ceil);
  8850. return floatround(weaponGoal[level-1],floatround_ceil);
  8851. }
  8852.  
  8853. // one of this for every player on team
  8854. new Float:result = weaponGoal[level-1] * float(team_player_count(cs_get_user_team(id)));
  8855.  
  8856. // modifiers for nade and knife levels
  8857. if(equal(weaponName[level-1],HEGRENADE)) result *= get_pcvar_float(gg_teamplay_nade_mod);
  8858. else if(equal(weaponName[level-1],KNIFE)) result *= get_pcvar_float(gg_teamplay_knife_mod);
  8859.  
  8860. if(result <= 0.0) result = 1.0;
  8861. return floatround(result,floatround_ceil);
  8862. }
  8863.  
  8864. // gets the level a player should use for his level
  8865. stock get_level_weapon(theLevel,var[],varLen)
  8866. {
  8867. if(warmup > 0 && warmupWeapon[0]) copy(var,varLen,warmupWeapon);
  8868. else if(theLevel > 0) copy(var,varLen,weaponName[theLevel-1]);
  8869. else var[0] = 0;
  8870. }
  8871.  
  8872. // easy function to precache sound via cvar
  8873. stock precache_sound_by_cvar(pcvar)
  8874. {
  8875. new value[64];
  8876. get_pcvar_string(pcvar,value,63);
  8877. precache_sound_special(value);
  8878. }
  8879.  
  8880. // precache sounds with a little bit of magic
  8881. stock precache_sound_special(sound[])
  8882. {
  8883. if(!sound[0]) return;
  8884.  
  8885. if(containi(sound,".mp3") != -1) precache_generic(sound);
  8886. else
  8887. {
  8888. // stop at ( character to allow precaching sounds that use speak's special functions, eg sound/ambience/xtal_down1(e70)
  8889. new value[64], len = copyc(value,63,sound,'(');
  8890.  
  8891. // make sure we have a suffix for precaching
  8892. if(containi(value,".wav") == -1) formatex(value[len],63-len,".wav");
  8893.  
  8894. // precache_sound doesn't take the "sound/" prefix
  8895. if(equali(value,"sound/",6)) precache_sound(value[6]);
  8896. else precache_sound(value);
  8897. }
  8898. }
  8899.  
  8900. // gets a player's "authid", or whatever token we want to identify them with.
  8901. // if you already know the value of gg_stats_ip, you can pass it in and save a cvar check.
  8902. stock get_gg_authid(id,ret[],len,stats_ip=-777)
  8903. {
  8904. new mode = stats_ip;
  8905. if(mode == -777) mode = get_pcvar_num(gg_stats_ip);
  8906.  
  8907. switch(mode)
  8908. {
  8909. case 0: return get_user_authid(id,ret,len); // 0 = by authid
  8910. case -1, 2: return get_user_name(id,ret,len); // 2 = by name
  8911. }
  8912.  
  8913. return get_user_ip(id,ret,len); // 1 = by ip
  8914. }
  8915.  
  8916. // figure out which gungame.cfg (or gungame_teamplay.cfg) file to use
  8917. stock get_gg_config_file(teamplay=0,filename[],len)
  8918. {
  8919. formatex(filename,len,"%s/gungame%s.cfg",cfgDir,(teamplay) ? "_teamplay" : "");
  8920.  
  8921. if(!file_exists(filename))
  8922. {
  8923. formatex(filename,len,"gungame%s.cfg",(teamplay) ? "_teamplay" : "");
  8924. if(!file_exists(filename)) filename[0] = 0;
  8925. }
  8926. }
  8927.  
  8928. // executes what's inside of the config file
  8929. stock exec_gg_config_file(teamplay=0,allowToggling=0)
  8930. {
  8931. new oldActive = ggActive, oldTeamplay = get_pcvar_num(gg_teamplay);
  8932.  
  8933. new cfgFile[64];
  8934. get_gg_config_file(teamplay,cfgFile,63);
  8935. if(cfgFile[0] && file_exists(cfgFile))
  8936. {
  8937. server_cmd("exec ^"%s^"",cfgFile);
  8938. server_exec();
  8939. }
  8940.  
  8941. // remember old values of gg_enabled and gg_teamplay if toggling is not allowed.
  8942. // this is like we just turned teamplay on via command and we want to make sure
  8943. // the configs get run appropriately, but obviously teamplay should still be on afterwards.
  8944. if(!allowToggling)
  8945. {
  8946. set_pcvar_num(gg_enabled,oldActive);
  8947. set_pcvar_num(gg_teamplay,oldTeamplay);
  8948. }
  8949.  
  8950. // reselect random weapon order
  8951. new lastOIstr[6], lastOI;
  8952.  
  8953. get_localinfo("gg_last_oi",lastOIstr,5);
  8954. lastOI = str_to_num(lastOIstr);
  8955.  
  8956. // decrement it 1 b/c we probably already did do_rOrder
  8957. // and don't want to end up skipping orders
  8958. if(lastOI > 0)
  8959. {
  8960. num_to_str(lastOI-1,lastOIstr,5);
  8961. set_localinfo("gg_last_oi",lastOIstr);
  8962. }
  8963.  
  8964. do_rOrder(1); // thanks for pointing this out Tomek Kalkowski
  8965.  
  8966. // in case cvars changed. thanks BbIX!
  8967. setup_weapon_order();
  8968. }
  8969.  
  8970. // figure out which gungame_mapcycle file to use
  8971. stock get_gg_mapcycle_file(filename[],len)
  8972. {
  8973. static testFile[64];
  8974.  
  8975. // cstrike/addons/amxmodx/configs/gungame_mapcycle.cfg
  8976. formatex(testFile,63,"%s/gungame_mapcycle.cfg",cfgDir);
  8977. if(file_exists(testFile))
  8978. {
  8979. copy(filename,len,testFile);
  8980. return 1;
  8981. }
  8982.  
  8983. // cstrike/addons/amxmodx/configs/gungame_mapcycle.txt
  8984. formatex(testFile,63,"%s/gungame_mapcycle.txt",cfgDir);
  8985. if(file_exists(testFile))
  8986. {
  8987. copy(filename,len,testFile);
  8988. return 1;
  8989. }
  8990.  
  8991. // cstrike/gungame_mapcycle.cfg
  8992. testFile = "gungame_mapcycle.cfg";
  8993. if(file_exists(testFile))
  8994. {
  8995. copy(filename,len,testFile);
  8996. return 1;
  8997. }
  8998.  
  8999. // cstrike/gungame_mapcycle.txt
  9000. testFile = "gungame_mapcycle.txt";
  9001. if(file_exists(testFile))
  9002. {
  9003. copy(filename,len,testFile);
  9004. return 1;
  9005. }
  9006.  
  9007. return 0;
  9008. }
  9009.  
  9010. // another easy function to play sound via cvar
  9011. stock play_sound_by_cvar(id,pcvar)
  9012. {
  9013. static value[64];
  9014. get_pcvar_string(pcvar,value,63);
  9015.  
  9016. if(!value[0]) return;
  9017.  
  9018. if(containi(value,".mp3") != -1) client_cmd(id,"mp3 play ^"%s^"",value);
  9019. else client_cmd(id,"spk ^"%s^"",value);
  9020. }
  9021.  
  9022. // a taskable play_sound_by_cvar
  9023. public play_sound_by_cvar_task(params[2])
  9024. {
  9025. play_sound_by_cvar(params[0],params[1]);
  9026. }
  9027.  
  9028. // this functions take a filepath, but manages speak/mp3 play
  9029. stock play_sound(id,value[])
  9030. {
  9031. if(!value[0]) return;
  9032.  
  9033. if(containi(value,".mp3") != -1) client_cmd(id,"mp3 play ^"%s^"",value);
  9034. else
  9035. {
  9036. if(equali(value,"sound/",6)) client_cmd(id,"spk ^"%s^"",value[6]);
  9037. else client_cmd(id,"spk ^"%s^"",value);
  9038. }
  9039. }
  9040.  
  9041. // find the highest level player and his level
  9042. stock get_leader(&retLevel=0,&retNumLeaders=0,&retRunnerUp=0,&retRunnerUp3=0)
  9043. {
  9044. new player, leader, numLeaders, runnerUp, runnerUp3, runnerUp4;
  9045.  
  9046. // locate highest player
  9047. for(player=1;player<=maxPlayers;player++)
  9048. {
  9049. if(!is_user_connected(player)) continue;
  9050.  
  9051. if(leader == 0 || level[player] > level[leader])
  9052. {
  9053. // about to dethrown leader, monitor runnerup
  9054. if(leader && (runnerUp == 0 || level[leader] > level[runnerUp]))
  9055. runnerUp = leader;
  9056.  
  9057. leader = player;
  9058. numLeaders = 1; // reset tied count
  9059. }
  9060. else if(level[player] == level[leader])
  9061. numLeaders++;
  9062. else
  9063. {
  9064. // monitor runnerup
  9065. if(runnerUp == 0 || level[player] > level[runnerUp])
  9066. runnerUp = player; // locul 2
  9067. }
  9068. }
  9069.  
  9070. // locate highest player
  9071. for(player=1;player<=maxPlayers;player++)
  9072. {
  9073. if(!is_user_connected(player)) continue;
  9074.  
  9075. if(player != leader)
  9076. {
  9077. if(runnerUp == 0 || level[player] > level[runnerUp])
  9078. {
  9079. // about to dethrown runnerUp, monitor runnerup
  9080. if(runnerUp && (runnerUp3 == 0 || level[runnerUp] > level[runnerUp3]))
  9081. runnerUp3 = runnerUp;
  9082.  
  9083. runnerUp = player;
  9084. }
  9085. else if(level[player] == level[runnerUp])
  9086. numLeaders++;
  9087. else
  9088. {
  9089. // monitor runnerup
  9090. if(runnerUp3 == 0 || level[player] > level[runnerUp3])
  9091. runnerUp3 = player; // locul 3
  9092. }
  9093. }
  9094. }
  9095.  
  9096. // locate highest player
  9097. for(player=1;player<=maxPlayers;player++)
  9098. {
  9099. if(!is_user_connected(player)) continue;
  9100.  
  9101. if(player != leader && player != runnerUp)
  9102. {
  9103. if(runnerUp3 == 0 || level[player] > level[runnerUp3])
  9104. {
  9105. // about to dethrown runnerUp, monitor runnerup
  9106. if(runnerUp3 && (runnerUp4 == 0 || level[runnerUp3] > level[runnerUp4]))
  9107. runnerUp4 = runnerUp3;
  9108.  
  9109. runnerUp3 = player;
  9110. }
  9111. else if(level[player] == level[runnerUp3])
  9112. numLeaders++;
  9113. else
  9114. {
  9115. // monitor runnerup
  9116. if(runnerUp4 == 0 || level[player] > level[runnerUp4])
  9117. runnerUp4 = player; // locul 4
  9118. }
  9119. }
  9120. }
  9121.  
  9122.  
  9123.  
  9124.  
  9125. retLevel = level[leader];
  9126. retNumLeaders = numLeaders;
  9127. retRunnerUp = runnerUp;
  9128. retRunnerUp3 = runnerUp3;
  9129.  
  9130. return leader;
  9131. }
  9132.  
  9133. // gets the number of players on a particular level
  9134. stock num_players_on_level(checkLvl)
  9135. {
  9136. new player, result;
  9137. for(player=1;player<=maxPlayers;player++)
  9138. {
  9139. if(is_user_connected(player) && level[player] == checkLvl)
  9140. result++;
  9141. }
  9142. return result;
  9143. }
  9144.  
  9145. // a butchered version of teame06's CS Color Chat Function.
  9146. // actually it's now almost completely different, but that's
  9147. // where I started from.
  9148. gungame_print(id,custom,tag,msg[],any:...)
  9149. {
  9150. new messages = get_pcvar_num(gg_messages);
  9151. if(!messages || (messages & MSGS_HIDETEXT)) return 0;
  9152.  
  9153. new changeCount, num, i, j, argnum = numargs(), player, colored_messages = !(messages & MSGS_NOCOLOR);
  9154. static newMsg[191], message[191], changed[8], players[32];
  9155.  
  9156. if(id)
  9157. {
  9158. players[0] = id;
  9159. num = 1;
  9160. }
  9161. else get_players(players,num);
  9162.  
  9163. for(i=0;i<num;i++)
  9164. {
  9165. player = players[i];
  9166. changeCount = 0;
  9167.  
  9168. if(!is_user_connected(player)) continue;
  9169.  
  9170. // we have to change LANG_PLAYER into
  9171. // a player-specific argument, because
  9172. // ML doesn't work well with SayText
  9173. for(j=4;j<argnum;j++)
  9174. {
  9175. if(getarg(j) == LANG_PLAYER_C)
  9176. {
  9177. setarg(j,0,player);
  9178. changed[changeCount++] = j;
  9179. }
  9180. }
  9181.  
  9182. // do user formatting
  9183. vformat(newMsg,190,msg,5);
  9184.  
  9185. // and now we have to change what we changed
  9186. // back into LANG_PLAYER, so that the next
  9187. // player will be able to have it in his language
  9188. for(j=0;j<changeCount;j++)
  9189. {
  9190. setarg(changed[j],0,LANG_PLAYER_C);
  9191. }
  9192.  
  9193. // optimized color swapping
  9194. if(colored_messages)
  9195. {
  9196. replace_all(newMsg,190,"%n","^x03"); // %n = team color
  9197. replace_all(newMsg,190,"%g","^x04"); // %g = green
  9198. replace_all(newMsg,190,"%e","^x01"); // %e = regular
  9199. }
  9200. else
  9201. {
  9202. replace_all(newMsg,190,"%n","");
  9203. replace_all(newMsg,190,"%g","");
  9204. replace_all(newMsg,190,"%e","");
  9205. }
  9206.  
  9207. // now do our formatting (I used two variables because sharing one caused glitches)
  9208.  
  9209. if(tag)
  9210. {
  9211. if(colored_messages) formatex(message,190,"^x04[%L]^x01 %s",player,"GUNGAME",newMsg);
  9212. else formatex(message,190,"^x01[%L] %s",player,"GUNGAME",newMsg);
  9213. }
  9214. else formatex(message,190,"^x01%s",newMsg);
  9215.  
  9216. message_begin(MSG_ONE,gmsgSayText,_,player);
  9217. write_byte((custom > 0) ? custom : player);
  9218. write_string(message);
  9219. message_end();
  9220. }
  9221.  
  9222. return 1;
  9223. }
  9224.  
  9225. // show a HUD message to a user
  9226. gungame_hudmessage(id,Float:holdTime,msg[],any:...)
  9227. {
  9228. new messages = get_pcvar_num(gg_messages);
  9229. if(!messages || (messages & MSGS_HIDEHUD)) return 0;
  9230.  
  9231. // user formatting
  9232. static newMsg[191];
  9233. vformat(newMsg,190,msg,4);
  9234.  
  9235. // show it
  9236. set_hudmessage(255,255,255,-1.0,0.8,0,6.0,holdTime,0.1,0.5);
  9237. return ShowSyncHudMsg(id,hudSyncReqKills,newMsg);
  9238. }
  9239.  
  9240. // start a map vote
  9241. stock start_mapvote()
  9242. {
  9243. new dmmName[24], plugin;
  9244.  
  9245. // Galileo - galileo.amxx
  9246. if(galileoID != -1)
  9247. {
  9248. log_amx("Starting a map vote from Galileo");
  9249.  
  9250. server_cmd("gal_startvote -nochange");
  9251. }
  9252.  
  9253. // AMXX Nextmap Chooser - mapchooser.amxx
  9254. else if((plugin = is_plugin_loaded("Nextmap Chooser")) != -1)
  9255. {
  9256. log_amx("Starting a map vote from Nextmap Chooser");
  9257.  
  9258. new oldWinLimit = get_cvar_num("mp_winlimit"), oldMaxRounds = get_cvar_num("mp_maxrounds");
  9259. set_cvar_num("mp_winlimit",0); // skip winlimit check
  9260. set_cvar_num("mp_maxrounds",-1); // trick plugin to think game is almost over
  9261.  
  9262. // call the vote
  9263. if(callfunc_begin_i(get_func_id("voteNextmap",plugin),plugin) == 1)
  9264. callfunc_end();
  9265.  
  9266. // set maxrounds back
  9267. set_cvar_num("mp_winlimit",oldWinLimit);
  9268. set_cvar_num("mp_maxrounds",oldMaxRounds);
  9269. }
  9270.  
  9271. // Deagles' Map Management 2.30b - deagsmapmanage230b.amxx
  9272. else if((plugin = is_plugin_loaded("DeagsMapManage")) != -1)
  9273. {
  9274. dmmName = "DeagsMapManage";
  9275. }
  9276.  
  9277. // Deagles' Map Management 2.40 - deagsmapmanager.amxx
  9278. else if((plugin = is_plugin_loaded("DeagsMapManager")) != -1)
  9279. {
  9280. dmmName = "DeagsMapManager";
  9281. }
  9282.  
  9283. // Mapchooser4 - mapchooser4.amxx
  9284. else if((plugin = is_plugin_loaded("Nextmap Chooser 4")) != -1)
  9285. {
  9286. log_amx("Starting a map vote from Nextmap Chooser 4");
  9287.  
  9288. new oldWinLimit = get_cvar_num("mp_winlimit"), oldMaxRounds = get_cvar_num("mp_maxrounds");
  9289. set_cvar_num("mp_winlimit",0); // skip winlimit check
  9290. set_cvar_num("mp_maxrounds",1); // trick plugin to think game is almost over
  9291.  
  9292. // deactivate g_buyingtime variable
  9293. if(callfunc_begin_i(get_func_id("buyFinished",plugin),plugin) == 1)
  9294. callfunc_end();
  9295.  
  9296. // call the vote
  9297. if(callfunc_begin_i(get_func_id("voteNextmap",plugin),plugin) == 1)
  9298. {
  9299. callfunc_push_str("",false);
  9300. callfunc_end();
  9301. }
  9302.  
  9303. // set maxrounds back
  9304. set_cvar_num("mp_winlimit",oldWinLimit);
  9305. set_cvar_num("mp_maxrounds",oldMaxRounds);
  9306. }
  9307.  
  9308. // NOTHING?
  9309. else log_amx("Using gg_vote_setting without any compatible plugins: could not start a vote!");
  9310.  
  9311. // do DMM stuff
  9312. if(dmmName[0])
  9313. {
  9314. log_amx("Starting a map vote from %s",dmmName);
  9315.  
  9316. // allow voting
  9317. /*if(callfunc_begin("dmapvotemode",dmmName) == 1)
  9318. {
  9319. callfunc_push_int(0); // server
  9320. callfunc_end();
  9321. }*/
  9322.  
  9323. new oldWinLimit = get_cvar_num("mp_winlimit"), Float:oldTimeLimit = get_cvar_float("mp_timelimit");
  9324. set_cvar_num("mp_winlimit",99999); // don't allow extending
  9325. set_cvar_float("mp_timelimit",0.0); // don't wait for buying
  9326. set_cvar_num("enforce_timelimit",1); // don't change map after vote
  9327.  
  9328. // call the vote
  9329. if(callfunc_begin_i(get_func_id("startthevote",plugin),plugin) == 1)
  9330. callfunc_end();
  9331.  
  9332. set_cvar_num("mp_winlimit",oldWinLimit);
  9333. set_cvar_float("mp_timelimit",oldTimeLimit);
  9334.  
  9335. // disallow further voting
  9336. /*if(callfunc_begin("dmapcyclemode",dmmName) == 1)
  9337. {
  9338. callfunc_push_int(0); // server
  9339. callfunc_end();
  9340. }*/
  9341.  
  9342. set_task(20.1,"dmm_stop_mapchange");
  9343. }
  9344. }
  9345.  
  9346. // stop DMM from changing maps after the vote has been tallied
  9347. public dmm_stop_mapchange()
  9348. {
  9349. remove_task(333333,1); // outside
  9350. }
  9351.  
  9352. // set amx_nextmap to the next map
  9353. stock set_nextmap()
  9354. {
  9355. new mapCycleFile[64];
  9356. get_gg_mapcycle_file(mapCycleFile,63);
  9357.  
  9358. // no mapcycle, leave amx_nextmap alone
  9359. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  9360. {
  9361. set_localinfo("gg_cycle_num","0");
  9362. return 0;
  9363. }
  9364.  
  9365. new strVal[10];
  9366.  
  9367. // have not gotten cycleNum yet (only get it once, because
  9368. // set_nextmap is generally called at least twice per map, and we
  9369. // don't want to change it twice)
  9370. if(cycleNum == -1)
  9371. {
  9372. get_localinfo("gg_cycle_num",strVal,9);
  9373. cycleNum = str_to_num(strVal);
  9374. }
  9375.  
  9376. new firstMap[32], currentMap[32], lineData[32], i, line, foundMap;
  9377. get_mapname(currentMap,31);
  9378.  
  9379. new file = fopen(mapCycleFile,"rt");
  9380. while(file && !feof(file))
  9381. {
  9382. fgets(file,lineData,31);
  9383.  
  9384. trim(lineData);
  9385. replace(lineData,31,".bsp",""); // remove extension
  9386. new len = strlen(lineData) - 2;
  9387.  
  9388. // stop at a comment
  9389. for(i=0;i<len;i++)
  9390. {
  9391. // supports config-style (;) and coding-style (//)
  9392. if(lineData[i] == ';' || (lineData[i] == '/' && lineData[i+1] == '/'))
  9393. {
  9394. copy(lineData,i,lineData);
  9395. break;
  9396. }
  9397. }
  9398.  
  9399. trim(lineData);
  9400. if(!lineData[0]) continue;
  9401.  
  9402. // save first map
  9403. if(!firstMap[0]) copy(firstMap,31,lineData);
  9404.  
  9405. // we reached the line after our current map's line
  9406. if(line == cycleNum+1)
  9407. {
  9408. // remember so
  9409. foundMap = 1;
  9410.  
  9411. // get ready to change to it
  9412. set_cvar_string("amx_nextmap",lineData);
  9413.  
  9414. // remember this map's line for next time
  9415. num_to_str(line,strVal,9);
  9416. set_localinfo("gg_cycle_num",strVal);
  9417.  
  9418. break;
  9419. }
  9420.  
  9421. line++;
  9422. }
  9423. if(file) fclose(file);
  9424.  
  9425. // we didn't find next map
  9426. if(!foundMap)
  9427. {
  9428. // reset line number to first (it's zero-based)
  9429. set_localinfo("gg_cycle_num","0");
  9430.  
  9431. // no maps listed, go to current
  9432. if(!firstMap[0]) set_cvar_string("amx_nextmap",currentMap);
  9433.  
  9434. // go to first map listed
  9435. else set_cvar_string("amx_nextmap",firstMap);
  9436. }
  9437.  
  9438. return 1;
  9439. }
  9440.  
  9441. // go to amx_nextmap
  9442. public goto_nextmap()
  9443. {
  9444. new mapCycleFile[64];
  9445. get_gg_mapcycle_file(mapCycleFile,63);
  9446.  
  9447. // no gungame mapcycle
  9448. if(!mapCycleFile[0] || !file_exists(mapCycleFile))
  9449. {
  9450. new custom[256];
  9451. get_pcvar_string(gg_changelevel_custom,custom,255);
  9452.  
  9453. // try custom changelevel command
  9454. if(custom[0])
  9455. {
  9456. server_cmd(custom);
  9457. return;
  9458. }
  9459. }
  9460.  
  9461. if(galileoID != -1)
  9462. {
  9463. if(callfunc_begin_i(get_func_id("map_change",galileoID),galileoID) == 1)
  9464. {
  9465. callfunc_end();
  9466. return;
  9467. }
  9468. }
  9469.  
  9470. // otherwise, go to amx_nextmap
  9471. new nextMap[32];
  9472. get_cvar_string("amx_nextmap",nextMap,31);
  9473.  
  9474. server_cmd("changelevel %s",nextMap);
  9475. }
  9476.  
  9477. // find a player's weapon entity
  9478. stock get_weapon_ent(id,wpnid=0,wpnName[]="")
  9479. {
  9480. // who knows what wpnName will be
  9481. static newName[24];
  9482.  
  9483. // need to find the name
  9484. if(wpnid) get_weaponname(wpnid,newName,23);
  9485.  
  9486. // go with what we were told
  9487. else copy(newName,23,wpnName);
  9488.  
  9489. // prefix it if we need to
  9490. if(!equal(newName,"weapon_",7))
  9491. format(newName,23,"weapon_%s",newName);
  9492.  
  9493. return fm_find_ent_by_owner(maxPlayers,newName,id);
  9494. }
  9495.  
  9496. // counts number of chars in a string, by (probably) Twilight Suzuka
  9497. stock str_count(str[],searchchar)
  9498. {
  9499. new i = 0;
  9500. new maxlen = strlen(str);
  9501. new count = 0;
  9502.  
  9503. for(i=0;i<=maxlen;i++)
  9504. {
  9505. if(str[i] == searchchar)
  9506. count++;
  9507. }
  9508. return count;
  9509. }
  9510.  
  9511. // find the nth occurance of a character in a string, based on str_count
  9512. stock str_find_num(str[],searchchar,number)
  9513. {
  9514. new i;
  9515. new maxlen = strlen(str);
  9516. new found = 0;
  9517.  
  9518. for(i=0;i<=maxlen;i++)
  9519. {
  9520. if(str[i] == searchchar)
  9521. {
  9522. if(++found == number)
  9523. return i;
  9524. }
  9525. }
  9526. return -1;
  9527. }
  9528.  
  9529. // works like contain, but looks only for a specific character
  9530. stock contain_char(str[],chara)
  9531. {
  9532. new i;
  9533. while(str[i] != 0)
  9534. {
  9535. if(str[i] == chara) return i;
  9536. i++;
  9537. }
  9538. return -1;
  9539. }
  9540.  
  9541. // cuts a snippet out of a string
  9542. stock remove_snippet(string[],strLen,start,end)
  9543. {
  9544. new i, newpos;
  9545. for(i=start;i<strLen;i++)
  9546. {
  9547. if(!string[i]) break;
  9548. newpos = i + end - start + 1;
  9549.  
  9550. if(newpos >= strLen) string[i] = 0;
  9551. else string[i] = string[newpos];
  9552. }
  9553.  
  9554. return 1;
  9555. }
  9556.  
  9557. // gets a player id that triggered certain logevents, by VEN
  9558. stock get_loguser_index()
  9559. {
  9560. static loguser[80], name[32];
  9561. read_logargv(0,loguser,79);
  9562. parse_loguser(loguser,name,31);
  9563.  
  9564. return get_user_index(name);
  9565. }
  9566.  
  9567. // checks if a space is vacant, by VEN
  9568. stock bool:is_hull_vacant(const Float:origin[3],hull)
  9569. {
  9570. new tr = 0;
  9571. engfunc(EngFunc_TraceHull,origin,origin,0,hull,0,tr);
  9572.  
  9573. if(!get_tr2(tr,TR_StartSolid) && !get_tr2(tr,TR_AllSolid) && get_tr2(tr,TR_InOpen))
  9574. return true;
  9575.  
  9576. return false;
  9577. }
  9578.  
  9579. // gets a weapon's category, just a shortcut to the weaponSlots table basically
  9580. stock get_weapon_category(id=0,name[]="")
  9581. {
  9582. if(name[0])
  9583. {
  9584. if(equal(name,"weapon_",7)) id = get_weaponid(name);
  9585. else
  9586. {
  9587. static newName[24];
  9588. formatex(newName,23,"weapon_%s",name);
  9589. id = get_weaponid(newName);
  9590. }
  9591. }
  9592.  
  9593. if(id < 1 || id > 30) return -1;
  9594. return weaponSlots[id];
  9595. }
  9596.  
  9597. // if a player is allowed to score (at least 1 rival player)
  9598. stock can_score(id)
  9599. {
  9600. if(!is_user_connected(id)) return 0;
  9601.  
  9602. new penalty = get_pcvar_num(gg_tk_penalty);
  9603. for(new player=1;player<=maxPlayers;player++)
  9604. {
  9605. // this player is on a real team, and he's on the opposite team, or we are playing FFA
  9606. if( player != id && is_user_connected(player) && on_valid_team(player) && (penalty < 0 || cs_get_user_team(id) != cs_get_user_team(player)) )
  9607. return 1;
  9608. }
  9609.  
  9610. return 0;
  9611. }
  9612.  
  9613. // returns 1 if there are only bots in the server, 0 if not
  9614. stock only_bots()
  9615. {
  9616. new player;
  9617. for(player=1;player<=maxPlayers;player++)
  9618. {
  9619. if(is_user_connected(player) && !is_user_bot(player))
  9620. return 0;
  9621. }
  9622.  
  9623. // didn't find any humans
  9624. return 1;
  9625. }
  9626.  
  9627. // gives a player a weapon efficiently
  9628. stock ham_give_weapon(id,const weapon[])
  9629. {
  9630. if(!equal(weapon,"weapon_",7)) return 0;
  9631.  
  9632. new wEnt = engfunc(EngFunc_CreateNamedEntity,engfunc(EngFunc_AllocString,weapon));
  9633. if(!pev_valid(wEnt)) return 0;
  9634.  
  9635. set_pev(wEnt,pev_spawnflags,SF_NORESPAWN);
  9636. dllfunc(DLLFunc_Spawn,wEnt);
  9637.  
  9638. if(!ExecuteHamB(Ham_AddPlayerItem,id,wEnt))
  9639. {
  9640. if(pev_valid(wEnt)) set_pev(wEnt,pev_flags,pev(wEnt,pev_flags) | FL_KILLME);
  9641. return 0;
  9642. }
  9643.  
  9644. ExecuteHamB(Ham_Item_AttachToPlayer,wEnt,id)
  9645. return 1;
  9646. }
  9647.  
  9648. // takes a weapon from a player efficiently
  9649. stock ham_strip_weapon(id,const weapon[])
  9650. {
  9651. if(!equal(weapon,"weapon_",7)) return 0;
  9652.  
  9653. new wId = get_weaponid(weapon);
  9654. if(!wId) return 0;
  9655.  
  9656. new wEnt;
  9657. while((wEnt = engfunc(EngFunc_FindEntityByString,wEnt,"classname",weapon)) && pev(wEnt,pev_owner) != id) {}
  9658. if(!wEnt) return 0;
  9659.  
  9660. if(get_user_weapon(id) == wId) ExecuteHamB(Ham_Weapon_RetireWeapon,wEnt);
  9661.  
  9662. if(!ExecuteHamB(Ham_RemovePlayerItem,id,wEnt)) return 0;
  9663. ExecuteHamB(Ham_Item_Kill,wEnt);
  9664.  
  9665. set_pev(id,pev_weapons,pev(id,pev_weapons) & ~(1<<wId));
  9666.  
  9667. if(wId == CSW_C4)
  9668. {
  9669. cs_set_user_plant(id,0,0);
  9670. cs_set_user_bpammo(id,CSW_C4,0);
  9671. }
  9672. else if(wId == CSW_SMOKEGRENADE || wId == CSW_FLASHBANG || wId == CSW_HEGRENADE)
  9673. cs_set_user_bpammo(id,wId,0);
  9674.  
  9675. return 1;
  9676. }
  9677.  
  9678. // gets the weapon that a killer used, just like CHalfLifeMultiplay::DeathNotice
  9679. stock get_killer_weapon(killer,inflictor,retVar[],retLen)
  9680. {
  9681. static killer_weapon_name[32];
  9682. killer_weapon_name = "world"; // by default, the player is killed by the world
  9683.  
  9684. if(pev_valid(killer) && (pev(killer,pev_flags) & FL_CLIENT))
  9685. {
  9686. if(pev_valid(inflictor))
  9687. {
  9688. if(inflictor == killer)
  9689. {
  9690. // if the inflictor is the killer, then it must be their current weapon doing the damage
  9691. new weapon = get_user_weapon(killer);
  9692. get_weaponname(weapon,killer_weapon_name,31);
  9693. }
  9694. else pev(inflictor,pev_classname,killer_weapon_name,31); // it's just that easy
  9695. }
  9696. }
  9697. else
  9698. {
  9699. if(pev_valid(killer)) pev(inflictor,pev_classname,killer_weapon_name,31);
  9700. else if(killer == 0) killer_weapon_name = "worldspawn";
  9701. }
  9702.  
  9703. // strip the monster_* or weapon_* from the inflictor's classname
  9704. if(equal(killer_weapon_name,"weapon_",7))
  9705. copy(killer_weapon_name,31,killer_weapon_name[7]);
  9706. else if(equal(killer_weapon_name,"monster_",8))
  9707. copy(killer_weapon_name,31,killer_weapon_name[8]);
  9708. else if(equal(killer_weapon_name,"func_",5))
  9709. copy(killer_weapon_name,31,killer_weapon_name[5]);
  9710.  
  9711. // output
  9712. copy(retVar,retLen,killer_weapon_name);
  9713. }
  9714.  
  9715. // gets a team's color
  9716. stock get_team_color(CsTeams:team,ret[],retLen)
  9717. {
  9718. switch(team)
  9719. {
  9720. case CS_TEAM_T: return formatex(ret,retLen,"FF3F3F");
  9721. case CS_TEAM_CT: return formatex(ret,retLen,"99CCFF");
  9722. }
  9723.  
  9724. return formatex(ret,retLen,"FFFFFF");
  9725. }
  9726.  
  9727. // gets the name of a team
  9728. stock get_team_name(CsTeams:team,ret[],retLen)
  9729. {
  9730. switch(team)
  9731. {
  9732. case CS_TEAM_T: return formatex(ret,retLen,"TERRORIST");
  9733. case CS_TEAM_CT: return formatex(ret,retLen,"CT");
  9734. case CS_TEAM_SPECTATOR: return formatex(ret,retLen,"SPECTATOR");
  9735. }
  9736.  
  9737. return formatex(ret,retLen,"UNASSIGNED");
  9738. }
  9739.  
  9740. // gets the amount of players on a team
  9741. stock team_player_count(CsTeams:team)
  9742. {
  9743. new player, count;
  9744. for(player=1;player<=maxPlayers;player++)
  9745. {
  9746. if(is_user_connected(player) && cs_get_user_team(player) == team)
  9747. count++;
  9748. }
  9749.  
  9750. return count;
  9751. }
  9752.  
  9753. // is this player on a valid team?
  9754. on_valid_team(id)
  9755. {
  9756. new CsTeams:team = cs_get_user_team(id);
  9757. return (team == CS_TEAM_T || team == CS_TEAM_CT);
  9758. }
  9759.  
  9760. // gets a number's suffix. sort of bad, has to convert to string.
  9761. stock get_number_suffix(number,ret[],retLen)
  9762. {
  9763. static str[8];
  9764. num_to_str(number,str,7);
  9765. new len = strlen(str);
  9766.  
  9767. if(number >= 10 && str[len-2] == '1') // second to last digit
  9768. return formatex(ret,retLen,"th"); // 10-19 end in 'th
  9769.  
  9770. switch(str[len-1]) // last digit
  9771. {
  9772. case '1': return formatex(ret,retLen,"st");
  9773. case '2': return formatex(ret,retLen,"nd");
  9774. case '3': return formatex(ret,retLen,"rd");
  9775. }
  9776.  
  9777. return formatex(ret,retLen,"th");
  9778. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement