Advertisement
Rojeda

Untitled

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