Advertisement
Zonas

Untitled

Jul 25th, 2019
452
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 115.17 KB | None | 0 0
  1. // *********************************************************************************
  2. // PREPROCESSOR
  3. // *********************************************************************************
  4. #pragma semicolon 1 // Force strict semicolon mode.
  5.  
  6. // *********************************************************************************
  7. // INCLUDES
  8. // *********************************************************************************
  9. #include <sourcemod>
  10. #include <sdktools>
  11. #include <sdkhooks>
  12. #include <tf2>
  13. #include <tf2_stocks>
  14. #include <tf2attributes>
  15. #include <morecolors>
  16.  
  17. #pragma newdecls required
  18.  
  19. // *********************************************************************************
  20. // CONSTANTS
  21. // *********************************************************************************
  22. // ---- Plugin-related constants ---------------------------------------------------
  23. #define PLUGIN_NAME "[TF2] Yet Another Dodgeball Plugin"
  24. #define PLUGIN_AUTHOR "Damizean, Edited by blood and soul"
  25. #define PLUGIN_VERSION "1.4.2"
  26. #define PLUGIN_CONTACT "https://savita-gaming.com"
  27.  
  28. // ---- General settings -----------------------------------------------------------
  29. #define FPS_LOGIC_RATE 20.0
  30. #define FPS_LOGIC_INTERVAL 1.0 / FPS_LOGIC_RATE
  31.  
  32. // ---- Maximum structure sizes ----------------------------------------------------
  33. #define MAX_ROCKETS 100
  34. #define MAX_ROCKET_CLASSES 50
  35. #define MAX_SPAWNER_CLASSES 50
  36. #define MAX_SPAWN_POINTS 100
  37.  
  38. // ---- PyroVision Stuff -----------------------------------------------------------
  39. #define PYROVISION_ATTRIBUTE "vision opt in flags"
  40.  
  41. #define USAGE "Usage: sm_ab [0/1]"
  42. int abPrevention[MAXPLAYERS + 1];
  43. int firstJoined[MAXPLAYERS + 1];
  44.  
  45. // ---- Asherkin's RocketBounce Stuff ----------------------------------------------
  46. #define MAX_EDICT_BITS 11
  47. #define MAX_EDICTS (1 << MAX_EDICT_BITS)
  48.  
  49. int g_nBounces[MAX_EDICTS];
  50.  
  51. Handle g_hMaxBouncesConVar;
  52. int g_config_iMaxBounces = 2;
  53.  
  54. // ---- Airblast -------------------------------------------------------------------
  55. bool Airblast[MAXPLAYERS + 1] = { true, ... };
  56.  
  57. // Particlessss
  58. //int g_RocketParticle[MAXPLAYERS + 1];
  59.  
  60. // ---- Flags and types constants --------------------------------------------------
  61. enum Musics
  62. {
  63. Music_RoundStart,
  64. Music_RoundWin,
  65. Music_RoundLose,
  66. Music_Gameplay,
  67. SizeOfMusicsArray
  68. };
  69.  
  70. enum BehaviourTypes
  71. {
  72. Behaviour_Unknown,
  73. Behaviour_Homing
  74. };
  75.  
  76. enum RocketFlags
  77. {
  78. RocketFlag_None = 0,
  79. RocketFlag_PlaySpawnSound = 1 << 0,
  80. RocketFlag_PlayBeepSound = 1 << 1,
  81. RocketFlag_PlayAlertSound = 1 << 2,
  82. RocketFlag_ElevateOnDeflect = 1 << 3,
  83. RocketFlag_IsNeutral = 1 << 4,
  84. RocketFlag_Exploded = 1 << 5,
  85. RocketFlag_OnSpawnCmd = 1 << 6,
  86. RocketFlag_OnDeflectCmd = 1 << 7,
  87. RocketFlag_OnKillCmd = 1 << 8,
  88. RocketFlag_OnExplodeCmd = 1 << 9,
  89. RocketFlag_CustomModel = 1 << 10,
  90. RocketFlag_CustomSpawnSound = 1 << 11,
  91. RocketFlag_CustomBeepSound = 1 << 12,
  92. RocketFlag_CustomAlertSound = 1 << 13,
  93. RocketFlag_Elevating = 1 << 14,
  94. RocketFlag_IsAnimated = 1 << 15
  95. };
  96.  
  97. enum RocketSound
  98. {
  99. RocketSound_Spawn,
  100. RocketSound_Beep,
  101. RocketSound_Alert
  102. };
  103.  
  104. enum SpawnerFlags
  105. {
  106. SpawnerFlag_Team_Red = 1,
  107. SpawnerFlag_Team_Blu = 2,
  108. SpawnerFlag_Team_Both = 3
  109. };
  110.  
  111. #define TestFlags(%1,%2) (!!((%1) & (%2)))
  112. #define TestFlagsAnd(%1,%2) (((%1) & (%2)) == %2)
  113.  
  114. // ---- Other resources ------------------------------------------------------------
  115. #define SOUND_DEFAULT_SPAWN "weapons/sentry_rocket.wav"
  116. #define SOUND_DEFAULT_BEEP "weapons/sentry_scan.wav"
  117. #define SOUND_DEFAULT_ALERT "weapons/sentry_spot.wav"
  118. #define SOUND_DEFAULT_SPEEDUPALERT "misc/doomsday_lift_warning.wav"
  119. #define SNDCHAN_MUSIC 32
  120. #define PARTICLE_NUKE_1 "fireSmokeExplosion"
  121. #define PARTICLE_NUKE_2 "fireSmokeExplosion1"
  122. #define PARTICLE_NUKE_3 "fireSmokeExplosion2"
  123. #define PARTICLE_NUKE_4 "fireSmokeExplosion3"
  124. #define PARTICLE_NUKE_5 "fireSmokeExplosion4"
  125. #define PARTICLE_NUKE_COLLUMN "fireSmoke_collumnP"
  126. #define PARTICLE_NUKE_1_ANGLES view_as<float> ({270.0, 0.0, 0.0})
  127. #define PARTICLE_NUKE_2_ANGLES PARTICLE_NUKE_1_ANGLES
  128. #define PARTICLE_NUKE_3_ANGLES PARTICLE_NUKE_1_ANGLES
  129. #define PARTICLE_NUKE_4_ANGLES PARTICLE_NUKE_1_ANGLES
  130. #define PARTICLE_NUKE_5_ANGLES PARTICLE_NUKE_1_ANGLES
  131. #define PARTICLE_NUKE_COLLUMN_ANGLES PARTICLE_NUKE_1_ANGLES
  132.  
  133. // Debug
  134. //#define DEBUG
  135.  
  136. // *********************************************************************************
  137. // VARIABLES
  138. // *********************************************************************************
  139.  
  140. // -----<<< Cvars >>>-----
  141. Handle g_hCvarEnabled;
  142. Handle g_hCvarEnableCfgFile;
  143. Handle g_hCvarDisableCfgFile;
  144. Handle g_hCvarSpeedo;
  145. Handle g_hCvarAnnounce;
  146. Handle g_hCvarPyroVisionEnabled = INVALID_HANDLE;
  147. Handle g_hCvarAirBlastCommandEnabled;
  148. Handle g_hCvarDeflectCountAnnounce;
  149. Handle g_hCvarRedirectBeep;
  150. Handle g_hCvarPreventTauntKillEnabled;
  151. Handle g_hCvarStealPrevention;
  152. Handle g_hCvarStealPreventionNumber;
  153. Handle g_hCvarDelayPrevention;
  154. Handle g_hCvarDelayPreventionTime;
  155. Handle g_hCvarDelayPreventionSpeedup;
  156. Handle g_hCvarVoteRocketClassCommandEnabled;
  157. Handle g_hCvarVoteClassPercentage;
  158. Handle g_hCvarVoteClassCooldown;
  159. Handle g_hCvarServerChatTag;
  160. Handle g_hCvarMainChatColor;
  161. Handle g_hCvarKeywordChatColor;
  162.  
  163. // -----<<< Gameplay >>>-----
  164. //int g_stolen[MAXPLAYERS + 1];
  165. bool g_bEnabled; // Is the plugin enabled?
  166. bool g_bRoundStarted; // Has the round started?
  167. int g_iRoundCount; // Current round count since map start
  168. int g_iRocketsFired; // No. of rockets fired since round start
  169. Handle g_hLogicTimer; // Logic timer
  170. float g_fLastSpawnTime; // Time at which the last rocket had spawned
  171. float g_fNextSpawnTime; // Time at which the next rocket will be able to spawn
  172. int g_iLastDeadTeam; // The team of the last dead client. If none, it's a random team.
  173. int g_iLastDeadClient; // The last dead client. If none, it's a random client.
  174. int g_iPlayerCount;
  175. Handle g_hHud;
  176. int g_iRocketSpeed;
  177. Handle g_hTimerHud;
  178.  
  179. enum eRocketSteal
  180. {
  181. stoleRocket = false,
  182. rocketsStolen
  183. };
  184.  
  185. int bStealArray[MAXPLAYERS + 1][eRocketSteal];
  186.  
  187. // -----<<< Configuration >>>-----
  188. bool g_bMusicEnabled;
  189. bool g_bMusic[view_as<int>(SizeOfMusicsArray)];
  190. char g_strMusic[view_as<int>(SizeOfMusicsArray)][PLATFORM_MAX_PATH];
  191. bool g_bUseWebPlayer;
  192. char g_strWebPlayerUrl[256];
  193. char g_strServerChatTag[256];
  194. char g_strMainChatColor[256];
  195. char g_strKeywordChatColor[256];
  196.  
  197. // -----<<< Structures >>>-----
  198. // Rockets
  199. bool g_bRocketIsValid[MAX_ROCKETS];
  200. bool g_bRocketIsNuke[MAX_ROCKETS];
  201. bool g_bPreventingDelay;
  202. int g_iRocketEntity[MAX_ROCKETS];
  203. int g_iRocketTarget[MAX_ROCKETS];
  204. int g_iRocketSpawner[MAX_ROCKETS];
  205. int g_iRocketClass[MAX_ROCKETS];
  206. RocketFlags g_iRocketFlags[MAX_ROCKETS];
  207. float g_fRocketSpeed[MAX_ROCKETS];
  208. float g_fRocketDirection[MAX_ROCKETS][3];
  209. int g_iRocketDeflections[MAX_ROCKETS];
  210. float g_fRocketLastDeflectionTime[MAX_ROCKETS];
  211. float g_fRocketLastBeepTime[MAX_ROCKETS];
  212. int g_iLastCreatedRocket;
  213. int g_iRocketCount;
  214. float g_fSavedSpeed;
  215. float g_fSavedSpeedIncrement;
  216.  
  217. // Classes
  218. char g_strRocketClassName[MAX_ROCKET_CLASSES][16];
  219. char g_strRocketClassLongName[MAX_ROCKET_CLASSES][32];
  220. char g_strSavedClassName[32];
  221. BehaviourTypes g_iRocketClassBehaviour[MAX_ROCKET_CLASSES];
  222. char g_strRocketClassModel[MAX_ROCKET_CLASSES][PLATFORM_MAX_PATH];
  223. RocketFlags g_iRocketClassFlags[MAX_ROCKET_CLASSES];
  224. float g_fRocketClassBeepInterval[MAX_ROCKET_CLASSES];
  225. char g_strRocketClassSpawnSound[MAX_ROCKET_CLASSES][PLATFORM_MAX_PATH];
  226. char g_strRocketClassBeepSound[MAX_ROCKET_CLASSES][PLATFORM_MAX_PATH];
  227. char g_strRocketClassAlertSound[MAX_ROCKET_CLASSES][PLATFORM_MAX_PATH];
  228. float g_fRocketClassCritChance[MAX_ROCKET_CLASSES];
  229. float g_fRocketClassDamage[MAX_ROCKET_CLASSES];
  230. float g_fRocketClassDamageIncrement[MAX_ROCKET_CLASSES];
  231. float g_fRocketClassSpeed[MAX_ROCKET_CLASSES];
  232. float g_fRocketClassSpeedIncrement[MAX_ROCKET_CLASSES];
  233. float g_fRocketClassTurnRate[MAX_ROCKET_CLASSES];
  234. float g_fRocketClassTurnRateIncrement[MAX_ROCKET_CLASSES];
  235. float g_fRocketClassElevationRate[MAX_ROCKET_CLASSES];
  236. float g_fRocketClassElevationLimit[MAX_ROCKET_CLASSES];
  237. float g_fRocketClassRocketsModifier[MAX_ROCKET_CLASSES];
  238. float g_fRocketClassPlayerModifier[MAX_ROCKET_CLASSES];
  239. float g_fRocketClassControlDelay[MAX_ROCKET_CLASSES];
  240. float g_fRocketClassTargetWeight[MAX_ROCKET_CLASSES];
  241. Handle g_hRocketClassCmdsOnSpawn[MAX_ROCKET_CLASSES];
  242. Handle g_hRocketClassCmdsOnDeflect[MAX_ROCKET_CLASSES];
  243. Handle g_hRocketClassCmdsOnKill[MAX_ROCKET_CLASSES];
  244. Handle g_hRocketClassCmdsOnExplode[MAX_ROCKET_CLASSES];
  245. Handle g_hRocketClassTrie;
  246. char g_iRocketClassCount;
  247.  
  248. // Spawner classes
  249. char g_strSpawnersName[MAX_SPAWNER_CLASSES][32];
  250. int g_iSpawnersMaxRockets[MAX_SPAWNER_CLASSES];
  251. float g_fSpawnersInterval[MAX_SPAWNER_CLASSES];
  252. Handle g_hSpawnersChancesTable[MAX_SPAWNER_CLASSES];
  253. Handle g_hSpawnersTrie;
  254. int g_iSpawnersCount;
  255.  
  256. // Array containing the spawn points for the Red team, and
  257. // their associated spawner class.
  258. int g_iCurrentRedSpawn;
  259. int g_iSpawnPointsRedCount;
  260. int g_iSpawnPointsRedClass[MAX_SPAWN_POINTS];
  261. int g_iSpawnPointsRedEntity[MAX_SPAWN_POINTS];
  262.  
  263. // Array containing the spawn points for the Blu team, and
  264. // their associated spawner class.
  265. int g_iCurrentBluSpawn;
  266. int g_iSpawnPointsBluCount;
  267. int g_iSpawnPointsBluClass[MAX_SPAWN_POINTS];
  268. int g_iSpawnPointsBluEntity[MAX_SPAWN_POINTS];
  269.  
  270. // The default spawner class.
  271. int g_iDefaultRedSpawner;
  272. int g_iDefaultBluSpawner;
  273.  
  274. //Observer
  275. int g_observer;
  276. int g_op_rocket;
  277.  
  278. //Voting
  279. bool g_bVoteClassEnabled; // check if players are allowed to vote for a rocket class change
  280. bool g_bCanVoteClass; // check if voting for rocket class is on cooldown
  281. bool g_bClassVoted[MAXPLAYERS + 1] = {false, ...}; // check which players have voted for a rocket class change
  282. int g_iClassVoters = 0; // maximum number of votes
  283. int g_iClassVotes = 0; // how many rocket class votes recieved
  284. int g_iClassVotesRequired; // how many rocket class votes are needed
  285. int g_iTimeVoted = 0;
  286.  
  287. // *********************************************************************************
  288. // PLUGIN
  289. // *********************************************************************************
  290. public Plugin myinfo =
  291. {
  292. name = PLUGIN_NAME,
  293. author = PLUGIN_AUTHOR,
  294. description = PLUGIN_NAME,
  295. version = PLUGIN_VERSION,
  296. url = PLUGIN_CONTACT
  297. };
  298.  
  299. // *********************************************************************************
  300. // METHODS
  301. // *********************************************************************************
  302.  
  303. /* OnPluginStart()
  304. **
  305. ** When the plugin is loaded.
  306. ** -------------------------------------------------------------------------- */
  307. public void OnPluginStart()
  308. {
  309. char strModName[32]; GetGameFolderName(strModName, sizeof(strModName));
  310. if (!StrEqual(strModName, "tf"))SetFailState("This plugin is only for Team Fortress 2.");
  311.  
  312. CreateConVar("tf_dodgeballupdated_version", PLUGIN_VERSION, PLUGIN_NAME, FCVAR_SPONLY | FCVAR_UNLOGGED | FCVAR_DONTRECORD | FCVAR_REPLICATED | FCVAR_NOTIFY);
  313. g_hCvarEnabled = CreateConVar("tf_dodgeball_enabled", "1", "Enable Dodgeball on TFDB maps?", _, true, 0.0, true, 1.0);
  314. g_hCvarEnableCfgFile = CreateConVar("tf_dodgeball_enablecfg", "sourcemod/dodgeball_enable.cfg", "Config file to execute when enabling the Dodgeball game mode.");
  315. g_hCvarDisableCfgFile = CreateConVar("tf_dodgeball_disablecfg", "sourcemod/dodgeball_disable.cfg", "Config file to execute when disabling the Dodgeball game mode.");
  316. g_hCvarSpeedo = CreateConVar("tf_dodgeball_speedo", "1", "Enable HUD speedometer");
  317. g_hCvarAnnounce = CreateConVar("tf_dodgeball_announce", "1", "Enable kill announces in chat");
  318. g_hCvarPyroVisionEnabled = CreateConVar("tf_dodgeball_pyrovision", "0", "Enable pyrovision for everyone");
  319. g_hMaxBouncesConVar = CreateConVar("tf_dodgeball_rbmax", "10000", "Max number of times a rocket will bounce.", FCVAR_NONE, true, 0.0, false);
  320. g_hCvarAirBlastCommandEnabled = CreateConVar("tf_dodgeball_airblast", "1", "Enable if airblast is enabled or not");
  321. g_hCvarDeflectCountAnnounce = CreateConVar("tf_dodgeball_count_deflect", "1", "Enable number of deflections in kill announce");
  322. g_hCvarRedirectBeep = CreateConVar("tf_dodgeball_rdrbeep", "1", "Do redirects beep?");
  323. g_hCvarPreventTauntKillEnabled = CreateConVar("tf_dodgeball_block_tauntkill", "0", "Block taunt kills?");
  324. g_hCvarStealPrevention = CreateConVar("tf_dodgeball_steal_prevention", "0", "Enable steal prevention?");
  325. g_hCvarStealPreventionNumber = CreateConVar("tf_dodgeball_sp_number", "3", "How many steals before you get slayed?");
  326. g_hCvarDelayPrevention = CreateConVar("tf_dodgeball_delay_prevention", "0", "Enable delay prevention?");
  327. g_hCvarDelayPreventionTime = CreateConVar("tf_dodgeball_dp_time", "5", "How much time (in seconds) before delay prevention activates?", FCVAR_NONE, true, 0.0, false);
  328. g_hCvarDelayPreventionSpeedup = CreateConVar("tf_dodgeball_dp_speedup", "100", "How much speed (in hammer units per second) should the rocket gain (20 Refresh Rate for every 0.1 seconds) for delay prevention? Multiply by (15/352) for mph.", FCVAR_NONE, true, 0.0, false);
  329. g_hCvarVoteRocketClassCommandEnabled = CreateConVar("tf_dodgeball_voteclass", "1", "Should voting for rocket class be enabled or not?");
  330. g_hCvarVoteClassPercentage = CreateConVar("tf_dodgeball_voteclass_percentage", "0.60", "Percentage of votes required to change rocket class.", FCVAR_NONE, true, 0.0, true, 1.0);
  331. g_hCvarVoteClassCooldown = CreateConVar("tf_dodgeball_voteclass_cooldown", "30", "Seconds before another vote for rocket class can be initated.", FCVAR_NONE, true, 0.0);
  332.  
  333. g_hCvarServerChatTag = CreateConVar("tf_dodgeball_servertag", "{DARKOLIVEGREEN}[TFDB]", "Tag that appears at the start of each chat announcement.");
  334. g_hCvarMainChatColor = CreateConVar("tf_dodgeball_maincolor", "{WHITE}", "Color assigned to the majority of the words in chat announcements.");
  335. g_hCvarKeywordChatColor = CreateConVar("tf_dodgeball_keywordcolor", "{DARKOLIVEGREEN}", "Color assigned to the most important words in chat announcements.");
  336.  
  337. // Commands
  338. RegConsoleCmd("sm_ab", Command_ToggleAirblast, USAGE);
  339. RegAdminCmd("sm_tfdb", Command_DodgeballAdminMenu, ADMFLAG_GENERIC, "A menu for admins to modify things inside the plugin.");
  340.  
  341. RegConsoleCmd("sm_currentrocket", Command_PostCurrentRocketClass, "Posts a chat message of the name of the current main rocket class.");
  342. RegConsoleCmd("sm_voterocket", Command_VoteRocketClass, "Vote to change the current rocket class.");
  343. RegConsoleCmd("sm_votespeed", Command_VoteRocketClass, "Vote to change the current rocket class.");
  344. RegConsoleCmd("sm_vr", Command_VoteRocketClass, "Vote to change the current rocket class.");
  345. RegConsoleCmd("sm_vrs", Command_VoteRocketClass, "Vote to change the current rocket class.");
  346.  
  347.  
  348. ServerCommand("tf_arena_use_queue 0");
  349.  
  350. HookConVarChange(g_hMaxBouncesConVar, tf2dodgeball_hooks);
  351. HookConVarChange(g_hCvarPyroVisionEnabled, tf2dodgeball_hooks);
  352. HookConVarChange(g_hCvarVoteRocketClassCommandEnabled, tf2dodgeball_hooks);
  353. HookConVarChange(g_hCvarVoteClassPercentage, tf2dodgeball_hooks);
  354. HookConVarChange(g_hCvarVoteClassCooldown, tf2dodgeball_hooks);
  355.  
  356. g_bVoteClassEnabled = GetConVarBool(g_hCvarVoteRocketClassCommandEnabled);
  357.  
  358. HookConVarChange(g_hCvarServerChatTag, tf2dodgeball_hooks);
  359. HookConVarChange(g_hCvarMainChatColor, tf2dodgeball_hooks);
  360. HookConVarChange(g_hCvarKeywordChatColor, tf2dodgeball_hooks);
  361.  
  362. GetConVarString(g_hCvarServerChatTag, g_strServerChatTag, sizeof(g_strServerChatTag));
  363. GetConVarString(g_hCvarMainChatColor, g_strMainChatColor, sizeof(g_strMainChatColor));
  364. GetConVarString(g_hCvarKeywordChatColor, g_strKeywordChatColor, sizeof(g_strKeywordChatColor));
  365.  
  366. g_hRocketClassTrie = CreateTrie();
  367. g_hSpawnersTrie = CreateTrie();
  368.  
  369. g_bCanVoteClass = true;
  370.  
  371. g_hHud = CreateHudSynchronizer();
  372.  
  373. AutoExecConfig(true, "tf2_dodgeball");
  374.  
  375. RegisterCommands();
  376. }
  377.  
  378. /* OnConfigsExecuted()
  379. **
  380. ** When all the configuration files have been executed, try to enable the
  381. ** Dodgeball.
  382. ** -------------------------------------------------------------------------- */
  383. public void OnConfigsExecuted()
  384. {
  385. if (GetConVarBool(g_hCvarEnabled) && IsDodgeBallMap())
  386. {
  387. EnableDodgeBall();
  388. }
  389. }
  390.  
  391. /* OnMapStart()
  392. **
  393. ** When the map starts, clear vote variables.
  394. ** -------------------------------------------------------------------------- */
  395.  
  396. public void OnMapStart()
  397. {
  398. g_iClassVoters = 0;
  399. g_iClassVotes = 0;
  400. g_iClassVotesRequired = 0;
  401. }
  402.  
  403. /* OnMapEnd()
  404. **
  405. ** When the map ends, disable DodgeBall.
  406. ** -------------------------------------------------------------------------- */
  407. public void OnMapEnd()
  408. {
  409. DisableDodgeBall();
  410.  
  411. g_bVoteClassEnabled = false;
  412. }
  413.  
  414. public Action Command_DodgeballAdminMenu(int client, int args)
  415. {
  416. Menu menu = new Menu(DodgeballAdmin_Handler, MENU_ACTIONS_ALL);
  417.  
  418. menu.SetTitle("Dodgeball Admin Menu");
  419.  
  420. menu.AddItem("0", "Max Rocket Count");
  421. menu.AddItem("1", "Speed Multiplier");
  422. menu.AddItem("2", "Main Rocket Class");
  423. menu.AddItem("3", "Refresh Configurations");
  424.  
  425. menu.ExitButton = true;
  426. menu.Display(client, MENU_TIME_FOREVER);
  427.  
  428. return Plugin_Handled;
  429. }
  430.  
  431. public int DodgeballAdmin_Handler(Menu menu, MenuAction action, int param1, int param2)
  432. {
  433. switch (action)
  434. {
  435. case MenuAction_Start:
  436. {
  437. // It's important to log anything in any way, the best is printtoserver, but if you just want to log to client to make it easier to get progress done, feel free.
  438. PrintToServer("Displaying menu"); // Log it
  439. }
  440.  
  441. case MenuAction_Display:
  442. {
  443. PrintToServer("Client %d was sent menu with panel %x", param1, param2); // Log so you can check if it gets sent.
  444. }
  445.  
  446. case MenuAction_Select:
  447. {
  448. char sInfo[32];
  449. menu.GetItem(param2, sInfo, sizeof(sInfo));
  450.  
  451. switch (param2)
  452. {
  453. case 0:
  454. {
  455. DrawMaxRocketCountMenu(param1);
  456. }
  457. case 1:
  458. {
  459. DrawRocketSpeedMenu(param1);
  460. }
  461. case 2:
  462. {
  463. if (!g_strSavedClassName[0]) {
  464. CPrintToChat(param1, "%s %sNo main rocket class detected, %saborting%s...", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor, g_strMainChatColor);
  465. return;
  466. }
  467. DrawRocketClassMenu(param1);
  468. }
  469. case 3:
  470. {
  471. // Clean up everything
  472. DestroyRocketClasses();
  473. DestroySpawners();
  474. // Then reinitialize
  475. char strMapName[64]; GetCurrentMap(strMapName, sizeof(strMapName));
  476. char strMapFile[PLATFORM_MAX_PATH]; Format(strMapFile, sizeof(strMapFile), "%s.cfg", strMapName);
  477. ParseConfigurations();
  478. ParseConfigurations(strMapFile);
  479. CPrintToChatAll("%s %s%N %srefreshed the %sdodgeball configs%s.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor, g_strMainChatColor);
  480. }
  481. }
  482. }
  483.  
  484. case MenuAction_Cancel:
  485. {
  486. PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); // Logging once again.
  487. }
  488.  
  489. case MenuAction_End:
  490. {
  491. delete menu;
  492. }
  493.  
  494. case MenuAction_DrawItem:
  495. {
  496. int style;
  497. char info[32];
  498. menu.GetItem(param2, info, sizeof(info), style);
  499. }
  500.  
  501. case MenuAction_DisplayItem:
  502. {
  503. char info[32];
  504. menu.GetItem(param2, info, sizeof(info));
  505. }
  506. }
  507. }
  508.  
  509. void DrawMaxRocketCountMenu(int client)
  510. {
  511. Menu menu = new Menu(DodgeballAdminRocketCount_Handler, MENU_ACTIONS_ALL);
  512.  
  513. menu.SetTitle("How many rockets?");
  514.  
  515. menu.AddItem("1", "One");
  516. menu.AddItem("2", "Two");
  517. menu.AddItem("3", "Three");
  518. menu.AddItem("4", "Four");
  519. menu.AddItem("5", "Five");
  520.  
  521. menu.ExitButton = true;
  522. menu.Display(client, MENU_TIME_FOREVER);
  523. }
  524.  
  525. void DrawRocketSpeedMenu(int client)
  526. {
  527. Menu menu = new Menu(DodgeballAdminRocketSpeed_Handler, MENU_ACTIONS_ALL);
  528.  
  529. menu.SetTitle("How fast should the rockets go?");
  530.  
  531. menu.AddItem("1", "25% (Slow)");
  532. menu.AddItem("2", "50% (Normal)");
  533. menu.AddItem("3", "75% (Fast)");
  534. menu.AddItem("4", "100% (Silly Fast)");
  535.  
  536. menu.ExitButton = true;
  537. menu.Display(client, MENU_TIME_FOREVER);
  538. }
  539.  
  540. void DrawRocketClassMenu(int client)
  541. {
  542. Menu menu = new Menu(DodgeballAdminRocketClass_Handler, MENU_ACTIONS_ALL);
  543.  
  544. menu.SetTitle("Which class should the rocket be set to?");
  545.  
  546. for (int currentClass = 0; currentClass < g_iRocketClassCount; currentClass++)
  547. {
  548. char classNumber[16];
  549. IntToString(currentClass, classNumber, sizeof(classNumber));
  550. if (StrEqual(g_strSavedClassName, g_strRocketClassLongName[currentClass]))
  551. {
  552. char currentClassName[32];
  553. strcopy(currentClassName, sizeof(currentClassName), "[Current] ");
  554. StrCat(currentClassName, sizeof(currentClassName), g_strSavedClassName);
  555. menu.AddItem(classNumber, currentClassName);
  556. }
  557. else menu.AddItem(classNumber, g_strRocketClassLongName[currentClass]);
  558. }
  559.  
  560. menu.ExitButton = true;
  561. menu.Display(client, MENU_TIME_FOREVER);
  562. }
  563.  
  564. public int DodgeballAdminRocketCount_Handler(Menu menu, MenuAction action, int param1, int param2)
  565. {
  566. switch (action)
  567. {
  568. case MenuAction_Start:
  569. {
  570. // It's important to log anything in any way, the best is printtoserver, but if you just want to log to client to make it easier to get progress done, feel free.
  571. PrintToServer("Displaying menu"); // Log it
  572. }
  573.  
  574. case MenuAction_Display:
  575. {
  576. PrintToServer("Client %d was sent menu with panel %x", param1, param2); // Log so you can check if it gets sent.
  577. }
  578.  
  579. case MenuAction_Select:
  580. {
  581. char sInfo[32];
  582. menu.GetItem(param2, sInfo, sizeof(sInfo));
  583.  
  584. switch (param2)
  585. {
  586. case 0:
  587. {
  588. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  589. g_iSpawnersMaxRockets[iSpawnerClassBlu] = 1;
  590.  
  591. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  592. g_iSpawnersMaxRockets[iSpawnerClassRed] = 1;
  593.  
  594. CPrintToChatAll("%s %s%N %schanged the max rockets to %s1.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  595. }
  596. case 1:
  597. {
  598. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  599. g_iSpawnersMaxRockets[iSpawnerClassBlu] = 2;
  600.  
  601. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  602. g_iSpawnersMaxRockets[iSpawnerClassRed] = 2;
  603.  
  604. CPrintToChatAll("%s %s%N %schanged the max rockets to %s2.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  605. }
  606. case 2:
  607. {
  608. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  609. g_iSpawnersMaxRockets[iSpawnerClassBlu] = 3;
  610.  
  611. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  612. g_iSpawnersMaxRockets[iSpawnerClassRed] = 3;
  613.  
  614. CPrintToChatAll("%s %s%N %schanged the max rockets to %s3.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  615. }
  616. case 3:
  617. {
  618. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  619. g_iSpawnersMaxRockets[iSpawnerClassBlu] = 4;
  620.  
  621. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  622. g_iSpawnersMaxRockets[iSpawnerClassRed] = 4;
  623.  
  624. CPrintToChatAll("%s %s%N %schanged the max rockets to %s4.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  625. }
  626. case 4:
  627. {
  628. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  629. g_iSpawnersMaxRockets[iSpawnerClassBlu] = 5;
  630.  
  631. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  632. g_iSpawnersMaxRockets[iSpawnerClassRed] = 5;
  633.  
  634. CPrintToChatAll("%s %s%N %schanged the max rockets to %s5.", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  635. }
  636. }
  637. }
  638.  
  639. case MenuAction_Cancel:
  640. {
  641. PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); // Logging once again.
  642. }
  643.  
  644. case MenuAction_End:
  645. {
  646. delete menu;
  647. }
  648.  
  649. case MenuAction_DrawItem:
  650. {
  651. int style;
  652. char info[32];
  653. menu.GetItem(param2, info, sizeof(info), style);
  654. }
  655.  
  656. case MenuAction_DisplayItem:
  657. {
  658. char info[32];
  659. menu.GetItem(param2, info, sizeof(info));
  660. }
  661. }
  662. }
  663.  
  664. public int DodgeballAdminRocketSpeed_Handler(Menu menu, MenuAction action, int param1, int param2)
  665. {
  666. switch (action)
  667. {
  668. case MenuAction_Start:
  669. {
  670. // It's important to log anything in any way, the best is printtoserver, but if you just want to log to client to make it easier to get progress done, feel free.
  671. PrintToServer("Displaying menu"); // Log it
  672. }
  673.  
  674. case MenuAction_Display:
  675. {
  676. PrintToServer("Client %d was sent menu with panel %x", param1, param2); // Log so you can check if it gets sent.
  677. }
  678.  
  679. case MenuAction_Select:
  680. {
  681. char sInfo[32];
  682. menu.GetItem(param2, sInfo, sizeof(sInfo));
  683. float kvSpeed = g_fSavedSpeed;
  684. float kvSpeedIncrement = g_fSavedSpeedIncrement;
  685.  
  686. switch (param2)
  687. {
  688. case 0:
  689. {
  690. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  691. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  692. int iClassRed = GetRandomRocketClass(iSpawnerClassRed);
  693. int iClassBlu = GetRandomRocketClass(iSpawnerClassBlu);
  694.  
  695. g_fRocketSpeed[iClassRed] = kvSpeed / 2;
  696. g_fRocketClassSpeedIncrement[iClassRed] = kvSpeedIncrement / 2;
  697.  
  698. g_fRocketSpeed[iClassBlu] = kvSpeed / 2;
  699. g_fRocketClassSpeedIncrement[iClassBlu] = kvSpeedIncrement / 2;
  700.  
  701. CPrintToChatAll("%s %s%N %schanged the rocket speed to %s25%% (Slow)", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  702. }
  703. case 1:
  704. {
  705. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  706. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  707. int iClassRed = GetRandomRocketClass(iSpawnerClassRed);
  708. int iClassBlu = GetRandomRocketClass(iSpawnerClassBlu);
  709.  
  710. g_fRocketSpeed[iClassRed] = kvSpeed;
  711. g_fRocketClassSpeedIncrement[iClassRed] = kvSpeedIncrement;
  712.  
  713. g_fRocketSpeed[iClassBlu] = kvSpeed;
  714. g_fRocketClassSpeedIncrement[iClassBlu] = kvSpeedIncrement;
  715.  
  716. CPrintToChatAll("%s %s%N %schanged the rocket speed to %s50%% (Normal)", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  717. }
  718. case 2:
  719. {
  720. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  721. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  722. int iClassRed = GetRandomRocketClass(iSpawnerClassRed);
  723. int iClassBlu = GetRandomRocketClass(iSpawnerClassBlu);
  724.  
  725. g_fRocketSpeed[iClassRed] = kvSpeed * 2;
  726. g_fRocketClassSpeedIncrement[iClassRed] = kvSpeedIncrement * 2;
  727.  
  728. g_fRocketSpeed[iClassBlu] = kvSpeed * 2;
  729. g_fRocketClassSpeedIncrement[iClassBlu] = kvSpeedIncrement * 2;
  730.  
  731. CPrintToChatAll("%s %s%N %schanged the rocket speed to %s75%% (Fast)", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  732. }
  733. case 3:
  734. {
  735. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  736. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  737. int iClassRed = GetRandomRocketClass(iSpawnerClassRed);
  738. int iClassBlu = GetRandomRocketClass(iSpawnerClassBlu);
  739.  
  740. g_fRocketSpeed[iClassRed] = kvSpeed * 3;
  741. g_fRocketClassSpeedIncrement[iClassRed] = kvSpeedIncrement * 3;
  742.  
  743. g_fRocketSpeed[iClassBlu] = kvSpeed * 3;
  744. g_fRocketClassSpeedIncrement[iClassBlu] = kvSpeedIncrement * 3;
  745.  
  746. CPrintToChatAll("%s %s%N %schanged the rocket speed to %s100%% (Silly Fast)", g_strServerChatTag, g_strKeywordChatColor, param1, g_strMainChatColor, g_strKeywordChatColor);
  747. }
  748. }
  749. }
  750.  
  751. case MenuAction_Cancel:
  752. {
  753. PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); // Logging once again.
  754. }
  755.  
  756. case MenuAction_End:
  757. {
  758. delete menu;
  759. }
  760.  
  761. case MenuAction_DrawItem:
  762. {
  763. int style;
  764. char info[32];
  765. menu.GetItem(param2, info, sizeof(info), style);
  766. }
  767.  
  768. case MenuAction_DisplayItem:
  769. {
  770. char info[32];
  771. menu.GetItem(param2, info, sizeof(info));
  772. }
  773. }
  774. }
  775.  
  776. public int DodgeballAdminRocketClass_Handler(Menu menu, MenuAction action, int param1, int param2)
  777. {
  778. switch (action)
  779. {
  780. case MenuAction_Start:
  781. {
  782. // It's important to log anything in any way, the best is printtoserver, but if you just want to log to client to make it easier to get progress done, feel free.
  783. PrintToServer("Displaying menu"); // Log it
  784. }
  785.  
  786. case MenuAction_Display:
  787. {
  788. PrintToServer("Client %d was sent menu with panel %x", param1, param2); // Log so you can check if it gets sent.
  789. }
  790.  
  791. case MenuAction_Select:
  792. {
  793. char sInfo[32];
  794. menu.GetItem(param2, sInfo, sizeof(sInfo));
  795.  
  796. SetMainRocketClass(param2, false, param1);
  797. }
  798.  
  799. case MenuAction_Cancel:
  800. {
  801. PrintToServer("Client %d's menu was cancelled for reason %d", param1, param2); // Logging once again.
  802. }
  803.  
  804. case MenuAction_End:
  805. {
  806. delete menu;
  807. }
  808.  
  809. case MenuAction_DrawItem:
  810. {
  811. int style;
  812. char info[32];
  813. menu.GetItem(param2, info, sizeof(info), style);
  814. }
  815.  
  816. case MenuAction_DisplayItem:
  817. {
  818. char info[32];
  819. menu.GetItem(param2, info, sizeof(info));
  820. }
  821. }
  822. }
  823.  
  824. //__ __ _
  825. //\ \ / /__| |_ ___ ___
  826. // \ V / _ \ _/ -_|_-<
  827. // \_/\___/\__\___/__/
  828.  
  829. public Action Command_VoteRocketClass(int client, int args) {
  830. if (!g_strSavedClassName[0])
  831. {
  832. g_bVoteClassEnabled = false;
  833. CPrintToChat(client, "%s %sNo main rocket class detected, voting for rocket class %sdisabled.", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  834. return Plugin_Handled;
  835. }
  836. else g_bVoteClassEnabled = true;
  837.  
  838. if(!g_bVoteClassEnabled) {
  839. CReplyToCommand(client, "%s %sVoting for rocket class is %snot enabled.", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  840. return Plugin_Handled;
  841. }
  842.  
  843. if(!g_bCanVoteClass) {
  844. CReplyToCommand(client,"%s %sYou cannot vote at this time (%s%ds %sleft).", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor, GetConVarInt(g_hCvarVoteClassCooldown) - (GetTime() - g_iTimeVoted), g_strMainChatColor);
  845. return Plugin_Handled;
  846. }
  847.  
  848. g_iClassVotesRequired = RoundToCeil(GetTotalClientCount() * GetConVarFloat(g_hCvarVoteClassPercentage));
  849.  
  850. if(g_bClassVoted[client]) {
  851. CReplyToCommand(client, "%s %sYou have %salready %svoted", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor, g_strMainChatColor);
  852. return Plugin_Handled;
  853. }
  854.  
  855. if(IsVoteInProgress()) {
  856. CReplyToCommand(client, "%s %sA vote is currently %sin progress", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  857. return Plugin_Handled;
  858. }
  859.  
  860. g_iClassVotes++;
  861. g_bClassVoted[client] = true;
  862.  
  863. CPrintToChatAll("%s %s%N %swants to change the rocket class (%s%d/%d%s votes)", g_strServerChatTag, g_strKeywordChatColor, client, g_strMainChatColor, g_strKeywordChatColor, g_iClassVotes, g_iClassVotesRequired, g_strMainChatColor);
  864.  
  865. if(g_iClassVotes >= g_iClassVotesRequired) {
  866. CreateTimer(2.0, Timer_StartRocketClassVote);
  867. g_bCanVoteClass = false;
  868.  
  869. g_iClassVotes = 0;
  870. for(int i = 0; i < sizeof(g_bClassVoted); i++) {
  871. g_bClassVoted[i] = false;
  872. }
  873.  
  874. CreateTimer(GetConVarFloat(g_hCvarVoteClassCooldown), Timer_AllowRocketClassVote);
  875. }
  876.  
  877. return Plugin_Handled;
  878. }
  879.  
  880. /*
  881. **����������������������������������������������������������������������������������
  882. ** __ ___ __
  883. ** / |/ /___ _____ ____ _____ ____ ____ ___ ___ ____ / /_
  884. ** / /|_/ / __ `/ __ \/ __ `/ __ `/ _ \/ __ `__ \/ _ \/ __ \/ __/
  885. ** / / / / /_/ / / / / /_/ / /_/ / __/ / / / / / __/ / / / /_
  886. ** /_/ /_/\__,_/_/ /_/\__,_/\__, /\___/_/ /_/ /_/\___/_/ /_/\__/
  887. ** /____/
  888. **����������������������������������������������������������������������������������
  889. */
  890.  
  891. // ___ _
  892. // / __|___ _ _ ___ _ _ __ _| |
  893. // | (_ / -_) ' \/ -_) '_/ _` | |
  894. // \___\___|_||_\___|_| \__,_|_|
  895.  
  896. /* IsDodgeBallMap()
  897. **
  898. ** Checks if the current map is a dodgeball map.
  899. ** -------------------------------------------------------------------------- */
  900. bool IsDodgeBallMap()
  901. {
  902. char strMap[64];
  903. GetCurrentMap(strMap, sizeof(strMap));
  904. return StrContains(strMap, "tfdb_", false) == 0;
  905. }
  906.  
  907. /* EnableDodgeBall()
  908. **
  909. ** Enables and hooks all the required events.
  910. ** -------------------------------------------------------------------------- */
  911. void EnableDodgeBall()
  912. {
  913. if (g_bEnabled == false)
  914. {
  915. // Parse configuration files
  916. char strMapName[64]; GetCurrentMap(strMapName, sizeof(strMapName));
  917. char strMapFile[PLATFORM_MAX_PATH]; Format(strMapFile, sizeof(strMapFile), "%s.cfg", strMapName);
  918. ParseConfigurations();
  919. ParseConfigurations(strMapFile);
  920.  
  921. ServerCommand("tf_dodgeball_rbmax %f", GetConVarFloat(g_hMaxBouncesConVar));
  922.  
  923. // Check if we have all the required information
  924. if (g_iRocketClassCount == 0)
  925. SetFailState("No rocket class defined.");
  926.  
  927. if (g_iSpawnersCount == 0)
  928. SetFailState("No spawner class defined.");
  929.  
  930. if (g_iDefaultRedSpawner == -1)
  931. SetFailState("No spawner class definition for the Red spawners exists in the config file.");
  932.  
  933. if (g_iDefaultBluSpawner == -1)
  934. SetFailState("No spawner class definition for the Blu spawners exists in the config file.");
  935.  
  936. // Hook events and info_target outputs.
  937. HookEvent("object_deflected", Event_ObjectDeflected);
  938. HookEvent("teamplay_round_start", OnRoundStart, EventHookMode_PostNoCopy);
  939. HookEvent("teamplay_setup_finished", OnSetupFinished, EventHookMode_PostNoCopy);
  940. HookEvent("teamplay_round_win", OnRoundEnd, EventHookMode_PostNoCopy);
  941. HookEvent("player_spawn", OnPlayerSpawn, EventHookMode_Post);
  942. HookEvent("player_death", OnPlayerDeath, EventHookMode_Pre);
  943. HookEvent("post_inventory_application", OnPlayerInventory, EventHookMode_Post);
  944. HookEvent("teamplay_broadcast_audio", OnBroadcastAudio, EventHookMode_Pre);
  945.  
  946.  
  947.  
  948. // Precache sounds
  949. PrecacheSound(SOUND_DEFAULT_SPAWN, true);
  950. PrecacheSound(SOUND_DEFAULT_BEEP, true);
  951. PrecacheSound(SOUND_DEFAULT_ALERT, true);
  952. PrecacheSound(SOUND_DEFAULT_SPEEDUPALERT, true);
  953. if (g_bMusicEnabled == true)
  954. {
  955. if (g_bMusic[Music_RoundStart])PrecacheSoundEx(g_strMusic[Music_RoundStart], true, true);
  956. if (g_bMusic[Music_RoundWin])PrecacheSoundEx(g_strMusic[Music_RoundWin], true, true);
  957. if (g_bMusic[Music_RoundLose])PrecacheSoundEx(g_strMusic[Music_RoundLose], true, true);
  958. if (g_bMusic[Music_Gameplay])PrecacheSoundEx(g_strMusic[Music_Gameplay], true, true);
  959. }
  960.  
  961. // Precache particles
  962. PrecacheParticle(PARTICLE_NUKE_1);
  963. PrecacheParticle(PARTICLE_NUKE_2);
  964. PrecacheParticle(PARTICLE_NUKE_3);
  965. PrecacheParticle(PARTICLE_NUKE_4);
  966. PrecacheParticle(PARTICLE_NUKE_5);
  967. PrecacheParticle(PARTICLE_NUKE_COLLUMN);
  968.  
  969. // Precache rocket resources
  970. for (int i = 0; i < g_iRocketClassCount; i++)
  971. {
  972. RocketFlags iFlags = g_iRocketClassFlags[i];
  973. if (TestFlags(iFlags, RocketFlag_CustomModel))PrecacheModelEx(g_strRocketClassModel[i], true, true);
  974. if (TestFlags(iFlags, RocketFlag_CustomSpawnSound))PrecacheSoundEx(g_strRocketClassSpawnSound[i], true, true);
  975. if (TestFlags(iFlags, RocketFlag_CustomBeepSound))PrecacheSoundEx(g_strRocketClassBeepSound[i], true, true);
  976. if (TestFlags(iFlags, RocketFlag_CustomAlertSound))PrecacheSoundEx(g_strRocketClassAlertSound[i], true, true);
  977. }
  978.  
  979. // Execute enable config file
  980. char strCfgFile[64]; GetConVarString(g_hCvarEnableCfgFile, strCfgFile, sizeof(strCfgFile));
  981. ServerCommand("exec \"%s\"", strCfgFile);
  982.  
  983. // Done.
  984. g_bEnabled = true;
  985. g_bRoundStarted = false;
  986. g_iRoundCount = 0;
  987. }
  988. }
  989.  
  990. /* DisableDodgeBall()
  991. **
  992. ** Disables all hooks and frees arrays.
  993. ** -------------------------------------------------------------------------- */
  994. void DisableDodgeBall()
  995. {
  996. if (g_bEnabled == true)
  997. {
  998. // Clean up everything
  999. DestroyRockets();
  1000. DestroyRocketClasses();
  1001. DestroySpawners();
  1002. if (g_hLogicTimer != INVALID_HANDLE)KillTimer(g_hLogicTimer);
  1003. g_hLogicTimer = INVALID_HANDLE;
  1004.  
  1005. // Disable music
  1006. g_bMusic[Music_RoundStart] =
  1007. g_bMusic[Music_RoundWin] =
  1008. g_bMusic[Music_RoundLose] =
  1009. g_bMusic[Music_Gameplay] = false;
  1010.  
  1011. // Unhook events and info_target outputs;
  1012. UnhookEvent("teamplay_round_start", OnRoundStart, EventHookMode_PostNoCopy);
  1013. UnhookEvent("teamplay_setup_finished", OnSetupFinished, EventHookMode_PostNoCopy);
  1014. UnhookEvent("teamplay_round_win", OnRoundEnd, EventHookMode_PostNoCopy);
  1015. UnhookEvent("player_spawn", OnPlayerSpawn, EventHookMode_Post);
  1016. UnhookEvent("player_death", OnPlayerDeath, EventHookMode_Pre);
  1017. UnhookEvent("post_inventory_application", OnPlayerInventory, EventHookMode_Post);
  1018. UnhookEvent("teamplay_broadcast_audio", OnBroadcastAudio, EventHookMode_Pre);
  1019.  
  1020. // Execute enable config file
  1021. char strCfgFile[64]; GetConVarString(g_hCvarDisableCfgFile, strCfgFile, sizeof(strCfgFile));
  1022. ServerCommand("exec \"%s\"", strCfgFile);
  1023.  
  1024. // Done.
  1025. g_bEnabled = false;
  1026. g_bRoundStarted = false;
  1027. g_iRoundCount = 0;
  1028. }
  1029. }
  1030.  
  1031.  
  1032. public void OnClientPutInServer(int clientId)
  1033. {
  1034. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1035. {
  1036. firstJoined[clientId] = true;
  1037. }
  1038. if (GetConVarBool(g_hCvarPreventTauntKillEnabled))
  1039. {
  1040. SDKHook(clientId, SDKHook_OnTakeDamage, TauntCheck);
  1041. }
  1042. }
  1043.  
  1044. public void OnClientConnected(int client)
  1045. {
  1046. if (IsFakeClient(client)) return;
  1047.  
  1048. g_bClassVoted[client] = false;
  1049. g_iClassVoters++;
  1050. g_iClassVotesRequired = RoundToCeil(GetTotalClientCount() * GetConVarFloat(g_hCvarVoteClassPercentage));
  1051. }
  1052.  
  1053. public void OnClientDisconnect(int client)
  1054. {
  1055. if(IsFakeClient(client)) return;
  1056.  
  1057. if (GetConVarBool(g_hCvarPreventTauntKillEnabled))
  1058. {
  1059. SDKUnhook(client, SDKHook_OnTakeDamage, TauntCheck);
  1060. }
  1061.  
  1062. if (GetConVarBool(g_hCvarStealPrevention))
  1063. {
  1064. bStealArray[client][stoleRocket] = false;
  1065. bStealArray[client][rocketsStolen] = 0;
  1066. }
  1067.  
  1068. if(g_bClassVoted[client])
  1069. {
  1070. g_iClassVotes--;
  1071. }
  1072.  
  1073. g_iClassVoters--;
  1074. g_iClassVotesRequired = RoundToCeil(GetTotalClientCount() * GetConVarFloat(g_hCvarVoteClassPercentage));
  1075.  
  1076. if (g_iClassVotes >= g_iClassVotesRequired && g_bVoteClassEnabled && g_iClassVoters != 0)
  1077. {
  1078. CreateTimer(2.0, Timer_StartRocketClassVote);
  1079. }
  1080. }
  1081.  
  1082. /* OnObjectDeflected
  1083. **
  1084. **
  1085. ** Check if client is human, don't airblast if bool is false
  1086. ** -------------------------------------------------------------------------- */
  1087. public Action Event_ObjectDeflected(Handle event, const char[] name, bool dontBroadcast)
  1088. {
  1089. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1090. {
  1091. int object1 = GetEventInt(event, "object_entindex");
  1092. if ((object1 >= 1) && (object1 <= MaxClients))
  1093. {
  1094. if (Airblast[object1])
  1095. {
  1096. float Vel[3];
  1097. TeleportEntity(object1, NULL_VECTOR, NULL_VECTOR, Vel); // Stops knockback
  1098. TF2_RemoveCondition(object1, TFCond_Dazed); // Stops slowdown
  1099. SetEntPropVector(object1, Prop_Send, "m_vecPunchAngle", Vel);
  1100. SetEntPropVector(object1, Prop_Send, "m_vecPunchAngleVel", Vel); // Stops screen shake
  1101. }
  1102. }
  1103. }
  1104. }
  1105.  
  1106.  
  1107. // ___ _
  1108. // / __|__ _ _ __ ___ _ __| |__ _ _ _
  1109. // | (_ / _` | ' \/ -_) '_ \ / _` | || |
  1110. // \___\__,_|_|_|_\___| .__/_\__,_|\_, |
  1111. // |_| |__/
  1112.  
  1113. /* OnRoundStart()
  1114. **
  1115. ** At round start, do something?
  1116. ** -------------------------------------------------------------------------- */
  1117. public Action OnRoundStart(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1118. {
  1119. if (GetConVarBool(g_hCvarStealPrevention))
  1120. {
  1121. for (int i = 0; i <= MaxClients; i++)
  1122. {
  1123. bStealArray[i][stoleRocket] = false;
  1124. bStealArray[i][rocketsStolen] = 0;
  1125. }
  1126. }
  1127.  
  1128. if (g_bMusic[Music_RoundStart])
  1129. {
  1130. EmitSoundToAll(g_strMusic[Music_RoundStart]);
  1131. }
  1132. g_iRocketSpeed = 0;
  1133. if (g_hTimerHud != INVALID_HANDLE)
  1134. {
  1135. KillTimer(g_hTimerHud);
  1136. g_hTimerHud = INVALID_HANDLE;
  1137. }
  1138. g_hTimerHud = CreateTimer(1.0, Timer_HudSpeed, _, TIMER_REPEAT);
  1139. }
  1140.  
  1141. /* OnSetupFinished()
  1142. **
  1143. ** When the setup finishes, populate the spawn points arrays and create the
  1144. ** Dodgeball game logic timer.
  1145. ** -------------------------------------------------------------------------- */
  1146. public Action OnSetupFinished(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1147. {
  1148. if ((g_bEnabled == true) && (BothTeamsPlaying() == true))
  1149. {
  1150. PopulateSpawnPoints();
  1151.  
  1152. if (g_iLastDeadTeam == 0)
  1153. {
  1154. g_iLastDeadTeam = GetURandomIntRange(view_as<int>(TFTeam_Red), view_as<int>(TFTeam_Blue));
  1155. }
  1156. if (!IsValidClient(g_iLastDeadClient))g_iLastDeadClient = 0;
  1157.  
  1158. g_hLogicTimer = CreateTimer(FPS_LOGIC_INTERVAL, OnDodgeBallGameFrame, _, TIMER_REPEAT);
  1159. g_iPlayerCount = CountAlivePlayers();
  1160. g_iRocketsFired = 0;
  1161. g_iCurrentRedSpawn = 0;
  1162. g_iCurrentBluSpawn = 0;
  1163. g_fNextSpawnTime = GetGameTime();
  1164. g_bRoundStarted = true;
  1165. g_iRoundCount++;
  1166. }
  1167. }
  1168.  
  1169. /* OnRoundEnd()
  1170. **
  1171. ** At round end, stop the Dodgeball game logic timer and destroy the remaining
  1172. ** rockets.
  1173. ** -------------------------------------------------------------------------- */
  1174. public Action OnRoundEnd(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1175. {
  1176. if (g_hTimerHud != INVALID_HANDLE)
  1177. {
  1178. KillTimer(g_hTimerHud);
  1179. g_hTimerHud = INVALID_HANDLE;
  1180. }
  1181. if (g_hLogicTimer != INVALID_HANDLE)
  1182. {
  1183. KillTimer(g_hLogicTimer);
  1184. g_hLogicTimer = INVALID_HANDLE;
  1185. }
  1186.  
  1187. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1188. {
  1189. for (int i = 0; i < MAXPLAYERS + 1; i++)
  1190. {
  1191. firstJoined[i] = false;
  1192. }
  1193. }
  1194. if (g_bMusicEnabled == true)
  1195. {
  1196. if (g_bUseWebPlayer)
  1197. {
  1198. for (int iClient = 1; iClient <= MaxClients; iClient++)
  1199. {
  1200. if (IsValidClient(iClient))
  1201. {
  1202. ShowHiddenMOTDPanel(iClient, "MusicPlayerStop", "http://0.0.0.0/");
  1203. if (!IsFakeClient(iClient))
  1204. {
  1205. ClearSyncHud(iClient, g_hHud);
  1206. }
  1207. }
  1208. }
  1209. }
  1210. else if (g_bMusic[Music_Gameplay])
  1211. {
  1212. StopSoundToAll(SNDCHAN_MUSIC, g_strMusic[Music_Gameplay]);
  1213. }
  1214. }
  1215.  
  1216. DestroyRockets();
  1217. g_bRoundStarted = false;
  1218. }
  1219.  
  1220. public Action Command_ToggleAirblast(int clientId, int args)
  1221. {
  1222. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1223. {
  1224. char arg[128];
  1225.  
  1226. if (args > 1)
  1227. {
  1228. ReplyToCommand(clientId, "[SM] %s", USAGE);
  1229. return Plugin_Handled;
  1230. }
  1231.  
  1232. if (args == 0)
  1233. {
  1234. preventAirblast(clientId, !abPrevention[clientId]);
  1235. }
  1236. else if (args == 1)
  1237. {
  1238. GetCmdArg(1, arg, sizeof(arg));
  1239.  
  1240. if (strcmp(arg, "0") == 0)
  1241. {
  1242. preventAirblast(clientId, false);
  1243. }
  1244. else if (strcmp(arg, "1") == 0)
  1245. {
  1246. preventAirblast(clientId, true);
  1247. }
  1248. else
  1249. {
  1250. ReplyToCommand(clientId, "[SM] %s", USAGE);
  1251. return Plugin_Handled;
  1252. }
  1253. }
  1254.  
  1255. if (abPrevention[clientId])
  1256. {
  1257. ReplyToCommand(clientId, "[SM] %s", "Airblast Prevention Enabled");
  1258. }
  1259. else
  1260. {
  1261. ReplyToCommand(clientId, "[SM] %s", "Airblast Prevention Disabled");
  1262. }
  1263. }
  1264.  
  1265. if (!GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1266. {
  1267. ReplyToCommand(clientId, "[SM] %s", "Airblast Prevention is disabled on this server.");
  1268. preventAirblast(clientId, false);
  1269. }
  1270. return Plugin_Handled;
  1271. }
  1272.  
  1273. public Action Command_PostCurrentRocketClass(int client, int args)
  1274. {
  1275. if (args > 1)
  1276. {
  1277. ReplyToCommand(client, "[SM] %s", "Usage: sm_currentrocket");
  1278. return Plugin_Handled;
  1279. }
  1280.  
  1281. if (!g_strSavedClassName[0])
  1282. {
  1283. CPrintToChat(client, "%s %sCurrent Rocket: %sMultiple", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  1284. return Plugin_Handled;
  1285. }
  1286. CPrintToChatAll("%s %sCurrent Rocket: %s%s", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor, g_strSavedClassName);
  1287.  
  1288. return Plugin_Handled;
  1289. }
  1290.  
  1291.  
  1292. /* OnPlayerSpawn()
  1293. **
  1294. ** When the player spawns, force class to Pyro.
  1295. ** -------------------------------------------------------------------------- */
  1296. public Action OnPlayerSpawn(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1297. {
  1298. int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
  1299. int clientId = GetClientOfUserId(GetEventInt(hEvent, "userid"));
  1300. //g_stolen[iClient] = 0;
  1301.  
  1302. if (!IsValidClient(iClient))return;
  1303.  
  1304. TFClassType iClass = TF2_GetPlayerClass(iClient);
  1305. if (!(iClass == TFClass_Pyro || iClass == view_as<TFClassType>(TFClass_Unknown)))
  1306. {
  1307. TF2_SetPlayerClass(iClient, TFClass_Pyro, false, true);
  1308. TF2_RespawnPlayer(iClient);
  1309. }
  1310.  
  1311. for (int i = MaxClients; i; --i)
  1312. {
  1313. if (IsClientInGame(i) && IsPlayerAlive(i))
  1314. SetEntPropEnt(i, Prop_Data, "m_hActiveWeapon", GetPlayerWeaponSlot(i, TFWeaponSlot_Primary));
  1315. }
  1316.  
  1317. if (!GetConVarBool(g_hCvarPyroVisionEnabled))
  1318. {
  1319. return;
  1320. }
  1321. TF2Attrib_SetByName(iClient, PYROVISION_ATTRIBUTE, 1.0);
  1322.  
  1323. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1324. {
  1325. if (firstJoined[clientId])
  1326. {
  1327. //Enable ab prevention when a player joins the server
  1328. abPrevention[clientId] = true;
  1329. }
  1330.  
  1331. preventAirblast(clientId, true);
  1332. }
  1333. }
  1334.  
  1335. /* OnPlayerDeath()
  1336. **
  1337. ** When the player dies, set the last dead team to determine the next
  1338. ** rocket's team.
  1339. ** -------------------------------------------------------------------------- */
  1340. public Action OnPlayerDeath(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1341. {
  1342. if (g_bRoundStarted == false)
  1343. {
  1344. return;
  1345. }
  1346. int iAttacker = GetClientOfUserId(GetEventInt(hEvent, "attacker"));
  1347. int iVictim = GetClientOfUserId(GetEventInt(hEvent, "userid"));
  1348.  
  1349. if (GetConVarBool(g_hCvarAirBlastCommandEnabled))
  1350. {
  1351. int clientId = GetClientOfUserId(GetEventInt(hEvent, "userid"));
  1352. firstJoined[clientId] = false;
  1353. }
  1354. if (IsValidClient(iVictim))
  1355. {
  1356. if (GetConVarBool(g_hCvarStealPrevention))
  1357. {
  1358. bStealArray[iVictim][stoleRocket] = false;
  1359. bStealArray[iVictim][rocketsStolen] = 0;
  1360. }
  1361.  
  1362. g_iLastDeadClient = iVictim;
  1363. g_iLastDeadTeam = GetClientTeam(iVictim);
  1364.  
  1365. int iInflictor = GetEventInt(hEvent, "inflictor_entindex");
  1366. int iIndex = FindRocketByEntity(iInflictor);
  1367.  
  1368. if (iIndex != -1)
  1369. {
  1370. int iClass = g_iRocketClass[iIndex];
  1371. int iTarget = EntRefToEntIndex(g_iRocketTarget[iIndex]);
  1372. float fSpeed = g_fRocketSpeed[iIndex];
  1373. int iDeflections = g_iRocketDeflections[iIndex];
  1374.  
  1375. if (GetConVarBool(g_hCvarAnnounce))
  1376. {
  1377. if (GetConVarBool(g_hCvarDeflectCountAnnounce))
  1378. {
  1379. if (iVictim == iTarget)
  1380. {
  1381. CPrintToChatAll("%s %s%N %sdied to their rocket travelling %s%i %smph with %s%i %sdeflections!", g_strServerChatTag, g_strKeywordChatColor, g_iLastDeadClient, g_strMainChatColor, g_strKeywordChatColor, g_iRocketSpeed, g_strMainChatColor, g_strKeywordChatColor, iDeflections, g_strMainChatColor);
  1382. }
  1383. else
  1384. {
  1385. CPrintToChatAll("%s %s%N %sdied to %s%.15N's %srocket travelling %s%i %smph with %s%i %sdeflections!", g_strServerChatTag, g_strKeywordChatColor, g_iLastDeadClient, g_strMainChatColor, g_strKeywordChatColor, iTarget, g_strMainChatColor, g_strKeywordChatColor, g_iRocketSpeed, g_strMainChatColor, g_strKeywordChatColor, iDeflections, g_strMainChatColor);
  1386. }
  1387. }
  1388. else
  1389. {
  1390. CPrintToChatAll("%s %s%N %sdied to a rocket travelling %s%i %smph!", g_strServerChatTag, g_strKeywordChatColor, g_iLastDeadClient, g_strMainChatColor, g_strKeywordChatColor, g_iRocketSpeed, g_strMainChatColor);
  1391. }
  1392. }
  1393.  
  1394. if ((g_iRocketFlags[iIndex] & RocketFlag_OnExplodeCmd) && !(g_iRocketFlags[iIndex] & RocketFlag_Exploded))
  1395. {
  1396. ExecuteCommands(g_hRocketClassCmdsOnExplode[iClass], iClass, iInflictor, iAttacker, iTarget, g_iLastDeadClient, fSpeed, iDeflections);
  1397. g_iRocketFlags[iIndex] |= RocketFlag_Exploded;
  1398. }
  1399.  
  1400. if (TestFlags(g_iRocketFlags[iIndex], RocketFlag_OnKillCmd))
  1401. ExecuteCommands(g_hRocketClassCmdsOnKill[iClass], iClass, iInflictor, iAttacker, iTarget, g_iLastDeadClient, fSpeed, iDeflections);
  1402. }
  1403. }
  1404.  
  1405. SetRandomSeed(view_as<int>(GetGameTime()));
  1406. }
  1407.  
  1408. /* OnPlayerInventory()
  1409. **
  1410. ** Make sure the client only has the flamethrower equipped.
  1411. ** -------------------------------------------------------------------------- */
  1412. public Action OnPlayerInventory(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1413. {
  1414. int iClient = GetClientOfUserId(GetEventInt(hEvent, "userid"));
  1415. if (!IsValidClient(iClient))return;
  1416.  
  1417. for (int iSlot = 1; iSlot < 5; iSlot++)
  1418. {
  1419. int iEntity = GetPlayerWeaponSlot(iClient, iSlot);
  1420. if (iEntity != -1)RemoveEdict(iEntity);
  1421. }
  1422. }
  1423.  
  1424. /* OnPlayerRunCmd()
  1425. **
  1426. ** Block flamethrower's Mouse1 attack.
  1427. ** -------------------------------------------------------------------------- */
  1428. public Action OnPlayerRunCmd(int iClient, int &iButtons, int &iImpulse, float fVelocity[3], float fAngles[3], int &iWeapon)
  1429. {
  1430. if (g_bEnabled == true)iButtons &= ~IN_ATTACK;
  1431. return Plugin_Continue;
  1432. }
  1433.  
  1434. /* OnBroadcastAudio()
  1435. **
  1436. ** Replaces the broadcasted audio for our custom music files.
  1437. ** -------------------------------------------------------------------------- */
  1438. public Action OnBroadcastAudio(Handle hEvent, char[] strEventName, bool bDontBroadcast)
  1439. {
  1440. if (g_bMusicEnabled == true)
  1441. {
  1442. char strSound[PLATFORM_MAX_PATH];
  1443. GetEventString(hEvent, "sound", strSound, sizeof(strSound));
  1444. int iTeam = GetEventInt(hEvent, "team");
  1445.  
  1446. if (StrEqual(strSound, "Announcer.AM_RoundStartRandom") == true)
  1447. {
  1448. if (g_bUseWebPlayer == false)
  1449. {
  1450. if (g_bMusic[Music_Gameplay])
  1451. {
  1452. EmitSoundToAll(g_strMusic[Music_Gameplay], SOUND_FROM_PLAYER, SNDCHAN_MUSIC);
  1453. return Plugin_Handled;
  1454. }
  1455. }
  1456. else
  1457. {
  1458. for (int iClient = 1; iClient <= MaxClients; iClient++)
  1459. if (IsValidClient(iClient))
  1460. ShowHiddenMOTDPanel(iClient, "MusicPlayerStart", g_strWebPlayerUrl);
  1461.  
  1462. return Plugin_Handled;
  1463. }
  1464. }
  1465. else if (StrEqual(strSound, "Game.YourTeamWon") == true)
  1466. {
  1467. if (g_bMusic[Music_RoundWin])
  1468. {
  1469. for (int iClient = 1; iClient <= MaxClients; iClient++)
  1470. if (IsValidClient(iClient) && (iTeam == GetClientTeam(iClient)))
  1471. EmitSoundToClient(iClient, g_strMusic[Music_RoundWin]);
  1472.  
  1473. return Plugin_Handled;
  1474. }
  1475. }
  1476. else if (StrEqual(strSound, "Game.YourTeamLost") == true)
  1477. {
  1478. if (g_bMusic[Music_RoundLose])
  1479. {
  1480. for (int iClient = 1; iClient <= MaxClients; iClient++)
  1481. if (IsValidClient(iClient) && (iTeam == GetClientTeam(iClient)))
  1482. EmitSoundToClient(iClient, g_strMusic[Music_RoundLose]);
  1483.  
  1484. return Plugin_Handled;
  1485. }
  1486. return Plugin_Handled;
  1487. }
  1488. }
  1489. return Plugin_Continue;
  1490. }
  1491.  
  1492. /* OnDodgeBallGameFrame()
  1493. **
  1494. ** Every tick of the Dodgeball logic.
  1495. ** -------------------------------------------------------------------------- */
  1496. public Action OnDodgeBallGameFrame(Handle hTimer, any Data)
  1497. {
  1498. // Only if both teams are playing
  1499. if (BothTeamsPlaying() == false)return;
  1500.  
  1501. // Check if we need to fire more rockets.
  1502. if (GetGameTime() >= g_fNextSpawnTime)
  1503. {
  1504. if (g_iLastDeadTeam == view_as<int>(TFTeam_Red))
  1505. {
  1506. int iSpawnerEntity = g_iSpawnPointsRedEntity[g_iCurrentRedSpawn];
  1507. int iSpawnerClass = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  1508. if (g_iRocketCount < g_iSpawnersMaxRockets[iSpawnerClass])
  1509. {
  1510. CreateRocket(iSpawnerEntity, iSpawnerClass, view_as<int>(TFTeam_Red));
  1511. g_iCurrentRedSpawn = (g_iCurrentRedSpawn + 1) % g_iSpawnPointsRedCount;
  1512. }
  1513. }
  1514. else
  1515. {
  1516. int iSpawnerEntity = g_iSpawnPointsBluEntity[g_iCurrentBluSpawn];
  1517. int iSpawnerClass = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  1518. if (g_iRocketCount < g_iSpawnersMaxRockets[iSpawnerClass])
  1519. {
  1520. CreateRocket(iSpawnerEntity, iSpawnerClass, view_as<int>(TFTeam_Blue));
  1521. g_iCurrentBluSpawn = (g_iCurrentBluSpawn + 1) % g_iSpawnPointsBluCount;
  1522. }
  1523. }
  1524. }
  1525.  
  1526. // Manage the active rockets
  1527. int iIndex = -1;
  1528. while ((iIndex = FindNextValidRocket(iIndex)) != -1)
  1529. {
  1530. switch (g_iRocketClassBehaviour[g_iRocketClass[iIndex]])
  1531. {
  1532. case Behaviour_Unknown: { }
  1533. case Behaviour_Homing: { HomingRocketThink(iIndex); }
  1534. }
  1535. }
  1536. }
  1537.  
  1538. /*public Action ShowToTarget(int iIndex, int iClient)
  1539. {
  1540. int iParticle = EntRefToEntIndex(g_RocketParticle[iIndex]);
  1541. int iTarget = EntRefToEntIndex(g_iRocketTarget[iIndex]);
  1542.  
  1543. if (!IsValidEntity(iParticle))
  1544. return Plugin_Handled;
  1545.  
  1546. if (!IsValidClient(iTarget))
  1547. return Plugin_Handled;
  1548.  
  1549. if (iClient != iTarget)
  1550. return Plugin_Handled;
  1551.  
  1552. return Plugin_Continue;
  1553. }*/
  1554.  
  1555. public Action Timer_HudSpeed(Handle hTimer)
  1556. {
  1557. if (GetConVarBool(g_hCvarSpeedo))
  1558. {
  1559. SetHudTextParams(-1.0, 0.9, 1.1, 255, 255, 255, 255);
  1560. for (int iClient = 1; iClient <= MaxClients; iClient++)
  1561. {
  1562. if (IsValidClient(iClient) && !IsFakeClient(iClient) && g_iRocketSpeed != 0)
  1563. {
  1564. ShowSyncHudText(iClient, g_hHud, "Speed: %i mph", g_iRocketSpeed);
  1565. }
  1566. }
  1567. }
  1568. }
  1569.  
  1570. public Action Timer_StartRocketClassVote(Handle timer)
  1571. {
  1572. if(!g_bVoteClassEnabled)
  1573. return;
  1574.  
  1575. g_iTimeVoted = GetTime();
  1576.  
  1577. CPrintToChatAll("%s %sVoting for Rocket Class %sstarted!", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  1578.  
  1579. Menu menu = new Menu(Handler_RocketClassVoteMenu);
  1580. menu.SetTitle("Set the Rocket Class:");
  1581.  
  1582. for (int currentClass = 0; currentClass < g_iRocketClassCount; currentClass++)
  1583. {
  1584. char classNumber[16];
  1585. IntToString(currentClass, classNumber, sizeof(classNumber));
  1586. if (StrEqual(g_strSavedClassName, g_strRocketClassLongName[currentClass]))
  1587. {
  1588. char currentClassName[32];
  1589. strcopy(currentClassName, sizeof(currentClassName), "[Current] ");
  1590. StrCat(currentClassName, sizeof(currentClassName), g_strSavedClassName);
  1591. menu.AddItem(classNumber, currentClassName);
  1592. }
  1593. else menu.AddItem(classNumber, g_strRocketClassLongName[currentClass]);
  1594. }
  1595.  
  1596. char nochange[64];
  1597. Format(nochange, 64, "Don't Change");
  1598. char classCount[sizeof(g_iRocketClassCount)];
  1599. IntToString(g_iRocketClassCount + 1, classCount, sizeof(classCount));
  1600. menu.AddItem(classCount, nochange);
  1601.  
  1602. menu.ExitButton = false;
  1603. menu.DisplayVoteToAll(20);
  1604.  
  1605. LogMessage("[VRC] Voting for rocket class has successfully started.");
  1606. }
  1607.  
  1608. public int Handler_RocketClassVoteMenu(Menu menu, MenuAction action, int param1, int param2)
  1609. {
  1610. switch (action)
  1611. {
  1612. case MenuAction_End:
  1613. {
  1614. delete menu;
  1615. }
  1616. case MenuAction_Select:
  1617. {
  1618. char voter[64], choice[64];
  1619. GetClientName(param1, voter, sizeof(voter));
  1620. menu.GetItem(param2, choice, sizeof(choice));
  1621. LogMessage("[VRC] %s Selected Rocket Class %s", voter, choice);
  1622. }
  1623. case MenuAction_VoteEnd:
  1624. {
  1625. char classNum[64];
  1626. char className[64];
  1627. int votes, totalVotes;
  1628. GetMenuVoteInfo(param2, votes, totalVotes);
  1629.  
  1630. if (totalVotes < 1)
  1631. {
  1632. CPrintToChatAll("%s %sVoting ended with %sno Votes!", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  1633. return;
  1634. }
  1635.  
  1636. menu.GetItem(param1, classNum, sizeof(classNum));
  1637.  
  1638. strcopy(className, sizeof(className), g_strRocketClassLongName[param1]);
  1639.  
  1640. if (StrContains(className, "[Current]") != -1 || StringToInt(classNum) == (g_iRocketClassCount + 1))
  1641. {
  1642. CPrintToChatAll("%s %sCurrent Rocket Class %sStays", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor);
  1643. LogMessage("[VRC] Voting for Rocket Class has ended, current class kept.");
  1644. }
  1645. else
  1646. {
  1647. LogMessage("[VRC] Voting for Rocket Class has ended, changing class to %s.", className);
  1648. SetMainRocketClass(param1, true);
  1649. }
  1650. }
  1651. }
  1652. }
  1653.  
  1654. public Action Timer_AllowRocketClassVote(Handle timer, Handle hndl) {
  1655. g_bCanVoteClass = true;
  1656. }
  1657.  
  1658. // ___ _ _
  1659. // | _ \___ __| |_____| |_ ___
  1660. // | / _ \/ _| / / -_) _(_-<
  1661. // |_|_\___/\__|_\_\___|\__/__/
  1662.  
  1663. /* CreateRocket()
  1664. **
  1665. ** Fires a new rocket entity from the spawner's position.
  1666. ** -------------------------------------------------------------------------- */
  1667. public void CreateRocket(int iSpawnerEntity, int iSpawnerClass, int iTeam)
  1668. {
  1669. int iIndex = FindFreeRocketSlot();
  1670. if (iIndex != -1)
  1671. {
  1672. // Fetch a random rocket class and it's parameters.
  1673. int iClass = GetRandomRocketClass(iSpawnerClass);
  1674. RocketFlags iFlags = g_iRocketClassFlags[iClass];
  1675.  
  1676. // Create rocket entity.
  1677. int iEntity = CreateEntityByName(TestFlags(iFlags, RocketFlag_IsAnimated) ? "tf_projectile_sentryrocket" : "tf_projectile_rocket");
  1678. if (iEntity && IsValidEntity(iEntity))
  1679. {
  1680. // Fetch spawn point's location and angles.
  1681. float fPosition[3];
  1682. float fAngles[3];
  1683. float fDirection[3];
  1684. GetEntPropVector(iSpawnerEntity, Prop_Send, "m_vecOrigin", fPosition);
  1685. GetEntPropVector(iSpawnerEntity, Prop_Send, "m_angRotation", fAngles);
  1686. GetAngleVectors(fAngles, fDirection, NULL_VECTOR, NULL_VECTOR);
  1687.  
  1688. // Setup rocket entity.
  1689. SetEntPropEnt(iEntity, Prop_Send, "m_hOwnerEntity", 0);
  1690. SetEntProp(iEntity, Prop_Send, "m_bCritical", (GetURandomFloatRange(0.0, 100.0) <= g_fRocketClassCritChance[iClass]) ? 1 : 0, 1);
  1691. SetEntProp(iEntity, Prop_Send, "m_iTeamNum", iTeam, 1);
  1692. SetEntProp(iEntity, Prop_Send, "m_iDeflected", 1);
  1693. TeleportEntity(iEntity, fPosition, fAngles, view_as<float>( { 0.0, 0.0, 0.0 } ));
  1694.  
  1695. // Setup rocket structure with the newly created entity.
  1696. int iTargetTeam = (TestFlags(iFlags, RocketFlag_IsNeutral)) ? 0 : GetAnalogueTeam(iTeam);
  1697. int iTarget = SelectTarget(iTargetTeam);
  1698. float fModifier = CalculateModifier(iClass, 0);
  1699. g_bRocketIsValid[iIndex] = true;
  1700. g_iRocketFlags[iIndex] = iFlags;
  1701. g_iRocketEntity[iIndex] = EntIndexToEntRef(iEntity);
  1702. g_iRocketTarget[iIndex] = EntIndexToEntRef(iTarget);
  1703. g_iRocketSpawner[iIndex] = iSpawnerClass;
  1704. g_iRocketClass[iIndex] = iClass;
  1705. g_iRocketDeflections[iIndex] = 0;
  1706. g_fRocketLastDeflectionTime[iIndex] = GetGameTime();
  1707. g_fRocketLastBeepTime[iIndex] = GetGameTime();
  1708. g_fRocketSpeed[iIndex] = CalculateRocketSpeed(iClass, fModifier);
  1709. g_iRocketSpeed = RoundFloat(g_fRocketSpeed[iIndex] * 0.042614);
  1710.  
  1711. CopyVectors(fDirection, g_fRocketDirection[iIndex]);
  1712. SetEntDataFloat(iEntity, FindSendPropInfo("CTFProjectile_Rocket", "m_iDeflected") + 4, CalculateRocketDamage(iClass, fModifier), true);
  1713. DispatchSpawn(iEntity);
  1714.  
  1715. // Apply custom model, if specified on the flags.
  1716. if (TestFlags(iFlags, RocketFlag_CustomModel))
  1717. {
  1718. SetEntityModel(iEntity, g_strRocketClassModel[iClass]);
  1719. UpdateRocketSkin(iEntity, iTeam, TestFlags(iFlags, RocketFlag_IsNeutral));
  1720. }
  1721.  
  1722. // Execute commands on spawn.
  1723. if (TestFlags(iFlags, RocketFlag_OnSpawnCmd))
  1724. {
  1725. ExecuteCommands(g_hRocketClassCmdsOnSpawn[iClass], iClass, iEntity, 0, iTarget, g_iLastDeadClient, g_fRocketSpeed[iIndex], 0);
  1726. }
  1727.  
  1728. // Emit required sounds.
  1729. EmitRocketSound(RocketSound_Spawn, iClass, iEntity, iTarget, iFlags);
  1730. EmitRocketSound(RocketSound_Alert, iClass, iEntity, iTarget, iFlags);
  1731.  
  1732. // Done
  1733. g_iRocketCount++;
  1734. g_iRocketsFired++;
  1735. g_fLastSpawnTime = GetGameTime();
  1736. g_fNextSpawnTime = GetGameTime() + g_fSpawnersInterval[iSpawnerClass];
  1737. g_bRocketIsNuke[iIndex] = false;
  1738.  
  1739. //AttachParticle(iEntity, "burningplayer_rainbow_glow");
  1740. //AttachParticle(iEntity, "burningplayer_rainbow_glow_old");
  1741. //CreateTempParticle("superrare_greenenergy", iEntity, _, _, true);
  1742. //SDKHook(iEntity, SDKHook_SetTransmit, ShowToTarget);
  1743.  
  1744. //Observer
  1745. if (IsValidEntity(g_observer))
  1746. {
  1747. g_op_rocket = iEntity;
  1748. TeleportEntity(g_observer, fPosition, fAngles, view_as<float>( { 0.0, 0.0, 0.0 } ));
  1749. SetVariantString("!activator");
  1750. AcceptEntityInput(g_observer, "SetParent", g_op_rocket);
  1751. }
  1752. }
  1753. }
  1754. }
  1755.  
  1756. public void OnEntityDestroyed(int entity)
  1757. {
  1758. if (entity == -1)
  1759. {
  1760. return;
  1761. }
  1762.  
  1763. if (entity == g_op_rocket && g_bEnabled == true && IsValidEntity(g_observer) && IsValidEntity(g_op_rocket))
  1764. {
  1765. SetVariantString("");
  1766. AcceptEntityInput(g_observer, "ClearParent");
  1767. g_op_rocket = -1;
  1768.  
  1769. float opPos[3];
  1770. float opAng[3];
  1771.  
  1772. int spawner = GetRandomInt(0, 1);
  1773. if (spawner == 0)
  1774. spawner = g_iSpawnPointsRedEntity[0];
  1775. else
  1776. spawner = g_iSpawnPointsBluEntity[0];
  1777.  
  1778. if (IsValidEntity(spawner) && spawner > MAXPLAYERS)
  1779. {
  1780. GetEntPropVector(spawner, Prop_Data, "m_vecOrigin", opPos);
  1781. GetEntPropVector(spawner, Prop_Data, "m_angAbsRotation", opAng);
  1782. TeleportEntity(g_observer, opPos, opAng, NULL_VECTOR);
  1783. }
  1784. }
  1785. }
  1786.  
  1787. /* DestroyRocket()
  1788. **
  1789. ** Destroys the rocket at the given index.
  1790. ** -------------------------------------------------------------------------- */
  1791. void DestroyRocket(int iIndex)
  1792. {
  1793. if (IsValidRocket(iIndex) == true)
  1794. {
  1795. int iEntity = EntRefToEntIndex(g_iRocketEntity[iIndex]);
  1796. if (iEntity && IsValidEntity(iEntity))RemoveEdict(iEntity);
  1797. g_bRocketIsValid[iIndex] = false;
  1798. g_iRocketCount--;
  1799. }
  1800. }
  1801.  
  1802. /* DestroyRockets()
  1803. **
  1804. ** Destroys all the rockets that are currently active.
  1805. ** -------------------------------------------------------------------------- */
  1806. void DestroyRockets()
  1807. {
  1808. for (int iIndex = 0; iIndex < MAX_ROCKETS; iIndex++)
  1809. {
  1810. DestroyRocket(iIndex);
  1811. }
  1812. g_iRocketCount = 0;
  1813. }
  1814.  
  1815. /* IsValidRocket()
  1816. **
  1817. ** Checks if a rocket structure is valid.
  1818. ** -------------------------------------------------------------------------- */
  1819. bool IsValidRocket(int iIndex)
  1820. {
  1821. if ((iIndex >= 0) && (g_bRocketIsValid[iIndex] == true))
  1822. {
  1823. if (EntRefToEntIndex(g_iRocketEntity[iIndex]) == -1)
  1824. {
  1825. g_bRocketIsValid[iIndex] = false;
  1826. g_iRocketCount--;
  1827. return false;
  1828. }
  1829. return true;
  1830. }
  1831. return false;
  1832. }
  1833.  
  1834. /* FindNextValidRocket()
  1835. **
  1836. ** Retrieves the index of the next valid rocket from the current offset.
  1837. ** -------------------------------------------------------------------------- */
  1838. int FindNextValidRocket(int iIndex, bool bWrap = false)
  1839. {
  1840. for (int iCurrent = iIndex + 1; iCurrent < MAX_ROCKETS; iCurrent++)
  1841. if (IsValidRocket(iCurrent))
  1842. return iCurrent;
  1843.  
  1844. return (bWrap == true) ? FindNextValidRocket(-1, false) : -1;
  1845. }
  1846.  
  1847. /* FindFreeRocketSlot()
  1848. **
  1849. ** Retrieves the next free rocket slot since the current one. If all of them
  1850. ** are full, returns -1.
  1851. ** -------------------------------------------------------------------------- */
  1852. int FindFreeRocketSlot()
  1853. {
  1854. int iIndex = g_iLastCreatedRocket;
  1855. int iCurrent = iIndex;
  1856.  
  1857. do
  1858. {
  1859. if (!IsValidRocket(iCurrent))return iCurrent;
  1860. if ((++iCurrent) == MAX_ROCKETS)iCurrent = 0;
  1861. } while (iCurrent != iIndex);
  1862.  
  1863. return -1;
  1864. }
  1865.  
  1866. /* FindRocketByEntity()
  1867. **
  1868. ** Finds a rocket index from it's entity.
  1869. ** -------------------------------------------------------------------------- */
  1870. int FindRocketByEntity(int iEntity)
  1871. {
  1872. int iIndex = -1;
  1873. while ((iIndex = FindNextValidRocket(iIndex)) != -1)
  1874. if (EntRefToEntIndex(g_iRocketEntity[iIndex]) == iEntity)
  1875. return iIndex;
  1876.  
  1877. return -1;
  1878. }
  1879.  
  1880. /* HomingRocketThinkg()
  1881. **
  1882. ** Logic process for the Behaviour_Homing type rockets, wich is simply a
  1883. ** follower rocket, picking a random target.
  1884. ** -------------------------------------------------------------------------- */
  1885. void HomingRocketThink(int iIndex)
  1886. {
  1887. // Retrieve the rocket's attributes.
  1888. int iEntity = EntRefToEntIndex(g_iRocketEntity[iIndex]);
  1889. int iClass = g_iRocketClass[iIndex];
  1890. RocketFlags iFlags = g_iRocketFlags[iIndex];
  1891. int iTarget = EntRefToEntIndex(g_iRocketTarget[iIndex]);
  1892. int iTeam = GetEntProp(iEntity, Prop_Send, "m_iTeamNum", 1);
  1893. int iTargetTeam = (TestFlags(iFlags, RocketFlag_IsNeutral)) ? 0 : GetAnalogueTeam(iTeam);
  1894. int iDeflectionCount = GetEntProp(iEntity, Prop_Send, "m_iDeflected") - 1;
  1895. float fModifier = CalculateModifier(iClass, iDeflectionCount);
  1896.  
  1897. // Check if the target is available
  1898. if (!IsValidClient(iTarget, true))
  1899. {
  1900. iTarget = SelectTarget(iTargetTeam);
  1901. if (!IsValidClient(iTarget, true))return;
  1902. g_iRocketTarget[iIndex] = EntIndexToEntRef(iTarget);
  1903.  
  1904. if (GetConVarBool(g_hCvarRedirectBeep))
  1905. {
  1906. EmitRocketSound(RocketSound_Alert, iClass, iEntity, iTarget, iFlags);
  1907. }
  1908. }
  1909. // Has the rocket been deflected recently? If so, set new target.
  1910. else if ((iDeflectionCount > g_iRocketDeflections[iIndex]))
  1911. {
  1912. // Calculate new direction from the player's forward
  1913. int iClient = GetEntPropEnt(iEntity, Prop_Send, "m_hOwnerEntity");
  1914. if (IsValidClient(iClient))
  1915. {
  1916. float fViewAngles[3];
  1917. float fDirection[3];
  1918. GetClientEyeAngles(iClient, fViewAngles);
  1919. GetAngleVectors(fViewAngles, fDirection, NULL_VECTOR, NULL_VECTOR);
  1920. CopyVectors(fDirection, g_fRocketDirection[iIndex]);
  1921. UpdateRocketSkin(iEntity, iTeam, TestFlags(iFlags, RocketFlag_IsNeutral));
  1922. if (GetConVarBool(g_hCvarStealPrevention))
  1923. {
  1924. checkStolenRocket(iClient, iIndex);
  1925. }
  1926. }
  1927.  
  1928. // Set new target & deflection count
  1929. iTarget = SelectTarget(iTargetTeam, iIndex);
  1930. g_iRocketTarget[iIndex] = EntIndexToEntRef(iTarget);
  1931. g_iRocketDeflections[iIndex] = iDeflectionCount;
  1932. g_fRocketLastDeflectionTime[iIndex] = GetGameTime();
  1933. g_fRocketSpeed[iIndex] = CalculateRocketSpeed(iClass, fModifier);
  1934. g_iRocketSpeed = RoundFloat(g_fRocketSpeed[iIndex] * 0.042614);
  1935. g_bPreventingDelay = false;
  1936.  
  1937. SetEntDataFloat(iEntity, FindSendPropInfo("CTFProjectile_Rocket", "m_iDeflected") + 4, CalculateRocketDamage(iClass, fModifier), true);
  1938. if (TestFlags(iFlags, RocketFlag_ElevateOnDeflect))g_iRocketFlags[iIndex] |= RocketFlag_Elevating;
  1939. EmitRocketSound(RocketSound_Alert, iClass, iEntity, iTarget, iFlags);
  1940. //Send out temp entity to target
  1941. //SendTempEnt(iTarget, "superrare_greenenergy", iEntity, _, _, true);
  1942.  
  1943. // Execute appropiate command
  1944. if (TestFlags(iFlags, RocketFlag_OnDeflectCmd))
  1945. {
  1946. ExecuteCommands(g_hRocketClassCmdsOnDeflect[iClass], iClass, iEntity, iClient, iTarget, g_iLastDeadClient, g_fRocketSpeed[iIndex], iDeflectionCount);
  1947. }
  1948. }
  1949. else
  1950. {
  1951. // If the delay time since the last reflection has been elapsed, rotate towards the client.
  1952. if ((GetGameTime() - g_fRocketLastDeflectionTime[iIndex]) >= g_fRocketClassControlDelay[iClass])
  1953. {
  1954. // Calculate turn rate and retrieve directions.
  1955. float fTurnRate = CalculateRocketTurnRate(iClass, fModifier);
  1956. float fDirectionToTarget[3]; CalculateDirectionToClient(iEntity, iTarget, fDirectionToTarget);
  1957.  
  1958. // Elevate the rocket after a deflection (if it's enabled on the class definition, of course.)
  1959. if (g_iRocketFlags[iIndex] & RocketFlag_Elevating)
  1960. {
  1961. if (g_fRocketDirection[iIndex][2] < g_fRocketClassElevationLimit[iClass])
  1962. {
  1963. g_fRocketDirection[iIndex][2] = FMin(g_fRocketDirection[iIndex][2] + g_fRocketClassElevationRate[iClass], g_fRocketClassElevationLimit[iClass]);
  1964. fDirectionToTarget[2] = g_fRocketDirection[iIndex][2];
  1965. }
  1966. else
  1967. {
  1968. g_iRocketFlags[iIndex] &= ~RocketFlag_Elevating;
  1969. }
  1970. }
  1971.  
  1972. // Smoothly change the orientation to the new one.
  1973. LerpVectors(g_fRocketDirection[iIndex], fDirectionToTarget, g_fRocketDirection[iIndex], fTurnRate);
  1974. }
  1975.  
  1976. // If it's a nuke, beep every some time
  1977. if ((GetGameTime() - g_fRocketLastBeepTime[iIndex]) >= g_fRocketClassBeepInterval[iClass])
  1978. {
  1979. g_bRocketIsNuke[iIndex] = true;
  1980. EmitRocketSound(RocketSound_Beep, iClass, iEntity, iTarget, iFlags);
  1981. g_fRocketLastBeepTime[iIndex] = GetGameTime();
  1982. }
  1983.  
  1984. if (GetConVarBool(g_hCvarDelayPrevention))
  1985. {
  1986. checkRoundDelays(iIndex);
  1987. }
  1988. }
  1989.  
  1990. // Done
  1991. ApplyRocketParameters(iIndex);
  1992. }
  1993.  
  1994. /* CalculateModifier()
  1995. **
  1996. ** Gets the modifier for the damage/speed/rotation calculations.
  1997. ** -------------------------------------------------------------------------- */
  1998. float CalculateModifier(int iClass, int iDeflections)
  1999. {
  2000. return iDeflections +
  2001. (g_iRocketsFired * g_fRocketClassRocketsModifier[iClass]) +
  2002. (g_iPlayerCount * g_fRocketClassPlayerModifier[iClass]);
  2003. }
  2004.  
  2005. /* CalculateRocketDamage()
  2006. **
  2007. ** Calculates the damage of the rocket based on it's type and deflection count.
  2008. ** -------------------------------------------------------------------------- */
  2009. float CalculateRocketDamage(int iClass, float fModifier)
  2010. {
  2011. return g_fRocketClassDamage[iClass] + g_fRocketClassDamageIncrement[iClass] * fModifier;
  2012. }
  2013.  
  2014. /* CalculateRocketSpeed()
  2015. **
  2016. ** Calculates the speed of the rocket based on it's type and deflection count.
  2017. ** -------------------------------------------------------------------------- */
  2018. float CalculateRocketSpeed(int iClass, float fModifier)
  2019. {
  2020. return g_fRocketClassSpeed[iClass] + g_fRocketClassSpeedIncrement[iClass] * fModifier;
  2021. }
  2022.  
  2023. /* CalculateRocketTurnRate()
  2024. **
  2025. ** Calculates the rocket's turn rate based upon it's type and deflection count.
  2026. ** -------------------------------------------------------------------------- */
  2027. float CalculateRocketTurnRate(int iClass, float fModifier)
  2028. {
  2029. return g_fRocketClassTurnRate[iClass] + g_fRocketClassTurnRateIncrement[iClass] * fModifier;
  2030. }
  2031.  
  2032. /* CalculateDirectionToClient()
  2033. **
  2034. ** As the name indicates, calculates the orientation for the rocket to move
  2035. ** towards the specified client.
  2036. ** -------------------------------------------------------------------------- */
  2037. void CalculateDirectionToClient(int iEntity, int iClient, float fOut[3])
  2038. {
  2039. float fRocketPosition[3]; GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fRocketPosition);
  2040. GetClientEyePosition(iClient, fOut);
  2041. MakeVectorFromPoints(fRocketPosition, fOut, fOut);
  2042. NormalizeVector(fOut, fOut);
  2043. }
  2044.  
  2045. /* ApplyRocketParameters()
  2046. **
  2047. ** Transforms and applies the speed, direction and angles for the rocket
  2048. ** entity.
  2049. ** -------------------------------------------------------------------------- */
  2050. void ApplyRocketParameters(int iIndex)
  2051. {
  2052. int iEntity = EntRefToEntIndex(g_iRocketEntity[iIndex]);
  2053. float fAngles[3]; GetVectorAngles(g_fRocketDirection[iIndex], fAngles);
  2054. float fVelocity[3]; CopyVectors(g_fRocketDirection[iIndex], fVelocity);
  2055. ScaleVector(fVelocity, g_fRocketSpeed[iIndex]);
  2056. SetEntPropVector(iEntity, Prop_Data, "m_vecAbsVelocity", fVelocity);
  2057. SetEntPropVector(iEntity, Prop_Send, "m_angRotation", fAngles);
  2058. }
  2059.  
  2060. /* UpdateRocketSkin()
  2061. **
  2062. ** Changes the skin of the rocket based on it's team.
  2063. ** -------------------------------------------------------------------------- */
  2064. void UpdateRocketSkin(int iEntity, int iTeam, bool bNeutral)
  2065. {
  2066. if (bNeutral == true)SetEntProp(iEntity, Prop_Send, "m_nSkin", 2);
  2067. else SetEntProp(iEntity, Prop_Send, "m_nSkin", (iTeam == view_as<int>(TFTeam_Blue)) ? 0 : 1);
  2068. }
  2069.  
  2070. /* GetRandomRocketClass()
  2071. **
  2072. ** Generates a random value and retrieves a rocket class based upon a chances table.
  2073. ** -------------------------------------------------------------------------- */
  2074. int GetRandomRocketClass(int iSpawnerClass)
  2075. {
  2076. int iRandom = GetURandomIntRange(0, 101);
  2077. Handle hTable = g_hSpawnersChancesTable[iSpawnerClass];
  2078. int iTableSize = GetArraySize(hTable);
  2079. int iChancesLower = 0;
  2080. int iChancesUpper = 0;
  2081.  
  2082. for (int iEntry = 0; iEntry < iTableSize; iEntry++)
  2083. {
  2084. iChancesLower += iChancesUpper;
  2085. iChancesUpper = iChancesLower + GetArrayCell(hTable, iEntry);
  2086.  
  2087. if ((iRandom >= iChancesLower) && (iRandom < iChancesUpper))
  2088. {
  2089. return iEntry;
  2090. }
  2091. }
  2092.  
  2093. return 0;
  2094. }
  2095.  
  2096. /* EmitRocketSound()
  2097. **
  2098. ** Emits one of the rocket sounds
  2099. ** -------------------------------------------------------------------------- */
  2100. void EmitRocketSound(RocketSound iSound, int iClass, int iEntity, int iTarget, RocketFlags iFlags)
  2101. {
  2102. switch (iSound)
  2103. {
  2104. case RocketSound_Spawn:
  2105. {
  2106. if (TestFlags(iFlags, RocketFlag_PlaySpawnSound))
  2107. {
  2108. if (TestFlags(iFlags, RocketFlag_CustomSpawnSound))EmitSoundToAll(g_strRocketClassSpawnSound[iClass], iEntity);
  2109. else EmitSoundToAll(SOUND_DEFAULT_SPAWN, iEntity);
  2110. }
  2111. }
  2112. case RocketSound_Beep:
  2113. {
  2114. if (TestFlags(iFlags, RocketFlag_PlayBeepSound))
  2115. {
  2116. if (TestFlags(iFlags, RocketFlag_CustomBeepSound))EmitSoundToAll(g_strRocketClassBeepSound[iClass], iEntity);
  2117. else EmitSoundToAll(SOUND_DEFAULT_BEEP, iEntity);
  2118. }
  2119. }
  2120. case RocketSound_Alert:
  2121. {
  2122. if (TestFlags(iFlags, RocketFlag_PlayAlertSound))
  2123. {
  2124. if (TestFlags(iFlags, RocketFlag_CustomAlertSound))EmitSoundToClient(iTarget, g_strRocketClassAlertSound[iClass]);
  2125. else EmitSoundToClient(iTarget, SOUND_DEFAULT_ALERT, _, _, _, _, 0.5);
  2126. }
  2127. }
  2128. }
  2129. }
  2130.  
  2131. // ___ _ _ ___ _
  2132. // | _ \___ __| |_____| |_ / __| |__ _ ______ ___ ___
  2133. // | / _ \/ _| / / -_) _| | (__| / _` (_-<_-</ -_|_-<
  2134. // |_|_\___/\__|_\_\___|\__| \___|_\__,_/__/__/\___/__/
  2135. //
  2136.  
  2137. /* DestroyRocketClasses()
  2138. **
  2139. ** Frees up all the rocket classes defined now.
  2140. ** -------------------------------------------------------------------------- */
  2141. void DestroyRocketClasses()
  2142. {
  2143. for (int iIndex = 0; iIndex < g_iRocketClassCount; iIndex++)
  2144. {
  2145. Handle hCmdOnSpawn = g_hRocketClassCmdsOnSpawn[iIndex];
  2146. Handle hCmdOnKill = g_hRocketClassCmdsOnKill[iIndex];
  2147. Handle hCmdOnExplode = g_hRocketClassCmdsOnExplode[iIndex];
  2148. Handle hCmdOnDeflect = g_hRocketClassCmdsOnDeflect[iIndex];
  2149. if (hCmdOnSpawn != INVALID_HANDLE)CloseHandle(hCmdOnSpawn);
  2150. if (hCmdOnKill != INVALID_HANDLE)CloseHandle(hCmdOnKill);
  2151. if (hCmdOnExplode != INVALID_HANDLE)CloseHandle(hCmdOnExplode);
  2152. if (hCmdOnDeflect != INVALID_HANDLE)CloseHandle(hCmdOnDeflect);
  2153. g_hRocketClassCmdsOnSpawn[iIndex] = INVALID_HANDLE;
  2154. g_hRocketClassCmdsOnKill[iIndex] = INVALID_HANDLE;
  2155. g_hRocketClassCmdsOnExplode[iIndex] = INVALID_HANDLE;
  2156. g_hRocketClassCmdsOnDeflect[iIndex] = INVALID_HANDLE;
  2157. }
  2158. g_iRocketClassCount = 0;
  2159. ClearTrie(g_hRocketClassTrie);
  2160. }
  2161.  
  2162. // ___ ___ _ _ _ ___ _
  2163. // / __|_ __ __ ___ __ ___ _ | _ \___(_)_ _| |_ ___ __ _ _ _ __| | / __| |__ _ ______ ___ ___
  2164. // \__ \ '_ \/ _` \ V V / ' \ | _/ _ \ | ' \ _(_-< / _` | ' \/ _` | | (__| / _` (_-<_-</ -_|_-<
  2165. // |___/ .__/\__,_|\_/\_/|_||_| |_| \___/_|_||_\__/__/ \__,_|_||_\__,_| \___|_\__,_/__/__/\___/__/
  2166. // |_|
  2167.  
  2168. /* DestroySpawners()
  2169. **
  2170. ** Frees up all the spawner points defined up to now.
  2171. ** -------------------------------------------------------------------------- */
  2172. void DestroySpawners()
  2173. {
  2174. for (int iIndex = 0; iIndex < g_iSpawnersCount; iIndex++)
  2175. {
  2176. CloseHandle(g_hSpawnersChancesTable[iIndex]);
  2177. }
  2178. g_iSpawnersCount = 0;
  2179. g_iSpawnPointsRedCount = 0;
  2180. g_iSpawnPointsBluCount = 0;
  2181. g_iDefaultRedSpawner = -1;
  2182. g_iDefaultBluSpawner = -1;
  2183. g_strSavedClassName[0] = '\0';
  2184. ClearTrie(g_hSpawnersTrie);
  2185. }
  2186.  
  2187. /* PopulateSpawnPoints()
  2188. **
  2189. ** Iterates through all the possible spawn points and assigns them an spawner.
  2190. ** -------------------------------------------------------------------------- */
  2191. void PopulateSpawnPoints()
  2192. {
  2193. // Clear the current settings
  2194. g_iSpawnPointsRedCount = 0;
  2195. g_iSpawnPointsBluCount = 0;
  2196.  
  2197. // Iterate through all the info target points and check 'em out.
  2198. int iEntity = -1;
  2199. while ((iEntity = FindEntityByClassname(iEntity, "info_target")) != -1)
  2200. {
  2201. char strName[32]; GetEntPropString(iEntity, Prop_Data, "m_iName", strName, sizeof(strName));
  2202. if ((StrContains(strName, "rocket_spawn_red") != -1) || (StrContains(strName, "tf_dodgeball_red") != -1))
  2203. {
  2204. // Find most appropiate spawner class for this entity.
  2205. int iIndex = FindSpawnerByName(strName);
  2206. if (!IsValidRocket(iIndex)) iIndex = g_iDefaultRedSpawner;
  2207.  
  2208. // Upload to point list
  2209. g_iSpawnPointsRedClass[g_iSpawnPointsRedCount] = iIndex;
  2210. g_iSpawnPointsRedEntity[g_iSpawnPointsRedCount] = iEntity;
  2211. g_iSpawnPointsRedCount++;
  2212. }
  2213. if ((StrContains(strName, "rocket_spawn_blue") != -1) || (StrContains(strName, "tf_dodgeball_blu") != -1))
  2214. {
  2215. // Find most appropiate spawner class for this entity.
  2216. int iIndex = FindSpawnerByName(strName);
  2217. if (!IsValidRocket(iIndex))iIndex = g_iDefaultBluSpawner;
  2218.  
  2219. // Upload to point list
  2220. g_iSpawnPointsBluClass[g_iSpawnPointsBluCount] = iIndex;
  2221. g_iSpawnPointsBluEntity[g_iSpawnPointsBluCount] = iEntity;
  2222. g_iSpawnPointsBluCount++;
  2223. }
  2224. }
  2225.  
  2226. // Check if there exists spawn points
  2227. if (g_iSpawnPointsRedCount == 0)
  2228. SetFailState("No RED spawn points found on this map.");
  2229.  
  2230. if (g_iSpawnPointsBluCount == 0)
  2231. SetFailState("No BLU spawn points found on this map.");
  2232.  
  2233.  
  2234. //ObserverPoint
  2235. float opPos[3];
  2236. float opAng[3];
  2237.  
  2238. int spawner = GetRandomInt(0, 1);
  2239. if (spawner == 0)
  2240. spawner = g_iSpawnPointsRedEntity[0];
  2241. else
  2242. spawner = g_iSpawnPointsBluEntity[0];
  2243.  
  2244. if (IsValidEntity(spawner) && spawner > MAXPLAYERS)
  2245. {
  2246. GetEntPropVector(spawner, Prop_Data, "m_vecOrigin", opPos);
  2247. GetEntPropVector(spawner, Prop_Data, "m_angAbsRotation", opAng);
  2248. g_observer = CreateEntityByName("info_observer_point");
  2249. DispatchKeyValue(g_observer, "Angles", "90 0 0");
  2250. DispatchKeyValue(g_observer, "TeamNum", "0");
  2251. DispatchKeyValue(g_observer, "StartDisabled", "0");
  2252. DispatchSpawn(g_observer);
  2253. AcceptEntityInput(g_observer, "Enable");
  2254. TeleportEntity(g_observer, opPos, opAng, NULL_VECTOR);
  2255. }
  2256. else
  2257. {
  2258. g_observer = -1;
  2259. }
  2260.  
  2261. }
  2262.  
  2263. /* FindSpawnerByName()
  2264. **
  2265. ** Finds the first spawner wich contains the given name.
  2266. ** -------------------------------------------------------------------------- */
  2267. int FindSpawnerByName(char strName[32])
  2268. {
  2269. int iIndex = -1;
  2270. GetTrieValue(g_hSpawnersTrie, strName, iIndex);
  2271. return iIndex;
  2272. }
  2273.  
  2274.  
  2275. /*
  2276. **����������������������������������������������������������������������������������
  2277. ** ______ __
  2278. ** / ____/___ ____ ___ ____ ___ ____ _____ ____/ /____
  2279. ** / / / __ \/ __ `__ \/ __ `__ \/ __ `/ __ \/ __ / ___/
  2280. ** / /___/ /_/ / / / / / / / / / / / /_/ / / / / /_/ (__ )
  2281. ** \____/\____/_/ /_/ /_/_/ /_/ /_/\__,_/_/ /_/\__,_/____/
  2282. **
  2283. **����������������������������������������������������������������������������������
  2284. */
  2285.  
  2286. /* RegisterCommands()
  2287. **
  2288. ** Creates helper server commands to use with the plugin's events system.
  2289. ** -------------------------------------------------------------------------- */
  2290. void RegisterCommands()
  2291. {
  2292. RegServerCmd("tf_dodgeball_explosion", CmdExplosion);
  2293. RegServerCmd("tf_dodgeball_shockwave", CmdShockwave);
  2294. RegServerCmd("tf_dodgeball_resize", CmdResize);
  2295. }
  2296.  
  2297. public Action CmdResize(int iIndex)
  2298. {
  2299. int iEntity = EntRefToEntIndex(g_iRocketEntity[iIndex]);
  2300. if (iEntity && IsValidEntity(iEntity) && g_bRocketIsNuke[iEntity])
  2301. {
  2302. SetEntPropFloat(iEntity, Prop_Send, "m_flModelScale", (4.0));
  2303. }
  2304. }
  2305.  
  2306. /* CmdExplosion()
  2307. **
  2308. ** Creates a huge explosion at the location of the client.
  2309. ** -------------------------------------------------------------------------- */
  2310. public Action CmdExplosion(int iArgs)
  2311. {
  2312. if (iArgs == 1)
  2313. {
  2314. char strBuffer[8], iClient;
  2315. GetCmdArg(1, strBuffer, sizeof(strBuffer));
  2316. iClient = StringToInt(strBuffer);
  2317. if (IsValidEntity(iClient))
  2318. {
  2319. float fPosition[3];
  2320. GetClientAbsOrigin(iClient, fPosition);
  2321. switch (GetURandomIntRange(0, 4))
  2322. {
  2323. case 0:
  2324. {
  2325. PlayParticle(fPosition, PARTICLE_NUKE_1_ANGLES, PARTICLE_NUKE_1);
  2326. }
  2327. case 1:
  2328. {
  2329. PlayParticle(fPosition, PARTICLE_NUKE_2_ANGLES, PARTICLE_NUKE_2);
  2330. }
  2331. case 2:
  2332. {
  2333. PlayParticle(fPosition, PARTICLE_NUKE_3_ANGLES, PARTICLE_NUKE_3);
  2334. }
  2335. case 3:
  2336. {
  2337. PlayParticle(fPosition, PARTICLE_NUKE_4_ANGLES, PARTICLE_NUKE_4);
  2338. }
  2339. case 4:
  2340. {
  2341. PlayParticle(fPosition, PARTICLE_NUKE_5_ANGLES, PARTICLE_NUKE_5);
  2342. }
  2343. }
  2344. PlayParticle(fPosition, PARTICLE_NUKE_COLLUMN_ANGLES, PARTICLE_NUKE_COLLUMN);
  2345. }
  2346. }
  2347. else
  2348. {
  2349. PrintToServer("Usage: tf_dodgeball_explosion <client index>");
  2350. }
  2351.  
  2352. return Plugin_Handled;
  2353. }
  2354.  
  2355. /* CmdShockwave()
  2356. **
  2357. ** Creates a huge shockwave at the location of the client, with the given
  2358. ** parameters.
  2359. ** -------------------------------------------------------------------------- */
  2360. public Action CmdShockwave(int iArgs)
  2361. {
  2362. if (iArgs == 5)
  2363. {
  2364. char strBuffer[8];
  2365. int iClient;
  2366. int iTeam;
  2367. float fPosition[3];
  2368. int iDamage;
  2369. float fPushStrength;
  2370. float fRadius;
  2371. float fFalloffRadius;
  2372. GetCmdArg(1, strBuffer, sizeof(strBuffer)); iClient = StringToInt(strBuffer);
  2373. GetCmdArg(2, strBuffer, sizeof(strBuffer)); iDamage = StringToInt(strBuffer);
  2374. GetCmdArg(3, strBuffer, sizeof(strBuffer)); fPushStrength = StringToFloat(strBuffer);
  2375. GetCmdArg(4, strBuffer, sizeof(strBuffer)); fRadius = StringToFloat(strBuffer);
  2376. GetCmdArg(5, strBuffer, sizeof(strBuffer)); fFalloffRadius = StringToFloat(strBuffer);
  2377.  
  2378. if (IsValidClient(iClient))
  2379. {
  2380. iTeam = GetClientTeam(iClient);
  2381. GetClientAbsOrigin(iClient, fPosition);
  2382.  
  2383. for (iClient = 1; iClient <= MaxClients; iClient++)
  2384. {
  2385. if ((IsValidClient(iClient, true) == true) && (GetClientTeam(iClient) == iTeam))
  2386. {
  2387. float fPlayerPosition[3]; GetClientEyePosition(iClient, fPlayerPosition);
  2388. float fDistanceToShockwave = GetVectorDistance(fPosition, fPlayerPosition);
  2389.  
  2390. if (fDistanceToShockwave < fRadius)
  2391. {
  2392. float fImpulse[3];
  2393. float fFinalPush;
  2394. int iFinalDamage;
  2395. fImpulse[0] = fPlayerPosition[0] - fPosition[0];
  2396. fImpulse[1] = fPlayerPosition[1] - fPosition[1];
  2397. fImpulse[2] = fPlayerPosition[2] - fPosition[2];
  2398. NormalizeVector(fImpulse, fImpulse);
  2399. if (fImpulse[2] < 0.4) { fImpulse[2] = 0.4; NormalizeVector(fImpulse, fImpulse); }
  2400.  
  2401. if (fDistanceToShockwave < fFalloffRadius)
  2402. {
  2403. fFinalPush = fPushStrength;
  2404. iFinalDamage = iDamage;
  2405. }
  2406. else
  2407. {
  2408. float fImpact = (1.0 - ((fDistanceToShockwave - fFalloffRadius) / (fRadius - fFalloffRadius)));
  2409. fFinalPush = fImpact * fPushStrength;
  2410. iFinalDamage = RoundToFloor(fImpact * iDamage);
  2411. }
  2412. ScaleVector(fImpulse, fFinalPush);
  2413. SetEntPropVector(iClient, Prop_Data, "m_vecAbsVelocity", fImpulse);
  2414.  
  2415. Handle hDamage = CreateDataPack();
  2416. WritePackCell(hDamage, iClient);
  2417. WritePackCell(hDamage, iFinalDamage);
  2418. CreateTimer(0.1, ApplyDamage, hDamage, TIMER_FLAG_NO_MAPCHANGE);
  2419. }
  2420. }
  2421. }
  2422. }
  2423. }
  2424. else
  2425. {
  2426. PrintToServer("Usage: tf_dodgeball_shockwave <client index> <damage> <push strength> <radius> <falloff>");
  2427. }
  2428.  
  2429. return Plugin_Handled;
  2430. }
  2431.  
  2432. /* ExecuteCommands()
  2433. **
  2434. ** The core of the plugin's event system, unpacks and correctly formats the
  2435. ** given command strings to be executed.
  2436. ** -------------------------------------------------------------------------- */
  2437. void ExecuteCommands(Handle hDataPack, int iClass, int iRocket, int iOwner, int iTarget, int iLastDead, float fSpeed, int iNumDeflections)
  2438. {
  2439. ResetPack(hDataPack, false);
  2440. int iNumCommands = ReadPackCell(hDataPack);
  2441. while (iNumCommands-- > 0)
  2442. {
  2443. char strCmd[256];
  2444. char strBuffer[8];
  2445. ReadPackString(hDataPack, strCmd, sizeof(strCmd));
  2446. ReplaceString(strCmd, sizeof(strCmd), "@name", g_strRocketClassLongName[iClass]);
  2447. Format(strBuffer, sizeof(strBuffer), "%i", iRocket); ReplaceString(strCmd, sizeof(strCmd), "@rocket", strBuffer);
  2448. Format(strBuffer, sizeof(strBuffer), "%i", iOwner); ReplaceString(strCmd, sizeof(strCmd), "@owner", strBuffer);
  2449. Format(strBuffer, sizeof(strBuffer), "%i", iTarget); ReplaceString(strCmd, sizeof(strCmd), "@target", strBuffer);
  2450. Format(strBuffer, sizeof(strBuffer), "%i", iLastDead); ReplaceString(strCmd, sizeof(strCmd), "@dead", strBuffer);
  2451. Format(strBuffer, sizeof(strBuffer), "%f", fSpeed); ReplaceString(strCmd, sizeof(strCmd), "@speed", strBuffer);
  2452. Format(strBuffer, sizeof(strBuffer), "%i", iNumDeflections); ReplaceString(strCmd, sizeof(strCmd), "@deflections", strBuffer);
  2453. ServerCommand(strCmd);
  2454. }
  2455. }
  2456.  
  2457. /*
  2458. **����������������������������������������������������������������������������������
  2459. ** ______ _____
  2460. ** / ____/___ ____ / __(_)___ _
  2461. ** / / / __ \/ __ \/ /_/ / __ `/
  2462. ** / /___/ /_/ / / / / __/ / /_/ /
  2463. ** \____/\____/_/ /_/_/ /_/\__, /
  2464. ** /____/
  2465. **����������������������������������������������������������������������������������
  2466. */
  2467.  
  2468. /* ParseConfiguration()
  2469. **
  2470. ** Parses a Dodgeball configuration file. It doesn't clear any of the previous
  2471. ** data, so multiple files can be parsed.
  2472. ** -------------------------------------------------------------------------- */
  2473. bool ParseConfigurations(char strConfigFile[] = "general.cfg")
  2474. {
  2475. // Parse configuration
  2476. char strPath[PLATFORM_MAX_PATH];
  2477. char strFileName[PLATFORM_MAX_PATH];
  2478. Format(strFileName, sizeof(strFileName), "configs/dodgeball/%s", strConfigFile);
  2479. BuildPath(Path_SM, strPath, sizeof(strPath), strFileName);
  2480.  
  2481. // Try to parse if it exists
  2482. LogMessage("Executing configuration file %s", strPath);
  2483. if (FileExists(strPath, true))
  2484. {
  2485. KeyValues kvConfig = CreateKeyValues("TF2_Dodgeball");
  2486.  
  2487. if (FileToKeyValues(kvConfig, strPath) == false)
  2488. SetFailState("Error while parsing the configuration file.");
  2489.  
  2490. kvConfig.GotoFirstSubKey();
  2491.  
  2492. // Parse the subsections
  2493. do
  2494. {
  2495. char strSection[64];
  2496. KvGetSectionName(kvConfig, strSection, sizeof(strSection));
  2497.  
  2498. if (StrEqual(strSection, "general"))
  2499. ParseGeneral(kvConfig);
  2500. else if (StrEqual(strSection, "classes"))
  2501. ParseClasses(kvConfig);
  2502. else if (StrEqual(strSection, "spawners"))
  2503. ParseSpawners(kvConfig);
  2504. }
  2505. while (KvGotoNextKey(kvConfig));
  2506.  
  2507. CloseHandle(kvConfig);
  2508. }
  2509. }
  2510.  
  2511. /* ParseGeneral()
  2512. **
  2513. ** Parses general settings, such as the music, urls, etc.
  2514. ** -------------------------------------------------------------------------- */
  2515. void ParseGeneral(Handle kvConfig)
  2516. {
  2517. g_bMusicEnabled = view_as<bool>(KvGetNum(kvConfig, "music", 0));
  2518. if (g_bMusicEnabled == true)
  2519. {
  2520. g_bUseWebPlayer = view_as<bool>(KvGetNum(kvConfig, "use web player", 0));
  2521. KvGetString(kvConfig, "web player url", g_strWebPlayerUrl, sizeof(g_strWebPlayerUrl));
  2522.  
  2523. g_bMusic[Music_RoundStart] = KvGetString(kvConfig, "round start", g_strMusic[Music_RoundStart], PLATFORM_MAX_PATH) && strlen(g_strMusic[Music_RoundStart]);
  2524. g_bMusic[Music_RoundWin] = KvGetString(kvConfig, "round end (win)", g_strMusic[Music_RoundWin], PLATFORM_MAX_PATH) && strlen(g_strMusic[Music_RoundWin]);
  2525. g_bMusic[Music_RoundLose] = KvGetString(kvConfig, "round end (lose)", g_strMusic[Music_RoundLose], PLATFORM_MAX_PATH) && strlen(g_strMusic[Music_RoundLose]);
  2526. g_bMusic[Music_Gameplay] = KvGetString(kvConfig, "gameplay", g_strMusic[Music_Gameplay], PLATFORM_MAX_PATH) && strlen(g_strMusic[Music_Gameplay]);
  2527. }
  2528. }
  2529.  
  2530. /* ParseClasses()
  2531. **
  2532. ** Parses the rocket classes data from the given configuration file.
  2533. ** -------------------------------------------------------------------------- */
  2534. void ParseClasses(Handle kvConfig)
  2535. {
  2536. char strName[64];
  2537. char strBuffer[256];
  2538.  
  2539. KvGotoFirstSubKey(kvConfig);
  2540. do
  2541. {
  2542. int iIndex = g_iRocketClassCount;
  2543. RocketFlags iFlags;
  2544.  
  2545. // Basic parameters
  2546. KvGetSectionName(kvConfig, strName, sizeof(strName)); strcopy(g_strRocketClassName[iIndex], 16, strName);
  2547. KvGetString(kvConfig, "name", strBuffer, sizeof(strBuffer)); strcopy(g_strRocketClassLongName[iIndex], 32, strBuffer);
  2548. if (KvGetString(kvConfig, "model", strBuffer, sizeof(strBuffer)))
  2549. {
  2550. strcopy(g_strRocketClassModel[iIndex], PLATFORM_MAX_PATH, strBuffer);
  2551. if (strlen(g_strRocketClassModel[iIndex]) != 0)
  2552. {
  2553. iFlags |= RocketFlag_CustomModel;
  2554. if (KvGetNum(kvConfig, "is animated", 0))iFlags |= RocketFlag_IsAnimated;
  2555. }
  2556. }
  2557.  
  2558. KvGetString(kvConfig, "behaviour", strBuffer, sizeof(strBuffer), "homing");
  2559. if (StrEqual(strBuffer, "homing"))g_iRocketClassBehaviour[iIndex] = Behaviour_Homing;
  2560. else g_iRocketClassBehaviour[iIndex] = Behaviour_Unknown;
  2561.  
  2562. if (KvGetNum(kvConfig, "play spawn sound", 0) == 1)
  2563. {
  2564. iFlags |= RocketFlag_PlaySpawnSound;
  2565. if (KvGetString(kvConfig, "spawn sound", g_strRocketClassSpawnSound[iIndex], PLATFORM_MAX_PATH) && (strlen(g_strRocketClassSpawnSound[iIndex]) != 0))
  2566. {
  2567. iFlags |= RocketFlag_CustomSpawnSound;
  2568. }
  2569. }
  2570.  
  2571. if (KvGetNum(kvConfig, "play beep sound", 0) == 1)
  2572. {
  2573. iFlags |= RocketFlag_PlayBeepSound;
  2574. g_fRocketClassBeepInterval[iIndex] = KvGetFloat(kvConfig, "beep interval", 0.5);
  2575. if (KvGetString(kvConfig, "beep sound", g_strRocketClassBeepSound[iIndex], PLATFORM_MAX_PATH) && (strlen(g_strRocketClassBeepSound[iIndex]) != 0))
  2576. {
  2577. iFlags |= RocketFlag_CustomBeepSound;
  2578. }
  2579. }
  2580.  
  2581. if (KvGetNum(kvConfig, "play alert sound", 0) == 1)
  2582. {
  2583. iFlags |= RocketFlag_PlayAlertSound;
  2584. if (KvGetString(kvConfig, "alert sound", g_strRocketClassAlertSound[iIndex], PLATFORM_MAX_PATH) && strlen(g_strRocketClassAlertSound[iIndex]) != 0)
  2585. {
  2586. iFlags |= RocketFlag_CustomAlertSound;
  2587. }
  2588. }
  2589.  
  2590. // Behaviour modifiers
  2591. if (KvGetNum(kvConfig, "elevate on deflect", 1) == 1)iFlags |= RocketFlag_ElevateOnDeflect;
  2592. if (KvGetNum(kvConfig, "neutral rocket", 0) == 1)iFlags |= RocketFlag_IsNeutral;
  2593.  
  2594. // Movement parameters
  2595. g_fRocketClassDamage[iIndex] = KvGetFloat(kvConfig, "damage");
  2596. g_fRocketClassDamageIncrement[iIndex] = KvGetFloat(kvConfig, "damage increment");
  2597. g_fRocketClassCritChance[iIndex] = KvGetFloat(kvConfig, "critical chance");
  2598. g_fRocketClassSpeed[iIndex] = KvGetFloat(kvConfig, "speed");
  2599. g_fSavedSpeed = g_fRocketClassSpeed[iIndex];
  2600. g_fRocketClassSpeedIncrement[iIndex] = KvGetFloat(kvConfig, "speed increment");
  2601. g_fSavedSpeedIncrement = g_fRocketClassSpeedIncrement[iIndex];
  2602. g_fRocketClassTurnRate[iIndex] = KvGetFloat(kvConfig, "turn rate");
  2603. g_fRocketClassTurnRateIncrement[iIndex] = KvGetFloat(kvConfig, "turn rate increment");
  2604. g_fRocketClassElevationRate[iIndex] = KvGetFloat(kvConfig, "elevation rate");
  2605. g_fRocketClassElevationLimit[iIndex] = KvGetFloat(kvConfig, "elevation limit");
  2606. g_fRocketClassControlDelay[iIndex] = KvGetFloat(kvConfig, "control delay");
  2607. g_fRocketClassPlayerModifier[iIndex] = KvGetFloat(kvConfig, "no. players modifier");
  2608. g_fRocketClassRocketsModifier[iIndex] = KvGetFloat(kvConfig, "no. rockets modifier");
  2609. g_fRocketClassTargetWeight[iIndex] = KvGetFloat(kvConfig, "direction to target weight");
  2610.  
  2611. // Events
  2612. Handle hCmds = INVALID_HANDLE;
  2613. KvGetString(kvConfig, "on spawn", strBuffer, sizeof(strBuffer));
  2614. if ((hCmds = ParseCommands(strBuffer)) != INVALID_HANDLE) { iFlags |= RocketFlag_OnSpawnCmd; g_hRocketClassCmdsOnSpawn[iIndex] = hCmds; }
  2615. KvGetString(kvConfig, "on deflect", strBuffer, sizeof(strBuffer));
  2616. if ((hCmds = ParseCommands(strBuffer)) != INVALID_HANDLE) { iFlags |= RocketFlag_OnDeflectCmd; g_hRocketClassCmdsOnDeflect[iIndex] = hCmds; }
  2617. KvGetString(kvConfig, "on kill", strBuffer, sizeof(strBuffer));
  2618. if ((hCmds = ParseCommands(strBuffer)) != INVALID_HANDLE) { iFlags |= RocketFlag_OnKillCmd; g_hRocketClassCmdsOnKill[iIndex] = hCmds; }
  2619. KvGetString(kvConfig, "on explode", strBuffer, sizeof(strBuffer));
  2620. if ((hCmds = ParseCommands(strBuffer)) != INVALID_HANDLE) { iFlags |= RocketFlag_OnExplodeCmd; g_hRocketClassCmdsOnExplode[iIndex] = hCmds; }
  2621.  
  2622. // Done
  2623. SetTrieValue(g_hRocketClassTrie, strName, iIndex);
  2624. g_iRocketClassFlags[iIndex] = iFlags;
  2625. g_iRocketClassCount++;
  2626. }
  2627. while (KvGotoNextKey(kvConfig));
  2628. KvGoBack(kvConfig);
  2629. }
  2630.  
  2631. /* ParseSpawners()
  2632. **
  2633. ** Parses the spawn points classes data from the given configuration file.
  2634. ** -------------------------------------------------------------------------- */
  2635. void ParseSpawners(KeyValues kvConfig)
  2636. {
  2637. kvConfig.JumpToKey("spawners"); //jump to spawners section
  2638. char strBuffer[256];
  2639. kvConfig.GotoFirstSubKey(); //goto to first subkey of "spawners" section
  2640.  
  2641. do
  2642. {
  2643. int iIndex = g_iSpawnersCount;
  2644.  
  2645. // Basic parameters
  2646. kvConfig.GetSectionName(strBuffer, sizeof(strBuffer)); //okay, here we got section name, as example, red
  2647. strcopy(g_strSpawnersName[iIndex], 32, strBuffer); //here we copied it to the g_strSpawnersName array
  2648. g_iSpawnersMaxRockets[iIndex] = kvConfig.GetNum("max rockets", 1); //get some values...
  2649. g_fSpawnersInterval[iIndex] = kvConfig.GetFloat("interval", 1.0);
  2650.  
  2651. // Chances table
  2652. g_hSpawnersChancesTable[iIndex] = CreateArray(); //not interested in this
  2653. for (int iClassIndex = 0; iClassIndex < g_iRocketClassCount; iClassIndex++)
  2654. {
  2655. Format(strBuffer, sizeof(strBuffer), "%s%%", g_strRocketClassName[iClassIndex]);
  2656. PushArrayCell(g_hSpawnersChancesTable[iIndex], KvGetNum(kvConfig, strBuffer, 0));
  2657. if (KvGetNum(kvConfig, strBuffer, 0) == 100) strcopy(g_strSavedClassName, sizeof(g_strSavedClassName), g_strRocketClassLongName[iClassIndex]);
  2658. }
  2659.  
  2660. // Done.
  2661. SetTrieValue(g_hSpawnersTrie, g_strSpawnersName[iIndex], iIndex); //okay, push section name to g_hSpawnersTrie
  2662. g_iSpawnersCount++;
  2663. } while (kvConfig.GotoNextKey());
  2664.  
  2665. kvConfig.Rewind(); //rewind
  2666.  
  2667. GetTrieValue(g_hSpawnersTrie, "Red", g_iDefaultRedSpawner); //get value by section name, section name exists in the g_hSpawnersTrie, everything should work
  2668. GetTrieValue(g_hSpawnersTrie, "Blue", g_iDefaultBluSpawner);
  2669. }
  2670.  
  2671. /* ParseCommands()
  2672. **
  2673. ** Part of the event system, parses the given command strings and packs them
  2674. ** to a Datapack.
  2675. ** -------------------------------------------------------------------------- */
  2676. Handle ParseCommands(char[] strLine)
  2677. {
  2678. TrimString(strLine);
  2679. if (strlen(strLine) == 0)
  2680. {
  2681. return INVALID_HANDLE;
  2682. }
  2683. else
  2684. {
  2685. char strStrings[8][255];
  2686. int iNumStrings = ExplodeString(strLine, ";", strStrings, 8, 255);
  2687.  
  2688. Handle hDataPack = CreateDataPack();
  2689. WritePackCell(hDataPack, iNumStrings);
  2690. for (int i = 0; i < iNumStrings; i++)
  2691. {
  2692. WritePackString(hDataPack, strStrings[i]);
  2693. }
  2694.  
  2695. return hDataPack;
  2696. }
  2697. }
  2698.  
  2699. /*
  2700. **����������������������������������������������������������������������������������
  2701. ** ______ __
  2702. ** /_ __/___ ____ / /____
  2703. ** / / / __ \/ __ \/ / ___/
  2704. ** / / / /_/ / /_/ / (__ )
  2705. ** /_/ \____/\____/_/____/
  2706. **
  2707. **����������������������������������������������������������������������������������
  2708. */
  2709.  
  2710. /* ApplyDamage()
  2711. **
  2712. ** Applies a damage to a player.
  2713. ** -------------------------------------------------------------------------- */
  2714. public Action ApplyDamage(Handle hTimer, any hDataPack)
  2715. {
  2716. ResetPack(hDataPack, false);
  2717. int iClient = ReadPackCell(hDataPack);
  2718. int iDamage = ReadPackCell(hDataPack);
  2719. CloseHandle(hDataPack);
  2720. SlapPlayer(iClient, iDamage, true);
  2721. }
  2722.  
  2723. /* CopyVectors()
  2724. **
  2725. ** Copies the contents from a vector to another.
  2726. ** -------------------------------------------------------------------------- */
  2727. stock void CopyVectors(float fFrom[3], float fTo[3])
  2728. {
  2729. fTo[0] = fFrom[0];
  2730. fTo[1] = fFrom[1];
  2731. fTo[2] = fFrom[2];
  2732. }
  2733.  
  2734. /* LerpVectors()
  2735. **
  2736. ** Calculates the linear interpolation of the two given vectors and stores
  2737. ** it on the third one.
  2738. ** -------------------------------------------------------------------------- */
  2739. stock void LerpVectors(float fA[3], float fB[3], float fC[3], float t)
  2740. {
  2741. if (t < 0.0)t = 0.0;
  2742. if (t > 1.0)t = 1.0;
  2743.  
  2744. fC[0] = fA[0] + (fB[0] - fA[0]) * t;
  2745. fC[1] = fA[1] + (fB[1] - fA[1]) * t;
  2746. fC[2] = fA[2] + (fB[2] - fA[2]) * t;
  2747. }
  2748.  
  2749. /* IsValidClient()
  2750. **
  2751. ** Checks if the given client index is valid, and if it's alive or not.
  2752. ** -------------------------------------------------------------------------- */
  2753. stock bool IsValidClient(int iClient, bool bAlive = false)
  2754. {
  2755. if (iClient >= 1 &&
  2756. iClient <= MaxClients &&
  2757. IsClientConnected(iClient) &&
  2758. IsClientInGame(iClient) &&
  2759. (bAlive == false || IsPlayerAlive(iClient)))
  2760. {
  2761. return true;
  2762. }
  2763.  
  2764. return false;
  2765. }
  2766.  
  2767. /* BothTeamsPlaying()
  2768. **
  2769. ** Checks if there are players on both teams.
  2770. ** -------------------------------------------------------------------------- */
  2771. stock bool BothTeamsPlaying()
  2772. {
  2773. bool bRedFound;
  2774. bool bBluFound;
  2775. for (int iClient = 1; iClient <= MaxClients; iClient++)
  2776. {
  2777. if (IsValidClient(iClient, true) == false)continue;
  2778. int iTeam = GetClientTeam(iClient);
  2779. if (iTeam == view_as<int>(TFTeam_Red))bRedFound = true;
  2780. if (iTeam == view_as<int>(TFTeam_Blue))bBluFound = true;
  2781. }
  2782. return bRedFound && bBluFound;
  2783. }
  2784.  
  2785. /* CountAlivePlayers()
  2786. **
  2787. ** Retrieves the number of players alive.
  2788. ** -------------------------------------------------------------------------- */
  2789. stock int CountAlivePlayers()
  2790. {
  2791. int iCount = 0;
  2792. for (int iClient = 1; iClient <= MaxClients; iClient++)
  2793. {
  2794. if (IsValidClient(iClient, true))iCount++;
  2795. }
  2796. return iCount;
  2797. }
  2798.  
  2799. /* GetTotalClientCount()
  2800. **
  2801. ** Retrieves the number of real players connected.
  2802. ** -------------------------------------------------------------------------- */
  2803. stock int GetTotalClientCount() {
  2804. int count = 0;
  2805. for (int i = 1; i <= MaxClients; i++) {
  2806. if (IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) > 1) {
  2807. count += 1;
  2808. }
  2809. }
  2810. return count;
  2811. }
  2812.  
  2813. /* SelectTarget()
  2814. **
  2815. ** Determines a random target of the given team for the homing rocket.
  2816. ** -------------------------------------------------------------------------- */
  2817. stock int SelectTarget(int iTeam, int iRocket = -1)
  2818. {
  2819. int iTarget = -1;
  2820. float fTargetWeight = 0.0;
  2821. float fRocketPosition[3];
  2822. float fRocketDirection[3];
  2823. float fWeight;
  2824. bool bUseRocket;
  2825.  
  2826. if (iRocket != -1)
  2827. {
  2828. int iClass = g_iRocketClass[iRocket];
  2829. int iEntity = EntRefToEntIndex(g_iRocketEntity[iRocket]);
  2830.  
  2831. GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fRocketPosition);
  2832. CopyVectors(g_fRocketDirection[iRocket], fRocketDirection);
  2833. fWeight = g_fRocketClassTargetWeight[iClass];
  2834.  
  2835. bUseRocket = true;
  2836. }
  2837.  
  2838. for (int iClient = 1; iClient <= MaxClients; iClient++)
  2839. {
  2840. // If the client isn't connected, skip.
  2841. if (!IsValidClient(iClient, true))continue;
  2842. if (iTeam && GetClientTeam(iClient) != iTeam)continue;
  2843.  
  2844. // Determine if this client should be the target.
  2845. float fNewWeight = GetURandomFloatRange(0.0, 100.0);
  2846.  
  2847. if (bUseRocket == true)
  2848. {
  2849. float fClientPosition[3]; GetClientEyePosition(iClient, fClientPosition);
  2850. float fDirectionToClient[3]; MakeVectorFromPoints(fRocketPosition, fClientPosition, fDirectionToClient);
  2851. fNewWeight += GetVectorDotProduct(fRocketDirection, fDirectionToClient) * fWeight;
  2852. }
  2853.  
  2854. if ((iTarget == -1) || fNewWeight >= fTargetWeight)
  2855. {
  2856. iTarget = iClient;
  2857. fTargetWeight = fNewWeight;
  2858. }
  2859. }
  2860.  
  2861. return iTarget;
  2862. }
  2863.  
  2864. /* StopSoundToAll()
  2865. **
  2866. ** Stops a sound for all the clients on the given channel.
  2867. ** -------------------------------------------------------------------------- */
  2868. stock void StopSoundToAll(int iChannel, const char[] strSound)
  2869. {
  2870. for (int iClient = 1; iClient <= MaxClients; iClient++)
  2871. {
  2872. if (IsValidClient(iClient))StopSound(iClient, iChannel, strSound);
  2873. }
  2874. }
  2875.  
  2876. /* PlayParticle()
  2877. **
  2878. ** Plays a particle system at the given location & angles.
  2879. ** -------------------------------------------------------------------------- */
  2880. stock void PlayParticle(float fPosition[3], float fAngles[3], char[] strParticleName, float fEffectTime = 5.0, float fLifeTime = 9.0)
  2881. {
  2882. int iEntity = CreateEntityByName("info_particle_system");
  2883. if (iEntity && IsValidEdict(iEntity))
  2884. {
  2885. TeleportEntity(iEntity, fPosition, fAngles, NULL_VECTOR);
  2886. DispatchKeyValue(iEntity, "effect_name", strParticleName);
  2887. ActivateEntity(iEntity);
  2888. AcceptEntityInput(iEntity, "Start");
  2889. CreateTimer(fEffectTime, StopParticle, EntIndexToEntRef(iEntity));
  2890. CreateTimer(fLifeTime, KillParticle, EntIndexToEntRef(iEntity));
  2891. }
  2892. else
  2893. {
  2894. LogError("ShowParticle: could not create info_particle_system");
  2895. }
  2896. }
  2897.  
  2898. /* StopParticle()
  2899. **
  2900. ** Turns of the particle system. Automatically called by PlayParticle
  2901. ** -------------------------------------------------------------------------- */
  2902. public Action StopParticle(Handle hTimer, any iEntityRef)
  2903. {
  2904. if (iEntityRef != INVALID_ENT_REFERENCE)
  2905. {
  2906. int iEntity = EntRefToEntIndex(iEntityRef);
  2907. if (iEntity && IsValidEntity(iEntity))
  2908. {
  2909. AcceptEntityInput(iEntity, "Stop");
  2910. }
  2911. }
  2912. }
  2913.  
  2914. /* KillParticle()
  2915. **
  2916. ** Destroys the particle system. Automatically called by PlayParticle
  2917. ** -------------------------------------------------------------------------- */
  2918. public Action KillParticle(Handle hTimer, any iEntityRef)
  2919. {
  2920. if (iEntityRef != INVALID_ENT_REFERENCE)
  2921. {
  2922. int iEntity = EntRefToEntIndex(iEntityRef);
  2923. if (iEntity && IsValidEntity(iEntity))
  2924. {
  2925. RemoveEdict(iEntity);
  2926. }
  2927. }
  2928. }
  2929.  
  2930. /* PrecacheParticle()
  2931. **
  2932. ** Forces the client to precache a particle system.
  2933. ** -------------------------------------------------------------------------- */
  2934. stock void PrecacheParticle(char[] strParticleName)
  2935. {
  2936. PlayParticle(view_as<float>( { 0.0, 0.0, 0.0 } ), view_as<float>( { 0.0, 0.0, 0.0 } ), strParticleName, 0.1, 0.1);
  2937. }
  2938.  
  2939. /* FindEntityByClassnameSafe()
  2940. **
  2941. ** Used to iterate through entity types, avoiding problems in cases where
  2942. ** the entity may not exist anymore.
  2943. ** -------------------------------------------------------------------------- */
  2944. stock void FindEntityByClassnameSafe(int iStart, const char[] strClassname)
  2945. {
  2946. while (iStart > -1 && !IsValidEntity(iStart))
  2947. {
  2948. iStart--;
  2949. }
  2950. return FindEntityByClassname(iStart, strClassname);
  2951. }
  2952.  
  2953. /* GetAnalogueTeam()
  2954. **
  2955. ** Gets the analogue team for this. In case of Red, it's Blue, and viceversa.
  2956. ** -------------------------------------------------------------------------- */
  2957. stock int GetAnalogueTeam(int iTeam)
  2958. {
  2959. if (iTeam == view_as<int>(TFTeam_Red))return view_as<int>(TFTeam_Blue);
  2960. return view_as<int>(TFTeam_Red);
  2961. }
  2962.  
  2963. /* ShowHiddenMOTDPanel()
  2964. **
  2965. ** Shows a hidden MOTD panel, useful for streaming music.
  2966. ** -------------------------------------------------------------------------- */
  2967. stock void ShowHiddenMOTDPanel(int iClient, char[] strTitle, char[] strMsg, char[] strType = "2")
  2968. {
  2969. Handle hPanel = CreateKeyValues("data");
  2970. KvSetString(hPanel, "title", strTitle);
  2971. KvSetString(hPanel, "type", strType);
  2972. KvSetString(hPanel, "msg", strMsg);
  2973. ShowVGUIPanel(iClient, "info", hPanel, false);
  2974. CloseHandle(hPanel);
  2975. }
  2976.  
  2977. /* PrecacheSoundEx()
  2978. **
  2979. ** Precaches a sound and adds it to the download table.
  2980. ** -------------------------------------------------------------------------- */
  2981. stock void PrecacheSoundEx(char[] strFileName, bool bPreload = false, bool bAddToDownloadTable = false)
  2982. {
  2983. char strFinalPath[PLATFORM_MAX_PATH];
  2984. Format(strFinalPath, sizeof(strFinalPath), "sound/%s", strFileName);
  2985. PrecacheSound(strFileName, bPreload);
  2986. if (bAddToDownloadTable == true)AddFileToDownloadsTable(strFinalPath);
  2987. }
  2988.  
  2989. /* PrecacheModelEx()
  2990. **
  2991. ** Precaches a models and adds it to the download table.
  2992. ** -------------------------------------------------------------------------- */
  2993. stock void PrecacheModelEx(char[] strFileName, bool bPreload = false, bool bAddToDownloadTable = false)
  2994. {
  2995. PrecacheModel(strFileName, bPreload);
  2996. if (bAddToDownloadTable)
  2997. {
  2998. char strDepFileName[PLATFORM_MAX_PATH];
  2999. Format(strDepFileName, sizeof(strDepFileName), "%s.res", strFileName);
  3000.  
  3001. if (FileExists(strDepFileName))
  3002. {
  3003. // Open stream, if possible
  3004. Handle hStream = OpenFile(strDepFileName, "r");
  3005. if (hStream == INVALID_HANDLE) { LogMessage("Error, can't read file containing model dependencies."); return; }
  3006.  
  3007. while (!IsEndOfFile(hStream))
  3008. {
  3009. char strBuffer[PLATFORM_MAX_PATH];
  3010. ReadFileLine(hStream, strBuffer, sizeof(strBuffer));
  3011. CleanString(strBuffer);
  3012.  
  3013. // If file exists...
  3014. if (FileExists(strBuffer, true))
  3015. {
  3016. // Precache depending on type, and add to download table
  3017. if (StrContains(strBuffer, ".vmt", false) != -1)PrecacheDecal(strBuffer, true);
  3018. else if (StrContains(strBuffer, ".mdl", false) != -1)PrecacheModel(strBuffer, true);
  3019. else if (StrContains(strBuffer, ".pcf", false) != -1)PrecacheGeneric(strBuffer, true);
  3020. AddFileToDownloadsTable(strBuffer);
  3021. }
  3022. }
  3023.  
  3024. // Close file
  3025. CloseHandle(hStream);
  3026. }
  3027. }
  3028. }
  3029.  
  3030. /* CleanString()
  3031. **
  3032. ** Cleans the given string from any illegal character.
  3033. ** -------------------------------------------------------------------------- */
  3034. stock void CleanString(char[] strBuffer)
  3035. {
  3036. // Cleanup any illegal characters
  3037. int Length = strlen(strBuffer);
  3038. for (int iPos = 0; iPos < Length; iPos++)
  3039. {
  3040. switch (strBuffer[iPos])
  3041. {
  3042. case '\r':strBuffer[iPos] = ' ';
  3043. case '\n':strBuffer[iPos] = ' ';
  3044. case '\t':strBuffer[iPos] = ' ';
  3045. }
  3046. }
  3047.  
  3048. // Trim string
  3049. TrimString(strBuffer);
  3050. }
  3051.  
  3052. /* FMax()
  3053. **
  3054. ** Returns the maximum of the two values given.
  3055. ** -------------------------------------------------------------------------- */
  3056. stock float FMax(float a, float b)
  3057. {
  3058. return (a > b) ? a:b;
  3059. }
  3060.  
  3061. /* FMin()
  3062. **
  3063. ** Returns the minimum of the two values given.
  3064. ** -------------------------------------------------------------------------- */
  3065. stock float FMin(float a, float b)
  3066. {
  3067. return (a < b) ? a:b;
  3068. }
  3069.  
  3070. /* GetURandomIntRange()
  3071. **
  3072. **
  3073. ** -------------------------------------------------------------------------- */
  3074. stock int GetURandomIntRange(const int iMin, const int iMax)
  3075. {
  3076. return iMin + (GetURandomInt() % (iMax - iMin + 1));
  3077. }
  3078.  
  3079. /* GetURandomFloatRange()
  3080. **
  3081. **
  3082. ** -------------------------------------------------------------------------- */
  3083. stock float GetURandomFloatRange(float fMin, float fMax)
  3084. {
  3085. return fMin + (GetURandomFloat() * (fMax - fMin));
  3086. }
  3087.  
  3088. // Pyro vision
  3089. public void tf2dodgeball_hooks(Handle convar, const char[] oldValue, const char[] newValue)
  3090. {
  3091. if (GetConVarBool(g_hCvarPyroVisionEnabled))
  3092. {
  3093. for (int i = 1; i <= MaxClients; ++i)
  3094. {
  3095. if (IsClientInGame(i))
  3096. {
  3097. TF2Attrib_SetByName(i, PYROVISION_ATTRIBUTE, 1.0);
  3098. }
  3099. }
  3100. }
  3101. else
  3102. {
  3103. for (int i = 1; i <= MaxClients; ++i)
  3104. {
  3105. if (IsClientInGame(i))
  3106. {
  3107. TF2Attrib_RemoveByName(i, PYROVISION_ATTRIBUTE);
  3108. }
  3109. }
  3110. }
  3111. if(convar == g_hMaxBouncesConVar)
  3112. g_config_iMaxBounces = StringToInt(newValue);
  3113. if(convar == g_hCvarVoteRocketClassCommandEnabled)
  3114. g_bVoteClassEnabled = view_as<bool>(StringToInt(newValue));
  3115. if(convar == g_hCvarServerChatTag)
  3116. strcopy(g_strServerChatTag, sizeof(g_strServerChatTag), newValue);
  3117. if(convar == g_hCvarMainChatColor)
  3118. strcopy(g_strMainChatColor, sizeof(g_strMainChatColor), newValue);
  3119. if(convar == g_hCvarKeywordChatColor)
  3120. strcopy(g_strKeywordChatColor, sizeof(g_strKeywordChatColor), newValue);
  3121. }
  3122.  
  3123. // Asherkins RocketBounce
  3124.  
  3125. public void OnEntityCreated(int entity, const char[] classname)
  3126. {
  3127. if (!StrEqual(classname, "tf_projectile_rocket", false))
  3128. return;
  3129.  
  3130. if (StrEqual(classname, "tf_projectile_rocket") || StrEqual(classname, "tf_projectile_sentryrocket"))
  3131. {
  3132. if (IsValidEntity(entity))
  3133. {
  3134. SetEntPropEnt(entity, Prop_Send, "m_hOriginalLauncher", entity);
  3135. SetEntPropEnt(entity, Prop_Send, "m_hLauncher", entity);
  3136. }
  3137. }
  3138.  
  3139. g_nBounces[entity] = 0;
  3140. SDKHook(entity, SDKHook_StartTouch, OnStartTouch);
  3141. }
  3142.  
  3143. public Action OnStartTouch(int entity, int other)
  3144. {
  3145. if (other > 0 && other <= MaxClients)
  3146. return Plugin_Continue;
  3147.  
  3148. // Only allow a rocket to bounce x times.
  3149. if (g_nBounces[entity] >= g_config_iMaxBounces)
  3150. return Plugin_Continue;
  3151.  
  3152. SDKHook(entity, SDKHook_Touch, OnTouch);
  3153. return Plugin_Handled;
  3154. }
  3155.  
  3156. public Action OnTouch(int entity, int other)
  3157. {
  3158. float vOrigin[3];
  3159. GetEntPropVector(entity, Prop_Data, "m_vecOrigin", vOrigin);
  3160.  
  3161. float vAngles[3];
  3162. GetEntPropVector(entity, Prop_Data, "m_angRotation", vAngles);
  3163.  
  3164. float vVelocity[3];
  3165. GetEntPropVector(entity, Prop_Data, "m_vecAbsVelocity", vVelocity);
  3166.  
  3167. Handle trace = TR_TraceRayFilterEx(vOrigin, vAngles, MASK_SHOT, RayType_Infinite, TEF_ExcludeEntity, entity);
  3168.  
  3169. if (!TR_DidHit(trace))
  3170. {
  3171. CloseHandle(trace);
  3172. return Plugin_Continue;
  3173. }
  3174.  
  3175. float vNormal[3];
  3176. TR_GetPlaneNormal(trace, vNormal);
  3177.  
  3178. //PrintToServer("Surface Normal: [%.2f, %.2f, %.2f]", vNormal[0], vNormal[1], vNormal[2]);
  3179.  
  3180. CloseHandle(trace);
  3181.  
  3182. float dotProduct = GetVectorDotProduct(vNormal, vVelocity);
  3183.  
  3184. ScaleVector(vNormal, dotProduct);
  3185. ScaleVector(vNormal, 2.0);
  3186.  
  3187. float vBounceVec[3];
  3188. SubtractVectors(vVelocity, vNormal, vBounceVec);
  3189.  
  3190. float vNewAngles[3];
  3191. GetVectorAngles(vBounceVec, vNewAngles);
  3192.  
  3193. //PrintToServer("Angles: [%.2f, %.2f, %.2f] -> [%.2f, %.2f, %.2f]", vAngles[0], vAngles[1], vAngles[2], vNewAngles[0], vNewAngles[1], vNewAngles[2]);
  3194. //PrintToServer("Velocity: [%.2f, %.2f, %.2f] |%.2f| -> [%.2f, %.2f, %.2f] |%.2f|", vVelocity[0], vVelocity[1], vVelocity[2], GetVectorLength(vVelocity), vBounceVec[0], vBounceVec[1], vBounceVec[2], GetVectorLength(vBounceVec));
  3195.  
  3196. TeleportEntity(entity, NULL_VECTOR, vNewAngles, vBounceVec);
  3197.  
  3198. g_nBounces[entity]++;
  3199.  
  3200. SDKUnhook(entity, SDKHook_Touch, OnTouch);
  3201. return Plugin_Handled;
  3202. }
  3203.  
  3204. public bool TEF_ExcludeEntity(int entity, int contentsMask, any data)
  3205. {
  3206. return (entity != data);
  3207. }
  3208.  
  3209. void preventAirblast(int clientId, bool prevent)
  3210. {
  3211. int flags;
  3212.  
  3213. if (prevent == true)
  3214. {
  3215. abPrevention[clientId] = true;
  3216. flags = GetEntityFlags(clientId) | FL_NOTARGET;
  3217. }
  3218. else
  3219. {
  3220. abPrevention[clientId] = false;
  3221. flags = GetEntityFlags(clientId) & ~FL_NOTARGET;
  3222. }
  3223.  
  3224. SetEntityFlags(clientId, flags);
  3225. }
  3226.  
  3227. public Action TauntCheck(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom)
  3228. {
  3229. switch (damagecustom)
  3230. {
  3231. case TF_CUSTOM_TAUNT_ARMAGEDDON:
  3232. {
  3233. damage = 0.0;
  3234. return Plugin_Changed;
  3235. }
  3236.  
  3237. }
  3238. return Plugin_Continue;
  3239. }
  3240.  
  3241. void checkStolenRocket(int clientId, int entId)
  3242. {
  3243. if (EntRefToEntIndex(g_iRocketTarget[entId]) != clientId && !bStealArray[clientId][stoleRocket])
  3244. {
  3245. bStealArray[clientId][stoleRocket] = true;
  3246. if (bStealArray[clientId][rocketsStolen] < GetConVarInt(g_hCvarStealPreventionNumber))
  3247. {
  3248. bStealArray[clientId][rocketsStolen]++;
  3249. CreateTimer(0.1, tStealTimer, GetClientUserId(clientId), TIMER_FLAG_NO_MAPCHANGE);
  3250. SlapPlayer(clientId, 0, true);
  3251. PrintToChat(clientId, "\x03Do not steal rockets. [Warning %i/%i]", bStealArray[clientId][rocketsStolen], GetConVarInt(g_hCvarStealPreventionNumber));
  3252. }
  3253. else
  3254. {
  3255. ForcePlayerSuicide(clientId);
  3256. PrintToChat(clientId, "\x03You have been slain for stealing rockets.");
  3257. PrintToChatAll("\x03%N was slain for stealing rockets.", clientId);
  3258. }
  3259. }
  3260. }
  3261.  
  3262. void checkRoundDelays(int entId)
  3263. {
  3264. int iEntity = EntRefToEntIndex(g_iRocketEntity[entId]);
  3265. int iTarget = EntRefToEntIndex(g_iRocketTarget[entId]);
  3266. float timeToCheck;
  3267. if (g_iRocketDeflections[entId] == 0)
  3268. timeToCheck = g_fLastSpawnTime;
  3269. else
  3270. timeToCheck = g_fRocketLastDeflectionTime[entId];
  3271.  
  3272. if (iTarget != INVALID_ENT_REFERENCE && (GetGameTime() - timeToCheck) >= GetConVarFloat(g_hCvarDelayPreventionTime))
  3273. {
  3274. g_fRocketSpeed[entId] += GetConVarFloat(g_hCvarDelayPreventionSpeedup);
  3275. if (!g_bPreventingDelay)
  3276. {
  3277. CPrintToChatAll("{FULLRED}[SVH] {TURQUOISE}%N {DARKGRAY}is delaying, the rocket will now speed up.", iTarget);
  3278. EmitSoundToAll(SOUND_DEFAULT_SPEEDUPALERT, iEntity, SNDCHAN_AUTO, SNDLEVEL_GUNFIRE);
  3279. }
  3280. g_bPreventingDelay = true;
  3281. }
  3282. }
  3283.  
  3284. /* SetMainRocketClass()
  3285. **
  3286. ** Takes a specified rocket class index and sets it as the only rocket class able to spawn.
  3287. ** -------------------------------------------------------------------------- */
  3288. stock void SetMainRocketClass(int Index, bool isVote, int client = 0)
  3289. {
  3290. int iSpawnerClassRed = g_iSpawnPointsRedClass[g_iCurrentRedSpawn];
  3291. char strBufferRed[256];
  3292. strcopy(strBufferRed, sizeof(strBufferRed), "Red");
  3293.  
  3294. Format(strBufferRed, sizeof(strBufferRed), "%s%%", g_strRocketClassName[Index]);
  3295. SetArrayCell(g_hSpawnersChancesTable[iSpawnerClassRed], Index, 100);
  3296.  
  3297. for (int iClassIndex = 0; iClassIndex < g_iRocketClassCount; iClassIndex++)
  3298. {
  3299. if (!(iClassIndex == Index))
  3300. {
  3301. Format(strBufferRed, sizeof(strBufferRed), "%s%%", g_strRocketClassName[iClassIndex]);
  3302. SetArrayCell(g_hSpawnersChancesTable[iSpawnerClassRed], iClassIndex, 0);
  3303. }
  3304. }
  3305.  
  3306. int iSpawnerClassBlu = g_iSpawnPointsBluClass[g_iCurrentBluSpawn];
  3307. char strBufferBlue[256];
  3308. strcopy(strBufferBlue, sizeof(strBufferBlue), "Blue");
  3309.  
  3310. Format(strBufferBlue, sizeof(strBufferBlue), "%s%%", g_strRocketClassName[Index]);
  3311. SetArrayCell(g_hSpawnersChancesTable[iSpawnerClassBlu], Index, 100);
  3312.  
  3313. char strSelectionBlue[256];
  3314. strcopy(strSelectionBlue, sizeof(strBufferBlue), strBufferBlue);
  3315.  
  3316. for (int iClassIndex = 0; iClassIndex < g_iRocketClassCount; iClassIndex++)
  3317. {
  3318. if (!(iClassIndex == Index))
  3319. {
  3320. Format(strBufferBlue, sizeof(strBufferBlue), "%s%%", g_strRocketClassName[iClassIndex]);
  3321. SetArrayCell(g_hSpawnersChancesTable[iSpawnerClassBlu], iClassIndex, 0);
  3322. }
  3323. }
  3324.  
  3325. int iClass = GetRandomRocketClass(iSpawnerClassRed);
  3326. strcopy(g_strSavedClassName, sizeof(g_strSavedClassName), g_strRocketClassLongName[iClass]);
  3327.  
  3328. if (isVote)
  3329. CPrintToChatAll("%s %sVote %sfinished! %sRocket class changed to %s%s", g_strServerChatTag, g_strMainChatColor, g_strKeywordChatColor, g_strMainChatColor, g_strKeywordChatColor, g_strSavedClassName);
  3330. else CPrintToChatAll("%s %s%N %schanged the rocket class to %s%s", g_strServerChatTag, g_strKeywordChatColor, client, g_strMainChatColor, g_strKeywordChatColor, g_strRocketClassLongName[iClass]);
  3331. }
  3332.  
  3333. public Action tStealTimer(Handle hTimer, int iClientUid)
  3334. {
  3335. int iClient = GetClientOfUserId(iClientUid);
  3336. bStealArray[iClient][stoleRocket] = false;
  3337. }
  3338.  
  3339. /*void AttachParticle(int iEntity, char[] strParticleType)
  3340. {
  3341. int iParticle = CreateEntityByName("info_particle_system");
  3342.  
  3343. char strName[128];
  3344. if (IsValidEdict(iParticle))
  3345. {
  3346. float fPos[3];
  3347. GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fPos);
  3348. fPos[2] += 10;
  3349. TeleportEntity(iParticle, fPos, NULL_VECTOR, NULL_VECTOR);
  3350.  
  3351. Format(strName, sizeof(strName), "target%i", iEntity);
  3352. DispatchKeyValue(iEntity, "targetname", strName);
  3353.  
  3354. DispatchKeyValue(iParticle, "targetname", "tf2particle");
  3355. DispatchKeyValue(iParticle, "parentname", strName);
  3356. DispatchKeyValue(iParticle, "effect_name", strParticleType);
  3357. DispatchSpawn(iParticle);
  3358. SetVariantString(strName);
  3359. AcceptEntityInput(iParticle, "SetParent", iParticle, iParticle, 0);
  3360. SetVariantString("");
  3361. AcceptEntityInput(iParticle, "SetParentAttachment", iParticle, iParticle, 0);
  3362. ActivateEntity(iParticle);
  3363. AcceptEntityInput(iParticle, "start");
  3364.  
  3365. g_RocketParticle[iEntity] = iParticle;
  3366. }
  3367. }*/
  3368.  
  3369. stock void CreateTempParticle(char[] particle, int entity = -1, float origin[3] = NULL_VECTOR, float angles[3] = { 0.0, 0.0, 0.0 }, bool resetparticles = false)
  3370. {
  3371. int tblidx = FindStringTable("ParticleEffectNames");
  3372.  
  3373. char tmp[256];
  3374. int stridx = INVALID_STRING_INDEX;
  3375.  
  3376. for (int i = 0; i < GetStringTableNumStrings(tblidx); i++)
  3377. {
  3378. ReadStringTable(tblidx, i, tmp, sizeof(tmp));
  3379. if (StrEqual(tmp, particle, false))
  3380. {
  3381. stridx = i;
  3382. break;
  3383. }
  3384. }
  3385.  
  3386. TE_Start("TFParticleEffect");
  3387. TE_WriteFloat("m_vecOrigin[0]", origin[0]);
  3388. TE_WriteFloat("m_vecOrigin[1]", origin[1]);
  3389. TE_WriteFloat("m_vecOrigin[2]", origin[2]);
  3390. TE_WriteVector("m_vecAngles", angles);
  3391. TE_WriteNum("m_iParticleSystemIndex", stridx);
  3392. TE_WriteNum("entindex", entity);
  3393. TE_WriteNum("m_iAttachType", 1);
  3394. TE_WriteNum("m_bResetParticles", resetparticles);
  3395. TE_SendToAll();
  3396. }
  3397.  
  3398. stock void ClearTempParticles(int client)
  3399. {
  3400. float empty[3];
  3401. CreateTempParticle("sandwich_fx", client, empty, empty, true);
  3402. }
  3403.  
  3404. /*void StolenRocket(int iClient, int iTarget)
  3405. {
  3406. if (iTarget != iClient && GetClientTeam(iClient) == GetClientTeam(iTarget))
  3407. {
  3408. PrintToChatAll("\x03%N\x01 stole \x03%N\x01's rocket!", iClient, iTarget);
  3409. g_stolen[iClient]++;
  3410. if (g_stolen[iClient] >= GetConVarInt(g_hCvarStealPreventionNumber))
  3411. {
  3412. g_stolen[iClient] = 0;
  3413. ForcePlayerSuicide(iClient);
  3414. PrintToChat(iClient, "\x03You stole %d rockets and was slayed.", g_hCvarStealPreventionNumber);
  3415. }
  3416. }
  3417. }*/
  3418.  
  3419.  
  3420. // EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement