Last active
September 14, 2018 05:13
-
-
Save dhkatz/d7cade1adbfcb04ca98b7e2817a5ee64 to your computer and use it in GitHub Desktop.
Garry's Mod Boss Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Put in either addons/boss_framework/lua/autorun/boss_framework.lua or just lua/autorun/boss_framework.lua | |
if SERVER then | |
local BossEnabled = CreateConVar("boss_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Enable/disable the boss system.") | |
local BossCooldown = CreateConVar("boss_cooldown", "300", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Cooldown between when a boss can even possibly spawn.") | |
local BossThreshold = CreateConVar("boss_threshold", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Number of players required for a boss to spawn.") | |
AddCSLuaFile() | |
-------------------- | |
-- BOSS FRAMEWORK -- | |
-------------------- | |
boss = {} | |
boss.Active = false | |
boss.Current = NULL | |
boss.Next = CurTime() | |
local Bosses = {} | |
local Indexes = {} | |
function boss.Register(name, tbl) | |
tbl.Name = name | |
-- You should probably add some validation here | |
Bosses[string.lower(name)] = tbl | |
local index = #Indexes + 1 | |
Indexes[index] = string.lower(name) | |
for _, ply in ipairs(player.GetAll()) do | |
net.Start("BossRegister") | |
net.WriteString(name) | |
net.Send(ply) | |
end | |
return index | |
end | |
function boss.GetByName(name) | |
return Bosses[string.lower(name)] | |
end | |
function boss.GetByIndex(index) | |
return Bosses[Indexes[index]] | |
end | |
function boss.GetAllBosses() | |
return Bosses | |
end | |
function boss.GetCurrent() | |
return boss.Current | |
end | |
function boss.IsActive() | |
return boss.Active | |
end | |
function boss.Think() | |
if player.GetCount() < BossThreshold:GetInt() then return end | |
if boss.Active then return end | |
if boss.Next > CurTime() then return end | |
for name, b in pairs(Bosses) do | |
if math.random() > b.Chance then continue end | |
local ent = ents.Create(b.Class) | |
ent:SetPos(table.Random(ents.FindByClass("info_player_start")):GetPos()) | |
ent:SetHealth(b.Health) | |
if b.Spawn then | |
b:Spawn(ent) | |
end | |
ent:Spawn() | |
ent.IsBoss = true | |
ent.BossName = b.Name | |
boss.Active = true | |
boss.Current = ent | |
hook.Run("BossSpawned", b.Name, ent) | |
return | |
end | |
end | |
----------------------- | |
-- CUSTOM BOSS HOOKS -- | |
----------------------- | |
-- Called when the boss is spawned, you can create your own custom "BossSpawned" hooks too! | |
hook.Add("BossSpawned", "BossSpawned.Alert", function(name, ent, force) | |
for _, ply in ipairs(player.GetAll()) do | |
ply:ChatPrint("[ALERT] World boss '" .. name .. "' has entered the area!") | |
end | |
end) | |
-- Called when the boss is killed, you can create your own custom "BossSpawned" hooks too! | |
hook.Add("BossKilled", "BossKilled.Alert", function(name, ent, killer) | |
for _, ply in ipairs(player.GetAll()) do | |
ply:ChatPrint("[ALERT] World boss '" .. name .. "' has been defeated!") | |
end | |
end) | |
---------------- | |
-- NETWORKING -- | |
---------------- | |
util.AddNetworkString("BossRegister") | |
util.AddNetworkString("BossForce") | |
util.AddNetworkString("BossReset") | |
net.Receive("BossForce", function(ply) | |
local data = net.ReadTable() | |
if not ply:IsAdmin() then return end | |
local b = Bosses[string.lower(data.Name)] | |
if not b then return end | |
local ent = ents.Create(b.Class) | |
ent:SetPos(data.Pos or table.Random(ents.FindByClass("info_player_start")):GetPos()) | |
ent:SetHealth(b.Health) | |
if b.Spawn then | |
b:Spawn(ent) | |
end | |
ent:Spawn() | |
ent.IsBoss = true | |
ent.BossForced = true | |
ent.BossName = b.Name | |
boss.Active = true | |
boss.Current = ent | |
hook.Run("BossSpawned", b.Name, ent, true) | |
end) | |
net.Receive("BossReset", function(ply) | |
if not ply:IsAdmin() then return end | |
boss.Next = CurTime() | |
end) | |
---------------- | |
-- HOOK LOGIC -- | |
---------------- | |
hook.Add("Initialize", "BOSS.Initialize", function() | |
local files, _ = file.Find("bosses/*.lua", "LUA") | |
print("-------------------------------") | |
print(" INITIALIZING BOSSES FRAMEWORK ") | |
print("-------------------------------") | |
print(" LOADING CUSTOM BOSSES ") | |
print("-------------------------------") | |
for _, f in pairs(files) do | |
print("Loaded boss '" .. (string.len(f) > 13 and string.sub(f, 1, 13) or f) .. "'.") | |
include("bosses/" .. f) | |
end | |
print("-------------------------------") | |
print(" FINISHED LOADING BOSSES ") | |
print("-------------------------------") | |
end) | |
hook.Add("PlayerInitialSpawn", "BOSS.PlayerInitialSpawn", function(ply) | |
for name in pairs(Bosses) do | |
net.Start("BossRegister") | |
net.WriteString(name) | |
net.Send(ply) | |
end | |
end) | |
hook.Add("Think", "BOSS.Think", function() | |
if not BossEnabled:GetBool() then return end | |
boss.Think() | |
end) | |
local function BossDied(ent, ply) | |
if not ent.IsBoss then return end | |
if not (IsValid(boss.Current) or boss.Active) then return end | |
if not Bosses[string.lower(ent.BossName)] then return end | |
hook.Run("BossKilled", ent.BossName, ent, ply) | |
boss.Current = NULL | |
boss.Active = false | |
if not ent.BossForced then | |
boss.Next = CurTime() + BossCooldown:GetFloat() | |
end | |
if not isentity(ply) or not ply:IsPlayer() then | |
return | |
end | |
local b = Bosses[string.lower(ent.BossName)] | |
if b.Killed then | |
b:Killed(ply) | |
end | |
end | |
hook.Add("OnNPCKilled", "BOSS.OnNPCKilled", BossDied) | |
hook.Add("EntityRemoved", "BOSS.EntityRemoved", BossDied) | |
end | |
if CLIENT then | |
local Bosses = {} | |
----------------------- | |
-- NETWORKING BOSSES -- | |
---------------------- | |
net.Receive("BossRegister", function() | |
local name = net.ReadString() | |
table.insert(Bosses, name) | |
end) | |
----------------------- | |
-- CUSTOM COMMANDS -- | |
----------------------- | |
concommand.Add("boss_list", function(ply, cmd, args) | |
print("--------------------------------") | |
print(" BOSS TABLE ") | |
print("--------------------------------") | |
PrintTable(Bosses) | |
print("--------------------------------") | |
end, nil, "Print all bosses to console.") | |
concommand.Add("boss_force", function(ply, cmd, args) | |
if not ply:IsAdmin() then | |
return | |
end | |
local name = isnumber(tonumber(args[1])) and Bosses[tonumber(args[1])] or isstring(args[1]) and args[1] or table.Random(Bosses) | |
net.Start("BossForce") | |
net.WriteTable({ | |
Name = name | |
}) | |
net.SendToServer() | |
end, nil, "Force spawn a random boss. (Admin only)") | |
concommand.Add("boss_spawn", function(ply, cmd, args) | |
if not ply:IsAdmin() then return end | |
local name = isnumber(tonumber(args[1])) and Bosses[tonumber(args[1])] or isstring(args[1]) and args[1] or table.Random(Bosses) | |
local tr = ply:GetEyeTrace() | |
if not tr.Hit then print("You are not looking anywhere!") return end | |
net.Start("BossForce") | |
net.WriteTable({ | |
Name = name, | |
Pos = tr.HitPos | |
}) | |
net.SendToServer() | |
end, nil, "Force spawn a boss at the location you are looking.") | |
concommand.Add("boss_reset", function(ply, cmd, args) | |
if not ply:IsAdmin() then return end | |
net.Start("BossReset") | |
net.SendToServer() | |
end, nil, "Reset the cooldown.") | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Put in either addons/boss_framework/lua/bosses/super_combine.lua or lua/bosses/super_combine.lua | |
local BOSS = {} | |
BOSS.Health = 5000 -- Starting health of boss | |
BOSS.Class = "npc_combine_s" -- NPC class of the boss | |
BOSS.Chance = 1 / 10000 -- Chance the boss will spawn each tick, experiment with this | |
-- This gets run when the boss gets killed, the player that killed the boss is provided | |
function BOSS:Killed(ply) | |
ply:ChatPrint("You DEFEATED world boss '" .. self.Name .. "'!") | |
ply:SetHealth(ply:GetMaxHealth()) | |
ply:SetArmor(100) | |
end | |
-- This gets run when the boss is about to be spawned, the entity created is passed. You can modify the NPC right before it is spawned here. | |
function BOSS:Spawn(ent) | |
ent:SetKeyValue("additionalequipment", "weapon_smg1") | |
end | |
BOSS_SUPERCOMBINE = boss.Register("Super Combine", BOSS) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment