diff --git a/CHANGES.md b/CHANGES.md index 2df2cf6..2d9c757 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,4 +5,4 @@ * Fixed grapple usage in courses and gamemodes. * Fixed DataTheft crash when touching data bank. * Fixed error when loading course. -* Fixed collisions issues. +* Fixed collisions issues. \ No newline at end of file diff --git a/README.md b/README.md index 577f3fe..6ae1748 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ There are lua modules ([source](https://github.com/fluffy-servers/gmod-discord-r This version of the beatrun works on any version of the game (Chromium or not). ## Changes added by me -* [Custom online courses service](https://courses.beatrun.ru)! It's free 🤯! DM @Jonny_Bro#4226 for an API key. +* [Custom online courses database](https://courses.beatrun.ru)! It's free 🤯! * Allow Overdrive usage on the server - `Beatrun_AllowOvedriveInMultiplayer`. * Change HUD's colors - `Beatrun_HUDTextColor`, `Beatrun_HUDCornerColor`, `Beatrun_HUDFloatingXPColor`. * Discord Rich Presence (extract `lua` folder to `garrysmod`, along side with `addons` folder). @@ -12,8 +12,10 @@ This version of the beatrun works on any version of the game (Chromium or not). * Change max moving speed - `Beatrun_MaxSpeed`. * Ability to remove ziplines that created with *Zipline Gun* - RMB. * Removed your SteamID from right corner, because I can. +* Allow players to spawn props without admin rights - `Beatrun_AllowPropSpawn`. ## Fixes from previous version -* Database update because Cloudflare 🤡. +* Fixed player collision. +* Working on a new Gamemodes menu... (currently doesn't work at all). -### [All changes](https://github.com/JonnyBro/beatrun/blob/master/CHANGES.md) +### [All changes](https://github.com/JonnyBro/beatrun/blob/master/CHANGES.md) \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/entities/entities/br_datacube/shared.lua b/beatrun/gamemodes/beatrun/entities/entities/br_datacube/shared.lua index b6b8c90..ca4fad2 100644 --- a/beatrun/gamemodes/beatrun/entities/entities/br_datacube/shared.lua +++ b/beatrun/gamemodes/beatrun/entities/entities/br_datacube/shared.lua @@ -36,7 +36,6 @@ function ENT:Initialize() end hook.Add("ShouldCollide", "DataCubeCollisions", function(ent1, ent2) - -- If players are about to collide with each other, then they won't collide. if ent1.DataCube and ent2.DataCube then return false end end) diff --git a/beatrun/gamemodes/beatrun/entities/weapons/runnerhands/shared.lua b/beatrun/gamemodes/beatrun/entities/weapons/runnerhands/shared.lua index b23b659..2e67eb9 100644 --- a/beatrun/gamemodes/beatrun/entities/weapons/runnerhands/shared.lua +++ b/beatrun/gamemodes/beatrun/entities/weapons/runnerhands/shared.lua @@ -26,8 +26,8 @@ SWEP.DrawWeaponInfoBox = false SWEP.HoldType = "fist" -SWEP.Spawnable = false -SWEP.AdminSpawnable = false +SWEP.Spawnable = true +SWEP.AdminSpawnable = true --[[Just don't draw the hands, we don't need 'em]] diff --git a/beatrun/gamemodes/beatrun/gamemode/cl/Menu_Gamemodes.lua b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes.lua similarity index 72% rename from beatrun/gamemodes/beatrun/gamemode/cl/Menu_Gamemodes.lua rename to beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes.lua index d443aaf..2dfc581 100644 --- a/beatrun/gamemodes/beatrun/gamemode/cl/Menu_Gamemodes.lua +++ b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes.lua @@ -9,51 +9,29 @@ local gamemodePanel = { gamemodePanel.x = 960 - gamemodePanel.w * 0.5 gamemodePanel.y = 540 - gamemodePanel.h * 0.5 + local function closeButton() AEUI:Clear() end local function infectionButton() - net.Start("Beatrun_ToggleInfection") + net.Start("Beatrun_ToggleGamemode") + net.WriteString("infection") net.SendToServer() end local function datatheftButton() - net.Start("Beatrun_ToggleDataTheft") + net.Start("Beatrun_ToggleGamemode") + net.WriteString("datatheft") net.SendToServer() end -local loadoutnum = 1 -local maxloadoutnum = 1 - -local function createButton() - net.Start("Beatrun_CreateLoadout") - net.SendToServer() - maxloadoutnum = maxloadoutnum + 1 - LocalPlayer():EmitSound("buttonclick.wav") -end - -local function resetloadoutButton() - net.Start("Beatrun_ResetLoadouts") - net.SendToServer() - loadoutnum = 1 - maxloadoutnum = 1 - LocalPlayer():EmitSound("buttonclick.wav") -end - -local function leftButton() - if loadoutnum ~= 1 then - loadoutnum = loadoutnum - 1 - LocalPlayer():EmitSound("buttonclick.wav") - end -end - -local function rightButton() - if loadoutnum ~= maxloadoutnum then - loadoutnum = loadoutnum + 1 - LocalPlayer():EmitSound("buttonclick.wav") - end -end +-- local function createButton() +-- net.Start("Beatrun_CreateLoadout") +-- net.SendToServer() +-- maxloadoutnum = maxloadoutnum + 1 +-- LocalPlayer():EmitSound("buttonclick.wav") +-- end local function isSA() return not LocalPlayer():IsSuperAdmin() @@ -63,17 +41,17 @@ AEUI:AddText(gamemodePanel, "Gamemodes Select", "AEUIVeryLarge", 20, 30) AEUI:AddButton(gamemodePanel, " X ", closeButton, "AEUILarge", gamemodePanel.w - 47, 0) local infectionbutton = AEUI:AddButton(gamemodePanel, "Toggle Infection", infectionButton, "AEUILarge", gamemodePanel.w - 330, gamemodePanel.h - 550) -infectionbutton.greyed = isSA() +infectionbutton.greyed = isSA local datatheftbutton = AEUI:AddButton(gamemodePanel, "Toggle Data Theft", datatheftButton, "AEUILarge", gamemodePanel.w - 330, gamemodePanel.h - 450) -datatheftbutton.greyed = isSA() +datatheftbutton.greyed = isSA -- local loadoutbutton = AEUI:AddButton(gamemodePanel, "Create a new loadout", createButton, "AEUILarge", gamemodePanel.w - 330, gamemodePanel.h - 450) --- loadoutbutton.greyed = isSA() +-- loadoutbutton.greyed = isSA -- local resetbutton = AEUI:AddButton(gamemodePanel, "Resets all loadouts", resetloadoutButton, "AEUILarge", gamemodePanel.w - 330, gamemodePanel.h - 550) --- resetbutton.greyed = isSA() +-- resetbutton.greyed = isSA -- local leftloadout = AEUI:AddButton(gamemodePanel, " < ", leftButton, "AEUILarge", gamemodePanel.w - 225, gamemodePanel.h - 175) --- leftloadout.greyed = isSA() +-- leftloadout.greyed = isSA -- local rightloadout = AEUI:AddButton(gamemodePanel, " > ", rightButton, "AEUILarge", gamemodePanel.w - 150, gamemodePanel.h - 175) --- rightloadout.greyed = isSA() +-- rightloadout.greyed = isSA -- AEUI:AddText(gamemodePanel, "Change through loadouts", "AEUILarge", gamemodePanel.w - 360, gamemodePanel.h - 125) local weaponsList = { @@ -90,19 +68,22 @@ local weaponsList = { function OpenGMMenu(ply) AEUI:AddPanel(gamemodePanel) AEUI:AddPanel(weaponsList) + local loaded_weapons = {} + for i, _ in pairs(DATATHEFT_LOADOUTS) do for _, v in pairs(DATATHEFT_LOADOUTS[i]) do table.insert(loaded_weapons, v) end end + for _, v in pairs(weapons.GetList()) do if not string.find(v.ClassName:lower(), "base") then local weaponentry = AEUI:AddText(weaponsList, v.ClassName, "AEUILarge", 10, 40 * #weaponsList.elements) function weaponentry:onclick() LocalPlayer():EmitSound("buttonclick.wav") end - weaponentry.greyed = isSA() + weaponentry.greyed = isSA end end end diff --git a/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_UI_new.lua b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_UI_new.lua new file mode 100644 index 0000000..c9e0d38 --- /dev/null +++ b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_UI_new.lua @@ -0,0 +1,490 @@ +function CLoadout:GetWeaponIcon(class) + if file.Exists("materials/entities/" .. class .. ".png", "GAME") then return "entities/" .. class .. ".png" end + if file.Exists("materials/vgui/entities/" .. class .. ".vtf", "GAME") then return "vgui/entities/" .. class end +end + +function CLoadout:UpdateLists() + if IsValid(self.listAvailable) then + self:UpdateAvailableList() + end + + if IsValid(self.listLoadoutItems) then + self:UpdateLoadoutList() + end +end + +function CLoadout:CreateAvailableWeaponIcon(class) + local weapon = self.weaponRegistry[class] + + if not weapon then return end + if self.categoryFilter and weapon.category ~= self.categoryFilter then return end + + if self.filter ~= "" then + local foundClass = string.find(class, self.filter, 1, true) + local foundName = string.find(string.lower(weapon.name), self.filter, 1, true) + + if not foundClass and not foundName then return end + end + + local localPly = LocalPlayer() + + local icon = self.listAvailable:Add("CLoadoutWeaponIcon") + icon:SetWeaponName(weapon.name) + icon:SetWeaponClass(class) + + icon.DoClick = function() + if not localPly:IsAdmin() then + Derma_Message("You can't edit loadouts.", "Loadout editor", "OK") + else + self:AddWeapon(class) + self:UpdateLoadoutList() + icon:Remove() + end + end + + icon.OpenMenu = function() + local menu = DermaMenu() + + menu:AddOption("Copy to clipboard", function() + SetClipboardText(class) + end) + + menu:Open() + end +end + +function CLoadout:UpdateAvailableList() + self.listAvailable:Clear() + + local inLoadout = {} + + for _, item in ipairs(DATATHEFT_LOADOUTS[self.loadoutIndex]) do + inLoadout[item[1]] = true + end + + for class, _ in SortedPairsByMemberValue(self.weaponRegistry, "name") do + if not inLoadout[class] then + self:CreateAvailableWeaponIcon(class) + end + end + + self.listAvailable:InvalidateLayout(true) + self.scrollAvailable:InvalidateLayout() +end + +function CLoadout:UpdateLoadoutList() + self.comboLoadouts._blockCallback = true + self.comboLoadouts:Clear() + + for index, loadout in ipairs(DATATHEFT_LOADOUTS) do + self.comboLoadouts:AddChoice(tostring(index), nil, index == self.loadoutIndex) + end + + self.comboLoadouts._blockCallback = nil + self.listLoadoutItems:Clear() + + local items = DATATHEFT_LOADOUTS[self.loadoutIndex] + + for index, item in ipairs(items) do + local class = item[1] + local icon = self.listLoadoutItems:Add("CLoadoutWeaponIcon") + icon:SetWeaponClass(class) + icon._itemIndex = index + + icon.DoClick = function() + self:RemoveWeapon(index) + self:CreateAvailableWeaponIcon(class) + icon:Remove() + end + + local regWeapon = self.weaponRegistry[class] + + if not regWeapon then + if not self.hintedMissingWeapons then + self.hintedMissingWeapons = true + + Derma_Message("This loadout has weapons that are currently unavailable.\nMake sure they are installed to use them.", "Missing weapons", "OK") + end + + icon:SetWeaponName(class) + icon:SetMaterial("icon16/cancel.png") + + continue + end + + icon:SetWeaponName(regWeapon.name) + + if regWeapon.adminOnly then + icon:SetAdminOnly(true) + end + + if not regWeapon.noPrimary then + icon.Primary = item[2] + end + + if not regWeapon.noSecondary then + icon.Secondary = item[3] + end + end + + self.labelCount:SetTextColor(#items > self:GetWeaponLimit() and Color(255, 50, 50) or color_white) + self.labelCount:SetText(string.format("%d/%d", #items, self:GetWeaponLimit())) + self.labelCount:SizeToContents() + + self.listLoadoutItems:InvalidateLayout(true) + + self.scrollLoadoutItems:InvalidateLayout() +end + +function CLoadout:ShowPanel() + if IsValid(self.frame) then + self.frame:Close() + self.frame = nil + + return + end + + local frameW = math.max(ScrW() * 0.6, 820) + local frameH = math.max(ScrH() * 0.6, 500) + frameW = math.Clamp(frameW, 600, ScrW()) + frameH = math.Clamp(frameH, 400, ScrH()) + + local frame = vgui.Create("DFrame") + frame:SetTitle("Click on any weapon to add/remove it from your loadout.") + frame:SetPos(0, 0) + frame:SetSize(frameW, frameH) + frame:SetSizable(true) + frame:SetDraggable(true) + frame:SetDeleteOnClose(true) + frame:SetScreenLock(true) + frame:SetMinWidth(600) + frame:SetMinHeight(400) + frame:Center() + frame:MakePopup() + + self.frame = frame + + frame._maximized = false + frame.btnMaxim:SetDisabled(false) + + frame.btnClose.DoClick = function() + frame:Close() + end + + frame.OnClose = function() + self:Apply() + end + + local leftPanel = vgui.Create("DPanel", frame) + local rightPanel = vgui.Create("DPanel", frame) + + local function PaintBackground(_, sw, sh) + surface.SetDrawColor(32, 32, 32, 255) + surface.DrawRect(0, 0, sw, sh) + end + + leftPanel.Paint = PaintBackground + rightPanel.Paint = PaintBackground + + local div = vgui.Create("DHorizontalDivider", frame) + div:Dock(FILL) + div:SetLeft(leftPanel) + div:SetRight(rightPanel) + div:SetDividerWidth(4) + div:SetLeftMin(200) + div:SetRightMin(200) + div:SetLeftWidth(frameW * 0.56) + + frame.btnMaxim.DoClick = function() + if frame._maximized then + frame:SetSize(frame._oldDimensions[1], frame._oldDimensions[2]) + frame:Center() + frame._maximized = false + frame._oldDimensions = nil + else + frame._maximized = true + + frame._oldDimensions = {frame:GetWide(), frame:GetTall()} + + frame:SetPos(0, 0) + frame:SetSize(ScrW(), ScrH()) + end + + frame:SetDraggable(not frame._maximized) + frame:SetSizable(not frame._maximized) + div:SetLeftWidth(frame:GetWide() * 0.56) + end + + ----- LEFT PANEL STUFF + self.comboCategory = vgui.Create("DComboBox", leftPanel) + self.comboCategory:SetFont("Trebuchet24") + self.comboCategory:SetSortItems(false) + self.comboCategory:SetTextColor(Color(150, 255, 150)) + self.comboCategory:SetTall(30) + self.comboCategory:Dock(TOP) + self.comboCategory:DockMargin(2, 2, 2, 2) + self.comboCategory:AddChoice("Available weapons", nil, true) + + for _, name in ipairs(self.categories) do + self.comboCategory:AddChoice(name) + end + + self.comboCategory.Paint = function(_, sw, sh) + surface.SetDrawColor(0, 0, 0, 240) + surface.DrawRect(0, 0, sw, sh) + end + + self.comboCategory.OnSelect = function(_, index) + index = tonumber(index) - 1 + + if index == 0 then + self.categoryFilter = nil + else + self.categoryFilter = self.categories[index] + end + + self:UpdateLists() + end + + local entrySearch = vgui.Create("DTextEntry", leftPanel) + entrySearch:SetFont("ChatFont") + entrySearch:SetMaximumCharCount(64) + entrySearch:SetTabbingDisabled(true) + entrySearch:SetPlaceholderText("Search...") + entrySearch:SetTall(38) + entrySearch:Dock(BOTTOM) + + entrySearch.OnChange = function(s) + self.filter = string.lower(string.Trim(s:GetText())) + self:UpdateAvailableList() + end + + -- available weapons list + self.scrollAvailable = vgui.Create("DScrollPanel", leftPanel) + self.scrollAvailable:Dock(FILL) + + self.listAvailable = vgui.Create("DIconLayout", self.scrollAvailable) + self.listAvailable:Dock(FILL) + self.listAvailable:DockMargin(0, 0, 0, 0) + self.listAvailable:SetSpaceX(4) + self.listAvailable:SetSpaceY(4) + + ----- RIGHT PANEL STUFF + local panelOptions = vgui.Create("DPanel", rightPanel) + panelOptions:SetTall(32) + panelOptions:Dock(TOP) + panelOptions:DockPadding(2, 2, 2, 2) + panelOptions:SetPaintBackground(false) + + local buttonCopy = vgui.Create("DButton", panelOptions) + buttonCopy:SetText("") + buttonCopy:SetImage("icon16/brick_go.png") + buttonCopy:SetTooltip("Add weapons from your inventory") + buttonCopy:SetWide(24) + buttonCopy:Dock(RIGHT) + + buttonCopy.DoClick = function() + Derma_Query("This will add all weapons that you're currently holding to this loadout. Continue?", "Add weapons from your inventory", "Yes", function() + self:AddInventoryWeapons() + end, "No") + end + + local buttonRemove = vgui.Create("DButton", panelOptions) + buttonRemove:SetText("") + buttonRemove:SetImage("icon16/delete.png") + buttonRemove:SetTooltip("Delete loadout") + buttonRemove:SetWide(24) + buttonRemove:Dock(RIGHT) + + buttonRemove.DoClick = function() + local loadoutName = DATATHEFT_LOADOUTS[self.loadoutIndex].name + local helpText = string.format("Are you sure you want to delete \"%s\"?", loadoutName) + + Derma_Query(helpText, "Delete loadout", "Yes", function() + self:DeleteLoadout(self.loadoutIndex) + self:Save() + end, "No") + end + + local buttonNew = vgui.Create("DButton", panelOptions) + buttonNew:SetText("") + buttonNew:SetImage("icon16/add.png") + buttonNew:SetTooltip("Create loadout") + buttonNew:SetWide(24) + buttonNew:Dock(RIGHT) + + buttonNew.DoClick = function() + self.loadoutIndex = self:CreateLoadout(self.loadoutIndex + 1) + self:Save() + self:UpdateLists() + end + + self.comboLoadouts = vgui.Create("DComboBox", panelOptions) + self.comboLoadouts:SetFont("Trebuchet24") + self.comboLoadouts:SetSortItems(false) + self.comboLoadouts:Dock(FILL) + self.comboLoadouts:SetTextColor(Color(193, 202, 255)) + + self.comboLoadouts.Paint = function(_, sw, sh) + surface.SetDrawColor(0, 0, 0, 240) + surface.DrawRect(0, 0, sw, sh) + end + + self.comboLoadouts.OnSelect = function(s, index) + if s._blockCallback then return end + + self.loadoutIndex = tonumber(index) + self.hintedMissingWeapons = nil + + self:UpdateLists() + end + + local panelToggle = vgui.Create("DPanel", rightPanel) + panelToggle:SetTall(52) + panelToggle:Dock(BOTTOM) + panelToggle:DockPadding(8, 8, 8, 8) + panelToggle._animState = self.enabled and 1 or 0 + + panelToggle.Paint = function(s, sw, sh) + s._animState = Lerp(FrameTime() * 10, s._animState, self.enabled and 1 or 0) + + surface.SetDrawColor(50 + 50 * (1 - s._animState), 50 + 50 * s._animState, 50) + surface.DrawRect(0, 0, sw, sh) + end + + self.labelCount = vgui.Create("DLabel", panelToggle) + self.labelCount:SetText("0/0") + self.labelCount:Dock(RIGHT) + + self.scrollLoadoutItems = vgui.Create("DScrollPanel", rightPanel) + self.scrollLoadoutItems:Dock(FILL) + self.listLoadoutItems = vgui.Create("DIconLayout", self.scrollLoadoutItems) + self.listLoadoutItems:Dock(FILL) + self.listLoadoutItems:DockMargin(0, 0, 0, 0) + self.listLoadoutItems:SetSpaceX(4) + self.listLoadoutItems:SetSpaceY(4) + + self:UpdateLists() +end + +if engine.ActiveGamemode() == "beatrun" then + list.Set("DesktopWindows", "CLoadoutDesktopIcon", { + title = "DataTheft loadouts editor", + icon = "entities/weapon_smg1.png", + init = function() + CLoadout:ShowPanel() + end + }) +end + +do + local WeaponIcon = {} + + local iconMaterials = { + ammo = Material("icon16/bullet_yellow.png") + } + + AccessorFunc(WeaponIcon, "m_bAdminOnly", "AdminOnly") + AccessorFunc(WeaponIcon, "m_bFavorite", "Favorite") + + function WeaponIcon:Init() + self:SetPaintBackground(false) + self:SetSize(140, 128) + self:SetText("") + self:SetDoubleClickingEnabled(false) + + self.Image = self:Add("DImage") + self.Image:SetPos(0, 0) + self.Image:SetSize(128, 128) + self.Image:SetVisible(false) + self.Image:SetKeepAspect(false) + + self.WeaponName = "" + self.WeaponClass = "" + self.Border = 0 + self.TextColor = Color(255, 255, 255, 255) + self.TextOutlineColor = Color(0, 0, 0, 255) + end + + function WeaponIcon:SetWeaponName(name) + self.WeaponName = name + end + + function WeaponIcon:SetWeaponClass(class) + self.WeaponClass = class + local icon_path = CLoadout:GetWeaponIcon(class) + + if icon_path then + self:SetMaterial(icon_path) + end + end + + function WeaponIcon:SetMaterial(name) + self.m_MaterialName = name + local mat = Material(name) + + if not mat or mat:IsError() then + name = name:Replace("entities/", "VGUI/entities/") + name = name:Replace(".png", "") + mat = Material(name) + end + + if not mat or mat:IsError() then return end + self.Image:SetMaterial(mat) + end + + function WeaponIcon:DoClick() + end + + function WeaponIcon:OpenMenu() + end + + function WeaponIcon:PaintOver() + end + + function WeaponIcon:Paint(w, h) + self.Border = self.Depressed and 8 or 0 + render.PushFilterMag(TEXFILTER.ANISOTROPIC) + render.PushFilterMin(TEXFILTER.ANISOTROPIC) + + self.Image:PaintAt(self.Border, self.Border, w - self.Border * 2, h - self.Border * 2) + render.PopFilterMin() + render.PopFilterMag() + + if self:IsHovered() or self.Depressed or self:IsChildHovered() then + surface.SetDrawColor(255, 255, 255, 255) + else + surface.SetDrawColor(0, 0, 0, 255) + end + + surface.DrawOutlinedRect(0, 0, w, h, 4) + local infoH = 20 + local infoY = h - infoH - 4 + + surface.SetDrawColor(30, 30, 30, 240) + surface.DrawRect(4, infoY, w - 8, infoH) + draw.SimpleTextOutlined(self.WeaponName, "Default", 8, infoY + infoH * 0.5, self.TextColor, 0, 1, 1, self.TextOutlineColor) + surface.SetDrawColor(255, 255, 255, 255) + + local str + + if self.Primary then + if self.Secondary then + str = self.Primary .. "/" .. self.Secondary + else + str = self.Primary + end + elseif self.Secondary then + str = self.Secondary + end + + if str then + surface.SetMaterial(iconMaterials.ammo) + surface.DrawTexturedRect(w - 18, infoY + 3, 16, 16) + + draw.SimpleTextOutlined(str, "Default", w - 18, infoY + infoH * 0.5, self.TextColor, 2, 1, 1, self.TextOutlineColor) + end + end + + vgui.Register("CLoadoutWeaponIcon", WeaponIcon, "DButton") +end \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_new.lua b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_new.lua new file mode 100644 index 0000000..c27dfb6 --- /dev/null +++ b/beatrun/gamemodes/beatrun/gamemode/cl/off/Menu_Gamemodes_new.lua @@ -0,0 +1,122 @@ +function CLoadout:InitRegistry() + local registry = {} + + for _, v in pairs(list.Get("Weapon")) do + if not v.ClassName or not v.Spawnable then continue end + + registry[v.ClassName] = { + name = (v.PrintName and v.PrintName ~= "") and v.PrintName or v.ClassName, + } + end + + self.weaponRegistry = registry + + table.sort(self.categories) +end + +function CLoadout:CreateLoadout(items) + local loadout = {} + + if istable(items) and table.IsSequential(items) then + for _, item in ipairs(items) do + loadout[#loadout + 1] = { item[1] } + end + end + + return table.insert(DATATHEFT_LOADOUTS, loadout) +end + +function CLoadout:DeleteLoadout(index) + table.remove(DATATHEFT_LOADOUTS, index) + + if #DATATHEFT_LOADOUTS == 0 then + self:CreateLoadout() + end + + self.loadoutIndex = #DATATHEFT_LOADOUTS + self:UpdateLists() +end + +function CLoadout:Apply() + local loadout = DATATHEFT_LOADOUTS[self.loadoutIndex] + + loadout = util.Compress(util.TableToJSON(loadout)) + + if not loadut then + LocalPlayer():ChatPrint("Failed to compress the loadut!") + + return + end + + net.Start("Beatrun_UpdateLoadouts", false) + net.WriteData(loadout, #loadout) + net.SendToServer() +end + +function CLoadout:AddWeapon(class) + local items = DATATHEFT_LOADOUTS[self.loadoutIndex] + + if #items < self:GetWeaponLimit() then + table.insert(items, { class }) + else + Derma_Message("Your loadout is full!", "Loadout", "OK") + end +end + +function CLoadout:AddInventoryWeapons() + local items = DATATHEFT_LOADOUTS[self.loadoutIndex] + + local alreadyInLoadout = {} + + for _, v in ipairs(items) do + alreadyInLoadout[v[1]] = true + end + + local weaponsList = LocalPlayer():GetWeapons() + + for _, v in ipairs(weaponsList) do + local class = (v.GetClass and v:GetClass()) or v.ClassName + + if not alreadyInLoadout[class] then + table.insert(DATATHEFT_LOADOUTS[self.loadoutIndex], { class }) + end + end + + self:UpdateLists() +end + +function CLoadout:RemoveWeapon(index) + table.remove(DATATHEFT_LOADOUTS[self.loadoutIndex], index) +end + +function CLoadout:Init() + self.filter = "" + + self.loadoutIndex = 1 + DATATHEFT_LOADOUTS = {} + + if IsValid(self.frame) then + self.frame:Close() + self.frame = nil + end + + self:InitRegistry() + + if #DATATHEFT_LOADOUTS == 0 then + self:CreateLoadout() + end + + self:Apply() +end + +hook.Add("InitPostEntity", "CLoadout_Initialize", function() + hook.Remove("InitPostEntity", "CLoadout_Initialize") + + timer.Simple(1, function() + CLoadout:Init() + end) +end) + +concommand.Add("Beatrun_GamemodesMenu", function() + CLoadout:ShowPanel() +end, nil, "Opens the loadout customization window.") \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/player_class/player_beatrun.lua b/beatrun/gamemodes/beatrun/gamemode/player_class/player_beatrun.lua index 25cf042..1ce09bc 100644 --- a/beatrun/gamemodes/beatrun/gamemode/player_class/player_beatrun.lua +++ b/beatrun/gamemodes/beatrun/gamemode/player_class/player_beatrun.lua @@ -301,7 +301,7 @@ hook.Add("SetupMove", "SpawnFreeze", function(ply, mv, cmd) end) hook.Add("ShouldCollide", "NoPlayerCollisions", function(ent1, ent2) - if ent1:IsPlayer() and ent2.NoPlayerCollisions then + if ent1:IsPlayer() and (ent2:IsPlayer() or ent2.NoPlayerCollisions) then if ent2.BRCollisionFunc then return ent2:BRCollisionFunc(ent1) else return false end end diff --git a/beatrun/gamemodes/beatrun/gamemode/sh/MenuBinds.lua b/beatrun/gamemodes/beatrun/gamemode/sh/MenuBinds.lua index 8c05865..ca77de6 100644 --- a/beatrun/gamemodes/beatrun/gamemode/sh/MenuBinds.lua +++ b/beatrun/gamemodes/beatrun/gamemode/sh/MenuBinds.lua @@ -2,4 +2,8 @@ hook.Add("PlayerButtonDown", "CourseMenuBind", function(ply, button) if (game.SinglePlayer() or CLIENT and IsFirstTimePredicted()) and button == KEY_F4 then ply:ConCommand("Beatrun_CourseMenu") end + + if (game.SinglePlayer() or CLIENT and IsFirstTimePredicted()) and button == KEY_F3 then + ply:ConCommand("Beatrun_GamemodesMenu") + end end) \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/sh/Menu_Gamemodes.lua b/beatrun/gamemodes/beatrun/gamemode/sh/Menu_Gamemodes.lua deleted file mode 100644 index 49a2a23..0000000 --- a/beatrun/gamemodes/beatrun/gamemode/sh/Menu_Gamemodes.lua +++ /dev/null @@ -1,5 +0,0 @@ -hook.Add("PlayerButtonDown", "GMMenuBind", function(ply, button) - if (game.SinglePlayer() or CLIENT and IsFirstTimePredicted()) and button == KEY_F3 then - ply:ConCommand("Beatrun_GamemodesMenu") - end -end) \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/sh/Misc.lua b/beatrun/gamemodes/beatrun/gamemode/sh/Misc.lua index 8cf3ad0..66d7fdd 100644 --- a/beatrun/gamemodes/beatrun/gamemode/sh/Misc.lua +++ b/beatrun/gamemodes/beatrun/gamemode/sh/Misc.lua @@ -1,12 +1,13 @@ if SERVER then local meta = FindMetaTable("Player") + local allowPropSpawn = CreateConVar("Beatrun_AllowPropSpawn", "0", {FCVAR_ARCHIVE}, "Allow players to spawn props and entities") util.AddNetworkString("SPParkourEvent") local spawn = {"PlayerGiveSWEP", "PlayerSpawnEffect", "PlayerSpawnNPC", "PlayerSpawnObject", "PlayerSpawnProp", "PlayerSpawnRagdoll", "PlayerSpawnSENT", "PlayerSpawnSWEP", "PlayerSpawnVehicle"} local function BlockSpawn(ply) - if not ply:IsSuperAdmin() then return false end + if not ply:IsAdmin() and not allowPropSpawn:GetBool() then return false end end for k, v in ipairs(spawn) do @@ -16,7 +17,7 @@ if SERVER then hook.Add("IsSpawnpointSuitable", "NoSpawnFrag", function(ply) return true end) hook.Add("AllowPlayerPickup", "AllowAdminsPickUp", function(ply, ent) - if not ply:IsSuperAdmin() then return false end + if not ply:IsAdmin() and not allowPropSpawn:GetBool() then return false end end) function meta:GTAB(minutes) diff --git a/beatrun/gamemodes/beatrun/gamemode/sh/_Helpers.lua b/beatrun/gamemodes/beatrun/gamemode/sh/_Helpers.lua index 5153ed1..3d8b40e 100644 --- a/beatrun/gamemodes/beatrun/gamemode/sh/_Helpers.lua +++ b/beatrun/gamemodes/beatrun/gamemode/sh/_Helpers.lua @@ -1,6 +1,8 @@ local vmatrixmeta = FindMetaTable("VMatrix") local playermeta = FindMetaTable("Player") +CLoadout = {} + function CLIENT_IFTP() return CLIENT and IsFirstTimePredicted() end diff --git a/beatrun/gamemodes/beatrun/gamemode/sv/Menu_Gamemodes.lua b/beatrun/gamemodes/beatrun/gamemode/sv/Menu_Gamemodes.lua deleted file mode 100644 index b7864b6..0000000 --- a/beatrun/gamemodes/beatrun/gamemode/sv/Menu_Gamemodes.lua +++ /dev/null @@ -1,22 +0,0 @@ -util.AddNetworkString("Beatrun_ToggleDataTheft") -util.AddNetworkString("Beatrun_ToggleInfection") - -local datatheft, infection = false - -net.Receive("Beatrun_ToggleDataTheft", function(_, ply) - datatheft = not datatheft - if datatheft then - Beatrun_StartDataTheft() - else - Beatrun_StopDataTheft() - end -end) - -net.Receive("Beatrun_ToggleInfection", function(_, ply) - infection = not infection - if infection then - Beatrun_StartInfection() - else - Beatrun_StopInfection() - end -end) \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes.lua b/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes.lua new file mode 100644 index 0000000..7882a49 --- /dev/null +++ b/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes.lua @@ -0,0 +1,28 @@ +util.AddNetworkString("Beatrun_ToggleGamemode") +util.AddNetworkString("Beatrun_UpdateDataTheftLoadout") + +local datatheft, infection = false + +net.Receive("Beatrun_ToggleGamemode", function(_, ply) + local gm = net.ReadString() + + if gm == "datatheft" then + datatheft = not datatheft + if datatheft then + Beatrun_StartDataTheft() + else + Beatrun_StopDataTheft() + end + elseif gm == "infection" then + infection = not infection + if infection then + Beatrun_StartInfection() + else + Beatrun_StopInfection() + end + end +end) + +net.Receive("Beatrun_UpdateDataTheftLoadout", function(_, ply) + +end) \ No newline at end of file diff --git a/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes_new.lua b/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes_new.lua new file mode 100644 index 0000000..a4a9c73 --- /dev/null +++ b/beatrun/gamemodes/beatrun/gamemode/sv/off/Menu_Gamemodes_new.lua @@ -0,0 +1,20 @@ +util.AddNetworkString("Beatrun_UpdateLoadouts") + +local function IsAvailableForPlayer(ply) + return ply:IsAdmin() +end + +net.Receive("Beatrun_UpdateLoadouts", function(len, ply) + local data = net.ReadData(len) + data = util.Decompress(data) + + if not data or data == "" then return end + + local loadout = util.JSONToTable(data) + + if not loadout then return print("Failed to parse %s\"s loadout!", ply:Nick()) end + + local canUse, reason = IsAvailableForPlayer(ply) + + if not canUse then return ply:ChatPrint("[Loadout] " .. reason) end +end) \ No newline at end of file