-- Shared, server-authoritative progression configuration. -- Prices and rewards are only acted upon by sv_progression.lua. Clients receive -- this file so the shop can render the same catalogue without duplicating it. CustomCoopProgression = CustomCoopProgression or {} local Progression = CustomCoopProgression Progression.KillReward = 1 Progression.DeathCreditCost = 5 Progression.DefaultModelID = "kleiner" Progression.DefaultWeaponID = "none" Progression.MaximumShopPrice = 100000000 Progression.MusicCooldownPadding = 10 Progression.AdminShopTestingBypass = true Progression.HoverpackHoldDelay = 0.3 Progression.HoverpackRiseSpeed = 24 Progression.HoverpackDrainPerSecond = 16 Progression.HoverpackRechargeDelay = 1.25 Progression.HoverpackRechargePerSecond = 14 Progression.HoverpackWalkingRechargePerSecond = 22 Progression.HoverpackSound = "PhysicsCannister.ThrusterLoop" Progression.HoverpackSoundVolume = 0.55 Progression.HoverpackSoundPitch = 115 Progression.Ranks = { { score = 0, name = "Newbie" }, { score = 10, name = "Survivor" }, { score = 50, name = "Hunter" }, { score = 150, name = "Slayer" }, { score = 500, name = "Veteran" }, { score = 1500, name = "Exterminator" }, { score = 5000, name = "Legend" } } Progression.Models = { { id = "kleiner", name = "Dr. Kleiner", model = "models/player/kleiner.mdl", price = 0, description = "The free default model." }, { id = "male_citizen", name = "Male Citizen", model = "models/player/group01/male_07.mdl", price = 5, description = "A survivor from City 17." }, { id = "female_citizen", name = "Female Citizen", model = "models/player/group01/female_04.mdl", price = 5, description = "A survivor from City 17." }, { id = "barney", name = "Barney Calhoun", model = "models/player/barney.mdl", price = 10, description = "Civil Protection's least loyal officer." }, { id = "alyx", name = "Alyx Vance", model = "models/player/alyx.mdl", price = 15, description = "Resistance fighter and engineer." }, { id = "monk", name = "Father Grigori", model = "models/player/monk.mdl", price = 25, description = "A familiar face from Ravenholm." }, { id = "combine", name = "Combine Soldier", model = "models/player/combine_soldier.mdl", price = 50, description = "Standard Combine infantry." }, { id = "combine_elite", name = "Combine Elite", model = "models/player/combine_super_soldier.mdl", price = 100, description = "An elite Overwatch soldier." } } Progression.Weapons = { { id = "none", name = "No Bonus Weapon", weaponClass = "", price = 0, description = "Use only weapons supplied by the map." }, { id = "glock", name = "Glock", weaponClass = "coop_glock", price = 15, description = "A reliable permanent sidearm unlock." }, { id = "mp5", name = "MP5", weaponClass = "coop_mp5", price = 40, description = "A permanent compact SMG unlock." }, { id = "pumpshotgun", name = "Pump Shotgun", weaponClass = "coop_pumpshotgun", price = 75, description = "A permanent close-range weapon unlock." }, { id = "m4", name = "M4", weaponClass = "coop_m4", price = 125, description = "A permanent rifle unlock." }, { id = "nyan_gun", name = "Nyan Gun", weaponClass = "weapon_nyangun", price = 1000, description = "Rainbows, music and extremely colourful destruction." }, { id = "lightsaber", name = "Lightsaber", weaponClass = "weapon_lightsaber", price = 1000, description = "A permanent weapon from a galaxy far, far away." }, { id = "orbital_friendship_cannon", name = "Orbital Friendship Cannon", weaponClass = "orbital_friendship_cannon", price = 5000, description = "Deliver friendship from orbit." }, { id = "sexyness", name = "Sexyness (2-bit)", weaponClass = "pist_weagon", price = 100000, description = "The absurdly powerful Ultimate Admin Gun." } } Progression.Music = { { id = "trololo", name = "Trolololo", sound = "custom_coop_music/trololo.mp3", price = 250, duration = 162, spatial = true, minimumDistance = 120, maximumDistance = 2200, description = "Your character plays this song as moving, positional audio. Unlocks permanently." } } Progression.Behaviours = { { id = "hoverpack", name = "Hoverpack", price = 500, description = "Hold Space after jumping to hover and rise slowly. Toggle this behaviour on or off." }, { id = "godmode_90", name = "God Mode — 90 Seconds", price = 1000, duration = 90, consumable = true, description = "Activate 90 seconds of complete damage immunity. Each use is purchased separately." } } -- Only these combat NPC classes award points. Keeping an allow-list avoids -- rewards for friendly citizens, scripted targets and manually invented entity -- classes. Add a class here if a future coop map uses another real monster. Progression.MonsterClasses = { npc_advisor = true, npc_antlion = true, npc_antlionguard = true, npc_antlion_worker = true, npc_barnacle = true, npc_clawscanner = true, npc_combine_s = true, npc_combinedropship = true, npc_combinegunship = true, npc_cscanner = true, npc_fastzombie = true, npc_fastzombie_torso = true, npc_headcrab = true, npc_headcrab_black = true, npc_headcrab_fast = true, npc_headcrab_poison = true, npc_helicopter = true, npc_hunter = true, npc_manhack = true, npc_metropolice = true, npc_poisonzombie = true, npc_rollermine = true, npc_sniper = true, npc_stalker = true, npc_strider = true, npc_turret_ceiling = true, npc_turret_floor = true, npc_turret_ground = true, npc_vortigaunt = true, npc_zombie = true, npc_zombie_torso = true, npc_zombine = true, monster_alien_controller = true, monster_alien_grunt = true, monster_alien_slave = true, monster_apache = true, monster_barnacle = true, monster_bigmomma = true, monster_bullchicken = true, monster_gargantua = true, monster_headcrab = true, monster_houndeye = true, monster_human_assassin = true, monster_human_grunt = true, monster_ichthyosaur = true, monster_leech = true, monster_nihilanth = true, monster_osprey = true, monster_snark = true, monster_tentacle = true, monster_zombie = true } local function FindByID(items, id) for _, item in ipairs(items) do if item.id == id then return item end end end function Progression.GetModel(id) return FindByID(Progression.Models, id) end function Progression.GetWeapon(id) return FindByID(Progression.Weapons, id) end function Progression.GetMusic(id) return FindByID(Progression.Music, id) end function Progression.GetBehaviour(id) return FindByID(Progression.Behaviours, id) end function Progression.GetRank(score) local result = Progression.Ranks[1].name score = math.max(tonumber(score) or 0, 0) for _, rank in ipairs(Progression.Ranks) do if score < rank.score then break end result = rank.name end return result end local function SetHoverpackThrusting(ply, thrusting) if SERVER and Progression.SetHoverpackThrusting then Progression.SetHoverpackThrusting(ply, thrusting) end end hook.Add("SetupMove", "CustomCoopProgressionHoverpack", function(ply, moveData) local jumpHeld = moveData:KeyDown(IN_JUMP) local suitPower = ply.GetSuitPower and ply:GetSuitPower() or 100 local canHover = ply:GetNW2Bool("CustomCoopHoverpackEnabled", false) and ply:Alive() and ply:GetMoveType() == MOVETYPE_WALK and ply:WaterLevel() < 2 and not ply:InVehicle() and suitPower > 0.01 if not jumpHeld or not canHover then ply.CustomCoopHoverHoldStarted = nil ply.CustomCoopHoverJumpWasHeld = false SetHoverpackThrusting(ply, false) return end if not ply.CustomCoopHoverJumpWasHeld then ply.CustomCoopHoverHoldStarted = CurTime() end ply.CustomCoopHoverJumpWasHeld = true -- Continually reset while grounded. A normal jump therefore happens first, -- and hovering only starts after Space remains held in the air. if ply:OnGround() then ply.CustomCoopHoverHoldStarted = CurTime() SetHoverpackThrusting(ply, false) return end ply.CustomCoopHoverHoldStarted = ply.CustomCoopHoverHoldStarted or CurTime() if CurTime() - ply.CustomCoopHoverHoldStarted < Progression.HoverpackHoldDelay then SetHoverpackThrusting(ply, false) return end local velocity = moveData:GetVelocity() velocity.z = Progression.HoverpackRiseSpeed moveData:SetVelocity(velocity) SetHoverpackThrusting(ply, true) end)