Advertisement
Guest User

Untitled

a guest
Sep 20th, 2013
290
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.47 KB | None | 0 0
  1. #pragma semicolon 1
  2.  
  3. #include <sourcemod>
  4. #include <tf2_stocks>
  5.  
  6. #define PL_VERSION "0.2"
  7.  
  8. #define TF_CLASS_DEMOMAN 4
  9. #define TF_CLASS_ENGINEER 9
  10. #define TF_CLASS_HEAVY 6
  11. #define TF_CLASS_MEDIC 5
  12. #define TF_CLASS_PYRO 7
  13. #define TF_CLASS_SCOUT 1
  14. #define TF_CLASS_SNIPER 2
  15. #define TF_CLASS_SOLDIER 3
  16. #define TF_CLASS_SPY 8
  17. #define TF_CLASS_UNKNOWN 0
  18.  
  19. #define TF_TEAM_BLU 3
  20. #define TF_TEAM_RED 2
  21.  
  22. #define SIZE_OF_INT 2147483647 // without 0
  23.  
  24. //This code is based on the Class Restrictions Mod from Tsunami: http://forums.alliedmods.net/showthread.php?t=73104
  25.  
  26. public Plugin:myinfo =
  27. {
  28. name = "Class Warfare",
  29. author = "Tsunami,JonathanFlynn",
  30. description = "Class Vs Class",
  31. version = PL_VERSION,
  32. url = "https://github.com/JonathanFlynn/Class-Warfare"
  33. }
  34.  
  35. new g_iClass[MAXPLAYERS + 1];
  36. new Handle:g_hEnabled;
  37. new Handle:g_hFlags;
  38. new Handle:g_hImmunity;
  39. new Handle:g_hClassChangeInterval;
  40. new Float:g_hLimits[4][10];
  41. new String:g_sSounds[10][24] = {"", "vo/scout_no03.wav", "vo/sniper_no04.wav", "vo/soldier_no01.wav",
  42. "vo/demoman_no03.wav", "vo/medic_no03.wav", "vo/heavy_no02.wav",
  43. "vo/pyro_no01.wav", "vo/spy_no02.wav", "vo/engineer_no03.wav"};
  44.  
  45. static String:ClassNames[TFClassType][] = {"", "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" };
  46.  
  47. new g_iBlueClass;
  48. new g_iRedClass;
  49.  
  50. new RandomizedThisRound = 0;
  51.  
  52. public OnPluginStart()
  53. {
  54. CreateConVar("sm_classwarfare_version", PL_VERSION, "Class Warfare in TF2.", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD);
  55.  
  56. g_hEnabled = CreateConVar("sm_classwarfare_enabled", "1", "Enable/disable the Class Warfare mod in TF2.");
  57. g_hFlags = CreateConVar("sm_classwarfare_flags", "", "Admin flags for restricted classes in TF2.");
  58. g_hImmunity = CreateConVar("sm_classwarfare_immunity", "0", "Enable/disable admins being immune for restricted classes in TF2.");
  59. g_hClassChangeInterval = CreateConVar("sm_classwarfare_change_interval", "0", "Shuffle the classes every x minutes, 0 for round only");
  60.  
  61. HookEvent("player_changeclass", Event_PlayerClass);
  62. HookEvent("player_spawn", Event_PlayerSpawn);
  63. HookEvent("player_team", Event_PlayerTeam);
  64.  
  65. HookEvent("teamplay_round_start", Event_RoundStart);
  66. HookEvent("teamplay_setup_finished",Event_SetupFinished);
  67.  
  68. HookEvent("teamplay_round_win",Event_RoundOver);
  69.  
  70. new seeds[1];
  71. seeds[0] = GetTime();
  72. SetURandomSeed(seeds, 1);
  73.  
  74. // for (new i = 0; i < 10; i++) {
  75. // LogError("Random[%i] = %i", i, Math_GetRandomInt(TF_CLASS_SCOUT, TF_CLASS_ENGINEER));
  76. // }
  77.  
  78. }
  79.  
  80. public OnMapStart()
  81. {
  82. SetupClassRestrictions();
  83.  
  84. decl i, String:sSound[32];
  85. for(i = 1; i < sizeof(g_sSounds); i++)
  86. {
  87. Format(sSound, sizeof(sSound), "sound/%s", g_sSounds[i]);
  88. PrecacheSound(g_sSounds[i]);
  89. AddFileToDownloadsTable(sSound);
  90. }
  91. }
  92.  
  93. public Event_RoundOver(Handle:event, const String:name[], bool:dontBroadcast) {
  94.  
  95. //new WinnerTeam = GetEventInt(event, "team");
  96. new FullRound = GetEventInt(event, "full_round");
  97. //new WinReason = GetEventInt(event, "winreason");
  98. //new FlagCapLimit = GetEventInt(event, "flagcaplimit");
  99.  
  100. //PrintToChatAll("Full Round? %d | WinnerTeam: %d | WinReason: %d | FlagCapLimit: %d", FullRound, WinnerTeam, WinReason, FlagCapLimit);
  101.  
  102. //On Dustbowl, each stage is a mini-round. If we switch up between minirounds,
  103. //the teams may end up in a stalemate with lots of times on the clock...
  104.  
  105. if(FullRound == 1)
  106. {
  107. RandomizedThisRound = 0;
  108. }
  109. }
  110.  
  111. public OnClientPutInServer(client)
  112. {
  113. g_iClass[client] = TF_CLASS_UNKNOWN;
  114. }
  115.  
  116. public Event_PlayerClass(Handle:event, const String:name[], bool:dontBroadcast)
  117. {
  118. if(!GetConVarBool(g_hEnabled))
  119. return;
  120.  
  121. new iClient = GetClientOfUserId(GetEventInt(event, "userid")),
  122. iClass = GetEventInt(event, "class");
  123.  
  124. if(!IsValidClass(iClient, iClass))
  125. {
  126. //Don't need to show class selection again until we offer multiple classes
  127. //new iTeam = GetClientTeam(iClient);
  128. //ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
  129. //EmitSoundToClient(iClient, g_sSounds[iClass]);
  130. //TF2_SetPlayerClass(iClient, TFClassType:g_iClass[iClient]);
  131.  
  132. PrintCenterText(iClient, "%s%s%s%s%s", ClassNames[iClass], " Is Not An Option This Round! It's Red ", ClassNames[g_iRedClass], " vs Blue ", ClassNames[g_iBlueClass] );
  133. PrintToChat(iClient, "%s%s%s%s%s", ClassNames[iClass], " Is Not An Option This Round! It's Red ", ClassNames[g_iRedClass], " vs Blue ", ClassNames[g_iBlueClass] );
  134. AssignValidClass(iClient);
  135. }
  136. }
  137.  
  138.  
  139. public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
  140. {
  141. RoundClassRestrictions();
  142. PrintStatus();
  143. }
  144.  
  145. public Action:Event_SetupFinished(Handle:event, const String:name[], bool:dontBroadcast)
  146. {
  147. PrintStatus();
  148. }
  149.  
  150. public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast)
  151. {
  152. new iClient = GetClientOfUserId(GetEventInt(event, "userid"));
  153. g_iClass[iClient] = _:TF2_GetPlayerClass(iClient);
  154.  
  155. if(!IsValidClass(iClient,g_iClass[iClient]))
  156. { //new iTeam = GetClientTeam(iClient);
  157. //ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
  158. //EmitSoundToClient(iClient, g_sSounds[g_iClass[iClient]]);
  159.  
  160. AssignValidClass(iClient);
  161. }
  162. }
  163.  
  164. public Event_PlayerTeam(Handle:event, const String:name[], bool:dontBroadcast)
  165. {
  166. new iClient = GetClientOfUserId(GetEventInt(event, "userid"));
  167.  
  168. if(!IsValidClass(iClient,g_iClass[iClient]))
  169. {
  170. //new iTeam = GetClientTeam(iClient);
  171. //ShowVGUIPanel(iClient, iTeam == TF_TEAM_BLU ? "class_blue" : "class_red");
  172. //EmitSoundToClient(iClient, g_sSounds[g_iClass[iClient]]);
  173. AssignValidClass(iClient);
  174. }
  175. }
  176.  
  177. bool:IsValidClass(iClient, iClass) {
  178.  
  179. new iTeam = GetClientTeam(iClient);
  180.  
  181. if(!(GetConVarBool(g_hImmunity) && IsImmune(iClient)) && IsFull(iTeam, iClass)) {
  182. return false;
  183. }
  184. return true;
  185. }
  186.  
  187. bool:IsFull(iTeam, iClass)
  188. {
  189. // If plugin is disabled, or team or class is invalid, class is not full
  190. if(!GetConVarBool(g_hEnabled) || iTeam < TF_TEAM_RED || iClass < TF_CLASS_SCOUT)
  191. return false;
  192.  
  193. // Get team's class limit
  194. new iLimit,
  195. Float:flLimit = g_hLimits[iTeam][iClass];
  196.  
  197. // If limit is a percentage, calculate real limit
  198. if(flLimit > 0.0 && flLimit < 1.0)
  199. iLimit = RoundToNearest(flLimit * GetTeamClientCount(iTeam));
  200. else
  201. iLimit = RoundToNearest(flLimit);
  202.  
  203. // If limit is -1, class is not full
  204. if(iLimit == -1)
  205. return false;
  206. // If limit is 0, class is full
  207. else if(iLimit == 0)
  208. return true;
  209.  
  210. // Loop through all clients
  211. for(new i = 1, iCount = 0; i <= MaxClients; i++)
  212. {
  213. // If client is in game, on this team, has this class and limit has been reached, class is full
  214. if(IsClientInGame(i) && GetClientTeam(i) == iTeam && _:TF2_GetPlayerClass(i) == iClass && ++iCount > iLimit)
  215. return true;
  216. }
  217.  
  218. return false;
  219. }
  220.  
  221. PrintStatus() {
  222. if(!GetConVarBool(g_hEnabled))
  223. return;
  224.  
  225. PrintCenterTextAll("%s%s%s%s", "This is Class Warfare: Red ", ClassNames[g_iRedClass], " vs Blue ", ClassNames[g_iBlueClass] );
  226. PrintToChatAll("%s%s%s%s", "This is Class Warfare: Red ", ClassNames[g_iRedClass], " vs Blue ", ClassNames[g_iBlueClass] );
  227. }
  228. bool:IsImmune(iClient)
  229. {
  230. if(!iClient || !IsClientInGame(iClient))
  231. return false;
  232.  
  233. decl String:sFlags[32];
  234. GetConVarString(g_hFlags, sFlags, sizeof(sFlags));
  235.  
  236. // If flags are specified and client has generic or root flag, client is immune
  237. return !StrEqual(sFlags, "") && GetUserFlagBits(iClient) & (ReadFlagString(sFlags)|ADMFLAG_ROOT);
  238. }
  239.  
  240. AssignPlayerClasses() {
  241. for (new i = 1; i <= MaxClients; ++i) {
  242. if (IsClientConnected(i) && (!IsValidClass(i,g_iClass[i]))) {
  243. AssignValidClass(i);
  244. }
  245. }
  246. }
  247.  
  248. // Run once per real round (event fires multiple times)
  249. RoundClassRestrictions() {
  250. if ( RandomizedThisRound == 0) {
  251. SetupClassRestrictions();
  252. }
  253. RandomizedThisRound = 1;
  254. AssignPlayerClasses();
  255. }
  256.  
  257. SetupClassRestrictions() {
  258.  
  259. for(new i = TF_CLASS_SCOUT; i <= TF_CLASS_ENGINEER; i++)
  260. {
  261. g_hLimits[TF_TEAM_BLU][i] = 0.0;
  262. g_hLimits[TF_TEAM_RED][i] = 0.0;
  263. }
  264.  
  265. g_iBlueClass = Math_GetRandomInt(TF_CLASS_SCOUT, TF_CLASS_ENGINEER);
  266. g_iRedClass = Math_GetRandomInt(TF_CLASS_SCOUT, TF_CLASS_ENGINEER);
  267.  
  268. g_hLimits[TF_TEAM_BLU][g_iBlueClass] = -1.0;
  269. g_hLimits[TF_TEAM_RED][g_iRedClass] = -1.0;
  270.  
  271. new seconds = GetConVarInt(g_hClassChangeInterval) * 60;
  272. if (seconds > 0) {
  273. CreateTimer(float(seconds), TimerClassChange);
  274. }
  275.  
  276. }
  277.  
  278. public Action:TimerClassChange(Handle:timer, any:client)
  279. {
  280. SetupClassRestrictions();
  281. PrintToChatAll("%s%s%s%s", "Mid Round Class Change: Red ", ClassNames[g_iRedClass], " vs Blue ", ClassNames[g_iBlueClass] );
  282. }
  283.  
  284. AssignValidClass(iClient)
  285. {
  286. // Loop through all classes, starting at random class
  287. for(new i = (TF_CLASS_SCOUT, TF_CLASS_ENGINEER), iClass = i, iTeam = GetClientTeam(iClient);;)
  288. {
  289. // If team's class is not full, set client's class
  290. if(!IsFull(iTeam, i))
  291. {
  292. TF2_SetPlayerClass(iClient, TFClassType:i);
  293. TF2_RegeneratePlayer(iClient);
  294. // if (!IsPlayerAlive(iClient)) {
  295. // TF2_RespawnPlayer(iClient);
  296. // }
  297. g_iClass[iClient] = i;
  298. break;
  299. }
  300. // If next class index is invalid, start at first class
  301. else if(++i > TF_CLASS_ENGINEER)
  302. i = TF_CLASS_SCOUT;
  303. // If loop has finished, stop searching
  304. else if(i == iClass)
  305. break;
  306. }
  307. }
  308.  
  309. stock Math_GetRandomInt(min, max)
  310. {
  311. new random = GetURandomInt();
  312.  
  313. if (random == 0) {
  314. random++;
  315. }
  316.  
  317. return RoundToCeil(float(random) / (float(SIZE_OF_INT) / float(max - min + 1))) + min - 1;
  318. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement