UPGRADEABLE_WEAPONS = { "tf_weapon_scattergun", "tf_weapon_pistol", "tf_weapon_bat", "tf_weapon_rocketlauncher", "tf_weapon_shotgun_primary", "tf_weapon_shovel", "tf_weapon_flamethrower", "tf_weapon_fireaxe", "tf_weapon_grenadelauncher", "tf_weapon_pipebomblauncher", "tf_weapon_bottle", "tf_weapon_minigun", "tf_weapon_fists", "tf_weapon_wrench", "tf_weapon_syringegun_medic", "tf_weapon_medigun", "tf_weapon_bonesaw", "tf_weapon_sniperrifle", "tf_weapon_smg", "tf_weapon_club", "tf_weapon_revolver", "tf_weapon_builder", "tf_weapon_knife", "tf_weapon_invis", }; WEARS = { ["factory new"] = 0.0, ["minimal wear"] = 0.25, ["field-tested"] = 0.5, ["well-worn"] = 0.75, ["battle scarred"] = 1.0, }; UNUSUALS = { ["reset"] = 0, ["hot"] = 701, ["isotope"] = 702, ["cool"] = 703, ["energy orb"] = 704, }; KILLSTREAKS = { ["reset"] = 0, ["team shine"] = 1, ["deadly daffodil"] = 2, ["manndarin"] = 3, ["mean green"] = 4, ["agonizing emerald"] = 5, ["villainous violet"] = 6, ["hot rod"] = 7, }; WARPAINT_WEAPONS = { [TF_CLASS_SCOUT] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_scattergun", "the shortstop", "the soda popper" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_pistol", "the winger" }, [LOADOUT_POSITION_MELEE] = { "the holy mackerel" } }, [TF_CLASS_SOLDIER] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_rocketlauncher", "the black box", "the air strike" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_shotgun_primary", "panic attack shotgun", "the reserve shooter" }, [LOADOUT_POSITION_MELEE] = { "the disciplinary action" } }, [TF_CLASS_PYRO] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_flamethrower", "the degreaser", "the dragon's fury" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_shotgun_primary", "panic attack shotgun", "the reserve shooter", "the detonator", "the scorch shot", }, [LOADOUT_POSITION_MELEE] = { "the powerjack", "the back scratcher" } }, [TF_CLASS_DEMOMAN] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_grenadelauncher", "the loch-n-load", "the loose cannon", "the iron bomber" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_pipebomblauncher" }, [LOADOUT_POSITION_MELEE] = { "the scotsman's skullcutter", "the claidheamohmor", "the persian persuader" } }, [TF_CLASS_HEAVYWEAPONS] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_minigun", "the brass beast", "tomislav" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_shotgun_primary", "panic attack shotgun", "the family business" }, [LOADOUT_POSITION_MELEE] = {} }, [TF_CLASS_ENGINEER] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_shotgun_primary", "panic attack shotgun", "the rescue ranger" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_pistol" }, [LOADOUT_POSITION_MELEE] = { "tf_weapon_wrench", "the jag" } }, [TF_CLASS_MEDIC] = { [LOADOUT_POSITION_PRIMARY] = { "the crusader's crossbow" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_medigun" }, [LOADOUT_POSITION_MELEE] = { "the ubersaw", "the amputator" } }, [TF_CLASS_SNIPER] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_sniperrifle", "the bazaar bargain" }, [LOADOUT_POSITION_SECONDARY] = { "tf_weapon_smg" }, [LOADOUT_POSITION_MELEE] = { "the shahanshah" } }, [TF_CLASS_SPY] = { [LOADOUT_POSITION_PRIMARY] = { "tf_weapon_revolver" }, [LOADOUT_POSITION_SECONDARY] = {}, [LOADOUT_POSITION_MELEE] = { "tf_weapon_knife" } }, }; DEFAULT_WARPAINT_WEAPONS = { [TF_CLASS_SCOUT] = { "tf_weapon_scattergun", "The Winger", "The Holy Mackerel" }, [TF_CLASS_SOLDIER] = { "tf_weapon_rocketlauncher", "tf_weapon_shotgun", "The Disciplinary Action" }, [TF_CLASS_PYRO] = { "tf_weapon_flamethrower", "The Detonator", "The Powerjack" }, [TF_CLASS_DEMOMAN] = { "tf_weapon_grenadelauncher", "tf_weapon_pipebomblauncher", "The Scotsman's Skullcutter" }, [TF_CLASS_HEAVYWEAPONS] = { "tf_weapon_minigun", "The Family Business", nil }, [TF_CLASS_ENGINEER] = { "The Rescue Ranger", "tf_weapon_pistol", "tf_weapon_wrench" }, [TF_CLASS_MEDIC] = { "The Crusader's Crossbow", "tf_weapon_medigun", "The Amputator" }, [TF_CLASS_SNIPER] = { "tf_weapon_sniperrifle", "tf_weapon_smg", "The Shahanshah" }, [TF_CLASS_SPY] = { "tf_weapon_revolver", nil, "tf_weapon_knife" }, }; -- Console has a limit to how many characters you can print to it at a time, need to split up documentation HELP_TEXT1 = [[ COMMANDS -------- !give <weapon name/defindex> [warpaint id] [wear value/label] [effect value/label] [killstreak value/label] - Give yourself an item, optionally with a warpaint and other attributes -- Wear Values -- 0.00 - `factory new` 0.25 - `minimal wear` 0.50 - `field-tested` 0.75 - `well-worn` 1.00 - `battle scarred` -- Effect Values -- 0 - `reset` 701 - `hot` 702 - `isotope` 703 - `cool` 704 - `energy orb` -- Killstreak Values -- 0 - `reset` 1 - `team shine` 2 - `deadly daffodil` 3 - `manndarin` 4 - `mean green` 5 - `agonizing emerald` 6 - `villainous violet` 7 - `hot rod` --- Examples --- !give `The Shortstop` !give `The Shortstop` 420 !give `The Shortstop` 420 `factory new` !give `The Shortstop` 420 fac !give 220 420 battle !give 220 420 1 !give tf_weapon_scattergun 420 min !give 13 420 battle cool `hot rod` ]]; HELP_TEXT2 = [[ !givebot <weapon name/defindex> [warpaint id] [warpaint value/label] [effect value/label] [killstreak value/label] - (Same usage as !give.) Give a bot under your crosshair an item, optionally with and other attributes !paint <warpaint id> - Change the warpaint of your currently held weapon, keeping its other attributes !loadoutpaint [warpaint id] - With no arguments, (just !loadoutpaint) this command will toggle off - With an argument, this command will give you warpaint items with the warpaint id every time you spawn for every class !next - With loadoutpaint active, switch your active weapon to the next warpaint weapon !prev - With loadoutpaint active, switch your active weapon to the previous warpaint weapon !wear <wear value/label> - Change the wear of your currently held weapon, keeping its other attributes ]] HELP_TEXT3 = [[ !effect <effect value/label> - Change the unusual effect attached to your currently held weapon, keeping its other attributes !killstreak or !ks <killstreak value/label> - Change the killstreak sheen of your currently held weapon, keeping its other attributes !randomseed or !rs - Randomize the paintkit seed on your currently held weapon !seed [new seed] - With no arguments, (just !seed) this command will return the seed of the currently held weapon - With an argument, this command will change the seed of the currently held weapon !thirdperson - Toggle thirdperson mode on yourself !switchteam - Switch your team between red/blue. !wavestart - Start / Restart the wave. !wavepause - Pause / Unpause bot spawning and AI. KEYBINDS -------- +Reload - Toggle hud visibility ]] local pop_interface = Entity("point_populator_interface"); local gamerules = ents.FindByClass("tf_gamerules"); local wave_paused = false; -- Split a string by delimiter function string.split(s, delim) delim = delim or "%s"; -- whitespace local t = {}; for str in string.gmatch(s, "([^"..delim.."]+)") do -- voodoo magic table.insert(t, str); end return t end -- Round a number (because including a round function in your programming language is too difficult) math.round = function(num, decimals) if (not decimals or decimals <= 0) then return math.floor(num + 0.5); else local mod = 10 ^ decimals; return math.floor((num * mod) + 0.5) / mod; end end -- Random float math.randomfloat = function(m, n) if (m) then if (n) then if (n == m) then return m; elseif (m > n) then m, n = n, m; end -- n should be greater than m local dif = n - m; local mod = dif * math.random(); return m + mod; else return m * math.random(); end else return math.random(); end end -- Parse player chat message, returning command name and args list if message was command function ParseCommand(text) if (not text or #text == 0 or string.sub(text, 1, 1) ~= "!") then return; end local cmd = nil; local args = {}; -- Construct cmd and args local t = string.split(text, " "); local string_start = nil; for index, str in pairs(t) do local firstchar = string.sub(str, 1, 1); local lastchar = string.sub(str, #str); -- Sanity check string chars if ((#str == 1 and firstchar == "`") or (not string_start and firstchar ~= "`" and lastchar == "`") or (firstchar == "!" and string.find(str, "`"))) then return; end if (not string_start) then -- Command name if (not cmd and firstchar == "!") then cmd = string.sub(str, 2); -- Invalid command name if (not cmd or #cmd == 0) then return; end -- String start elseif (firstchar == "`") then if (lastchar ~= "`") then string_start = index; -- ... and end else table.insert(args, string.sub(str, 2, -2)); end -- Normal arg else table.insert(args, str); end -- String end else if (lastchar == "`") then local s = table.concat(t, " ", string_start, index); table.insert(args, string.sub(s, 2, -2)); string_start = nil; end end end -- Missing closing ` for string if (string_start) then return; end return cmd, args; end -- Find key in table where s is a substring of that key function FindSubstringKey(t, s) local chosen = nil; for str, value in pairs(t) do local i, j = string.find(str, string.lower(s), 1, true); if (i ~= 1) then goto continue; end -- First substring if (not chosen) then chosen = str; -- Multiple matches else return; end ::continue:: end return chosen; end function IsValidPlayer(ent) return IsValid(ent) and ent:IsPlayer(); end function IsValidRealPlayer(ent) return IsValid(ent) and ent:IsRealPlayer(); end function IsValidAlivePlayer(ent) return IsValid(ent) and ent:IsPlayer() and ent:IsAlive(); end function IsValidAliveRealPlayer(ent) return IsValid(ent) and ent:IsRealPlayer() and ent:IsAlive(); end -- Grab the CEntity table local _ = Entity("info_target", false, false); local CEntity = getmetatable(_); _:Remove(); -- Delayed ShowHudText display function CEntity:ShowHudDialogue(text, clr, fadein, sound_interval, sound_duration, fadeout, holdtime, fxtime) if (not IsValidPlayer(self)) then return; end -- Defaults fadein = fadein or 0.025; sound_interval = sound_interval or 0.2; sound_duration = (sound_duration and sound_duration / sound_interval) or (#text * fadein) / sound_interval -- an approximation fadeout = fadeout or 0.3; holdtime = holdtime or 3; fxtime = fxtime or 0.1; -- Unpack clr local r, g, b; if (clr and #clr == 3) then r, g, b = table.unpack(clr); else r, g, b = 255, 255, 255; end -- Display self:ShowHudText({ channel = 0, x = -1, y = 0.3, effect = 2, r1 = r, g1 = g, b1 = b, a1 = 0, r2 = 0, g2 = 0, b2 = 0, a2 = 0, fadeinTime = fadein, fadeoutTime = fadeout, holdTime = holdtime, fxTime = fxtime, }, text); -- Sounds for typing out the chars timer.Create(sound_interval, function() if (math.random(2) == 1) then self:PlaySoundToSelf("ui/panel_close.wav"); else self:PlaySoundToSelf("ui/panel_open.wav"); end end, sound_duration); end -- Get player eye angles function CEntity:GetEyeAngles() if (not IsValidPlayer(self)) then return; end return Vector(self["m_angEyeAngles[0]"], self["m_angEyeAngles[1]"], 0); end -- Get weapon slot function CEntity:GetSlot() if (not IsValid(self) or not self:IsWeapon()) then return; end local player = self.m_hOwner or self.m_hOwnerEntity; if (not IsValidPlayer(player)) then return; end for slot = 0, 6 do if (player:GetPlayerItemBySlot(slot) == self) then return slot; end end end -- Get base weapon name useable in WARPAINT_WEAPONS function CEntity:GetBaseWeaponName() if (not IsValid(self) or not self:IsWeapon()) then return; end local weaponname = string.lower(self:GetItemName()); -- Fixup shotgun weapon names if (weaponname and string.find(weaponname, "tf_weapon_shotgun")) then weaponname = "tf_weapon_shotgun_primary"; end -- Remove upgradeable local i, j = string.find(weaponname, "upgradeable "); if (i and j) then weaponname = string.sub(weaponname, j+1); end return weaponname; end -- Give a warpaint item to a player function CEntity:GiveWarpaintItem(weaponname, warpaint, wear, effect, seed, killstreak) if (not IsValidAlivePlayer(self) or not weaponname) then return; end -- Warpaints only work with tf_weapon_shotgun_primary if (string.find(weaponname, "tf_weapon_shotgun")) then weaponname = "tf_weapon_shotgun_primary"; end -- Need to make sure stock weapons are upgradeable to allow warpaints... local wep = nil; local i, j = string.find(weaponname, "upgradeable"); -- User entered upgradeable already in weapon name if (i == 1) then wep = self:GiveItem(weaponname); -- Add it otherwise else if (table.HasValue(UPGRADEABLE_WEAPONS, weaponname)) then wep = self:GiveItem("upgradeable "..weaponname); else wep = self:GiveItem(weaponname); end end if (not IsValid(wep)) then self:Print(PRINT_TARGET_CHAT, "Could not give weapon. Usage: !give <weapon name/defindex> [warpaint id] [warpaint value/label]"); return; end -- Warpaint if (warpaint) then wep:SetAttributeValue("paintkit_proto_def_index", tonumber(warpaint)); if (not seed) then seed = math.round(math.randomfloat(0, 2^64)); end wep:SetAttributeValue("custom_paintkit_seed_lo", seed); wep:SetAttributeValue("custom_paintkit_seed_hi", seed); -- For some reason "paintkit_proto_def_index" gets reset on the weapon after setting it -- We need to access it later so we store it here wep._paintkit = warpaint; end -- Default to factory new when no wear provided wear = wear or 0.0; local attributes = { { wear, "Set_item_texture_wear", WEARS, "Invalid wear name, Choosing Factory New." }, { effect, "attach particle effect", UNUSUALS, "Invalid effect name." }, { killstreak, "killstreak idleeffect", KILLSTREAKS, "Invalid killstreak name." }, }; for index, t in pairs(attributes) do local arg, attr, reftable, errormsg = table.unpack(t); if (arg) then if (tonumber(arg)) then wep:SetAttributeValue(attr, tonumber(arg)); else local chosen = FindSubstringKey(reftable, arg); if (not chosen) then self:Print(PRINT_TARGET_CHAT, "Invalid command usage: "..errormsg); else -- Give specialized killstreak tier if (reftable == KILLSTREAKS) then wep:SetAttributeValue("killstreak tier", 2); end wep:SetAttributeValue(attr, reftable[chosen]); end end end end return wep; end function HandleSimpleCommand(player, args, var, giveitem_args) if (#args == 0) then if (not var) then player:Print(PRINT_TARGET_CHAT, "The weapon does not have this attribute."); else player:Print(PRINT_TARGET_CHAT, tostring(var)); end else player:GiveWarpaintItem(table.unpack(giveitem_args)); end end -- Called after a player typed a message in chat function OnPlayerChat(event_table) local cmd, args = ParseCommand(event_table.text); local player = ents.GetPlayerByUserId(event_table.userid); local wep = player.m_hActiveWeapon; if (not IsValid(wep)) then return; end local wear = wep:GetAttributeValue("Set_item_texture_wear"); local effect = wep:GetAttributeValue("attach particle effect"); local seed = wep:GetAttributeValue("custom_paintkit_seed_lo"); local killstreak = wep:GetAttributeValue("killstreak idleeffect"); if (not cmd) then return; end if (cmd == "give" and #args > 0) then local weaponname = string.lower(args[1]); local itemid = tonumber(weaponname); if (itemid) then weaponname = string.lower(util.GetItemDefinitionNameByIndex(itemid)); end seed = math.round(math.randomfloat(0, 2^64)); player:GiveWarpaintItem(weaponname, args[2], args[3], args[4], seed, killstreak); elseif (cmd == "givebot" and #args > 0) then if (util.IsLagCompensationActive()) then return; end local ang = player:GetEyeAngles(); -- Trace line from eyes util.StartLagCompensation(player) local traceresult = util.Trace({ start = player, endpos = nil, distance = 8192, angles = ang, mask = MASK_SOLID, collisiongroup = COLLISION_GROUP_PLAYER, }); util.FinishLagCompensation(player) local bot = traceresult.Entity; if (not IsValidPlayer(bot) or not bot:IsAlive()) then player:Print(PRINT_TARGET_CHAT, "No bot found under crosshair"); return; end local weaponname = string.lower(args[1]); local itemid = tonumber(weaponname); if (itemid) then weaponname = string.lower(util.GetItemDefinitionNameByIndex(itemid)); end seed = math.round(math.randomfloat(0, 2^64)); bot:GiveWarpaintItem(weaponname, args[2], args[3], args[4], seed, killstreak); elseif (cmd == "paint") then HandleSimpleCommand(player, args, wep._paintkit, {string.lower(wep:GetItemName()), args[1], wear, effect, seed, killstreak}); elseif (cmd == "loadoutpaint") then if (player._loadoutpaint and #args == 0) then player._loadoutpaint = nil; else player._loadoutpaint = args[1]; end player:ForceRespawn(); elseif (cmd == "next" or cmd == "prev") then if (not player._loadoutpaint) then return; end local weaponname = wep:GetBaseWeaponName(); local mod = 1; if (cmd == "prev") then mod = -1; end local weptable = WARPAINT_WEAPONS[player.m_iClass][wep:GetSlot()]; for index, name in pairs(weptable) do if (weaponname == name) then if (index + mod > #weptable) then weaponname = weptable[1]; elseif (index + mod < 1) then weaponname = weptable[#weptable]; else weaponname = weptable[index + mod]; end break; end end player:GiveWarpaintItem(weaponname, wep._paintkit, wear, effect, seed, killstreak); elseif (cmd == "wear") then HandleSimpleCommand(player, args, wear, {string.lower(wep:GetItemName()), wep._paintkit, args[1], effect, seed, killstreak}); elseif (cmd == "effect") then HandleSimpleCommand(player, args, effect, {string.lower(wep:GetItemName()), wep._paintkit, wear, args[1], seed, killstreak}); elseif (cmd == "killstreak" or cmd == "ks") then HandleSimpleCommand(player, args, killstreak, {string.lower(wep:GetItemName()), wep._paintkit, wear, effect, seed, args[1]}); elseif (cmd == "randomseed") then seed = math.round(math.randomfloat(0, 2^64)); player:GiveWarpaintItem(string.lower(wep:GetItemName()), wep._paintkit, wear, effect, seed, killstreak); elseif (cmd == "rs") then seed = math.round(math.randomfloat(0, 2^16)); player:GiveWarpaintItem(string.lower(wep:GetItemName()), wep._paintkit, wear, effect, seed, killstreak); elseif (cmd == "seed") then HandleSimpleCommand(player, args, seed, {string.lower(wep:GetItemName()), wep._paintkit, wear, effect, args[1], killstreak}); elseif (cmd == "thirdperson") then player._thirdperson = player._thirdperson == 1 and 0 or 1 player:SetForcedTauntCam(player._thirdperson); elseif (cmd == "switchteam" or cmd == "switchteams") then if (player._reprogrammed) then player._reprogrammed = false; player:RemoveCond(TF_COND_REPROGRAMMED); else player._reprogrammed = true; player:AddCond(TF_COND_REPROGRAMMED); end -- Re-give our weapons to apply the opposite skin of the warpaint for slot = 0, 2 do local wep = player:GetPlayerItemBySlot(slot); if (IsValid(wep)) then local wear = wep:GetAttributeValue("Set_item_texture_wear") or 0; local effect = wep:GetAttributeValue("attach particle effect"); local seed = wep:GetAttributeValue("custom_paintkit_seed_lo"); local killstreak = wep:GetAttributeValue("killstreak idleeffect"); player:GiveWarpaintItem(string.lower(wep:GetItemName()), wep._paintkit, wear, effect, seed, killstreak); end end elseif (cmd == "wavestart") then gamerules.m_flRestartRoundTime = CurTime(); elseif (cmd == "wavepause") then -- Setup if (gamerules.m_iRoundState == 10) then player:Print(PRINT_TARGET_CHAT, "Wave has not been started yet."); return; end local players = ents.GetAllPlayers(); local flags = ents.FindAllByClass("item_teamflag"); if (not wave_paused) then wave_paused = true; pop_interface:PauseBotSpawning(); for index, pl in pairs(players) do if (pl:IsBot()) then pl:SetAttributeValue("no_attack", 1); pl:SetAttributeValue("no_duck", 1); pl:SetAttributeValue("no_jump", 1); pl._movespeed = pl:GetAttributeValue("move speed bonus") or 1; pl:SetAttributeValue("move speed bonus", 0.001); pl:BotCommand("interrupt_action -pos 0 -2000 750 -lookpos 0 -2000 750 -waituntildone -alwayslook"); end end for index, flag in pairs(flags) do flag:ForceDrop(); flag:Disable(); end else wave_paused = false; pop_interface:UnpauseBotSpawning(); for index, pl in pairs(players) do if (pl:IsBot()) then pl:SetAttributeValue("no_attack", nil); pl:SetAttributeValue("no_duck", nil); pl:SetAttributeValue("no_jump", nil); pl:SetAttributeValue("move speed bonus", pl._movespeed); pl:BotCommand("stop interrupt action"); end end for index, flag in pairs(flags) do flag:Enable(); end end elseif (cmd == "spawnbot") then local players = ents.GetAllPlayers(); local bot = nil; for _, team in pairs({2, 1, 3}) do for __, pl in pairs(players) do if (pl:IsBot() and pl.m_iTeamNum == team) then bot = pl; goto break_outer; end end end ::break_outer:: if (not bot) then player:Print(PRINT_TARGET_CHAT, "Could not find adequate target; missing bots on other teams."); return; end -- Move to red if (bot.m_iTeamNum ~= TEAM_RED) then bot:RunScriptCode("self.ForceChangeTeam(2, false);"); bot:SwitchClass(player.m_iClass); bot:ForceRespawn(); end -- give cosmetics and human model -- Teleport local trace; local position; local ang = Vector(player["m_angEyeAngles[0]"], player["m_angEyeAngles[1]"], 0); if (not util.IsLagCompensationActive()) then util.StartLagCompensation(player) trace = util.Trace({ start = player, distance = 8192, angles = ang, }); util.FinishLagCompensation(player) end if (not trace or not trace.Hit) then position = player:GetAbsOrigin(); else position = trace.HitPos; ang = Vector(ang.x, ang.y - 180, ang.z) end bot._think = timer.Create(0.001, function() bot:Teleport(position, ang, Vector(0,0,0)); end, 0); elseif (cmd == "commandhelp" or cmd == "commands") then timer.Create(0.1, function() player:Print(PRINT_TARGET_CONSOLE, HELP_TEXT1); end); timer.Create(0.15, function() player:Print(PRINT_TARGET_CONSOLE, HELP_TEXT2); end); timer.Create(0.2, function() player:Print(PRINT_TARGET_CONSOLE, HELP_TEXT3); end); end end function OnPlayerKey(player, key) if (not IsValidRealPlayer(player)) then return end; if (key == IN_RELOAD) then if (player._hudvisibility) then player._hudvisibility = false; else player._hudvisibility = true; end player:SetHUDVisibility(player._hudvisibility); end end function OnPlayerInventoryApplication(eventTable) local player = ents.GetPlayerByUserId(eventTable.userid); if (not IsValidRealPlayer(player)) then return; end player._hudvisibility = true; player._thirdperson = 0; player._reprogrammed = false; end function OnPlayerSpawn(player) timer.Create(1, function() player:ShowHudDialogue("Type !commands to get info on command usage in console", {20, 200, 50}, 0.025, 0.1, 1.3, 0.3, 5); end, 1); if (player._loadoutpaint) then local seed = math.round(math.randomfloat(0, 2^64)); local paint = player._loadoutpaint; for slot = 0, 2 do local wep = player:GetPlayerItemBySlot(slot); local weaponname = nil; if (IsValid(wep)) then weaponname = wep:GetBaseWeaponName(); end -- Get weapon name from default weapon list if (not table.HasValue(WARPAINT_WEAPONS[player.m_iClass][slot], weaponname)) then weaponname = DEFAULT_WARPAINT_WEAPONS[player.m_iClass][slot+1]; if (not weaponname) then goto continue; end end player:GiveWarpaintItem(weaponname, paint, nil, nil, seed); ::continue:: end end end function OnPlayerConnected(player) if (player:IsRealPlayer()) then player:AddCallback(ON_KEY_PRESSED, OnPlayerKey); player:AddCallback(ON_SPAWN, OnPlayerSpawn); player._hudvisibility = true; player._thirdperson = 0; player._reprogrammed = false; player._loadoutpaint = nil; end end function OnWaveInit(wave) wave_paused = false; if (not IsValid(pop_interface)) then pop_interface = Entity("point_populator_interface"); end end AddEventCallback("player_say", OnPlayerChat); AddEventCallback("post_inventory_application", OnPlayerInventoryApplication);