FlacoBey

Untitled

Jun 5th, 2019
180
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 41.99 KB | None | 0 0
  1. #pragma semicolon 1
  2. #pragma newdecls required
  3.  
  4. #include <sourcemod>
  5. #include <sdktools>
  6.  
  7. #define CVAR_FLAGS          FCVAR_NOTIFY
  8. #define CHAT_TAG            "\x04[\x05Weapon Spawn\x04] \x01"
  9. #define CONFIG_SPAWNS       "data/l4d_spawn_weapon.cfg"
  10. #define MAX_SPAWNS          32
  11. #define MAX_WEAPONS         10
  12. #define MAX_WEAPONS2        29
  13.  
  14. ConVar g_hCvarAllow, g_hCvarCount, g_hCvarGlow, g_hCvarGlowCol, g_hCvarMPGameMode, g_hCvarModes, g_hCvarModesOff, g_hCvarModesTog, g_hCvarRandom, g_hCvarRandomise;
  15. int g_iCvarCount, g_iCvarGlow, g_iCvarGlowCol, g_iCvarRandom, g_iCvarRandomise, g_iPlayerSpawn, g_iRoundStart, g_iSave[MAXPLAYERS+1], g_iSpawnCount, g_iSpawns[MAX_SPAWNS][2];
  16. bool g_bCvarAllow, g_bLeft4Dead2, g_bLoaded;
  17. Menu g_hMenuAng, g_hMenuList, g_hMenuPos;
  18.  
  19. ConVar g_hAmmoAutoShot, g_hAmmoChainsaw, g_hAmmoGL, g_hAmmoHunting, g_hAmmoM60, g_hAmmoRifle, g_hAmmoShotgun, g_hAmmoSmg, g_hAmmoSniper;
  20. int g_iAmmoAutoShot, g_iAmmoChainsaw, g_iAmmoGL, g_iAmmoHunting, g_iAmmoM60, g_iAmmoRifle, g_iAmmoShotgun, g_iAmmoSmg, g_iAmmoSniper;
  21.  
  22. static char g_sWeaponNames[MAX_WEAPONS][] =
  23. {
  24.     "Rifle",
  25.     "Auto Shotgun",
  26.     "Hunting Rifle",
  27.     "SMG",
  28.     "Pump Shotgun",
  29.     "Pistol",
  30.     "Molotov",
  31.     "Pipe Bomb",
  32.     "First Aid Kit",
  33.     "Pain Pills"
  34. };
  35. static char g_sWeapons[MAX_WEAPONS][] =
  36. {
  37.     "weapon_rifle",
  38.     "weapon_autoshotgun",
  39.     "weapon_hunting_rifle",
  40.     "weapon_smg",
  41.     "weapon_pumpshotgun",
  42.     "weapon_pistol",
  43.     "weapon_molotov",
  44.     "weapon_pipe_bomb",
  45.     "weapon_first_aid_kit",
  46.     "weapon_pain_pills"
  47. };
  48. static char g_sWeaponModels[MAX_WEAPONS][] =
  49. {
  50.     "models/w_models/weapons/w_rifle_m16a2.mdl",
  51.     "models/w_models/weapons/w_autoshot_m4super.mdl",
  52.     "models/w_models/weapons/w_sniper_mini14.mdl",
  53.     "models/w_models/weapons/w_smg_uzi.mdl",
  54.     "models/w_models/weapons/w_pumpshotgun_A.mdl",
  55.     "models/w_models/weapons/w_pistol_a.mdl",
  56.     "models/w_models/weapons/w_eq_molotov.mdl",
  57.     "models/w_models/weapons/w_eq_pipebomb.mdl",
  58.     "models/w_models/weapons/w_eq_medkit.mdl",
  59.     "models/w_models/weapons/w_eq_painpills.mdl"
  60. };
  61. static char g_sWeaponNames2[MAX_WEAPONS2][] =
  62. {
  63.     "Rifle",
  64.     "Auto Shotgun",
  65.     "Hunting Rifle",
  66.     "SMG",
  67.     "Pump Shotgun",
  68.     "Pistol",
  69.     "Molotov",
  70.     "Pipe Bomb",
  71.     "First Aid Kit",
  72.     "Pain Pills",
  73.  
  74.     "Shotgun Chrome",
  75.     "Rifle Desert",
  76.     "Grenade Launcher",
  77.     "M60",
  78.     "AK47",
  79.     "SG552",
  80.     "Shotgun Spas",
  81.     "SMG Silenced",
  82.     "SMG MP5",
  83.     "Sniper AWP",
  84.     "Sniper Military",
  85.     "Sniper Scout",
  86.     "Chainsaw",
  87.     "Pistol Magnum",
  88.     "VomitJar",
  89.     "Defibrillator",
  90.     "Upgradepack Explosive",
  91.     "Upgradepack Incendiary",
  92.     "Adrenaline"
  93. };
  94. static char g_sWeapons2[MAX_WEAPONS2][] =
  95. {
  96.     "weapon_rifle",
  97.     "weapon_autoshotgun",
  98.     "weapon_hunting_rifle",
  99.     "weapon_smg",
  100.     "weapon_pumpshotgun",
  101.     "weapon_pistol",
  102.     "weapon_molotov",
  103.     "weapon_pipe_bomb",
  104.     "weapon_first_aid_kit",
  105.     "weapon_pain_pills",
  106.  
  107.     "weapon_shotgun_chrome",
  108.     "weapon_rifle_desert",
  109.     "weapon_grenade_launcher",
  110.     "weapon_rifle_m60",
  111.     "weapon_rifle_ak47",
  112.     "weapon_rifle_sg552",
  113.     "weapon_shotgun_spas",
  114.     "weapon_smg_silenced",
  115.     "weapon_smg_mp5",
  116.     "weapon_sniper_awp",
  117.     "weapon_sniper_military",
  118.     "weapon_sniper_scout",
  119.     "weapon_chainsaw",
  120.     "weapon_pistol_magnum",
  121.     "weapon_vomitjar",
  122.     "weapon_defibrillator",
  123.     "weapon_upgradepack_explosive",
  124.     "weapon_upgradepack_incendiary",
  125.     "weapon_adrenaline"
  126. };
  127. static char g_sWeaponModels2[MAX_WEAPONS2][] =
  128. {
  129.     "models/w_models/weapons/w_rifle_m16a2.mdl",
  130.     "models/w_models/weapons/w_autoshot_m4super.mdl",
  131.     "models/w_models/weapons/w_sniper_mini14.mdl",
  132.     "models/w_models/weapons/w_smg_uzi.mdl",
  133.     "models/w_models/weapons/w_pumpshotgun_A.mdl",
  134.     "models/w_models/weapons/w_pistol_a.mdl",
  135.     "models/w_models/weapons/w_eq_molotov.mdl",
  136.     "models/w_models/weapons/w_eq_pipebomb.mdl",
  137.     "models/w_models/weapons/w_eq_medkit.mdl",
  138.     "models/w_models/weapons/w_eq_painpills.mdl",
  139.  
  140.     "models/w_models/weapons/w_shotgun.mdl",
  141.     "models/w_models/weapons/w_desert_rifle.mdl",
  142.     "models/w_models/weapons/w_grenade_launcher.mdl",
  143.     "models/w_models/weapons/w_m60.mdl",
  144.     "models/w_models/weapons/w_rifle_ak47.mdl",
  145.     "models/w_models/weapons/w_rifle_sg552.mdl",
  146.     "models/w_models/weapons/w_shotgun_spas.mdl",
  147.     "models/w_models/weapons/w_smg_a.mdl",
  148.     "models/w_models/weapons/w_smg_mp5.mdl",
  149.     "models/w_models/weapons/w_sniper_awp.mdl",
  150.     "models/w_models/weapons/w_sniper_military.mdl",
  151.     "models/w_models/weapons/w_sniper_scout.mdl",
  152.     "models/weapons/melee/w_chainsaw.mdl",
  153.     "models/w_models/weapons/w_desert_eagle.mdl",
  154.     "models/w_models/weapons/w_eq_bile_flask.mdl",
  155.     "models/w_models/weapons/w_eq_defibrillator.mdl",
  156.     "models/w_models/weapons/w_eq_explosive_ammopack.mdl",
  157.     "models/w_models/weapons/w_eq_incendiary_ammopack.mdl",
  158.     "models/w_models/weapons/w_eq_adrenaline.mdl"
  159. };
  160.  
  161. public void OnPluginStart()
  162. {
  163.     g_hCvarAllow =      CreateConVar(   "l4d_weapon_spawn_allow",           "1",            "0=Plugin off, 1=Plugin on.", CVAR_FLAGS );
  164.     g_hCvarGlow =       CreateConVar(   "l4d_weapon_spawn_glow",            "100",          "0=Off. Any other value is the range at which the glow will turn on.", CVAR_FLAGS );
  165.     g_hCvarGlowCol =    CreateConVar(   "l4d_weapon_spawn_glow_color",      "0 255 0",      "0=Default glow color. Three values between 0-255 separated by spaces. RGB Color255 - Red Green Blue.", CVAR_FLAGS );
  166.     g_hCvarModes =      CreateConVar(   "l4d_weapon_spawn_modes",           "",             "Turn on the plugin in these game modes, separate by commas (no spaces). (Empty = all).", CVAR_FLAGS );
  167.     g_hCvarModesOff =   CreateConVar(   "l4d_weapon_spawn_modes_off",       "",             "Turn off the plugin in these game modes, separate by commas (no spaces). (Empty = none).", CVAR_FLAGS );
  168.     g_hCvarModesTog =   CreateConVar(   "l4d_weapon_spawn_modes_tog",       "0",            "Turn on the plugin in these game modes. 0=All, 1=Coop, 2=Survival, 4=Versus, 8=Scavenge. Add numbers together.", CVAR_FLAGS );
  169.     g_hCvarCount =      CreateConVar(   "l4d_weapon_spawn_count",           "1",            "0=Infinite. How many items/weapons to give from 1 spawner.", CVAR_FLAGS );
  170.     g_hCvarRandom =     CreateConVar(   "l4d_weapon_spawn_random",          "-1",           "-1=All, 0=None. Otherwise randomly select this many weapons to spawn from the maps config.", CVAR_FLAGS );
  171.     g_hCvarRandomise =  CreateConVar(   "l4d_weapon_spawn_randomise",       "25",           "0=Off. Chance out of 100 to randomise the type of item/weapon regardless of what it's set to.", CVAR_FLAGS );
  172.     AutoExecConfig(true,                "l4d_weapon_spawn");
  173.  
  174.     g_hCvarMPGameMode = FindConVar("mp_gamemode");
  175.     g_hCvarMPGameMode.AddChangeHook(ConVarChanged_Allow);
  176.     g_hCvarAllow.AddChangeHook(ConVarChanged_Allow);
  177.     g_hCvarModes.AddChangeHook(ConVarChanged_Allow);
  178.     g_hCvarModesOff.AddChangeHook(ConVarChanged_Allow);
  179.     g_hCvarModesTog.AddChangeHook(ConVarChanged_Allow);
  180.     g_hCvarCount.AddChangeHook(ConVarChanged_Cvars);
  181.     g_hCvarRandom.AddChangeHook(ConVarChanged_Cvars);
  182.     g_hCvarRandomise.AddChangeHook(ConVarChanged_Cvars);
  183.     g_hCvarGlow.AddChangeHook(ConVarChanged_Glow);
  184.     g_hCvarGlowCol.AddChangeHook(ConVarChanged_Glow);
  185.  
  186.  
  187.     g_hAmmoRifle =          FindConVar("ammo_assaultrifle_max");
  188.     g_hAmmoSmg =            FindConVar("ammo_smg_max");
  189.     g_hAmmoHunting =        FindConVar("ammo_huntingrifle_max");
  190.  
  191.     g_hAmmoRifle.AddChangeHook(ConVarChanged_Cvars);
  192.     g_hAmmoSmg.AddChangeHook(ConVarChanged_Cvars);
  193.     g_hAmmoHunting.AddChangeHook(ConVarChanged_Cvars);
  194.  
  195.     if( g_bLeft4Dead2 )
  196.     {
  197.         g_hAmmoShotgun =    FindConVar("ammo_shotgun_max");
  198.         g_hAmmoGL =         FindConVar("ammo_grenadelauncher_max");
  199.         g_hAmmoChainsaw =   FindConVar("ammo_chainsaw_max");
  200.         g_hAmmoAutoShot =   FindConVar("ammo_autoshotgun_max");
  201.         g_hAmmoM60 =        FindConVar("ammo_m60_max");
  202.         g_hAmmoSniper =     FindConVar("ammo_sniperrifle_max");
  203.  
  204.         g_hAmmoGL.AddChangeHook(ConVarChanged_Cvars);
  205.         g_hAmmoChainsaw.AddChangeHook(ConVarChanged_Cvars);
  206.         g_hAmmoAutoShot.AddChangeHook(ConVarChanged_Cvars);
  207.         g_hAmmoM60.AddChangeHook(ConVarChanged_Cvars);
  208.         g_hAmmoSniper.AddChangeHook(ConVarChanged_Cvars);
  209.     } else {
  210.         g_hAmmoShotgun =    FindConVar("ammo_buckshot_max");
  211.     }
  212.  
  213.     g_hAmmoShotgun.AddChangeHook(ConVarChanged_Cvars);
  214.  
  215.     RegAdminCmd("sm_weapon_spawn",          CmdSpawnerTemp,     ADMFLAG_ROOT,   "Opens a menu of weapons/items to spawn. Spawns a temporary weapon at your crosshair.");
  216.     RegAdminCmd("sm_weapon_spawn_save",     CmdSpawnerSave,     ADMFLAG_ROOT,   "Opens a menu of weapons/items to spawn. Spawns a weapon at your crosshair and saves to config.");
  217.     RegAdminCmd("sm_weapon_spawn_del",      CmdSpawnerDel,      ADMFLAG_ROOT,   "Removes the weapon you are pointing at and deletes from the config if saved.");
  218.     RegAdminCmd("sm_weapon_spawn_clear",    CmdSpawnerClear,    ADMFLAG_ROOT,   "Removes all weapons spawned by this plugin from the current map.");
  219.     RegAdminCmd("sm_weapon_spawn_wipe",     CmdSpawnerWipe,     ADMFLAG_ROOT,   "Removes all weapons spawned by this plugin from the current map and deletes them from the config.");
  220.     RegAdminCmd("sm_weapon_spawn_glow",     CmdSpawnerGlow,     ADMFLAG_ROOT,   "Toggle to enable glow on all weapons to see where they are placed.");
  221.     RegAdminCmd("sm_weapon_spawn_list",     CmdSpawnerList,     ADMFLAG_ROOT,   "Display a list weapon positions and the total number of.");
  222.     RegAdminCmd("sm_weapon_spawn_tele",     CmdSpawnerTele,     ADMFLAG_ROOT,   "Teleport to a weapon (Usage: sm_weapon_spawn_tele <index: 1 to MAX_SPAWNS (32)>).");
  223.     RegAdminCmd("sm_weapon_spawn_ang",      CmdSpawnerAng,      ADMFLAG_ROOT,   "Displays a menu to adjust the weapon angles your crosshair is over.");
  224.     RegAdminCmd("sm_weapon_spawn_pos",      CmdSpawnerPos,      ADMFLAG_ROOT,   "Displays a menu to adjust the weapon origin your crosshair is over.");
  225.  
  226.  
  227.  
  228.     g_hMenuList = new Menu(ListMenuHandler);
  229.     int max = MAX_WEAPONS;
  230.     if( g_bLeft4Dead2 ) max = MAX_WEAPONS2;
  231.     for( int i = 0; i < max; i++ )
  232.     {
  233.         if( g_bLeft4Dead2 )
  234.             g_hMenuList.AddItem("", g_sWeaponNames2[i]);
  235.         else
  236.             g_hMenuList.AddItem("", g_sWeaponNames[i]);
  237.     }
  238.     g_hMenuList.SetTitle("Spawn Weapon");
  239.     g_hMenuList.ExitBackButton = true;
  240. }
  241.  
  242. public void OnPluginEnd()
  243. {
  244.     ResetPlugin();
  245. }
  246.  
  247. public void OnMapStart()
  248. {
  249.     int max = MAX_WEAPONS;
  250.     if( g_bLeft4Dead2 ) max = MAX_WEAPONS2;
  251.     for( int i = 0; i < max; i++ )
  252.     {
  253.         if( g_bLeft4Dead2 )
  254.             PrecacheModel(g_sWeaponModels2[i], true);
  255.         else
  256.             PrecacheModel(g_sWeaponModels[i], true);
  257.     }
  258. }
  259.  
  260. public void OnMapEnd()
  261. {
  262.     ResetPlugin(false);
  263. }
  264.  
  265.  
  266.  
  267. // ====================================================================================================
  268. //                  CVARS
  269. // ====================================================================================================
  270. public void OnConfigsExecuted()
  271. {
  272.     IsAllowed();
  273. }
  274.  
  275. public void ConVarChanged_Allow(Handle convar, const char[] oldValue, const char[] newValue)
  276. {
  277.     IsAllowed();
  278. }
  279.  
  280. public void ConVarChanged_Cvars(Handle convar, const char[] oldValue, const char[] newValue)
  281. {
  282.     GetCvars();
  283. }
  284.  
  285. public void ConVarChanged_Glow(Handle convar, const char[] oldValue, const char[] newValue)
  286. {
  287.     g_iCvarGlow = g_hCvarGlow.IntValue;
  288.     g_iCvarGlowCol = GetColor(g_hCvarGlowCol);
  289.     VendorGlow(g_iCvarGlow);
  290. }
  291.  
  292. int GetColor(ConVar hCvar)
  293. {
  294.     char sTemp[12];
  295.     hCvar.GetString(sTemp, sizeof(sTemp));
  296.  
  297.     if( strcmp(sTemp, "") == 0 )
  298.         return 0;
  299.  
  300.     char sColors[3][4];
  301.     int color = ExplodeString(sTemp, " ", sColors, 3, 4);
  302.  
  303.     if( color != 3 )
  304.         return 0;
  305.  
  306.     color = StringToInt(sColors[0]);
  307.     color += 256 * StringToInt(sColors[1]);
  308.     color += 65536 * StringToInt(sColors[2]);
  309.  
  310.     return color;
  311. }
  312.  
  313. void GetCvars()
  314. {
  315.     g_iCvarCount = g_hCvarCount.IntValue;
  316.     g_iCvarRandom = g_hCvarRandom.IntValue;
  317.     g_iCvarRandomise = g_hCvarRandomise.IntValue;
  318.  
  319.     g_iAmmoRifle        = g_hAmmoRifle.IntValue;
  320.     g_iAmmoShotgun      = g_hAmmoShotgun.IntValue;
  321.     g_iAmmoSmg          = g_hAmmoSmg.IntValue;
  322.     g_iAmmoHunting      = g_hAmmoHunting.IntValue;
  323.  
  324.     if( g_bLeft4Dead2 )
  325.     {
  326.         g_iAmmoGL           = g_hAmmoGL.IntValue;
  327.         g_iAmmoChainsaw     = g_hAmmoChainsaw.IntValue;
  328.         g_iAmmoAutoShot     = g_hAmmoAutoShot.IntValue;
  329.         g_iAmmoM60          = g_hAmmoM60.IntValue;
  330.         g_iAmmoSniper       = g_hAmmoSniper.IntValue;
  331.     }
  332. }
  333.  
  334. void IsAllowed()
  335. {
  336.     bool bCvarAllow = g_hCvarAllow.BoolValue;
  337.     bool bAllowMode = IsAllowedGameMode();
  338.     GetCvars();
  339.  
  340.     if( g_bCvarAllow == false && bCvarAllow == true && bAllowMode == true )
  341.     {
  342.         g_bCvarAllow = true;
  343.         LoadSpawns();
  344.         HookEvent("player_spawn",       Event_PlayerSpawn,  EventHookMode_PostNoCopy);
  345.         HookEvent("round_start",        Event_RoundStart,   EventHookMode_PostNoCopy);
  346.         HookEvent("round_end",          Event_RoundEnd,     EventHookMode_PostNoCopy);
  347.     }
  348.  
  349.     else if( g_bCvarAllow == true && (bCvarAllow == false || bAllowMode == false) )
  350.     {
  351.         g_bCvarAllow = false;
  352.         ResetPlugin();
  353.         UnhookEvent("player_spawn",     Event_PlayerSpawn,  EventHookMode_PostNoCopy);
  354.         UnhookEvent("round_start",      Event_RoundStart,   EventHookMode_PostNoCopy);
  355.         UnhookEvent("round_end",        Event_RoundEnd,     EventHookMode_PostNoCopy);
  356.     }
  357. }
  358.  
  359. int g_iCurrentMode;
  360. bool IsAllowedGameMode()
  361. {
  362.     if( g_hCvarMPGameMode == null )
  363.         return false;
  364.  
  365.     int iCvarModesTog = g_hCvarModesTog.IntValue;
  366.     if( iCvarModesTog != 0 )
  367.     {
  368.         g_iCurrentMode = 0;
  369.  
  370.         int entity = CreateEntityByName("info_gamemode");
  371.         DispatchSpawn(entity);
  372.         HookSingleEntityOutput(entity, "OnCoop", OnGamemode, true);
  373.         HookSingleEntityOutput(entity, "OnSurvival", OnGamemode, true);
  374.         HookSingleEntityOutput(entity, "OnVersus", OnGamemode, true);
  375.         HookSingleEntityOutput(entity, "OnScavenge", OnGamemode, true);
  376.         ActivateEntity(entity);
  377.         AcceptEntityInput(entity, "PostSpawnActivate");
  378.         AcceptEntityInput(entity, "Kill");
  379.  
  380.         if( g_iCurrentMode == 0 )
  381.             return false;
  382.  
  383.         if( !(iCvarModesTog & g_iCurrentMode) )
  384.             return false;
  385.     }
  386.  
  387.     char sGameModes[64], sGameMode[64];
  388.     g_hCvarMPGameMode.GetString(sGameMode, sizeof(sGameMode));
  389.     Format(sGameMode, sizeof(sGameMode), ",%s,", sGameMode);
  390.  
  391.     g_hCvarModes.GetString(sGameModes, sizeof(sGameModes));
  392.     if( strcmp(sGameModes, "") )
  393.     {
  394.         Format(sGameModes, sizeof(sGameModes), ",%s,", sGameModes);
  395.         if( StrContains(sGameModes, sGameMode, false) == -1 )
  396.             return false;
  397.     }
  398.  
  399.     g_hCvarModesOff.GetString(sGameModes, sizeof(sGameModes));
  400.     if( strcmp(sGameModes, "") )
  401.     {
  402.         Format(sGameModes, sizeof(sGameModes), ",%s,", sGameModes);
  403.         if( StrContains(sGameModes, sGameMode, false) != -1 )
  404.             return false;
  405.     }
  406.  
  407.     return true;
  408. }
  409.  
  410. public void OnGamemode(const char[] output, int caller, int activator, float delay)
  411. {
  412.     if( strcmp(output, "OnCoop") == 0 )
  413.         g_iCurrentMode = 1;
  414.     else if( strcmp(output, "OnSurvival") == 0 )
  415.         g_iCurrentMode = 2;
  416.     else if( strcmp(output, "OnVersus") == 0 )
  417.         g_iCurrentMode = 4;
  418.     else if( strcmp(output, "OnScavenge") == 0 )
  419.         g_iCurrentMode = 8;
  420. }
  421.  
  422.  
  423.  
  424. // ====================================================================================================
  425. //                  EVENTS
  426. // ====================================================================================================
  427. public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast)
  428. {
  429.     ResetPlugin(false);
  430. }
  431.  
  432. public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
  433. {
  434.     if( g_iPlayerSpawn == 1 && g_iRoundStart == 0 )
  435.         CreateTimer(1.0, tmrStart, _, TIMER_FLAG_NO_MAPCHANGE);
  436.     g_iRoundStart = 1;
  437. }
  438.  
  439. public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast)
  440. {
  441.     if( g_iPlayerSpawn == 0 && g_iRoundStart == 1 )
  442.         CreateTimer(1.0, tmrStart, _, TIMER_FLAG_NO_MAPCHANGE);
  443.     g_iPlayerSpawn = 1;
  444. }
  445.  
  446. public Action tmrStart(Handle timer)
  447. {
  448.     ResetPlugin();
  449.     LoadSpawns();
  450. }
  451.  
  452.  
  453.  
  454. // ====================================================================================================
  455. //                  LOAD SPAWNS
  456. // ====================================================================================================
  457. void LoadSpawns()
  458. {
  459.     if( g_bLoaded || g_iCvarRandom == 0 ) return;
  460.     g_bLoaded = true;
  461.  
  462.     char sPath[PLATFORM_MAX_PATH];
  463.     BuildPath(Path_SM, sPath, sizeof(sPath), "%s", CONFIG_SPAWNS);
  464.     if( !FileExists(sPath) )
  465.         return;
  466.  
  467.     // Load config
  468.     KeyValues hFile = new KeyValues("spawns");
  469.     if( !hFile.ImportFromFile(sPath) )
  470.     {
  471.         delete hFile;
  472.         return;
  473.     }
  474.  
  475.     // Check for current map in the config
  476.     char sMap[64];
  477.     GetCurrentMap(sMap, 64);
  478.  
  479.     if( !hFile.JumpToKey(sMap) )
  480.     {
  481.         delete hFile;
  482.         return;
  483.     }
  484.  
  485.     // Retrieve how many weapons to display
  486.     int iCount = hFile.GetNum("num", 0);
  487.     if( iCount == 0 )
  488.     {
  489.         delete hFile;
  490.         return;
  491.     }
  492.  
  493.     // Spawn only a select few weapons?
  494.     int iIndexes[MAX_SPAWNS+1];
  495.     if( iCount > MAX_SPAWNS )
  496.         iCount = MAX_SPAWNS;
  497.  
  498.  
  499.     // Spawn saved weapons or create random
  500.     int iRandom = g_iCvarRandom;
  501.     if( iRandom == -1 || iRandom > iCount)
  502.         iRandom = iCount;
  503.     if( iRandom != -1 )
  504.     {
  505.         for( int i = 1; i <= iCount; i++ )
  506.             iIndexes[i-1] = i;
  507.  
  508.         SortIntegers(iIndexes, iCount, Sort_Random);
  509.         iCount = iRandom;
  510.     }
  511.  
  512.     // Get the weapon origins and spawn
  513.     char sTemp[10];
  514.     float vPos[3], vAng[3];
  515.     int index, iMod;
  516.     for( int i = 1; i <= iCount; i++ )
  517.     {
  518.         if( iRandom != -1 ) index = iIndexes[i-1];
  519.         else index = i;
  520.  
  521.         IntToString(index, sTemp, sizeof(sTemp));
  522.  
  523.         if( hFile.JumpToKey(sTemp) )
  524.         {
  525.             hFile.GetVector("ang", vAng);
  526.             hFile.GetVector("pos", vPos);
  527.             iMod = hFile.GetNum("mod");
  528.  
  529.             if( vPos[0] == 0.0 && vPos[1] == 0.0 && vPos[2] == 0.0 ) // Should never happen...
  530.                 LogError("Error: 0,0,0 origin. Iteration=%d. Index=%d. Random=%d. Count=%d.", i, index, iRandom, iCount);
  531.             else
  532.                 CreateSpawn(vPos, vAng, index, iMod, true);
  533.             hFile.GoBack();
  534.         }
  535.     }
  536.  
  537.     delete hFile;
  538. }
  539.  
  540.  
  541.  
  542. // ====================================================================================================
  543. //                  CREATE SPAWN
  544. // ====================================================================================================
  545. void CreateSpawn(const float vOrigin[3], const float vAngles[3], int index = 0, int model = 0, int autospawn = false)
  546. {
  547.     if( g_iSpawnCount >= MAX_SPAWNS )
  548.         return;
  549.  
  550.     int iSpawnIndex = -1;
  551.     for( int i = 0; i < MAX_SPAWNS; i++ )
  552.     {
  553.         if( g_iSpawns[i][0] == 0 )
  554.         {
  555.             iSpawnIndex = i;
  556.             break;
  557.         }
  558.     }
  559.  
  560.     if( iSpawnIndex == -1 )
  561.         return;
  562.  
  563.  
  564.     if( autospawn && g_iCvarRandomise && GetRandomInt(0, 100) <= g_iCvarRandomise )
  565.     {
  566.         if( g_bLeft4Dead2 )
  567.         {
  568.             model = GetRandomInt(0, MAX_WEAPONS2-1);
  569.  
  570.             if( model == 15 || model == 18 )        model = GetRandomInt(0, 14);
  571.             else if( model == 19 || model == 21 )   model = GetRandomInt(22, 28);
  572.         } else {
  573.             model = GetRandomInt(0, MAX_WEAPONS-1);
  574.         }
  575.     }
  576.  
  577.     char classname[64];
  578.     if( g_bLeft4Dead2 )
  579.         strcopy(classname, sizeof(classname), g_sWeapons2[model]);
  580.     else
  581.         strcopy(classname, sizeof(classname), g_sWeapons[model]);
  582.     int iCount = g_iCvarCount;
  583.  
  584.     if( iCount != 1 )
  585.     {
  586.         if( model != 15 && model != 18 && model != 19 && model != 21 )
  587.             StrCat(classname, sizeof(classname), "_spawn");
  588.         else
  589.             iCount = 1;
  590.     }
  591.  
  592.  
  593.     int entity_weapon = -1;
  594.     entity_weapon = CreateEntityByName(classname);
  595.     if( entity_weapon == -1 )
  596.         ThrowError("Failed to create entity '%s'", classname);
  597.  
  598.     DispatchKeyValue(entity_weapon, "solid", "6");
  599.     if( g_bLeft4Dead2 )
  600.         DispatchKeyValue(entity_weapon, "model", g_sWeaponModels2[model]);
  601.     else
  602.         DispatchKeyValue(entity_weapon, "model", g_sWeaponModels[model]);
  603.     DispatchKeyValue(entity_weapon, "rendermode", "3");
  604.     DispatchKeyValue(entity_weapon, "disableshadows", "1");
  605.  
  606.     if( iCount <= 0 ) // Infinite
  607.     {
  608.         DispatchKeyValue(entity_weapon, "spawnflags", "8");
  609.         DispatchKeyValue(entity_weapon, "count", "9999");
  610.     }
  611.     else if( iCount != 1 )
  612.     {
  613.         char sCount[5];
  614.         IntToString(iCount, sCount, sizeof(sCount));
  615.         DispatchKeyValue(entity_weapon, "count", sCount);
  616.     }
  617.  
  618.     float vAng[3], vPos[3];
  619.     vPos = vOrigin;
  620.     vAng = vAngles;
  621.     if( model == 8 ) // First aid
  622.     {
  623.         vAng[0] += 90.0;
  624.         vPos[2] += 1.0;
  625.     }
  626.     else if( g_bLeft4Dead2 && model == 28 ) // Adrenaline
  627.     {
  628.         vAng[1] -= 90.0;
  629.         vAng[2] -= 90.0;
  630.         vPos[2] += 1.0;
  631.     }
  632.     else if( g_bLeft4Dead2 && (model == 25 || model == 26 || model == 27 )) // Defib + Upgrades
  633.     {
  634.         vAng[1] -= 90.0;
  635.         vAng[2] += 90.0;
  636.     }
  637.     else if( g_bLeft4Dead2 && model == 22 ) // Chainsaw
  638.     {
  639.         vPos[2] += 3.0;
  640.     }
  641.  
  642.     TeleportEntity(entity_weapon, vPos, vAng, NULL_VECTOR);
  643.     DispatchSpawn(entity_weapon);
  644.  
  645.     if( iCount == 1 )
  646.     {
  647.         int ammo;
  648.  
  649.         if( model == 3 )                        ammo = g_iAmmoSmg;
  650.         else if( model == 0 )                   ammo = g_iAmmoRifle;
  651.         else if( model == 4 )                   ammo = g_iAmmoShotgun;
  652.         else if( model == 1 )                   ammo = g_iAmmoAutoShot;
  653.         else if( model == 2 )                   ammo = g_iAmmoHunting;
  654.         else if( g_bLeft4Dead2 )
  655.         {
  656.             if( model == 17 || model == 18 )                                ammo = g_iAmmoSmg;
  657.             else if( model == 11 || model == 14 || model == 15 )            ammo = g_iAmmoRifle;
  658.             else if( model == 10 )                                          ammo = g_iAmmoShotgun;
  659.             else if( model == 16 )                                          ammo = g_iAmmoAutoShot;
  660.             else if( model == 22 )                                          ammo = g_iAmmoChainsaw;
  661.             else if( model == 13 )                                          ammo = g_iAmmoM60;
  662.             else if( model == 12 )                                          ammo = g_iAmmoGL;
  663.             else if( model == 19 || model == 20 || model == 21 )            ammo = g_iAmmoSniper;
  664.         }
  665.         if( !g_bLeft4Dead2 && model == 1 ) ammo = g_iAmmoShotgun;
  666.  
  667.         SetEntProp(entity_weapon, Prop_Send, "m_iExtraPrimaryAmmo", ammo, 4);
  668.     }
  669.     SetEntityMoveType(entity_weapon, MOVETYPE_NONE);
  670.  
  671.     g_iSpawns[iSpawnIndex][0] = EntIndexToEntRef(entity_weapon);
  672.     g_iSpawns[iSpawnIndex][1] = index;
  673.  
  674.     g_iSpawnCount++;
  675. }
  676.  
  677.  
  678.  
  679. // ====================================================================================================
  680. //                  COMMANDS
  681. // ====================================================================================================
  682. //                  sm_weapon_spawn
  683. // ====================================================================================================
  684. public int ListMenuHandler(Menu menu, MenuAction action, int client, int index)
  685. {
  686.     if( action == MenuAction_Select )
  687.     {
  688.         if( g_iSave[client] == 0 )
  689.         {
  690.             CmdSpawnerTempMenu(client, index);
  691.         } else {
  692.             CmdSpawnerSaveMenu(client, index);
  693.         }
  694.  
  695.         g_hMenuList.Display(client, MENU_TIME_FOREVER);
  696.     }
  697. }
  698.  
  699. public Action CmdSpawnerTemp(int client, int args)
  700. {
  701.     if( !client )
  702.     {
  703.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  704.         return Plugin_Handled;
  705.     }
  706.     else if( g_iSpawnCount >= MAX_SPAWNS )
  707.     {
  708.         PrintToChat(client, "%sError: Cannot add anymore weapons. Used: (\x05%d/%d\x01).", CHAT_TAG, g_iSpawnCount, MAX_SPAWNS);
  709.         return Plugin_Handled;
  710.     }
  711.  
  712.     g_iSave[client] = 0;
  713.     g_hMenuList.Display(client, MENU_TIME_FOREVER);
  714.  
  715.     return Plugin_Handled;
  716. }
  717.  
  718. void CmdSpawnerTempMenu(int client, int weapon)
  719. {
  720.     if( !client )
  721.     {
  722.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  723.         return;
  724.     }
  725.     else if( g_iSpawnCount >= MAX_SPAWNS )
  726.     {
  727.         PrintToChat(client, "%sError: Cannot add anymore weapons. Used: (\x05%d/%d\x01).", CHAT_TAG, g_iSpawnCount, MAX_SPAWNS);
  728.         return;
  729.     }
  730.  
  731.     float vPos[3], vAng[3];
  732.     if( !SetTeleportEndPoint(client, vPos, vAng) )
  733.     {
  734.         PrintToChat(client, "%sCannot place weapon, please try again.", CHAT_TAG);
  735.         return;
  736.     }
  737.  
  738.     CreateSpawn(vPos, vAng, 0, weapon);
  739.     return;
  740. }
  741.  
  742. // ====================================================================================================
  743. //                  sm_weapon_spawn_save
  744. // ====================================================================================================
  745. public Action CmdSpawnerSave(int client, int args)
  746. {
  747.     if( !client )
  748.     {
  749.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  750.         return Plugin_Handled;
  751.     }
  752.     else if( g_iSpawnCount >= MAX_SPAWNS )
  753.     {
  754.         PrintToChat(client, "%sError: Cannot add anymore weapons. Used: (\x05%d/%d\x01).", CHAT_TAG, g_iSpawnCount, MAX_SPAWNS);
  755.         return Plugin_Handled;
  756.     }
  757.  
  758.     g_iSave[client] = 1;
  759.     g_hMenuList.Display(client, MENU_TIME_FOREVER);
  760.  
  761.     return Plugin_Handled;
  762. }
  763.  
  764. void CmdSpawnerSaveMenu(int client, int weapon)
  765. {
  766.     char sPath[PLATFORM_MAX_PATH];
  767.     BuildPath(Path_SM, sPath, sizeof(sPath), "%s", CONFIG_SPAWNS);
  768.     if( !FileExists(sPath) )
  769.     {
  770.         File hCfg = OpenFile(sPath, "w");
  771.         hCfg.WriteLine("");
  772.         delete hCfg;
  773.     }
  774.  
  775.     // Load config
  776.     KeyValues hFile = new KeyValues("spawns");
  777.     if( !hFile.ImportFromFile(sPath) )
  778.     {
  779.         PrintToChat(client, "%sError: Cannot read the weapon config, assuming empty file. (\x05%s\x01).", CHAT_TAG, sPath);
  780.     }
  781.  
  782.     // Check for current map in the config
  783.     char sMap[64];
  784.     GetCurrentMap(sMap, 64);
  785.     if( !hFile.JumpToKey(sMap, true) )
  786.     {
  787.         PrintToChat(client, "%sError: Failed to add map to weapon spawn config.", CHAT_TAG);
  788.         delete hFile;
  789.         return;
  790.     }
  791.  
  792.     // Retrieve how many weapons are saved
  793.     int iCount = hFile.GetNum("num", 0);
  794.     if( iCount >= MAX_SPAWNS )
  795.     {
  796.         PrintToChat(client, "%sError: Cannot add anymore weapons. Used: (\x05%d/%d\x01).", CHAT_TAG, iCount, MAX_SPAWNS);
  797.         delete hFile;
  798.         return;
  799.     }
  800.  
  801.     // Save count
  802.     iCount++;
  803.     hFile.SetNum("num", iCount);
  804.  
  805.     char sTemp[10];
  806.  
  807.     IntToString(iCount, sTemp, sizeof(sTemp));
  808.  
  809.     if( hFile.JumpToKey(sTemp, true) )
  810.     {
  811.         float vPos[3], vAng[3];
  812.         // Set player position as weapon spawn location
  813.         if( !SetTeleportEndPoint(client, vPos, vAng) )
  814.         {
  815.             PrintToChat(client, "%sCannot place weapon, please try again.", CHAT_TAG);
  816.             delete hFile;
  817.             return;
  818.         }
  819.  
  820.         // Save angle / origin
  821.         hFile.SetVector("ang", vAng);
  822.         hFile.SetVector("pos", vPos);
  823.         hFile.SetNum("mod", weapon);
  824.  
  825.         CreateSpawn(vPos, vAng, iCount, weapon);
  826.  
  827.         // Save cfg
  828.         hFile.Rewind();
  829.         hFile.ExportToFile(sPath);
  830.  
  831.         PrintToChat(client, "%s(\x05%d/%d\x01) - Saved at pos:[\x05%f %f %f\x01] ang:[\x05%f %f %f\x01]", CHAT_TAG, iCount, MAX_SPAWNS, vPos[0], vPos[1], vPos[2], vAng[0], vAng[1], vAng[2]);
  832.     }
  833.     else
  834.         PrintToChat(client, "%s(\x05%d/%d\x01) - Failed to save weapon.", CHAT_TAG, iCount, MAX_SPAWNS);
  835.  
  836.     delete hFile;
  837. }
  838.  
  839. // ====================================================================================================
  840. //                  sm_weapon_spawn_del
  841. // ====================================================================================================
  842. public Action CmdSpawnerDel(int client, int args)
  843. {
  844.     if( !g_bCvarAllow )
  845.     {
  846.         ReplyToCommand(client, "[Weapon Spawn] Plugin turned off.");
  847.         return Plugin_Handled;
  848.     }
  849.  
  850.     if( !client )
  851.     {
  852.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  853.         return Plugin_Handled;
  854.     }
  855.  
  856.     int entity = GetClientAimTarget(client, false);
  857.     if( entity == -1 ) return Plugin_Handled;
  858.     entity = EntIndexToEntRef(entity);
  859.  
  860.     int cfgindex, index = -1;
  861.     for( int i = 0; i < MAX_SPAWNS; i++ )
  862.     {
  863.         if( g_iSpawns[i][0] == entity )
  864.         {
  865.             index = i;
  866.             break;
  867.         }
  868.     }
  869.  
  870.     if( index == -1 )
  871.         return Plugin_Handled;
  872.  
  873.     cfgindex = g_iSpawns[index][1];
  874.     if( cfgindex == 0 )
  875.     {
  876.         RemoveSpawn(index);
  877.         return Plugin_Handled;
  878.     }
  879.  
  880.     for( int i = 0; i < MAX_SPAWNS; i++ )
  881.     {
  882.         if( g_iSpawns[i][1] > cfgindex )
  883.             g_iSpawns[i][1]--;
  884.     }
  885.  
  886.     g_iSpawnCount--;
  887.  
  888.     // Load config
  889.     char sPath[PLATFORM_MAX_PATH];
  890.     BuildPath(Path_SM, sPath, sizeof(sPath), "%s", CONFIG_SPAWNS);
  891.     if( !FileExists(sPath) )
  892.     {
  893.         PrintToChat(client, "%sError: Cannot find the weapon config (\x05%s\x01).", CHAT_TAG, CONFIG_SPAWNS);
  894.         return Plugin_Handled;
  895.     }
  896.  
  897.     KeyValues hFile = new KeyValues("spawns");
  898.     if( !hFile.ImportFromFile(sPath) )
  899.     {
  900.         PrintToChat(client, "%sError: Cannot load the weapon config (\x05%s\x01).", CHAT_TAG, sPath);
  901.         delete hFile;
  902.         return Plugin_Handled;
  903.     }
  904.  
  905.     // Check for current map in the config
  906.     char sMap[64];
  907.     GetCurrentMap(sMap, 64);
  908.  
  909.     if( !hFile.JumpToKey(sMap) )
  910.     {
  911.         PrintToChat(client, "%sError: Current map not in the weapon config.", CHAT_TAG);
  912.         delete hFile;
  913.         return Plugin_Handled;
  914.     }
  915.  
  916.     // Retrieve how many weapons
  917.     int iCount = hFile.GetNum("num", 0);
  918.     if( iCount == 0 )
  919.     {
  920.         delete hFile;
  921.         return Plugin_Handled;
  922.     }
  923.  
  924.     bool bMove;
  925.     char sTemp[16];
  926.  
  927.     // Move the other entries down
  928.     for( int i = cfgindex; i <= iCount; i++ )
  929.     {
  930.         IntToString(i, sTemp, sizeof(sTemp));
  931.  
  932.         if( hFile.JumpToKey(sTemp) )
  933.         {
  934.             if( !bMove )
  935.             {
  936.                 bMove = true;
  937.                 hFile.DeleteThis();
  938.                 RemoveSpawn(index);
  939.             }
  940.             else
  941.             {
  942.                 IntToString(i-1, sTemp, sizeof(sTemp));
  943.                 hFile.SetSectionName(sTemp);
  944.             }
  945.         }
  946.  
  947.         hFile.Rewind();
  948.         hFile.JumpToKey(sMap);
  949.     }
  950.  
  951.     if( bMove )
  952.     {
  953.         iCount--;
  954.         hFile.SetNum("num", iCount);
  955.  
  956.         // Save to file
  957.         hFile.Rewind();
  958.         hFile.ExportToFile(sPath);
  959.  
  960.         PrintToChat(client, "%s(\x05%d/%d\x01) - weapon removed from config.", CHAT_TAG, iCount, MAX_SPAWNS);
  961.     }
  962.     else
  963.         PrintToChat(client, "%s(\x05%d/%d\x01) - Failed to remove weapon from config.", CHAT_TAG, iCount, MAX_SPAWNS);
  964.  
  965.     delete hFile;
  966.     return Plugin_Handled;
  967. }
  968.  
  969. // ====================================================================================================
  970. //                  sm_weapon_spawn_clear
  971. // ====================================================================================================
  972. public Action CmdSpawnerClear(int client, int args)
  973. {
  974.     if( !client )
  975.     {
  976.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  977.         return Plugin_Handled;
  978.     }
  979.  
  980.     ResetPlugin();
  981.  
  982.     PrintToChat(client, "%s(0/%d) - All weapons removed from the map.", CHAT_TAG, MAX_SPAWNS);
  983.     return Plugin_Handled;
  984. }
  985.  
  986. // ====================================================================================================
  987. //                  sm_weapon_spawn_wipe
  988. // ====================================================================================================
  989. public Action CmdSpawnerWipe(int client, int args)
  990. {
  991.     if( !client )
  992.     {
  993.         ReplyToCommand(client, "[Weapon Spawn] Commands may only be used in-game on a dedicated server..");
  994.         return Plugin_Handled;
  995.     }
  996.  
  997.     char sPath[PLATFORM_MAX_PATH];
  998.     BuildPath(Path_SM, sPath, sizeof(sPath), "%s", CONFIG_SPAWNS);
  999.     if( !FileExists(sPath) )
  1000.     {
  1001.         PrintToChat(client, "%sError: Cannot find the weapon config (\x05%s\x01).", CHAT_TAG, sPath);
  1002.         return Plugin_Handled;
  1003.     }
  1004.  
  1005.     // Load config
  1006.     KeyValues hFile = new KeyValues("spawns");
  1007.     if( !hFile.ImportFromFile(sPath) )
  1008.     {
  1009.         PrintToChat(client, "%sError: Cannot load the weapon config (\x05%s\x01).", CHAT_TAG, sPath);
  1010.         delete hFile;
  1011.         return Plugin_Handled;
  1012.     }
  1013.  
  1014.     // Check for current map in the config
  1015.     char sMap[64];
  1016.     GetCurrentMap(sMap, 64);
  1017.  
  1018.     if( !hFile.JumpToKey(sMap, false) )
  1019.     {
  1020.         PrintToChat(client, "%sError: Current map not in the weapon config.", CHAT_TAG);
  1021.         delete hFile;
  1022.         return Plugin_Handled;
  1023.     }
  1024.  
  1025.     hFile.DeleteThis();
  1026.     ResetPlugin();
  1027.  
  1028.     // Save to file
  1029.     hFile.Rewind();
  1030.     hFile.ExportToFile(sPath);
  1031.     delete hFile;
  1032.  
  1033.     PrintToChat(client, "%s(0/%d) - All weapons removed from config, add with \x05sm_weapon_spawn_save\x01.", CHAT_TAG, MAX_SPAWNS);
  1034.     return Plugin_Handled;
  1035. }
  1036.  
  1037. // ====================================================================================================
  1038. //                  sm_weapon_spawn_glow
  1039. // ====================================================================================================
  1040. public Action CmdSpawnerGlow(int client, int args)
  1041. {
  1042.     static bool glow;
  1043.     glow = !glow;
  1044.     PrintToChat(client, "%sGlow has been turned %s", CHAT_TAG, glow ? "on" : "off");
  1045.  
  1046.     VendorGlow(glow);
  1047.     return Plugin_Handled;
  1048. }
  1049.  
  1050. void VendorGlow(int glow)
  1051. {
  1052.     int ent;
  1053.  
  1054.     for( int i = 0; i < MAX_SPAWNS; i++ )
  1055.     {
  1056.         ent = g_iSpawns[i][0];
  1057.         if( IsValidEntRef(ent) )
  1058.         {
  1059.             SetEntProp(ent, Prop_Send, "m_iGlowType", glow ? 3 : 0);
  1060.             if( glow )
  1061.             {
  1062.                 SetEntProp(ent, Prop_Send, "m_glowColorOverride", g_iCvarGlowCol);
  1063.                 SetEntProp(ent, Prop_Send, "m_nGlowRange", glow ? 0 : g_iCvarGlow);
  1064.             }
  1065.         }
  1066.     }
  1067. }
  1068.  
  1069. // ====================================================================================================
  1070. //                  sm_weapon_spawn_list
  1071. // ====================================================================================================
  1072. public Action CmdSpawnerList(int client, int args)
  1073. {
  1074.     float vPos[3];
  1075.     int count;
  1076.     for( int i = 0; i < MAX_SPAWNS; i++ )
  1077.     {
  1078.         if( IsValidEntRef(g_iSpawns[i][0]) )
  1079.         {
  1080.             count++;
  1081.             GetEntPropVector(g_iSpawns[i][0], Prop_Data, "m_vecOrigin", vPos);
  1082.             PrintToChat(client, "%s%d) %f %f %f", CHAT_TAG, i+1, vPos[0], vPos[1], vPos[2]);
  1083.         }
  1084.     }
  1085.     PrintToChat(client, "%sTotal: %d.", CHAT_TAG, count);
  1086.     return Plugin_Handled;
  1087. }
  1088.  
  1089. // ====================================================================================================
  1090. //                  sm_weapon_spawn_tele
  1091. // ====================================================================================================
  1092. public Action CmdSpawnerTele(int client, int args)
  1093. {
  1094.     if( args == 1 )
  1095.     {
  1096.         char arg[16];
  1097.         GetCmdArg(1, arg, 16);
  1098.         int index = StringToInt(arg) - 1;
  1099.         if( index > -1 && index < MAX_SPAWNS && IsValidEntRef(g_iSpawns[index][0]) )
  1100.         {
  1101.             float vPos[3];
  1102.             GetEntPropVector(g_iSpawns[index][0], Prop_Data, "m_vecOrigin", vPos);
  1103.             vPos[2] += 20.0;
  1104.             TeleportEntity(client, vPos, NULL_VECTOR, NULL_VECTOR);
  1105.             PrintToChat(client, "%sTeleported to %d.", CHAT_TAG, index + 1);
  1106.             return Plugin_Handled;
  1107.         }
  1108.  
  1109.         PrintToChat(client, "%sCould not find index for teleportation.", CHAT_TAG);
  1110.     }
  1111.     else
  1112.         PrintToChat(client, "%sUsage: sm_weapon_spawn_tele <index 1-%d>.", CHAT_TAG, MAX_SPAWNS);
  1113.     return Plugin_Handled;
  1114. }
  1115.  
  1116. // ====================================================================================================
  1117. //                  MENU ANGLE
  1118. // ====================================================================================================
  1119. public Action CmdSpawnerAng(int client, int args)
  1120. {
  1121.     ShowMenuAng(client);
  1122.     return Plugin_Handled;
  1123. }
  1124.  
  1125. void ShowMenuAng(int client)
  1126. {
  1127.     CreateMenus();
  1128.     g_hMenuAng.Display(client, MENU_TIME_FOREVER);
  1129. }
  1130.  
  1131. public int AngMenuHandler(Menu menu, MenuAction action, int client, int index)
  1132. {
  1133.     if( action == MenuAction_Select )
  1134.     {
  1135.         if( index == 6 )
  1136.             SaveData(client);
  1137.         else
  1138.             SetAngle(client, index);
  1139.         ShowMenuAng(client);
  1140.     }
  1141. }
  1142.  
  1143. void SetAngle(int client, int index)
  1144. {
  1145.     int aim = GetClientAimTarget(client, false);
  1146.     if( aim != -1 )
  1147.     {
  1148.         float vAng[3];
  1149.         int entity;
  1150.         aim = EntIndexToEntRef(aim);
  1151.  
  1152.         for( int i = 0; i < MAX_SPAWNS; i++ )
  1153.         {
  1154.             entity = g_iSpawns[i][0];
  1155.  
  1156.             if( entity == aim  )
  1157.             {
  1158.                 GetEntPropVector(entity, Prop_Send, "m_angRotation", vAng);
  1159.  
  1160.                 if( index == 0 ) vAng[0] += 2.0;
  1161.                 else if( index == 1 ) vAng[1] += 2.0;
  1162.                 else if( index == 2 ) vAng[2] += 2.0;
  1163.                 else if( index == 3 ) vAng[0] -= 2.0;
  1164.                 else if( index == 4 ) vAng[1] -= 2.0;
  1165.                 else if( index == 5 ) vAng[2] -= 2.0;
  1166.  
  1167.                 TeleportEntity(entity, NULL_VECTOR, vAng, NULL_VECTOR);
  1168.  
  1169.                 PrintToChat(client, "%sNew angles: %f %f %f", CHAT_TAG, vAng[0], vAng[1], vAng[2]);
  1170.                 break;
  1171.             }
  1172.         }
  1173.     }
  1174. }
  1175.  
  1176. // ====================================================================================================
  1177. //                  MENU ORIGIN
  1178. // ====================================================================================================
  1179. public Action CmdSpawnerPos(int client, int args)
  1180. {
  1181.     ShowMenuPos(client);
  1182.     return Plugin_Handled;
  1183. }
  1184.  
  1185. void ShowMenuPos(int client)
  1186. {
  1187.     CreateMenus();
  1188.     g_hMenuPos.Display(client, MENU_TIME_FOREVER);
  1189. }
  1190.  
  1191. public int PosMenuHandler(Menu menu, MenuAction action, int client, int index)
  1192. {
  1193.     if( action == MenuAction_Select )
  1194.     {
  1195.         if( index == 6 )
  1196.             SaveData(client);
  1197.         else
  1198.             SetOrigin(client, index);
  1199.         ShowMenuPos(client);
  1200.     }
  1201. }
  1202.  
  1203. void SetOrigin(int client, int index)
  1204. {
  1205.     int aim = GetClientAimTarget(client, false);
  1206.     if( aim != -1 )
  1207.     {
  1208.         float vPos[3];
  1209.         int entity;
  1210.         aim = EntIndexToEntRef(aim);
  1211.  
  1212.         for( int i = 0; i < MAX_SPAWNS; i++ )
  1213.         {
  1214.             entity = g_iSpawns[i][0];
  1215.  
  1216.             if( entity == aim  )
  1217.             {
  1218.                 GetEntPropVector(entity, Prop_Send, "m_vecOrigin", vPos);
  1219.  
  1220.                 if( index == 0 ) vPos[0] += 0.5;
  1221.                 else if( index == 1 ) vPos[1] += 0.5;
  1222.                 else if( index == 2 ) vPos[2] += 0.5;
  1223.                 else if( index == 3 ) vPos[0] -= 0.5;
  1224.                 else if( index == 4 ) vPos[1] -= 0.5;
  1225.                 else if( index == 5 ) vPos[2] -= 0.5;
  1226.  
  1227.                 TeleportEntity(entity, vPos, NULL_VECTOR, NULL_VECTOR);
  1228.  
  1229.                 PrintToChat(client, "%sNew origin: %f %f %f", CHAT_TAG, vPos[0], vPos[1], vPos[2]);
  1230.                 break;
  1231.             }
  1232.         }
  1233.     }
  1234. }
  1235.  
  1236. void SaveData(int client)
  1237. {
  1238.     int entity, index;
  1239.     int aim = GetClientAimTarget(client, false);
  1240.     if( aim == -1 )
  1241.         return;
  1242.  
  1243.     aim = EntIndexToEntRef(aim);
  1244.  
  1245.     for( int i = 0; i < MAX_SPAWNS; i++ )
  1246.     {
  1247.         entity = g_iSpawns[i][0];
  1248.  
  1249.         if( entity == aim  )
  1250.         {
  1251.             index = g_iSpawns[i][1];
  1252.             break;
  1253.         }
  1254.     }
  1255.  
  1256.     if( index == 0 )
  1257.         return;
  1258.  
  1259.     // Load config
  1260.     char sPath[PLATFORM_MAX_PATH];
  1261.     BuildPath(Path_SM, sPath, sizeof(sPath), "%s", CONFIG_SPAWNS);
  1262.     if( !FileExists(sPath) )
  1263.     {
  1264.         PrintToChat(client, "%sError: Cannot find the Weapon Spawn config (\x05%s\x01).", CHAT_TAG, CONFIG_SPAWNS);
  1265.         return;
  1266.     }
  1267.  
  1268.     KeyValues hFile = new KeyValues("spawns");
  1269.     if( !hFile.ImportFromFile(sPath) )
  1270.     {
  1271.         PrintToChat(client, "%sError: Cannot load the Weapon Spawn config (\x05%s\x01).", CHAT_TAG, sPath);
  1272.         delete hFile;
  1273.         return;
  1274.     }
  1275.  
  1276.     // Check for current map in the config
  1277.     char sMap[64];
  1278.     GetCurrentMap(sMap, 64);
  1279.  
  1280.     if( !hFile.JumpToKey(sMap) )
  1281.     {
  1282.         PrintToChat(client, "%sError: Current map not in the Weapon Spawn config.", CHAT_TAG);
  1283.         delete hFile;
  1284.         return;
  1285.     }
  1286.  
  1287.     float vAng[3], vPos[3];
  1288.     char sTemp[32];
  1289.     GetEntPropVector(entity, Prop_Send, "m_vecOrigin", vPos);
  1290.     GetEntPropVector(entity, Prop_Send, "m_angRotation", vAng);
  1291.  
  1292.     IntToString(index, sTemp, sizeof(sTemp));
  1293.     if( hFile.JumpToKey(sTemp) )
  1294.     {
  1295.         hFile.SetVector("ang", vAng);
  1296.         hFile.SetVector("pos", vPos);
  1297.  
  1298.         // Save cfg
  1299.         hFile.Rewind();
  1300.         hFile.ExportToFile(sPath);
  1301.  
  1302.         PrintToChat(client, "%sSaved origin and angles to the data config", CHAT_TAG);
  1303.     }
  1304. }
  1305.  
  1306. void CreateMenus()
  1307. {
  1308.     if( g_hMenuAng == null )
  1309.     {
  1310.         g_hMenuAng = new Menu(AngMenuHandler);
  1311.         g_hMenuAng.AddItem("", "X + 2.0");
  1312.         g_hMenuAng.AddItem("", "Y + 2.0");
  1313.         g_hMenuAng.AddItem("", "Z + 2.0");
  1314.         g_hMenuAng.AddItem("", "X - 2.0");
  1315.         g_hMenuAng.AddItem("", "Y - 2.0");
  1316.         g_hMenuAng.AddItem("", "Z - 2.0");
  1317.         g_hMenuAng.AddItem("", "SAVE");
  1318.         g_hMenuAng.SetTitle("Set Angle");
  1319.         g_hMenuAng.ExitButton = true;
  1320.     }
  1321.  
  1322.     if( g_hMenuPos == null )
  1323.     {
  1324.         g_hMenuPos = new Menu(PosMenuHandler);
  1325.         g_hMenuPos.AddItem("", "X + 0.5");
  1326.         g_hMenuPos.AddItem("", "Y + 0.5");
  1327.         g_hMenuPos.AddItem("", "Z + 0.5");
  1328.         g_hMenuPos.AddItem("", "X - 0.5");
  1329.         g_hMenuPos.AddItem("", "Y - 0.5");
  1330.         g_hMenuPos.AddItem("", "Z - 0.5");
  1331.         g_hMenuPos.AddItem("", "SAVE");
  1332.         g_hMenuPos.SetTitle("Set Position");
  1333.         g_hMenuPos.ExitButton = true;
  1334.     }
  1335. }
  1336.  
  1337.  
  1338.  
  1339. // ====================================================================================================
  1340. //                  STUFF
  1341. // ====================================================================================================
  1342. bool IsValidEntRef(int entity)
  1343. {
  1344.     if( entity && EntRefToEntIndex(entity) != INVALID_ENT_REFERENCE )
  1345.         return true;
  1346.     return false;
  1347. }
  1348.  
  1349. void ResetPlugin(bool all = true)
  1350. {
  1351.     g_bLoaded = false;
  1352.     g_iSpawnCount = 0;
  1353.     g_iRoundStart = 0;
  1354.     g_iPlayerSpawn = 0;
  1355.  
  1356.     if( all )
  1357.         for( int i = 0; i < MAX_SPAWNS; i++ )
  1358.             RemoveSpawn(i);
  1359. }
  1360.  
  1361. void RemoveSpawn(int index)
  1362. {
  1363.     int entity, client;
  1364.  
  1365.     entity = g_iSpawns[index][0];
  1366.     g_iSpawns[index][0] = 0;
  1367.     g_iSpawns[index][1] = 0;
  1368.  
  1369.     if( IsValidEntRef(entity) )
  1370.     {
  1371.         client = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
  1372.         if( client < 0 || client > MaxClients || !IsClientInGame(client) )
  1373.         {
  1374.             AcceptEntityInput(entity, "kill");
  1375.         }
  1376.     }
  1377. }
  1378.  
  1379.  
  1380.  
  1381. // ====================================================================================================
  1382. //                  POSITION
  1383. // ====================================================================================================
  1384. float GetGroundHeight(float vPos[3])
  1385. {
  1386.     float vAng[3];
  1387.     Handle trace = TR_TraceRayFilterEx(vPos, view_as<float>({ 90.0, 0.0, 0.0 }), MASK_ALL, RayType_Infinite, _TraceFilter);
  1388.     if( TR_DidHit(trace) )
  1389.         TR_GetEndPosition(vAng, trace);
  1390.  
  1391.     delete trace;
  1392.     return vAng[2];
  1393. }
  1394.  
  1395. // Taken from "[L4D2] Weapon/Zombie Spawner"
  1396. // By "Zuko & McFlurry"
  1397. bool SetTeleportEndPoint(int client, float vPos[3], float vAng[3])
  1398. {
  1399.     GetClientEyePosition(client, vPos);
  1400.     GetClientEyeAngles(client, vAng);
  1401.  
  1402.     Handle trace = TR_TraceRayFilterEx(vPos, vAng, MASK_SHOT, RayType_Infinite, _TraceFilter);
  1403.  
  1404.     if(TR_DidHit(trace))
  1405.     {
  1406.         float vNorm[3];
  1407.         float degrees = vAng[1];
  1408.         TR_GetEndPosition(vPos, trace);
  1409.         GetGroundHeight(vPos);
  1410.         vPos[2] += 1.0;
  1411.         TR_GetPlaneNormal(trace, vNorm);
  1412.         GetVectorAngles(vNorm, vAng);
  1413.         if( vNorm[2] == 1.0 )
  1414.         {
  1415.             vAng[0] = 0.0;
  1416.             vAng[1] = degrees + 180;
  1417.         }
  1418.         else
  1419.         {
  1420.             if( degrees > vAng[1] )
  1421.                 degrees = vAng[1] - degrees;
  1422.             else
  1423.                 degrees = degrees - vAng[1];
  1424.             vAng[0] += 90.0;
  1425.             RotateYaw(vAng, degrees + 180);
  1426.         }
  1427.     }
  1428.     else
  1429.     {
  1430.         delete trace;
  1431.         return false;
  1432.     }
  1433.     delete trace;
  1434.  
  1435.     vAng[1] += 90.0;
  1436.     vAng[2] -= 90.0;
  1437.     return true;
  1438. }
  1439.  
  1440. public bool _TraceFilter(int entity, int contentsMask)
  1441. {
  1442.     return entity > MaxClients || !entity;
  1443. }
  1444.  
  1445.  
  1446.  
  1447. //---------------------------------------------------------
  1448. // do a specific rotation on the given angles
  1449. //---------------------------------------------------------
  1450. void RotateYaw(float angles[3], float degree)
  1451. {
  1452.     float direction[3], normal[3];
  1453.     GetAngleVectors( angles, direction, NULL_VECTOR, normal );
  1454.  
  1455.     float sin = Sine( degree * 0.01745328 );     // Pi/180
  1456.     float cos = Cosine( degree * 0.01745328 );
  1457.     float a = normal[0] * sin;
  1458.     float b = normal[1] * sin;
  1459.     float c = normal[2] * sin;
  1460.     float x = direction[2] * b + direction[0] * cos - direction[1] * c;
  1461.     float y = direction[0] * c + direction[1] * cos - direction[2] * a;
  1462.     float z = direction[1] * a + direction[2] * cos - direction[0] * b;
  1463.     direction[0] = x;
  1464.     direction[1] = y;
  1465.     direction[2] = z;
  1466.  
  1467.     GetVectorAngles( direction, angles );
  1468.  
  1469.     float up[3];
  1470.     GetVectorVectors( direction, NULL_VECTOR, up );
  1471.  
  1472.     float roll = GetAngleBetweenVectors( up, normal, direction );
  1473.     angles[2] += roll;
  1474. }
  1475.  
  1476. //---------------------------------------------------------
  1477. // calculate the angle between 2 vectors
  1478. // the direction will be used to determine the sign of angle (right hand rule)
  1479. // all of the 3 vectors have to be normalized
  1480. //---------------------------------------------------------
  1481. float GetAngleBetweenVectors(const float vector1[3], const float vector2[3], const float direction[3])
  1482. {
  1483.     float vector1_n[3], vector2_n[3], direction_n[3], cross[3];
  1484.     NormalizeVector( direction, direction_n );
  1485.     NormalizeVector( vector1, vector1_n );
  1486.     NormalizeVector( vector2, vector2_n );
  1487.     float degree = ArcCosine( GetVectorDotProduct( vector1_n, vector2_n ) ) * 57.29577951;   // 180/Pi
  1488.     GetVectorCrossProduct( vector1_n, vector2_n, cross );
  1489.  
  1490.     if ( GetVectorDotProduct( cross, direction_n ) < 0.0 )
  1491.         degree *= -1.0;
  1492.  
  1493.     return degree;
  1494. }
Advertisement
Add Comment
Please, Sign In to add comment