Advertisement
Guest User

Untitled

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