Advertisement
Guest User

file

a guest
Dec 20th, 2014
443
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 48.05 KB | None | 0 0
  1. /*
  2. * SM:Conquest
  3. * Counter-Strike Source gameplay modification
  4. *
  5. * This plugin adds flags to any map which every team has to conquer
  6. * by standing near to it for an specified amount of time.
  7. * The team which controls all flags first wins the round.
  8. *
  9. * Credits:
  10. * L.Duke: The original idea, model and sounds were taken from his abandoned MM:S plugin "Conquest". Hugh thanks!
  11. * Rediem: Recreated the flag materials, win overlays and font. Adjusted the default config.
  12. *
  13. * Changelog:
  14. * 1.0 (06.04.2011): Initial release
  15. * 1.1 (20.04.2011): See changelog.txt
  16. * 1.2 (20.04.2011): Small hotfixes around speed and health class settings and flag adding
  17. * 1.3 (01.05.2011): See changelog.txt
  18. * 1.3.1 (28.07.2011): See changelog.txt
  19. * 1.4 (26.07.2013): Added CS:GO support
  20. * 1.4.1 (19.11.2013): See changelog.txt
  21. *
  22. * Thread: https://forums.alliedmods.net/showthread.php?t=154354
  23. * visit http://www.wcfan.de/
  24. */
  25. #pragma semicolon 1
  26. #include <sourcemod>
  27. #include <sdktools>
  28. #include <clientprefs>
  29. #include <sdkhooks>
  30. #include <cstrike>
  31. #include <colors>
  32. #include <smlib>
  33. #include <loghelper>
  34.  
  35. #define PLUGIN_VERSION "1.4.1"
  36.  
  37. #define PREFIX "{olive}SM:Conquest {default}>{green} "
  38.  
  39. #define PRIMARYAMMO_MODEL "models/items/boxmrounds.mdl"
  40. #define SECONDARYAMMO_MODEL "models/items/boxsrounds.mdl"
  41. #define AMMO_SOUND "items/ammo_pickup.wav"
  42.  
  43. new bool:g_bRoundEnded = false;
  44. new Handle:g_hStartSound = INVALID_HANDLE;
  45.  
  46. // ConVar handles
  47. new Handle:g_hCVRespawn;
  48. new Handle:g_hCVRespawnTime;
  49. new Handle:g_hCVSpawnProtection;
  50. new Handle:g_hCVPreventWeaponDrop;
  51. new Handle:g_hCVDropAmmo;
  52. new Handle:g_hCVPrimaryAmmoAmount;
  53. new Handle:g_hCVSecondaryAmmoAmount;
  54. new Handle:g_hCVDisableBuyzones;
  55. new Handle:g_hCVUseBuymenu;
  56. new Handle:g_hCVInBuyzone;
  57. new Handle:g_hCVUseClasses;
  58. new Handle:g_hCVShowWinOverlays;
  59. new Handle:g_hCVEnableContest;
  60. new Handle:g_hCVHandicap;
  61. new Handle:g_hCVHandicapCountBots;
  62. new Handle:g_hCVCaptureScore;
  63. new Handle:g_hCVTeamScore;
  64. new Handle:g_hCVRemoveObjectives;
  65. new Handle:g_hCVCaptureMoney;
  66. new Handle:g_hCVRemoveDroppedWeapons;
  67. new Handle:g_hCVEnforceTimelimit;
  68. new Handle:g_hCVFadeOnConquer;
  69. new Handle:g_hCVShowOnRadar;
  70. new Handle:g_hCVStripLosers;
  71. new Handle:g_hCVAmmoLifetime;
  72. new Handle:g_hCVAdvertiseCommands;
  73. new Handle:g_hCVStripBots;
  74. new Handle:g_hCVEndGame;
  75.  
  76. // Tag
  77. new Handle:g_hSVTags;
  78.  
  79. // Respawning and spawnprotection
  80. new Handle:g_hRespawnPlayer[MAXPLAYERS+2] = {INVALID_HANDLE,...};
  81. new Handle:g_hRemoveSpawnProtection[MAXPLAYERS+2] = {INVALID_HANDLE,...};
  82.  
  83. // Enforce map timelimit
  84. new Handle:g_hTimeLimitEnforcer = INVALID_HANDLE;
  85. new g_iMapStartTime = 0;
  86. new g_iTimeLimit = 0;
  87.  
  88. // Weapondrop ammo regive to the correct ammotype
  89. new g_iPlayerActiveSlot[MAXPLAYERS+2] = {-1,...};
  90. // Remove dropped weapons every 20 seconds
  91. new Handle:g_hRemoveWeapons = INVALID_HANDLE;
  92.  
  93. // CCSPlayer::m_iAccount offset
  94. new g_iAccount = -1;
  95.  
  96. new bool:g_bIsCSGO = false;
  97.  
  98. new Handle:g_hIgnoreRoundWinCond = INVALID_HANDLE;
  99. new g_iOldIgnoreRoundWinCond;
  100.  
  101. // Store the sound files configured in smconquest_sounds.cfg
  102. #define CSOUND_REDFLAG_CAPTURED 0
  103. #define CSOUND_BLUEFLAG_CAPTURED 1
  104. #define CSOUND_REDTEAM_WIN 2
  105. #define CSOUND_BLUETEAM_WIN 3
  106. #define CSOUND_ROUNDSTART 4
  107. #define CSOUND_FLAG_AMBIENCE 5
  108. #define CSOUND_REDTEAM_STARTS_CONQUERING 6
  109. #define CSOUND_BLUETEAM_STARTS_CONQUERING 7
  110.  
  111. #define CSOUND_NUMSOUNDS 8
  112. new String:g_sSoundFiles[CSOUND_NUMSOUNDS][PLATFORM_MAX_PATH];
  113.  
  114. #include "smconquest_models.sp"
  115. #include "smconquest_clientpref.sp"
  116. #include "smconquest_flags.sp"
  117. #include "smconquest_classes.sp"
  118. #include "smconquest_buymenu.sp"
  119. #include "smconquest_flagadmin.sp"
  120.  
  121. public Plugin:myinfo =
  122. {
  123. name = "SM:Conquest",
  124. author = "Jannik 'Peace-Maker' Hartung",
  125. description = "Conquer areas on maps to win",
  126. version = PLUGIN_VERSION,
  127. url = "http://www.wcfan.de/"
  128. }
  129.  
  130. public OnPluginStart()
  131. {
  132. new Handle:hVersion = CreateConVar("sm_conquest_version", PLUGIN_VERSION, "SM:Conquest version", FCVAR_PLUGIN|FCVAR_NOTIFY|FCVAR_REPLICATED|FCVAR_DONTRECORD);
  133. if(hVersion != INVALID_HANDLE)
  134. SetConVarString(hVersion, PLUGIN_VERSION);
  135.  
  136. g_hCVRespawn = CreateConVar("sm_conquest_respawn", "1", "Should a player respawn after x seconds?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  137. g_hCVRespawnTime = CreateConVar("sm_conquest_respawntime", "5", "How long should the player be dead until getting respawned?", FCVAR_PLUGIN, true, 1.0);
  138. g_hCVSpawnProtection = CreateConVar("sm_conquest_spawnprotection", "5", "How long should the player be invincible after spawn?", FCVAR_PLUGIN, true, 0.0);
  139. g_hCVPreventWeaponDrop = CreateConVar("sm_conquest_noweapondrop", "1", "Should players be disallowed to drop their weapons and remove them on death?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  140. g_hCVDropAmmo = CreateConVar("sm_conquest_dropammo", "1", "Should a dead player drop some ammo depending of his weapon?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  141. g_hCVPrimaryAmmoAmount = CreateConVar("sm_conquest_droppedprimaryammo", "10", "How much ammo should a primary ammo pack give?", FCVAR_PLUGIN, true, 0.0);
  142. g_hCVSecondaryAmmoAmount = CreateConVar("sm_conquest_droppedsecondaryammo", "10", "How much ammo should a secondary ammo pack give?", FCVAR_PLUGIN, true, 0.0);
  143. g_hCVDisableBuyzones = CreateConVar("sm_conquest_disablebuyzones", "1", "Disable the buyzones on map to stop the standard buying?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  144. g_hCVUseBuymenu = CreateConVar("sm_conquest_enablebuymenu", "1", "Use the custom buymenu?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  145. g_hCVInBuyzone = CreateConVar("sm_conquest_inbuyzone", "1", "Only allow buying with the custom menu in buyzones?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  146. g_hCVUseClasses = CreateConVar("sm_conquest_enableclasses", "1", "Enable the player class system?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  147. g_hCVShowWinOverlays = CreateConVar("sm_conquest_showwinoverlays", "1", "Should we display an overlay with the winning team logo? Don't enable this on runtime - only in config. (downloading)", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  148. g_hCVEnableContest = CreateConVar("sm_conquest_enablecontest", "1", "Should enemies interrupt the capture process when entering a zone?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  149. g_hCVHandicap = CreateConVar("sm_conquest_handicap", "1", "Should we decrease the amount of required players to the team count, if there are less players in the team than required?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  150. g_hCVHandicapCountBots = CreateConVar("sm_conquest_handicapcountbots", "1", "Should we count bots when counting the players in a team for the handicap?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  151. g_hCVCaptureScore = CreateConVar("sm_conquest_capturescore", "1", "How many frags should a player receive when conquering a flag?", FCVAR_PLUGIN, true, 0.0);
  152. g_hCVTeamScore = CreateConVar("sm_conquest_teamscore", "1", "How many points should a team earn when conquering all flags?", FCVAR_PLUGIN, true, 0.0);
  153. g_hCVRemoveObjectives = CreateConVar("sm_conquest_removeobjectives", "1", "Remove all bomb/hostage related stuff to prevent round end?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  154. g_hCVCaptureMoney = CreateConVar("sm_conquest_capturemoney", "500", "How much money should all players earn for capturing a flag?", FCVAR_PLUGIN, true, 0.0);
  155. g_hCVRemoveDroppedWeapons = CreateConVar("sm_conquest_removedroppedweapons", "20", "How often should we remove dropped weapons in x seconds interval?", FCVAR_PLUGIN, true, 0.0);
  156. g_hCVEnforceTimelimit = CreateConVar("sm_conquest_enforcetimelimit", "1", "End the game when the mp_timelimit is over - even midround?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  157. g_hCVFadeOnConquer = CreateConVar("sm_conquest_fadeonconquer", "1", "Fade the screen in the flag color for all players on conquer?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  158. g_hCVShowOnRadar = CreateConVar("sm_conquest_showonradar", "1", "Should enemies near an conquered flag appear on the radar of the team controlling the flag?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  159. g_hCVStripLosers = CreateConVar("sm_conquest_striplosers", "0", "Strip the losing team to knife on round end?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  160. g_hCVAmmoLifetime = CreateConVar("sm_conquest_ammolifetime", "60", "Remove dropped ammo packs after x seconds?", FCVAR_PLUGIN, true, 0.0);
  161. g_hCVAdvertiseCommands = CreateConVar("sm_conquest_advertisecommands", "1", "Advertise the !class and !buy commands in chat?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  162. g_hCVStripBots = CreateConVar("sm_conquest_stripbots", "1", "Strip bots to knife and set to default class on spawn?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  163. g_hCVEndGame = CreateConVar("sm_conquest_endmap", "0", "End the whole map when a team conquers all flags instead of only one round?", FCVAR_PLUGIN, true, 0.0, true, 1.0);
  164.  
  165. g_hSVTags = FindConVar("sv_tags");
  166.  
  167. LoadTranslations("common.phrases");
  168. LoadTranslations("smconquest.phrases");
  169.  
  170. // Flags
  171. g_hFlags = CreateArray();
  172. g_hPlayersInZone = CreateArray();
  173.  
  174. // Classes
  175. g_hClasses = CreateArray();
  176.  
  177. // Models
  178. g_hModels = CreateArray();
  179.  
  180. // Buymenu
  181. g_hBuyItemMenuArray = CreateArray();
  182.  
  183. // Are we running on csgo?
  184. if(GetFeatureStatus(FeatureType_Native, "GetEngineVersion") == FeatureStatus_Available)
  185. g_bIsCSGO = GetEngineVersion() == Engine_CSGO;
  186. else
  187. g_bIsCSGO = GuessSDKVersion() == SOURCE_SDK_CSGO;
  188.  
  189. g_iAccount = FindSendPropOffs("CCSPlayer", "m_iAccount");
  190. if(g_iAccount == -1)
  191. {
  192. SetFailState("Can't find CCSPlayer::m_iAccount offset.");
  193. }
  194.  
  195. if(g_bIsCSGO)
  196. {
  197. g_iSpottedOffset = FindSendPropOffs("CCSPlayer", "m_bSpotted");
  198. if(g_iSpottedOffset == -1)
  199. {
  200. SetFailState("Can't find CCSPlayer::m_bSpotted offset.");
  201. }
  202. }
  203. else
  204. {
  205. g_iPlayerSpottedOffset = FindSendPropOffs("CCSPlayerResource", "m_bPlayerSpotted");
  206. if(g_iPlayerSpottedOffset == -1)
  207. {
  208. SetFailState("Can't find CCSPlayerResource::m_bPlayerSpotted offset.");
  209. }
  210. }
  211.  
  212. // Hook game events
  213. HookEvent("round_end", Event_OnRoundEnd);
  214. HookEvent("round_start", Event_OnRoundStart);
  215. HookEvent("player_spawn", Event_OnPlayerSpawn);
  216. HookEvent("player_death", Event_OnPlayerDeath);
  217. HookEvent("player_team", Event_OnPlayerTeam);
  218. HookEvent("weapon_fire", Event_OnWeaponFire);
  219.  
  220. // Register public commands
  221. RegConsoleCmd("sm_class", Command_ShowClassMenu, "Displays the class selection menu");
  222. RegConsoleCmd("sm_buy", Command_ShowBuyMenu, "Displays the item buy menu");
  223.  
  224. // Register admin commands
  225. RegAdminCmd("sm_spawnammo", Command_SpawnAmmoPack, ADMFLAG_SLAY, "Spawns an ammo pack where you aim. Usage: sm_spawnammo <p|s>");
  226. RegAdminCmd("sm_flagadmin", Command_FlagAdmin, ADMFLAG_CONFIG, "Opens the flag administration menu");
  227.  
  228. // Hook chat for flag admin
  229. RegConsoleCmd("say", Command_Say);
  230. RegConsoleCmd("say_team", Command_Say);
  231.  
  232. // Init Clientprefs
  233. CreateClientCookies();
  234.  
  235. // Force the timelimit, even if the round never ends
  236. new Handle:hTimeLimit = FindConVar("mp_timelimit");
  237. HookConVarChange(hTimeLimit, ConVar_TimeLimitChanged);
  238. g_iTimeLimit = GetConVarInt(hTimeLimit)*60;
  239.  
  240. g_hIgnoreRoundWinCond = FindConVar("mp_ignore_round_win_conditions");
  241. if(g_hIgnoreRoundWinCond != INVALID_HANDLE)
  242. g_iOldIgnoreRoundWinCond = GetConVarInt(g_hIgnoreRoundWinCond);
  243.  
  244. AutoExecConfig(true, "plugin.smconquest");
  245.  
  246. for(new i=1;i<=MaxClients;i++)
  247. {
  248. if(IsClientInGame(i))
  249. OnClientPutInServer(i);
  250. }
  251. }
  252.  
  253. public OnPluginEnd()
  254. {
  255. MyRemoveServerTag("conquest");
  256. if(g_hIgnoreRoundWinCond != INVALID_HANDLE)
  257. SetConVarInt(g_hIgnoreRoundWinCond, g_iOldIgnoreRoundWinCond);
  258. }
  259.  
  260. // Check if we are lateloaded (not with serverstart)
  261. public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
  262. {
  263. RegPluginLibrary("smconquest");
  264. MarkNativeAsOptional("GetEngineVersion");
  265.  
  266. return APLRes_Success;
  267. }
  268.  
  269. /**
  270. * Forwards
  271. */
  272.  
  273. public OnMapStart()
  274. {
  275. // Load the model config. If it fails or is missing the flag_config fall back to the default info.
  276. new bool:bModelsLoaded = ParseModelConfig();
  277. if(!bModelsLoaded || strlen(g_sFlagModelPath) == 0)
  278. {
  279. // Flag model
  280. AddFileToDownloadsTable("models/conquest/flagv2/flag.mdl");
  281. AddFileToDownloadsTable("models/conquest/flagv2/flag.dx80.vtx");
  282. AddFileToDownloadsTable("models/conquest/flagv2/flag.dx90.vtx");
  283. AddFileToDownloadsTable("models/conquest/flagv2/flag.phy");
  284. AddFileToDownloadsTable("models/conquest/flagv2/flag.sw.vtx");
  285. AddFileToDownloadsTable("models/conquest/flagv2/flag.vvd");
  286. AddFileToDownloadsTable("models/conquest/flagv2/flag.xbox.vtx");
  287.  
  288. AddFileToDownloadsTable("materials/models/conquest/flagv2/ct_flag.vmt");
  289. AddFileToDownloadsTable("materials/models/conquest/flagv2/ct_flag.vtf");
  290. AddFileToDownloadsTable("materials/models/conquest/flagv2/neutralflag.vmt");
  291. AddFileToDownloadsTable("materials/models/conquest/flagv2/neutralflag.vtf");
  292. AddFileToDownloadsTable("materials/models/conquest/flagv2/t_flag.vmt");
  293. AddFileToDownloadsTable("materials/models/conquest/flagv2/t_flag.vtf");
  294.  
  295. strcopy(g_sFlagModelPath, sizeof(g_sFlagModelPath), "models/conquest/flagv2/flag.mdl");
  296. strcopy(g_sFlagAnimation, sizeof(g_sFlagAnimation), "flag_idle1");
  297. strcopy(g_FlagSkinOptions[WhiteFlag], sizeof(g_FlagSkinOptions[WhiteFlag]), "0");
  298. strcopy(g_FlagSkinOptions[RedFlag], sizeof(g_FlagSkinOptions[RedFlag]), "1");
  299. strcopy(g_FlagSkinOptions[BlueFlag], sizeof(g_FlagSkinOptions[BlueFlag]), "2");
  300.  
  301. PrecacheModel("models/conquest/flagv2/flag.mdl", true);
  302. }
  303. // Winning overlays fallback
  304. if(!g_bIsCSGO && GetConVarBool(g_hCVShowWinOverlays))
  305. {
  306. if(!bModelsLoaded || strlen(g_OverlayMaterials[m_CT]) == 0)
  307. {
  308.  
  309. AddFileToDownloadsTable("materials/conquest/v1/blue_wins.vmt");
  310. AddFileToDownloadsTable("materials/conquest/v1/blue_wins.vtf");
  311. PrecacheDecal("conquest/v1/blue_wins.vmt", true);
  312. strcopy(g_OverlayMaterials[m_CT], sizeof(g_OverlayMaterials[m_CT]), "conquest/v1/blue_wins.vtf");
  313. }
  314. else if(!bModelsLoaded || strlen(g_OverlayMaterials[m_T]) == 0)
  315. {
  316. AddFileToDownloadsTable("materials/conquest/v1/red_wins.vmt");
  317. AddFileToDownloadsTable("materials/conquest/v1/red_wins.vtf");
  318. PrecacheDecal("conquest/v1/red_wins.vmt", true);
  319. strcopy(g_OverlayMaterials[m_T], sizeof(g_OverlayMaterials[m_T]), "conquest/v1/red_wins.vtf");
  320. }
  321. }
  322. if(g_bIsCSGO)
  323. {
  324. // Ammo boxes
  325. AddFileToDownloadsTable("models/items/boxmrounds.dx90.vtx");
  326. AddFileToDownloadsTable("models/items/boxmrounds.mdl");
  327. AddFileToDownloadsTable("models/items/boxmrounds.phy");
  328. AddFileToDownloadsTable("models/items/boxmrounds.vvd");
  329. AddFileToDownloadsTable("models/items/boxsrounds.dx90.vtx");
  330. AddFileToDownloadsTable("models/items/boxsrounds.mdl");
  331. AddFileToDownloadsTable("models/items/boxsrounds.phy");
  332. AddFileToDownloadsTable("models/items/boxsrounds.vvd");
  333.  
  334. AddFileToDownloadsTable("materials/models/items/BoxMRounds.vtf");
  335. AddFileToDownloadsTable("materials/models/items/BoxMRounds_normal.vtf");
  336. AddFileToDownloadsTable("materials/models/items/BoxMRounds.vmt");
  337. AddFileToDownloadsTable("materials/models/items/BoxSRounds.vtf");
  338. AddFileToDownloadsTable("materials/models/items/BoxSRounds.vmt");
  339. }
  340.  
  341. // Game sounds
  342. // Load from smconquest_sounds.cfg
  343. new String:sFile[PLATFORM_MAX_PATH], String:sGame[10];
  344.  
  345. // Get the correct config for this game
  346. if(g_bIsCSGO)
  347. Format(sGame, sizeof(sGame), "csgo");
  348. else
  349. Format(sGame, sizeof(sGame), "css");
  350. BuildPath(Path_SM, sFile, sizeof(sFile), "configs/smconquest/%s/smconquest_sounds.cfg", sGame);
  351.  
  352. // Clear the sounds as a base
  353. for(new i=0;i<CSOUND_NUMSOUNDS;i++)
  354. Format(g_sSoundFiles[i], PLATFORM_MAX_PATH-1, "");
  355.  
  356. // The file exists? Sounds are disabled if not.
  357. if(FileExists(sFile))
  358. {
  359. new Handle:hKV = CreateKeyValues("ConquestSounds");
  360. decl String:sSection[64], String:sBuffer[PLATFORM_MAX_PATH];
  361. FileToKeyValues(hKV, sFile);
  362. if(KvGotoFirstSubKey(hKV))
  363. {
  364. do
  365. {
  366. // Is there actually a sound key?
  367. KvGetString(hKV, "sound", sBuffer, sizeof(sBuffer), "-1");
  368. if(!StrEqual(sBuffer, "-1"))
  369. {
  370. // CS:GO doesn't support flag ambience.
  371. KvGetSectionName(hKV, sSection, sizeof(sSection));
  372. if(StrEqual(sSection, "flag_ambience"))
  373. continue;
  374.  
  375. // It's in the sound folder
  376. Format(sBuffer, sizeof(sBuffer), "sound/%s", sBuffer);
  377.  
  378. // Check if we want to download that file or if it's already packed with CS:S?
  379. KvGetString(hKV, "is_game_sound", sSection, sizeof(sSection), "0");
  380. if(!StrEqual(sSection, "1"))
  381. {
  382. // Does this sound exist?
  383. if(!FileExists(sBuffer, true))
  384. {
  385. LogError("Can't find sound \"%s\". Check your smconquest_sounds.cfg.", sBuffer);
  386. continue;
  387. }
  388.  
  389. // Download that sound
  390. AddFileToDownloadsTable(sBuffer);
  391. }
  392.  
  393. // Precache it
  394. PrecacheSound(sBuffer[6], true);
  395.  
  396. // Which sound is set?
  397. KvGetSectionName(hKV, sSection, sizeof(sSection));
  398. if(StrEqual(sSection, "redteam_starts_conquering"))
  399. {
  400. strcopy(g_sSoundFiles[CSOUND_REDTEAM_STARTS_CONQUERING], PLATFORM_MAX_PATH-1, sBuffer[6]);
  401. }
  402. else if(StrEqual(sSection, "blueteam_starts_conquering"))
  403. {
  404. strcopy(g_sSoundFiles[CSOUND_BLUETEAM_STARTS_CONQUERING], PLATFORM_MAX_PATH-1, sBuffer[6]);
  405. }
  406. else if(StrEqual(sSection, "redflag_captured"))
  407. {
  408. strcopy(g_sSoundFiles[CSOUND_REDFLAG_CAPTURED], PLATFORM_MAX_PATH-1, sBuffer[6]);
  409. }
  410. else if(StrEqual(sSection, "blueflag_captured"))
  411. {
  412. strcopy(g_sSoundFiles[CSOUND_BLUEFLAG_CAPTURED], PLATFORM_MAX_PATH-1, sBuffer[6]);
  413. }
  414. else if(StrEqual(sSection, "redteam_win"))
  415. {
  416. strcopy(g_sSoundFiles[CSOUND_REDTEAM_WIN], PLATFORM_MAX_PATH-1, sBuffer[6]);
  417. }
  418. else if(StrEqual(sSection, "blueteam_win"))
  419. {
  420. strcopy(g_sSoundFiles[CSOUND_BLUETEAM_WIN], PLATFORM_MAX_PATH-1, sBuffer[6]);
  421. }
  422. else if(StrEqual(sSection, "roundstart"))
  423. {
  424. strcopy(g_sSoundFiles[CSOUND_ROUNDSTART], PLATFORM_MAX_PATH-1, sBuffer[6]);
  425. }
  426. else if(StrEqual(sSection, "flag_ambience"))
  427. {
  428. strcopy(g_sSoundFiles[CSOUND_FLAG_AMBIENCE], PLATFORM_MAX_PATH-1, sBuffer[6]);
  429. }
  430. }
  431. } while(KvGotoNextKey(hKV));
  432. }
  433.  
  434. CloseHandle(hKV);
  435. }
  436.  
  437. // Have to precache radio sounds to block them
  438. if(!g_bIsCSGO)
  439. {
  440. PrecacheSound("radio/ctwin.wav", false);
  441. PrecacheSound("radio/terwin.wav", false);
  442. }
  443.  
  444. if(g_bIsCSGO)
  445. {
  446. g_iLaserMaterial = PrecacheModel("materials/sprites/laserbeam.vmt", true);
  447. g_iHaloMaterial = PrecacheModel("materials/sprites/glow01.vmt", true);
  448. g_iGlowSprite = PrecacheModel("materials/sprites/blueflare1.vmt", true);
  449. }
  450. else
  451. {
  452. g_iLaserMaterial = PrecacheModel("materials/sprites/laser.vmt", true);
  453. g_iHaloMaterial = PrecacheModel("materials/sprites/halo01.vmt", true);
  454. g_iGlowSprite = PrecacheModel("sprites/blueglow2.vmt", true);
  455. }
  456.  
  457. PrecacheModel(PRIMARYAMMO_MODEL, true);
  458. PrecacheModel(SECONDARYAMMO_MODEL, true);
  459. PrecacheSound(AMMO_SOUND, true);
  460.  
  461. ParseFlagConfig();
  462. ParseClassConfig();
  463. ParseBuyConfig();
  464.  
  465. MyAddServerTag("conquest");
  466.  
  467. // Hook the player_manager, to show people on radar
  468. if(!g_bIsCSGO)
  469. {
  470. new iPlayerManager = FindEntityByClassname(0, "cs_player_manager");
  471. SDKHook(iPlayerManager, SDKHook_ThinkPost, Hook_OnPlayerManagerThinkPost);
  472. }
  473.  
  474. // Enforce the timelimit
  475. g_iMapStartTime = GetTime();
  476. if(GetConVarBool(g_hCVEnforceTimelimit))
  477. g_hTimeLimitEnforcer = CreateTimer(10.0, Timer_CheckTimeLimit, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
  478.  
  479. // Show the flag status
  480. CreateTimer(0.5, Timer_OnUpdateStatusPanel, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
  481.  
  482. // Advertise the commands
  483. if(GetConVarBool(g_hCVAdvertiseCommands))
  484. CreateTimer(300.0, Timer_OnAdvertCommands, 0, TIMER_FLAG_NO_MAPCHANGE);
  485. }
  486.  
  487. public OnMapEnd()
  488. {
  489. // Flag admin
  490. if(g_hDebugZoneTimer != INVALID_HANDLE)
  491. {
  492. KillTimer(g_hDebugZoneTimer);
  493. g_hDebugZoneTimer = INVALID_HANDLE;
  494. }
  495.  
  496. if(g_hStartSound != INVALID_HANDLE)
  497. {
  498. KillTimer(g_hStartSound);
  499. g_hStartSound = INVALID_HANDLE;
  500. }
  501.  
  502. if(g_hRemoveWeapons != INVALID_HANDLE)
  503. {
  504. KillTimer(g_hRemoveWeapons);
  505. g_hRemoveWeapons = INVALID_HANDLE;
  506. }
  507.  
  508. g_iMapStartTime = 0;
  509. if(g_hTimeLimitEnforcer != INVALID_HANDLE)
  510. {
  511. KillTimer(g_hTimeLimitEnforcer);
  512. g_hTimeLimitEnforcer = INVALID_HANDLE;
  513. }
  514. }
  515.  
  516. public OnConfigsExecuted()
  517. {
  518. // Don't have that annoying swish sound twice a second.
  519. if(!g_bIsCSGO)
  520. ServerCommand("sv_hudhint_sound 0");
  521.  
  522. if(g_hIgnoreRoundWinCond != INVALID_HANDLE)
  523. SetConVarInt(g_hIgnoreRoundWinCond, 1);
  524. // TODO Clean this up!
  525. if(GetConVarBool(g_hCVInBuyzone))
  526. ServerCommand("mp_buytime 99999");
  527. }
  528.  
  529. public OnClientPutInServer(client)
  530. {
  531. SDKHook(client, SDKHook_WeaponSwitch, Hook_OnWeaponSwitch);
  532. SDKHook(client, SDKHook_PostThinkPost, Hook_OnPostThinkPost);
  533. if(g_bIsCSGO)
  534. {
  535. SDKHook(client, SDKHook_PreThinkPost, Hook_OnThinkPost);
  536. SDKHook(client, SDKHook_ThinkPost, Hook_OnThinkPost); // Think isn't fired for clients in csgo? Only for bots
  537. }
  538. }
  539.  
  540. public OnClientDisconnect(client)
  541. {
  542. // remove him from zone touch arrays, if he has been in a zone
  543. RemovePlayerFromAllZones(client);
  544.  
  545. if(g_hRespawnPlayer[client] != INVALID_HANDLE)
  546. {
  547. KillTimer(g_hRespawnPlayer[client]);
  548. g_hRespawnPlayer[client] = INVALID_HANDLE;
  549. }
  550.  
  551. if(g_hRemoveSpawnProtection[client] != INVALID_HANDLE)
  552. {
  553. KillTimer(g_hRemoveSpawnProtection[client]);
  554. g_hRemoveSpawnProtection[client] = INVALID_HANDLE;
  555. }
  556.  
  557. if(g_hApplyPlayerClass[client] != INVALID_HANDLE)
  558. {
  559. KillTimer(g_hApplyPlayerClass[client]);
  560. g_hApplyPlayerClass[client] = INVALID_HANDLE;
  561. }
  562.  
  563. if(g_hShowTempFlagPosition[client] != INVALID_HANDLE)
  564. {
  565. KillTimer(g_hShowTempFlagPosition[client]);
  566. g_hShowTempFlagPosition[client] = INVALID_HANDLE;
  567. }
  568.  
  569. if(g_hShowTempZone[client] != INVALID_HANDLE)
  570. {
  571. KillTimer(g_hShowTempZone[client]);
  572. g_hShowTempZone[client] = INVALID_HANDLE;
  573. }
  574.  
  575. g_iPlayerEditsFlag[client] = -1;
  576. ClearVector(g_fTempFlagPosition[client]);
  577. ClearVector(g_fTempFlagAngle[client]);
  578.  
  579. g_iPlayerEditsVector[client] = NO_POINT;
  580. g_bPlayerAddsFlag[client] = false;
  581. ClearVector(g_fTempZoneVector1[client]);
  582. ClearVector(g_fTempZoneVector2[client]);
  583.  
  584. g_iPlayerClass[client] = -1;
  585. g_iPlayerWeaponSet[client] = -1;
  586. g_iPlayerTempClass[client] = -1;
  587. g_bPlayerJustJoined[client] = true;
  588.  
  589. g_iPlayerActiveSlot[client] = -1;
  590.  
  591. g_iPlayerGrenade[client][GRENADE_HE] = 0;
  592. g_iPlayerGrenade[client][GRENADE_FLASH] = 0;
  593. g_iPlayerGrenade[client][GRENADE_SMOKE] = 0;
  594.  
  595. g_bPlayerInBuyZone[client] = false;
  596. g_bPlayerIsBuying[client] = false;
  597.  
  598. g_bPlayerRenamesFlag[client] = false;
  599. g_bPlayerNamesNewFlag[client] = false;
  600. g_bPlayerSetsRequiredPlayers[client] = false;
  601. g_bPlayerSetsConquerTime[client] = false;
  602.  
  603. ResetCookieCache(client);
  604.  
  605. if(GetConVarBool(g_hCVDropAmmo) && IsClientInGame(client))
  606. {
  607. // Bad weapon?
  608. if(g_iPlayerActiveSlot[client] == -1)
  609. return;
  610.  
  611. // Remove weapons and put an ammo box instead
  612. // Always drop the ammo on the ground
  613. new Float:fOrigin[3];
  614. GetClientEyePosition(client, fOrigin);
  615.  
  616. fOrigin[2] += 10.0;
  617.  
  618. TR_TraceRayFilter(fOrigin, Float:{90.0,0.0,0.0}, MASK_PLAYERSOLID, RayType_Infinite, TraceRayNoPlayers, client);
  619. if (TR_DidHit())
  620. {
  621. TR_GetEndPosition(fOrigin);
  622. }
  623.  
  624. new bool:bPrimaryWeapon = g_iPlayerActiveSlot[client] == CS_SLOT_PRIMARY;
  625.  
  626. new Float:fAngle[3];
  627. GetClientEyeAngles(client, fAngle);
  628. fAngle[0] = 0.0;
  629. fAngle[2] = 0.0;
  630.  
  631. CreateAmmoPack(fOrigin, fAngle, bPrimaryWeapon);
  632. }
  633. }
  634.  
  635. /**
  636. * Events
  637. */
  638.  
  639. public Action:Event_OnPlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
  640. {
  641. new userid = GetEventInt(event, "userid");
  642. new client = GetClientOfUserId(userid);
  643.  
  644. // Just to be sure
  645. RemovePlayerFromAllZones(client);
  646.  
  647. // Don't do anything, if no flags for that map -> "disabled"
  648. if(GetArraySize(g_hFlags) == 0)
  649. return Plugin_Continue;
  650.  
  651. // Spawnprotection
  652. new Float:fRespawnTime = GetConVarFloat(g_hCVSpawnProtection);
  653. if(fRespawnTime > 0.0)
  654. {
  655. g_hRemoveSpawnProtection[client] = CreateTimer(fRespawnTime, Timer_OnDisableSpawnprotection, userid, TIMER_FLAG_NO_MAPCHANGE);
  656. SetEntProp(client, Prop_Data, "m_takedamage", 0);
  657. SetEntityRenderMode(client, RENDER_TRANSCOLOR);
  658. SetEntityRenderColor(client, 0, 255, 150, 170);
  659. }
  660.  
  661. g_iPlayerGrenade[client][GRENADE_HE] = 0;
  662. g_iPlayerGrenade[client][GRENADE_FLASH] = 0;
  663. g_iPlayerGrenade[client][GRENADE_SMOKE] = 0;
  664.  
  665. if(g_hApplyPlayerClass[client] != INVALID_HANDLE)
  666. {
  667. KillTimer(g_hApplyPlayerClass[client]);
  668. g_hApplyPlayerClass[client] = INVALID_HANDLE;
  669. }
  670.  
  671. // Remove any leftover progressbar, if he just spectated someone :o
  672. SetEntPropFloat(client, Prop_Send, "m_flProgressBarStartTime", 0.0);
  673. SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0);
  674.  
  675. // Player class
  676. if(GetConVarBool(g_hCVUseClasses))
  677. {
  678. // Strip weapons
  679. if(GetClientTeam(client) >= CS_TEAM_T)
  680. {
  681. // Don't strip the bot, if it's disabled :)
  682. if(!IsFakeClient(client) || (IsFakeClient(client) && GetConVarBool(g_hCVStripBots)))
  683. Client_RemoveAllWeapons(client, "weapon_knife", true);
  684. // Set the class with a delay
  685. g_hApplyPlayerClass[client] = CreateTimer(0.5, Timer_ApplyPlayerClass, userid, TIMER_FLAG_NO_MAPCHANGE);
  686. }
  687. }
  688.  
  689. g_bPlayerInBuyZone[client] = false;
  690. g_bPlayerIsBuying[client] = false;
  691.  
  692. return Plugin_Continue;
  693. }
  694.  
  695. public Action:Event_OnPlayerDeath(Handle:event, const String:name[], bool:dontBroadcast)
  696. {
  697. new userid = GetEventInt(event, "userid");
  698. new client = GetClientOfUserId(userid);
  699.  
  700. RemovePlayerFromAllZones(client);
  701.  
  702. // Don't do anything, if no flags for that map -> "disabled"
  703. if(GetArraySize(g_hFlags) == 0)
  704. return Plugin_Continue;
  705.  
  706. // Respawn the player with a delay
  707. if(g_hRespawnPlayer[client] != INVALID_HANDLE)
  708. {
  709. KillTimer(g_hRespawnPlayer[client]);
  710. g_hRespawnPlayer[client] = INVALID_HANDLE;
  711. }
  712.  
  713. // Stop giving him the weapons
  714. if(g_hApplyPlayerClass[client] != INVALID_HANDLE)
  715. {
  716. KillTimer(g_hApplyPlayerClass[client]);
  717. g_hApplyPlayerClass[client] = INVALID_HANDLE;
  718. }
  719.  
  720. // TODO: Add option to reset to default weaponset of that class on death/teamchange
  721.  
  722. if(GetConVarBool(g_hCVRespawn) && GetClientTeam(client) >= CS_TEAM_T)
  723. {
  724. new iRespawnTime = GetConVarInt(g_hCVRespawnTime);
  725.  
  726. new Handle:hDataPack = CreateDataPack();
  727. WritePackCell(hDataPack, userid);
  728. WritePackCell(hDataPack, iRespawnTime);
  729. ResetPack(hDataPack);
  730. g_hRespawnPlayer[client] = CreateTimer(1.0, Timer_OnPlayerRespawnTick, hDataPack, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE|TIMER_DATA_HNDL_CLOSE);
  731. Client_PrintKeyHintText(client, "%t", "Respawn in x seconds", iRespawnTime);
  732. }
  733.  
  734. // Drop ammo box
  735. if(GetConVarBool(g_hCVDropAmmo))
  736. {
  737. // Bad weapon?
  738. if(g_iPlayerActiveSlot[client] == -1)
  739. return Plugin_Continue;
  740.  
  741. // Remove weapons and put an ammo box instead
  742. // Always drop the ammo on the ground
  743. new Float:fOrigin[3];
  744. GetClientEyePosition(client, fOrigin);
  745.  
  746. fOrigin[2] += 10.0;
  747.  
  748. TR_TraceRayFilter(fOrigin, Float:{90.0,0.0,0.0}, MASK_PLAYERSOLID, RayType_Infinite, TraceRayNoPlayers, client);
  749. if (TR_DidHit())
  750. {
  751. TR_GetEndPosition(fOrigin);
  752. }
  753.  
  754. new bool:bPrimaryWeapon = g_iPlayerActiveSlot[client] == CS_SLOT_PRIMARY;
  755.  
  756. new Float:fAngle[3];
  757. GetClientEyeAngles(client, fAngle);
  758. fAngle[0] = 0.0;
  759. fAngle[2] = 0.0;
  760.  
  761. CreateAmmoPack(fOrigin, fAngle, bPrimaryWeapon);
  762. }
  763.  
  764. return Plugin_Continue;
  765. }
  766.  
  767. public Action:Event_OnPlayerTeam(Handle:event, const String:name[], bool:dontBroadcast)
  768. {
  769. new userid = GetEventInt(event, "userid");
  770. new client = GetClientOfUserId(userid);
  771. new team = GetEventInt(event, "team");
  772. new oldteam = GetEventInt(event, "oldteam");
  773. RemovePlayerFromAllZones(client);
  774.  
  775. // Stop giving him the weapons
  776. if(g_hApplyPlayerClass[client] != INVALID_HANDLE)
  777. {
  778. KillTimer(g_hApplyPlayerClass[client]);
  779. g_hApplyPlayerClass[client] = INVALID_HANDLE;
  780. }
  781.  
  782. // Don't do anything, if no flags for that map -> "disabled"
  783. if(GetArraySize(g_hFlags) == 0)
  784. return Plugin_Continue;
  785.  
  786. // Don't care, if he's joining the same team again :P
  787. if(oldteam == team)
  788. return Plugin_Continue;
  789.  
  790. if(team > CS_TEAM_SPECTATOR)
  791. {
  792. // Respawn the player, if he's not alive already or is being respawned
  793. if(GetConVarBool(g_hCVRespawn) && !IsPlayerAlive(client) && g_hRespawnPlayer[client] == INVALID_HANDLE)
  794. {
  795. new iRespawnTime = GetConVarInt(g_hCVRespawnTime);
  796.  
  797. new Handle:hDataPack = CreateDataPack();
  798. WritePackCell(hDataPack, userid);
  799. WritePackCell(hDataPack, iRespawnTime);
  800. ResetPack(hDataPack);
  801. g_hRespawnPlayer[client] = CreateTimer(1.0, Timer_OnPlayerRespawnTick, hDataPack, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE|TIMER_DATA_HNDL_CLOSE);
  802. Client_PrintKeyHintText(client, "%t", "Respawn in x seconds", iRespawnTime);
  803. }
  804.  
  805. // Reset the class, if it's team specific or full in the new team
  806. if(g_iPlayerClass[client] != -1)
  807. {
  808. new Handle:hClass = GetArrayCell(g_hClasses, g_iPlayerClass[client]);
  809.  
  810. // The current class needs to be for both teams
  811. new iTeam = GetArrayCell(hClass, CLASS_TEAM);
  812. if(iTeam == 0)
  813. {
  814. // Check if the class is already full in the new team.
  815. new iCurrentPlayers = GetTotalPlayersInClass(g_iPlayerClass[client], team);
  816. new iLimit = GetArrayCell(hClass, CLASS_LIMIT);
  817. if(iLimit != 0 && iCurrentPlayers >= iLimit)
  818. {
  819. // The class is full in the new team. Reset to default.
  820. g_iPlayerClass[client] = -1;
  821. g_iPlayerTempClass[client] = -1;
  822. g_iPlayerWeaponSet[client] = -1;
  823. // Apply the class directly again
  824. g_bPlayerJustJoined[client] = true;
  825. }
  826. }
  827. // This one is team specific. Reset to default.
  828. else
  829. {
  830. g_iPlayerClass[client] = -1;
  831. g_iPlayerTempClass[client] = -1;
  832. g_iPlayerWeaponSet[client] = -1;
  833. // Apply the class directly again
  834. g_bPlayerJustJoined[client] = true;
  835. }
  836. }
  837. // No class assigned before. Reset just to be sure;)
  838. else
  839. {
  840. g_iPlayerTempClass[client] = -1;
  841. g_iPlayerWeaponSet[client] = -1;
  842. // Apply the class directly again
  843. g_bPlayerJustJoined[client] = true;
  844. }
  845.  
  846. if(GetConVarBool(g_hCVUseClasses))
  847. {
  848. // Set the class with a delay
  849. g_hApplyPlayerClass[client] = CreateTimer(0.5, Timer_ApplyPlayerClass, userid, TIMER_FLAG_NO_MAPCHANGE);
  850. }
  851. }
  852.  
  853. return Plugin_Continue;
  854. }
  855.  
  856. public Action:Event_OnRoundStart(Handle:event, const String:name[], bool:dontBroadcast)
  857. {
  858. g_bRoundEnded = false;
  859.  
  860. // Remove the objectives
  861. if(GetConVarBool(g_hCVRemoveObjectives))
  862. {
  863. new iMaxEntities = GetMaxEntities(), String:eName[64];
  864. for (new i=MaxClients;i<iMaxEntities;i++)
  865. {
  866. if (IsValidEdict(i)
  867. && IsValidEntity(i)
  868. && GetEdictClassname(i, eName, sizeof(eName)))
  869. {
  870. // remove bombzones and hostages so no normal gameplay could end the round
  871. if(StrContains(eName, "hostage_entity") != -1
  872. || StrContains(eName, "func_bomb_target") != -1
  873. || StrContains(eName, "func_hostage_rescue") != -1)
  874. {
  875. AcceptEntityInput(i, "Kill");
  876. }
  877. }
  878. }
  879. }
  880.  
  881. // Remove all old flags first
  882. RemoveLeftFlags();
  883.  
  884. // Spawn all flags
  885. new iSize = GetArraySize(g_hFlags);
  886.  
  887. // Don't do anything, if no flags for that map -> "disabled"
  888. if(iSize == 0)
  889. return Plugin_Continue;
  890.  
  891. for(new i=0;i<iSize;i++)
  892. {
  893. SpawnFlag(i);
  894. }
  895.  
  896. // Clear the overlay
  897. if(!g_bIsCSGO && GetConVarBool(g_hCVShowWinOverlays))
  898. {
  899. Client_SetScreenOverlayForAll("");
  900. }
  901.  
  902. if(g_hStartSound != INVALID_HANDLE)
  903. {
  904. KillTimer(g_hStartSound);
  905. g_hStartSound = INVALID_HANDLE;
  906. }
  907.  
  908. // Only play the sound, if the admin has set a valid file
  909. // CS:GO doesn't support ambient sounds yet..
  910. // TODO: This needs fixing all over. Players joining after the round started don't hear the sound.
  911. if(!g_bIsCSGO && strlen(g_sSoundFiles[CSOUND_FLAG_AMBIENCE]) == 0)
  912. g_hStartSound = CreateTimer(3.0, Timer_OnStartSound, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
  913.  
  914. if(strlen(g_sSoundFiles[CSOUND_ROUNDSTART]) > 0)
  915. MyEmitSoundToAll(g_sSoundFiles[CSOUND_ROUNDSTART]);
  916.  
  917. if(g_hRemoveWeapons != INVALID_HANDLE)
  918. {
  919. KillTimer(g_hRemoveWeapons);
  920. g_hRemoveWeapons = INVALID_HANDLE;
  921. }
  922.  
  923. new Float:fRemoveInterval = GetConVarFloat(g_hCVRemoveDroppedWeapons);
  924. if(fRemoveInterval > 0.0)
  925. {
  926. g_hRemoveWeapons = CreateTimer(fRemoveInterval, Timer_OnRemoveWeapons, _, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT);
  927. }
  928.  
  929. return Plugin_Continue;
  930. }
  931.  
  932. public Action:Event_OnRoundEnd(Handle:event, const String:name[], bool:dontBroadcast)
  933. {
  934. g_bRoundEnded = true;
  935.  
  936. if(g_hStartSound != INVALID_HANDLE)
  937. {
  938. KillTimer(g_hStartSound);
  939. g_hStartSound = INVALID_HANDLE;
  940. }
  941.  
  942. if(g_hRemoveWeapons != INVALID_HANDLE)
  943. {
  944. KillTimer(g_hRemoveWeapons);
  945. g_hRemoveWeapons = INVALID_HANDLE;
  946. }
  947.  
  948. // Don't do anything, if no flags for that map -> "disabled"
  949. if(GetArraySize(g_hFlags) == 0)
  950. return Plugin_Continue;
  951.  
  952. // Stop the default round end radio sound
  953. for (new i = 1; i <= MaxClients; i++)
  954. {
  955. if (IsClientInGame(i) && !IsFakeClient(i))
  956. {
  957. StopSound(i, SNDCHAN_STATIC, "radio/ctwin.wav");
  958. StopSound(i, SNDCHAN_STATIC, "radio/terwin.wav");
  959. }
  960. }
  961.  
  962. return Plugin_Continue;
  963. }
  964.  
  965. /**
  966. * SDKHook Callbacks
  967. */
  968.  
  969. public OnEntityCreated(entity, const String:classname[])
  970. {
  971. // Remove the bomb
  972. if(StrEqual(classname, "weapon_c4", false) && GetConVarBool(g_hCVRemoveObjectives) && GetArraySize(g_hFlags) > 0)
  973. AcceptEntityInput(entity, "Kill");
  974. }
  975.  
  976. public Action:CS_OnCSWeaponDrop(client, weapon)
  977. {
  978. // Don't do anything, if no flags for that map -> "disabled" or no weapon dropped
  979. if(!GetConVarBool(g_hCVPreventWeaponDrop) || GetArraySize(g_hFlags) == 0 || weapon == -1)
  980. return Plugin_Continue;
  981.  
  982. // Primary or secondary weapon? Don't drop.
  983. if(IsClientInGame(client) && (Client_GetWeaponBySlot(client, CS_SLOT_PRIMARY) == weapon || Client_GetWeaponBySlot(client, CS_SLOT_SECONDARY) == weapon))
  984. {
  985. // Player buys a new weapon through the buymenu. delete the old.
  986. if(g_bPlayerIsBuying[client])
  987. {
  988. RemovePlayerItem(client, weapon);
  989. AcceptEntityInput(weapon, "Kill");
  990. return Plugin_Continue;
  991. }
  992.  
  993. return Plugin_Handled;
  994. }
  995.  
  996. // Drop grenades.
  997. // Need to do that, since we actually "drop" the grenade, when throwing it.
  998. // If we "block" it here, it still get's thrown, but the player don't change to his previous weapon, but stays empty-handed :O
  999. // We can remove them later on, with our OnRemoveWeapons timer
  1000. return Plugin_Continue;
  1001. }
  1002.  
  1003. // Keep track of which weapon the player is holding for dropping the correct ammo on death.
  1004. public Action:Hook_OnWeaponSwitch(client, weapon)
  1005. {
  1006. // Don't do anything, if no flags for that map -> "disabled"
  1007. if(GetArraySize(g_hFlags) == 0)
  1008. return Plugin_Continue;
  1009.  
  1010. // If that player isn't ingame anymore, stop
  1011. if(!IsClientInGame(client))
  1012. return Plugin_Continue;
  1013.  
  1014. if(Client_GetWeaponBySlot(client, CS_SLOT_PRIMARY) == weapon)
  1015. g_iPlayerActiveSlot[client] = CS_SLOT_PRIMARY;
  1016. else if(Client_GetWeaponBySlot(client, CS_SLOT_SECONDARY) == weapon)
  1017. g_iPlayerActiveSlot[client] = CS_SLOT_SECONDARY;
  1018. else
  1019. g_iPlayerActiveSlot[client] = -1;
  1020.  
  1021. return Plugin_Continue;
  1022. }
  1023.  
  1024. public bool:TraceRayNoPlayers(entity, mask, any:data)
  1025. {
  1026. if(entity == data || entity >= 1 || entity <= MaxClients)
  1027. {
  1028. return false;
  1029. }
  1030. return true;
  1031. }
  1032.  
  1033. public Hook_OnStartTouchAmmo(entity, other)
  1034. {
  1035. if(other < 1 || other > MaxClients || !IsPlayerAlive(other))
  1036. {
  1037. return;
  1038. }
  1039.  
  1040. // Get ammo type
  1041. decl String:sTargetName[64];
  1042. GetEntPropString(entity, Prop_Data, "m_iName", sTargetName, sizeof(sTargetName));
  1043. ReplaceString(sTargetName, sizeof(sTargetName), "scq_ammo_", "");
  1044. new iWeaponType = StringToInt(sTargetName);
  1045.  
  1046. // Primary ammo
  1047. if(iWeaponType == 0)
  1048. {
  1049. new iWeapon = Client_GetWeaponBySlot(other, CS_SLOT_PRIMARY);
  1050. if(iWeapon != INVALID_ENT_REFERENCE)
  1051. {
  1052. decl String:sWeapon[64];
  1053. new iPrimaryAmmo, iSecondaryAmmo = -1;
  1054. GetEdictClassname(iWeapon, sWeapon, sizeof(sWeapon));
  1055. Client_GetWeaponPlayerAmmo(other, sWeapon, iPrimaryAmmo, iSecondaryAmmo);
  1056. Client_SetWeaponPlayerAmmoEx(other, iWeapon, iPrimaryAmmo+GetConVarInt(g_hCVPrimaryAmmoAmount));
  1057. AcceptEntityInput(entity, "Kill");
  1058. EmitSoundToAll(AMMO_SOUND, other, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
  1059. }
  1060. }
  1061. else if(iWeaponType == 1)
  1062. {
  1063. new iWeapon = Client_GetWeaponBySlot(other, CS_SLOT_SECONDARY);
  1064. if(iWeapon != INVALID_ENT_REFERENCE)
  1065. {
  1066. decl String:sWeapon[64];
  1067. new iPrimaryAmmo, iSecondaryAmmo = -1;
  1068. GetEdictClassname(iWeapon, sWeapon, sizeof(sWeapon));
  1069. Client_GetWeaponPlayerAmmo(other, sWeapon, iPrimaryAmmo, iSecondaryAmmo);
  1070. Client_SetWeaponPlayerAmmoEx(other, iWeapon, iPrimaryAmmo+GetConVarInt(g_hCVSecondaryAmmoAmount));
  1071. AcceptEntityInput(entity, "Kill");
  1072. EmitSoundToAll(AMMO_SOUND, other);
  1073. }
  1074. }
  1075. }
  1076.  
  1077. public Hook_OnPostThinkPost(entity)
  1078. {
  1079. // Don't do anything, if no flags for that map -> "disabled"
  1080. if(GetArraySize(g_hFlags) == 0)
  1081. return;
  1082.  
  1083. // Simulate not being in buyzone, but keep the information for our own buymenu
  1084. new bool:bInBuyZone = GetEntProp(entity, Prop_Send, "m_bInBuyZone") == 1;
  1085. if(bInBuyZone)
  1086. {
  1087. if(GetConVarBool(g_hCVDisableBuyzones))
  1088. SetEntProp(entity, Prop_Send, "m_bInBuyZone", 0);
  1089. }
  1090.  
  1091. if(!g_bPlayerInBuyZone[entity] && bInBuyZone)
  1092. {
  1093. g_bPlayerInBuyZone[entity] = true;
  1094.  
  1095. }
  1096. else if(g_bPlayerInBuyZone[entity] && !bInBuyZone)
  1097. {
  1098. g_bPlayerInBuyZone[entity] = false;
  1099. }
  1100.  
  1101. // show the progressbar for spectating clients either
  1102. if(!IsPlayerAlive(entity) || IsClientObserver(entity))
  1103. {
  1104. // Only show the bar, when spectating a player directly
  1105. new Obs_Mode:iObsMode = Client_GetObserverMode(entity);
  1106. if(iObsMode == OBS_MODE_IN_EYE || iObsMode == OBS_MODE_CHASE)
  1107. {
  1108. new iObsTarget = Client_GetObserverTarget(entity);
  1109. if(iObsTarget != -1)
  1110. {
  1111. // Is this player currently conquering a flag?
  1112. new iSize = GetArraySize(g_hPlayersInZone), iNumPlayers, Handle:hPlayers, Handle:hFlag;
  1113. new iConquerStartTime, iTime, iClient;
  1114. for(new i=0;i<iSize;i++)
  1115. {
  1116. // Is this flag currently being conquered by someone?
  1117. hFlag = GetArrayCell(g_hFlags, i);
  1118. iConquerStartTime = GetArrayCell(hFlag, FLAG_CONQUERSTARTTIME);
  1119. if(iConquerStartTime != -1)
  1120. {
  1121. hPlayers = GetArrayCell(g_hPlayersInZone, i);
  1122. iNumPlayers = GetArraySize(hPlayers);
  1123. for(new x=0;x<iNumPlayers;x++)
  1124. {
  1125. iClient = GetArrayCell(hPlayers, x);
  1126. // We're spectaing a conqueror, show the bar either
  1127. if(iClient == iObsTarget)
  1128. {
  1129. iTime = GetArrayCell(hFlag, FLAG_TIME);
  1130. SetEntPropFloat(entity, Prop_Send, "m_flProgressBarStartTime", GetGameTime());
  1131. SetEntProp(entity, Prop_Send, "m_iProgressBarDuration", iTime - GetTime() + iConquerStartTime);
  1132. return;
  1133. }
  1134. }
  1135. }
  1136. }
  1137. }
  1138. }
  1139.  
  1140. SetEntPropFloat(entity, Prop_Send, "m_flProgressBarStartTime", 0.0);
  1141. SetEntProp(entity, Prop_Send, "m_iProgressBarDuration", 0);
  1142. }
  1143. }
  1144.  
  1145. /**
  1146. * Timer Callbacks
  1147. */
  1148.  
  1149. public Action:Timer_OnPlayerRespawnTick(Handle:timer, any:hDataPack)
  1150. {
  1151. new userid = ReadPackCell(hDataPack);
  1152. new client = GetClientOfUserId(userid);
  1153. if(g_bRoundEnded || !client || IsPlayerAlive(client) || GetClientTeam(client) < CS_TEAM_T)
  1154. {
  1155. g_hRespawnPlayer[client] = INVALID_HANDLE;
  1156. return Plugin_Stop;
  1157. }
  1158.  
  1159. new iPos = GetPackPosition(hDataPack);
  1160.  
  1161. new iSecondsLeft = ReadPackCell(hDataPack);
  1162.  
  1163. iSecondsLeft--;
  1164. SetPackPosition(hDataPack, iPos);
  1165. WritePackCell(hDataPack, iSecondsLeft);
  1166. ResetPack(hDataPack);
  1167.  
  1168. if(iSecondsLeft > 0)
  1169. {
  1170. Client_PrintKeyHintText(client, "%t", "Respawn in x seconds", iSecondsLeft);
  1171. }
  1172. else
  1173. {
  1174. g_hRespawnPlayer[client] = INVALID_HANDLE;
  1175. Client_PrintKeyHintText(client, "");
  1176. CS_RespawnPlayer(client);
  1177. return Plugin_Stop;
  1178. }
  1179.  
  1180. return Plugin_Continue;
  1181. }
  1182.  
  1183. public Action:Timer_OnDisableSpawnprotection(Handle:timer, any:userid)
  1184. {
  1185. new client = GetClientOfUserId(userid);
  1186. if(!client)
  1187. return Plugin_Stop;
  1188.  
  1189. g_hRemoveSpawnProtection[client] = INVALID_HANDLE;
  1190.  
  1191. SetEntProp(client, Prop_Data, "m_takedamage", 2);
  1192. SetEntityRenderMode(client, RENDER_NORMAL);
  1193. SetEntityRenderColor(client, 255, 255, 255, 255);
  1194.  
  1195. return Plugin_Stop;
  1196. }
  1197.  
  1198. public Action:Timer_OnStartSound(Handle:timer, any:data)
  1199. {
  1200. g_hStartSound = INVALID_HANDLE;
  1201.  
  1202. new iSize = GetArraySize(g_hFlags);
  1203. new Handle:hFlag, iFlag, Float:fPos[3];
  1204. for(new i=0;i<iSize;i++)
  1205. {
  1206. hFlag = GetArrayCell(g_hFlags, i);
  1207. iFlag = GetArrayCell(hFlag, FLAG_FLAGENTITY);
  1208. GetArrayArray(hFlag, FLAG_POSITION, fPos, 3);
  1209. fPos[2] += 30.0;
  1210. // TODO: Restart the sound everytime a player joins, so it's heared by everyone and not only those who were present on round start! AmbientSHook?
  1211. EmitAmbientSound(g_sSoundFiles[CSOUND_FLAG_AMBIENCE], fPos, iFlag);
  1212. }
  1213.  
  1214. return Plugin_Stop;
  1215. }
  1216.  
  1217. public Action:Timer_OnRemoveWeapons(Handle:timer, any:data)
  1218. {
  1219. if(GetConVarFloat(g_hCVRemoveDroppedWeapons) == 0.0)
  1220. {
  1221. g_hRemoveWeapons = INVALID_HANDLE;
  1222. return Plugin_Stop;
  1223. }
  1224.  
  1225. new iMaxEntities = GetMaxEntities();
  1226. decl String:sClassName[64];
  1227. for(new i=MaxClients+1;i<iMaxEntities;i++)
  1228. {
  1229. if(IsValidEntity(i)
  1230. && IsValidEdict(i)
  1231. && GetEdictClassname(i, sClassName, sizeof(sClassName))
  1232. && StrContains(sClassName, "weapon_") == 0
  1233. && GetEntPropEnt(i, Prop_Send, "m_hOwner") == -1)
  1234. AcceptEntityInput(i, "Kill");
  1235. }
  1236. return Plugin_Continue;
  1237. }
  1238.  
  1239. // Force the timelimit set with mp_timelimit, even midround
  1240. public Action:Timer_CheckTimeLimit(Handle:timer, any:data)
  1241. {
  1242. if(g_iTimeLimit != 0 && (GetTime() - g_iMapStartTime) >= g_iTimeLimit)
  1243. {
  1244. new iGameEnd = FindEntityByClassname(-1, "game_end");
  1245. if (iGameEnd == -1 && (iGameEnd = CreateEntityByName("game_end")) == -1)
  1246. {
  1247. LogError("Unable to create entity \"game_end\"!");
  1248. }
  1249. else
  1250. {
  1251. g_hTimeLimitEnforcer = INVALID_HANDLE;
  1252. AcceptEntityInput(iGameEnd, "EndGame");
  1253. return Plugin_Stop;
  1254. }
  1255. }
  1256.  
  1257. return Plugin_Continue;
  1258. }
  1259.  
  1260. // Teach the players the available commands
  1261. public Action:Timer_OnAdvertCommands(Handle:timer, any:data)
  1262. {
  1263. if(!GetConVarBool(g_hCVAdvertiseCommands))
  1264. return Plugin_Stop;
  1265.  
  1266. if(data == 0 && GetConVarBool(g_hCVUseClasses))
  1267. {
  1268. CPrintToChatAll("%s%t", PREFIX, "Advert !class");
  1269. // Only advert for the !buy command, if it's enabled ofc :)
  1270. if(GetConVarBool(g_hCVUseBuymenu))
  1271. data = 1;
  1272. }
  1273. else if(data == 1 && GetConVarBool(g_hCVUseBuymenu))
  1274. {
  1275. if(GetConVarBool(g_hCVInBuyzone))
  1276. CPrintToChatAll("%s%t %t", PREFIX, "Advert !buy", "Advert !buy in buyzone");
  1277. else
  1278. CPrintToChatAll("%s%t", PREFIX, "Advert !buy");
  1279. data = 0;
  1280. }
  1281. // We don't use any of the commands, so stop the timer.
  1282. else
  1283. {
  1284. return Plugin_Stop;
  1285. }
  1286.  
  1287. // Reshow the other advert in 5 minutes
  1288. CreateTimer(300.0, Timer_OnAdvertCommands, data, TIMER_FLAG_NO_MAPCHANGE);
  1289.  
  1290. return Plugin_Stop;
  1291. }
  1292.  
  1293. /**
  1294. *
  1295. * ConVar Change Callbacks
  1296. */
  1297.  
  1298. public ConVar_TimeLimitChanged(Handle:convar, const String:oldValue[], const String:newValue[])
  1299. {
  1300. if(!StrEqual(oldValue, newValue))
  1301. {
  1302. g_iTimeLimit = StringToInt(newValue)*60;
  1303. }
  1304. }
  1305.  
  1306. /**
  1307. * Helper functions
  1308. */
  1309.  
  1310. bool:CreateAmmoPack(Float:fOrigin[3], Float:fAngle[3], bool:bPrimaryAmmo)
  1311. {
  1312. new iAmmo = CreateEntityByName("prop_physics");
  1313. if(iAmmo != -1)
  1314. {
  1315. // Don't rotate pitch and roll
  1316. fAngle[0] = 0.0;
  1317. fAngle[2] = 0.0;
  1318. TeleportEntity(iAmmo, fOrigin, fAngle, NULL_VECTOR);
  1319.  
  1320. decl String:sTargetName[64];
  1321. Format(sTargetName, sizeof(sTargetName), "scq_ammo_%d", (bPrimaryAmmo?0:1));
  1322. DispatchKeyValue(iAmmo, "targetname", sTargetName);
  1323.  
  1324. // Spawn big model
  1325. if(bPrimaryAmmo)
  1326. {
  1327. SetEntityModel(iAmmo, PRIMARYAMMO_MODEL);
  1328. }
  1329. else
  1330. {
  1331. SetEntityModel(iAmmo, SECONDARYAMMO_MODEL);
  1332. }
  1333.  
  1334. DispatchSpawn(iAmmo);
  1335. ActivateEntity(iAmmo);
  1336.  
  1337. SDKHook(iAmmo, SDKHook_StartTouch, Hook_OnStartTouchAmmo);
  1338.  
  1339. // Remove it after x seconds
  1340. // Thanks to FoxMulder for his Snippet
  1341. // http://forums.alliedmods.net/showthread.php?t=129135
  1342. new Float:fAmmoLifeTime = GetConVarFloat(g_hCVAmmoLifetime);
  1343. if(fAmmoLifeTime > 0.0)
  1344. {
  1345. Format(sTargetName, sizeof(sTargetName), "OnUser1 !self:kill::%f:1", fAmmoLifeTime);
  1346. SetVariantString(sTargetName);
  1347. AcceptEntityInput(iAmmo, "AddOutput");
  1348. AcceptEntityInput(iAmmo, "FireUser1");
  1349. }
  1350. return true;
  1351. }
  1352.  
  1353. return false;
  1354. }
  1355.  
  1356. /**
  1357. * Helper functions
  1358. */
  1359.  
  1360. public Action:Command_SpawnAmmoPack(client, args)
  1361. {
  1362. if(args == 0)
  1363. {
  1364. ReplyToCommand(client, "%sUsage: sm_spawnammo <p|s>", PREFIX);
  1365. return Plugin_Handled;
  1366. }
  1367.  
  1368. decl String:sAmmoType[5];
  1369. GetCmdArgString(sAmmoType, sizeof(sAmmoType));
  1370. StripQuotes(sAmmoType);
  1371.  
  1372. new bool:bPrimaryAmmo;
  1373. if(StrEqual(sAmmoType, "p", false))
  1374. bPrimaryAmmo = true;
  1375. else if(StrEqual(sAmmoType, "s", false))
  1376. bPrimaryAmmo = false;
  1377. else
  1378. {
  1379. ReplyToCommand(client, "%sUsage: sm_spawnammo <p|s>", PREFIX);
  1380. return Plugin_Handled;
  1381. }
  1382.  
  1383. new Float:fOrigin[3], Float:fAngle[3], Float:fEnd[3];
  1384. GetClientEyePosition(client, fOrigin);
  1385. GetClientEyeAngles(client, fAngle);
  1386.  
  1387. // convert degrees to radians
  1388. fAngle[0] = DegToRad(fAngle[0]);
  1389. fAngle[1] = DegToRad(fAngle[1]);
  1390.  
  1391. // calculate entity destination after creation (raw number is an offset distance)
  1392. fEnd[0] = fOrigin[0] + 164 * Cosine(fAngle[0]) * Cosine(fAngle[1]);
  1393. fEnd[1] = fOrigin[1] + 164 * Cosine(fAngle[0]) * Sine(fAngle[1]);
  1394. fEnd[2] = fOrigin[2] - 50 * Sine(fAngle[0]);
  1395.  
  1396.  
  1397. TR_TraceRayFilter(fOrigin, fEnd, MASK_PLAYERSOLID, RayType_EndPoint, TraceRayNoPlayers, client);
  1398. if(TR_DidHit())
  1399. TR_GetEndPosition(fEnd);
  1400.  
  1401. CreateAmmoPack(fEnd, fAngle, bPrimaryAmmo);
  1402. return Plugin_Handled;
  1403. }
  1404.  
  1405. // Stock by psychonic
  1406. // http://forums.alliedmods.net/showpost.php?p=1294224&postcount=2
  1407. stock MyAddServerTag(const String:tag[])
  1408. {
  1409. decl String:currtags[128];
  1410. if (g_hSVTags == INVALID_HANDLE)
  1411. {
  1412. return;
  1413. }
  1414.  
  1415. GetConVarString(g_hSVTags, currtags, sizeof(currtags));
  1416. if (StrContains(currtags, tag) > -1)
  1417. {
  1418. // already have tag
  1419. return;
  1420. }
  1421.  
  1422. decl String:newtags[128];
  1423. Format(newtags, sizeof(newtags), "%s%s%s", currtags, (currtags[0]!=0)?",":"", tag);
  1424. new flags = GetConVarFlags(g_hSVTags);
  1425. SetConVarFlags(g_hSVTags, flags & ~FCVAR_NOTIFY);
  1426. SetConVarString(g_hSVTags, newtags);
  1427. SetConVarFlags(g_hSVTags, flags);
  1428. }
  1429.  
  1430. stock MyRemoveServerTag(const String:tag[])
  1431. {
  1432. decl String:newtags[128];
  1433. if (g_hSVTags == INVALID_HANDLE)
  1434. {
  1435. return;
  1436. }
  1437.  
  1438. GetConVarString(g_hSVTags, newtags, sizeof(newtags));
  1439. if (StrContains(newtags, tag) == -1)
  1440. {
  1441. // tag isn't on here, just bug out
  1442. return;
  1443. }
  1444.  
  1445. ReplaceString(newtags, sizeof(newtags), tag, "");
  1446. ReplaceString(newtags, sizeof(newtags), ",,", "");
  1447. new flags = GetConVarFlags(g_hSVTags);
  1448. SetConVarFlags(g_hSVTags, flags & ~FCVAR_NOTIFY);
  1449. SetConVarString(g_hSVTags, newtags);
  1450. SetConVarFlags(g_hSVTags, flags);
  1451. }
  1452.  
  1453. // Use ClientCommand("play.. for CS:GO
  1454. stock MyEmitSoundToAll(const String:sample[],
  1455. entity = SOUND_FROM_PLAYER,
  1456. channel = SNDCHAN_AUTO,
  1457. level = SNDLEVEL_NORMAL,
  1458. flags = SND_NOFLAGS,
  1459. Float:volume = SNDVOL_NORMAL,
  1460. pitch = SNDPITCH_NORMAL,
  1461. speakerentity = -1,
  1462. const Float:origin[3] = NULL_VECTOR,
  1463. const Float:dir[3] = NULL_VECTOR,
  1464. bool:updatePos = true,
  1465. Float:soundtime = 0.0)
  1466. {
  1467. if(g_bIsCSGO)
  1468. {
  1469. for(new i=1;i<=MaxClients;i++)
  1470. {
  1471. // Only play sounds to people who want to hear it.
  1472. if(IsClientInGame(i) && !IsFakeClient(i) && g_bPlaySounds[i])
  1473. // https://forums.alliedmods.net/showthread.php?p=1791668#post1791668
  1474. ClientCommand(i, "play */%s", sample); // The asterisk marks the file to be streamed, just as is automatically done with music, rather than looking it up from the audio cache.
  1475. }
  1476. }
  1477. else
  1478. {
  1479. new clients[MaxClients+1];
  1480. new numClients;
  1481. for(new i=1;i<=MaxClients;i++)
  1482. {
  1483. if(IsClientInGame(i) && !IsFakeClient(i) && g_bPlaySounds[i])
  1484. clients[numClients++] = i;
  1485. }
  1486. if(numClients > 0)
  1487. EmitSound(clients, numClients, sample, entity, channel, level, flags, volume, pitch, speakerentity, origin, dir, updatePos, soundtime);
  1488. }
  1489. }
  1490.  
  1491. stock GetTeamClientCountCheckBots(index)
  1492. {
  1493. if(GetConVarBool(g_hCVHandicapCountBots))
  1494. {
  1495. return GetTeamClientCount(index);
  1496. }
  1497. else
  1498. {
  1499. return Team_GetClientCount(index, CLIENTFILTER_NOBOTS);
  1500. }
  1501. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement