This commit is contained in:
lifestorm
2024-08-04 23:12:27 +03:00
parent 0e770b2b49
commit ba1fc01b16
7084 changed files with 2173495 additions and 14 deletions

367
lua/sam/modules/cami.lua Normal file
View File

@@ -0,0 +1,367 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
--[[
CAMI - Common Admin Mod Interface.
Copyright 2020 CAMI Contributors
Makes admin mods intercompatible and provides an abstract privilege interface
for third party addons.
Follows the specification on this page:
https://github.com/glua/CAMI/blob/master/README.md
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
]]
-- Version number in YearMonthDay format.
local version = 20201130
if CAMI and CAMI.Version >= version then return end
CAMI = CAMI or {}
CAMI.Version = version
--- @class CAMI_USERGROUP
--- defines the charactaristics of a usergroup
--- @field Name string @The name of the usergroup
--- @field Inherits string @The name of the usergroup this usergroup inherits from
--- @class CAMI_PRIVILEGE
--- defines the charactaristics of a privilege
--- @field Name string @The name of the privilege
--- @field MinAccess "'user'" | "'admin'" | "'superadmin'" @Default group that should have this privilege
--- @field Description string | nil @Optional text describing the purpose of the privilege
local CAMI_PRIVILEGE = {}
--- Optional function to check if a player has access to this privilege
--- (and optionally execute it on another player)
---
--- ⚠ **Warning**: This function may not be called by all admin mods
--- @param actor GPlayer @The player
--- @param target GPlayer | nil @Optional - the target
--- @return boolean @If they can or not
--- @return string | nil @Optional reason
function CAMI_PRIVILEGE:HasAccess(actor, target)
end
--- Contains the registered CAMI_USERGROUP usergroup structures.
--- Indexed by usergroup name.
--- @type CAMI_USERGROUP[]
local usergroups = CAMI.GetUsergroups and CAMI.GetUsergroups() or {
user = {
Name = "user",
Inherits = "user"
},
admin = {
Name = "admin",
Inherits = "user"
},
superadmin = {
Name = "superadmin",
Inherits = "admin"
}
}
--- Contains the registered CAMI_PRIVILEGE privilege structures.
--- Indexed by privilege name.
--- @type CAMI_PRIVILEGE[]
local privileges = CAMI.GetPrivileges and CAMI.GetPrivileges() or {}
--- Registers a usergroup with CAMI.
---
--- Use the source parameter to make sure CAMI.RegisterUsergroup function and
--- the CAMI.OnUsergroupRegistered hook don't cause an infinite loop
--- @param usergroup CAMI_USERGROUP @The structure for the usergroup you want to register
--- @param source any @Identifier for your own admin mod. Can be anything.
--- @return CAMI_USERGROUP @The usergroup given as an argument
function CAMI.RegisterUsergroup(usergroup, source)
usergroups[usergroup.Name] = usergroup
hook.Call("CAMI.OnUsergroupRegistered", nil, usergroup, source)
return usergroup
end
--- Unregisters a usergroup from CAMI. This will call a hook that will notify
--- all other admin mods of the removal.
---
--- ⚠ **Warning**: Call only when the usergroup is to be permanently removed.
---
--- Use the source parameter to make sure CAMI.UnregisterUsergroup function and
--- the CAMI.OnUsergroupUnregistered hook don't cause an infinite loop
--- @param usergroupName string @The name of the usergroup.
--- @param source any @Identifier for your own admin mod. Can be anything.
--- @return boolean @Whether the unregistering succeeded.
function CAMI.UnregisterUsergroup(usergroupName, source)
if not usergroups[usergroupName] then return false end
local usergroup = usergroups[usergroupName]
usergroups[usergroupName] = nil
hook.Call("CAMI.OnUsergroupUnregistered", nil, usergroup, source)
return true
end
--- Retrieves all registered usergroups.
--- @return CAMI_USERGROUP[] @Usergroups indexed by their names.
function CAMI.GetUsergroups()
return usergroups
end
--- Receives information about a usergroup.
--- @param usergroupName string
--- @return CAMI_USERGROUP | nil @Returns nil when the usergroup does not exist.
function CAMI.GetUsergroup(usergroupName)
return usergroups[usergroupName]
end
--- Checks to see if potentialAncestor is an ancestor of usergroupName.
--- All usergroups are ancestors of themselves.
---
--- Examples:
--- * `user` is an ancestor of `admin` and also `superadmin`
--- * `admin` is an ancestor of `superadmin`, but not `user`
--- @param usergroupName string @The usergroup to query
--- @param potentialAncestor string @The ancestor to query
--- @return boolean @Whether usergroupName inherits potentialAncestor.
function CAMI.UsergroupInherits(usergroupName, potentialAncestor)
repeat
if usergroupName == potentialAncestor then return true end
usergroupName = usergroups[usergroupName] and
usergroups[usergroupName].Inherits or
usergroupName
until not usergroups[usergroupName] or
usergroups[usergroupName].Inherits == usergroupName
-- One can only be sure the usergroup inherits from user if the
-- usergroup isn't registered.
return usergroupName == potentialAncestor or potentialAncestor == "user"
end
--- Find the base group a usergroup inherits from.
---
--- This function traverses down the inheritence chain, so for example if you have
--- `user` -> `group1` -> `group2`
--- this function will return `user` if you pass it `group2`.
---
--- **NOTE**: All usergroups must eventually inherit either user, admin or superadmin.
--- @param usergroupName string @The name of the usergroup
--- @return "'user'" | "'admin'" | "'superadmin'" @The name of the root usergroup
function CAMI.InheritanceRoot(usergroupName)
if not usergroups[usergroupName] then return end
local inherits = usergroups[usergroupName].Inherits
while inherits ~= usergroups[usergroupName].Inherits do
usergroupName = usergroups[usergroupName].Inherits
end
return usergroupName
end
--- Registers an addon privilege with CAMI.
---
--- ⚠ **Warning**: This should only be used by addons. Admin mods must *NOT*
--- register their privileges using this function.
--- @param privilege CAMI_PRIVILEGE
--- @return CAMI_PRIVILEGE @The privilege given as argument.
function CAMI.RegisterPrivilege(privilege)
privileges[privilege.Name] = privilege
hook.Call("CAMI.OnPrivilegeRegistered", nil, privilege)
return privilege
end
--- Unregisters a privilege from CAMI.
--- This will call a hook that will notify any admin mods of the removal.
---
--- ⚠ **Warning**: Call only when the privilege is to be permanently removed.
--- @param privilegeName string @The name of the privilege.
--- @return boolean @Whether the unregistering succeeded.
function CAMI.UnregisterPrivilege(privilegeName)
if not privileges[privilegeName] then return false end
local privilege = privileges[privilegeName]
privileges[privilegeName] = nil
hook.Call("CAMI.OnPrivilegeUnregistered", nil, privilege)
return true
end
--- Retrieves all registered privileges.
--- @return CAMI_PRIVILEGE[] @All privileges indexed by their names.
function CAMI.GetPrivileges()
return privileges
end
--- Receives information about a privilege.
--- @param privilegeName string
--- @return CAMI_PRIVILEGE | nil
function CAMI.GetPrivilege(privilegeName)
return privileges[privilegeName]
end
-- Default access handler
local defaultAccessHandler = {["CAMI.PlayerHasAccess"] =
function(_, actorPly, privilegeName, callback, targetPly, extraInfoTbl)
-- The server always has access in the fallback
if not IsValid(actorPly) then return callback(true, "Fallback.") end
local priv = privileges[privilegeName]
local fallback = extraInfoTbl and (
not extraInfoTbl.Fallback and actorPly:IsAdmin() or
extraInfoTbl.Fallback == "user" and true or
extraInfoTbl.Fallback == "admin" and actorPly:IsAdmin() or
extraInfoTbl.Fallback == "superadmin" and actorPly:IsSuperAdmin())
if not priv then return callback(fallback, "Fallback.") end
local hasAccess =
priv.MinAccess == "user" or
priv.MinAccess == "admin" and actorPly:IsAdmin() or
priv.MinAccess == "superadmin" and actorPly:IsSuperAdmin()
if hasAccess and priv.HasAccess then
hasAccess = priv:HasAccess(actorPly, targetPly)
end
callback(hasAccess, "Fallback.")
end,
["CAMI.SteamIDHasAccess"] =
function(_, _, _, callback)
callback(false, "No information available.")
end
}
--- @class CAMI_ACCESS_EXTRA_INFO
--- @field Fallback "'user'" | "'admin'" | "'superadmin'" @Fallback status for if the privilege doesn't exist. Defaults to `admin`.
--- @field IgnoreImmunity boolean @Ignore any immunity mechanisms an admin mod might have.
--- @field CommandArguments table @Extra arguments that were given to the privilege command.
--- Checks if a player has access to a privilege
--- (and optionally can execute it on targetPly)
---
--- This function is designed to be asynchronous but will be invoked
--- synchronously if no callback is passed.
---
--- ⚠ **Warning**: If the currently installed admin mod does not support
--- synchronous queries, this function will throw an error!
--- @param actorPly GPlayer @The player to query
--- @param privilegeName string @The privilege to query
--- @param callback fun(hasAccess: boolean, reason: string|nil) @Callback to receive the answer, or nil for synchronous
--- @param targetPly GPlayer | nil @Optional - target for if the privilege effects another player (eg kick/ban)
--- @param extraInfoTbl CAMI_ACCESS_EXTRA_INFO | nil @Table of extra information for the admin mod
--- @return boolean | nil @Synchronous only - if the player has the privilege
--- @return string | nil @Synchronous only - optional reason from admin mod
function CAMI.PlayerHasAccess(actorPly, privilegeName, callback, targetPly,
extraInfoTbl)
local hasAccess, reason = nil, nil
local callback_ = callback or function(hA, r) hasAccess, reason = hA, r end
hook.Call("CAMI.PlayerHasAccess", defaultAccessHandler, actorPly,
privilegeName, callback_, targetPly, extraInfoTbl)
if callback ~= nil then return end
if hasAccess == nil then
local err = [[The function CAMI.PlayerHasAccess was used to find out
whether Player %s has privilege "%s", but an admin mod did not give an
immediate answer!]]
error(string.format(err,
actorPly:IsPlayer() and actorPly:Nick() or tostring(actorPly),
privilegeName))
end
return hasAccess, reason
end
--- Get all the players on the server with a certain privilege
--- (and optionally who can execute it on targetPly)
---
--- **NOTE**: This is an asynchronous function!
--- @param privilegeName string @The privilege to query
--- @param callback fun(players: GPlayer[]) @Callback to receive the answer
--- @param targetPly GPlayer | nil @Optional - target for if the privilege effects another player (eg kick/ban)
--- @param extraInfoTbl CAMI_ACCESS_EXTRA_INFO | nil @Table of extra information for the admin mod
function CAMI.GetPlayersWithAccess(privilegeName, callback, targetPly,
extraInfoTbl)
local allowedPlys = {}
local allPlys = player.GetAll()
local countdown = #allPlys
local function onResult(ply, hasAccess, _)
countdown = countdown - 1
if hasAccess then table.insert(allowedPlys, ply) end
if countdown == 0 then callback(allowedPlys) end
end
for _, ply in ipairs(allPlys) do
CAMI.PlayerHasAccess(ply, privilegeName,
function(...) onResult(ply, ...) end,
targetPly, extraInfoTbl)
end
end
--- @class CAMI_STEAM_ACCESS_EXTRA_INFO
--- @field IgnoreImmunity boolean @Ignore any immunity mechanisms an admin mod might have.
--- @field CommandArguments table @Extra arguments that were given to the privilege command.
--- Checks if a (potentially offline) SteamID has access to a privilege
--- (and optionally if they can execute it on a target SteamID)
---
--- **NOTE**: This is an asynchronous function!
--- @param actorSteam string | nil @The SteamID to query
--- @param privilegeName string @The privilege to query
--- @param callback fun(hasAccess: boolean, reason: string|nil) @Callback to receive the answer
--- @param targetSteam string | nil @Optional - target SteamID for if the privilege effects another player (eg kick/ban)
--- @param extraInfoTbl CAMI_STEAM_ACCESS_EXTRA_INFO | nil @Table of extra information for the admin mod
function CAMI.SteamIDHasAccess(actorSteam, privilegeName, callback,
targetSteam, extraInfoTbl)
hook.Call("CAMI.SteamIDHasAccess", defaultAccessHandler, actorSteam,
privilegeName, callback, targetSteam, extraInfoTbl)
end
--- Signify that your admin mod has changed the usergroup of a player. This
--- function communicates to other admin mods what it thinks the usergroup
--- of a player should be.
---
--- Listen to the hook to receive the usergroup changes of other admin mods.
--- @param ply GPlayer @The player for which the usergroup is changed
--- @param old string @The previous usergroup of the player.
--- @param new string @The new usergroup of the player.
--- @param source any @Identifier for your own admin mod. Can be anything.
function CAMI.SignalUserGroupChanged(ply, old, new, source)
hook.Call("CAMI.PlayerUsergroupChanged", nil, ply, old, new, source)
end
--- Signify that your admin mod has changed the usergroup of a disconnected
--- player. This communicates to other admin mods what it thinks the usergroup
--- of a player should be.
---
--- Listen to the hook to receive the usergroup changes of other admin mods.
--- @param steamId string @The steam ID of the player for which the usergroup is changed
--- @param old string @The previous usergroup of the player.
--- @param new string @The new usergroup of the player.
--- @param source any @Identifier for your own admin mod. Can be anything.
function CAMI.SignalSteamIDUserGroupChanged(steamId, old, new, source)
hook.Call("CAMI.SteamIDUsergroupChanged", nil, steamId, old, new, source)
end

238
lua/sam/modules/chat.lua Normal file
View File

@@ -0,0 +1,238 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("Chat")
command.new("pm")
:SetPermission("pm", "user")
:AddArg("player", {allow_higher_target = true, single_target = true, cant_target_self = true})
:AddArg("text", {hint = "message", check = function(str)
return str:match("%S") ~= nil
end})
:GetRestArgs()
:Help("pm_help")
:OnExecute(function(ply, targets, message)
if ply:sam_get_pdata("unmute_time") then
return ply:sam_send_message("you_muted")
end
local target = targets[1]
ply:sam_send_message("pm_to", {
T = targets, V = message
})
if ply ~= target then
target:sam_send_message("pm_from", {
A = ply, V = message
})
end
end)
:End()
do
sam.permissions.add("see_admin_chat", nil, "admin")
local reports_enabled = sam.config.get_updated("Reports", true)
command.new("asay")
:SetPermission("asay", "user")
:AddArg("text", {hint = "message"})
:GetRestArgs()
:Help("asay_help")
:OnExecute(function(ply, message)
if reports_enabled.value and not ply:HasPermission("see_admin_chat") then
local success, time = sam.player.report(ply, message)
if success == false then
ply:sam_send_message("You need to wait {S Red} seconds.", {
S = time
})
else
ply:sam_send_message("to_admins", {
A = ply, V = message
})
end
return
end
local targets = {ply}
local players = player.GetHumans()
for i = 1, #players do
local v = players[i]
if v:HasPermission("see_admin_chat") and v ~= ply then
table.insert(targets, v)
end
end
sam.player.send_message(targets, "to_admins", {
A = ply, V = message
})
end)
:End()
if SERVER then
sam.hook_last("PlayerSay", "SAM.Chat.Asay", function(ply, text)
if text:sub(1, 1) == "@" then
ply:Say("!asay " .. text:sub(2))
return ""
end
end)
end
end
do
command.new("mute")
:SetPermission("mute", "admin")
:AddArg("player")
:AddArg("length", {optional = true, default = 0, min = 0})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("mute_help")
:OnExecute(function(ply, targets, length, reason)
local current_time = SysTime()
for i = 1, #targets do
local target = targets[i]
target:sam_set_pdata("unmute_time", length ~= 0 and (current_time + length * 60) or 0)
end
sam.player.send_message(nil, "mute", {
A = ply, T = targets, V = sam.format_length(length), V_2 = reason
})
end)
:End()
command.new("unmute")
:SetPermission("unmute", "admin")
:AddArg("player", {optional = true})
:Help("unmute_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:sam_set_pdata("unmute_time", nil)
end
sam.player.send_message(nil, "unmute", {
A = ply, T = targets
})
end)
:End()
if SERVER then
sam.hook_first("PlayerSay", "SAM.Chat.Mute", function(ply, text)
local unmute_time = ply:sam_get_pdata("unmute_time")
if not unmute_time then return end
if text:sub(1, 1) == "!" and text:sub(2, 2):match("%S") ~= nil then
local args = sam.parse_args(text:sub(2))
local cmd_name = args[1]
if not cmd_name then return end
local cmd = command.get_command(cmd_name)
if cmd then
return
end
end
if unmute_time == 0 or unmute_time > SysTime() then
return ""
else
ply:sam_set_pdata("unmute_time", nil)
end
end)
end
end
do
command.new("gag")
:SetPermission("gag", "admin")
:AddArg("player")
:AddArg("length", {optional = true, default = 0, min = 0})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("gag_help")
:OnExecute(function(ply, targets, length, reason)
for i = 1, #targets do
local target = targets[i]
target.sam_gagged = true
if length ~= 0 then
timer.Create("SAM.UnGag" .. target:SteamID64(), length * 60, 1, function()
RunConsoleCommand("sam", "ungag", "#" .. target:EntIndex())
end)
end
end
sam.player.send_message(nil, "gag", {
A = ply, T = targets, V = sam.format_length(length), V_2 = reason
})
end)
:End()
command.new("ungag")
:SetPermission("ungag", "admin")
:AddArg("player", {optional = true})
:Help("ungag_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local target = targets[i]
target.sam_gagged = nil
timer.Remove("SAM.UnGag" .. target:SteamID64())
end
sam.player.send_message(nil, "ungag", {
A = ply, T = targets
})
end)
:End()
if SERVER then
hook.Add("PlayerCanHearPlayersVoice", "SAM.Chat.Gag", function(_, ply)
if ply.sam_gagged then
return false
end
end)
hook.Add("PlayerInitialSpawn", "SAM.Gag", function(ply)
local gag_time = ply:sam_get_pdata("gagged")
if gag_time then
ply:sam_set_pdata("gagged", nil)
RunConsoleCommand("sam", "gag", "#" .. ply:EntIndex(), gag_time / 60, "LTAP")
end
end)
hook.Add("PlayerDisconnected", "SAM.Gag", function(ply)
if ply.sam_gagged then
ply:sam_set_pdata("gagged", timer.TimeLeft("SAM.UnGag" .. ply:SteamID64()) or 0)
end
end)
end
end

View File

@@ -0,0 +1,39 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--
-- Make command notifying only for ranks you select.
-- permission is command_notify. (by default admin+ has it)
-- You can NOT use this with 'command_hide_admin_name.lua'
--
if SAM_LOADED then return end
sam.permissions.add("command_notify", nil, "admin")
if SERVER then
local get_players = function()
local players = {}
for _, v in ipairs(player.GetAll()) do
if v:HasPermission("command_notify") then
table.insert(players, v)
end
end
return players
end
sam.player.old_send_message = sam.player.old_send_message or sam.player.send_message
function sam.player.send_message(ply, msg, tbl)
if ply == nil and debug.traceback():find("lua/sam/command/", 1, true) then
sam.player.old_send_message(get_players(), msg, tbl)
else
sam.player.old_send_message(ply, msg, tbl)
end
end
end

324
lua/sam/modules/darkrp.lua Normal file
View File

@@ -0,0 +1,324 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local add = not GAMEMODE and hook.Add or function(_, _, fn)
fn()
end
add("PostGamemodeLoaded", "SAM.DarkRP", function()
if not DarkRP then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("DarkRP")
command.new("arrest")
:SetPermission("arrest", "superadmin")
:AddArg("player")
:AddArg("number", {hint = "time", optional = true, min = 0, default = 0, round = true})
:Help("arrest_help")
:OnExecute(function(ply, targets, time)
if time == 0 then
time = math.huge
end
for i = 1, #targets do
local v = targets[i]
if v:isArrested() then
v:unArrest()
end
v:arrest(time, ply)
end
if time == math.huge then
sam.player.send_message(nil, "arrest", {
A = ply, T = targets
})
else
sam.player.send_message(nil, "arrest2", {
A = ply, T = targets, V = time
})
end
end)
:End()
command.new("unarrest")
:SetPermission("unarrest", "superadmin")
:AddArg("player", {optional = true})
:Help("unarrest_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:unArrest()
end
sam.player.send_message(nil, "unarrest", {
A = ply, T = targets
})
end)
:End()
command.new("setmoney")
:SetPermission("setmoney", "superadmin")
:AddArg("player", {single_target = true})
:AddArg("number", {hint = "amount", min = 0, round = true})
:Help("setmoney_help")
:OnExecute(function(ply, targets, amount)
local target = targets[1]
amount = hook.Call("playerWalletChanged", GAMEMODE, target, amount - target:getDarkRPVar("money"), target:getDarkRPVar("money")) or amount
DarkRP.storeMoney(target, amount)
target:setDarkRPVar("money", amount)
sam.player.send_message(nil, "setmoney", {
A = ply, T = targets, V = amount
})
end)
:End()
command.new("addmoney")
:SetPermission("addmoney", "superadmin")
:AddArg("player", {single_target = true})
:AddArg("number", {hint = "amount", min = 0, round = true})
:Help("addmoney_help")
:OnExecute(function(ply, targets, amount)
targets[1]:addMoney(amount)
sam.player.send_message(nil, "addmoney", {
A = ply, T = targets, V = DarkRP.formatMoney(amount)
})
end)
:End()
command.new("selldoor")
:SetPermission("selldoor", "superadmin")
:Help("selldoor_help")
:OnExecute(function(ply)
local ent = ply:GetEyeTrace().Entity
if not IsValid(ent) or not ent.keysUnOwn then
return ply:sam_send_message("door_invalid")
end
local door_owner = ent:getDoorOwner()
if not IsValid(door_owner) then
return ply:sam_send_message("door_no_owner")
end
ent:keysUnOwn(ply)
sam.player.send_message(nil, "selldoor", {
A = ply, T = {door_owner, admin = ply}
})
end)
:End()
command.new("sellall")
:SetPermission("sellall", "superadmin")
:AddArg("player", {single_target = true})
:Help("sellall_help")
:OnExecute(function(ply, targets, amount)
targets[1]:keysUnOwnAll()
sam.player.send_message(nil, "sellall", {
A = ply, T = targets
})
end)
:End()
command.new("setjailpos")
:SetPermission("setjailpos", "superadmin")
:Help("setjailpos_help")
:OnExecute(function(ply)
DarkRP.storeJailPos(ply, false)
sam.player.send_message(nil, "s_jail_pos", {
A = ply
})
end)
:End()
command.new("addjailpos")
:SetPermission("addjailpos", "superadmin")
:Help("addjailpos_help")
:OnExecute(function(ply)
DarkRP.storeJailPos(ply, true)
sam.player.send_message(nil, "a_jail_pos", {
A = ply
})
end)
:End()
local RPExtraTeams = RPExtraTeams
local job_index = nil
command.new("setjob")
:SetPermission("setjob", "admin")
:AddArg("player")
:AddArg("text", {hint = "job", check = function(job)
job = job:lower()
for i = 1, #RPExtraTeams do
local v = RPExtraTeams[i]
if v.name:lower() == job or v.command:lower() == job then
job_index = v.team
return true
end
end
return false
end})
:Help("setjob_help")
:OnExecute(function(ply, targets, job)
for i = 1, #targets do
targets[i]:changeTeam(job_index, true, true, true)
end
sam.player.send_message(nil, "setjob", {
A = ply, T = targets, V = job
})
end)
:End()
do
local get_shipment = function(name)
local found, key = DarkRP.getShipmentByName(name)
if found then return found, key end
name = name:lower()
local shipments = CustomShipments
for i = 1, #shipments do
local shipment = shipments[i]
if shipment.entity == name then
return DarkRP.getShipmentByName(shipment.name)
end
end
return false
end
local place_entity = function(ent, tr, ply)
local ang = ply:EyeAngles()
ang.pitch = 0
ang.yaw = ang.yaw - 90
ang.roll = 0
ent:SetAngles(ang)
local flush_point = tr.HitPos - (tr.HitNormal * 512)
flush_point = ent:NearestPoint(flush_point)
flush_point = ent:GetPos() - flush_point
flush_point = tr.HitPos + flush_point
ent:SetPos(flush_point)
end
command.new("shipment")
:SetPermission("shipment", "superadmin")
:AddArg("text", {hint = "weapon", check = get_shipment})
:Help("shipment_help")
:OnExecute(function(ply, weapon_name)
local trace = {}
trace.start = ply:EyePos()
trace.endpos = trace.start + ply:GetAimVector() * 85
trace.filter = ply
local tr = util.TraceLine(trace)
local shipment_info, shipment_key = get_shipment(weapon_name)
local crate = ents.Create(shipment_info.shipmentClass or "spawned_shipment")
crate.SID = ply.SID
crate:Setowning_ent(ply)
crate:SetContents(shipment_key, shipment_info.amount)
crate:SetPos(Vector(tr.HitPos.x, tr.HitPos.y, tr.HitPos.z))
crate.nodupe = true
crate.ammoadd = shipment_info.spareammo
crate.clip1 = shipment_info.clip1
crate.clip2 = shipment_info.clip2
crate:Spawn()
crate:SetPlayer(ply)
place_entity(crate, tr, ply)
local phys = crate:GetPhysicsObject()
phys:Wake()
if shipment_info.weight then
phys:SetMass(shipment_info.weight)
end
sam.player.send_message(nil, "shipment", {
A = ply, V = weapon_name
})
end)
:End()
end
sam.command.new("forcename")
:SetPermission("forcename", "superadmin")
:AddArg("player")
:AddArg("text", {hint = "name"})
:Help("forcename_help")
:OnExecute(function(ply, targets, name)
local target = targets[1]
DarkRP.retrieveRPNames(name, function(taken)
if not IsValid(target) then return end
if taken then
ply:sam_send_message("forcename_taken", {
V = name
})
return
end
sam.player.send_message(nil, "forcename", {
A = ply, T = targets, V = name
})
DarkRP.storeRPName(target, name)
target:setDarkRPVar("rpname", name)
end)
end)
:End()
end)

654
lua/sam/modules/fun.lua Normal file
View File

@@ -0,0 +1,654 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("Fun")
do
local sounds = {}
for i = 1, 6 do
sounds[i] = "physics/body/body_medium_impact_hard" .. i .. ".wav"
end
local slap = function(ply, damage, admin)
if not ply:Alive() or ply:sam_get_nwvar("frozen") then return end
ply:ExitVehicle()
ply:SetVelocity(Vector(math.random(-100, 100), math.random(-100, 100), math.random(200, 400)))
ply:EmitSound(sounds[math.random(1, 6)], 60, math.random(80, 120))
if damage > 0 then
ply:TakeDamage(damage, admin, DMG_GENERIC)
end
end
command.new("slap")
:SetPermission("slap", "admin")
:AddArg("player")
:AddArg("number", {hint = "damage", round = true, optional = true, min = 0, default = 0})
:Help("slap_help")
:OnExecute(function(ply, targets, damage)
for i = 1, #targets do
slap(targets[i], damage, ply)
end
if damage > 0 then
sam.player.send_message(nil, "slap_damage", {
A = ply, T = targets, V = damage
})
else
sam.player.send_message(nil, "slap", {
A = ply, T = targets
})
end
end)
:End()
end
command.new("slay")
:SetPermission("slay", "admin")
:AddArg("player")
:Help("slay_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local v = targets[i]
if not v:sam_get_exclusive(ply) then
v:Kill()
end
end
sam.player.send_message(nil, "slay", {
A = ply, T = targets
})
end)
:End()
command.new("hp")
:Aliases("sethp", "health", "sethealth")
:SetPermission("hp", "admin")
:AddArg("player")
:AddArg("number", {hint = "amount", min = 1, max = 2147483647, round = true, optional = true, default = 100})
:Help("hp_help")
:OnExecute(function(ply, targets, amount)
for i = 1, #targets do
targets[i]:SetHealth(amount)
end
sam.player.send_message(nil, "set_hp", {
A = ply, T = targets, V = amount
})
end)
:End()
command.new("armor")
:Aliases("setarmor")
:SetPermission("armor", "admin")
:AddArg("player")
:AddArg("number", {hint = "amount", min = 1, max = 2147483647, round = true, optional = true, default = 100})
:Help("armor_help")
:OnExecute(function(ply, targets, amount)
for i = 1, #targets do
targets[i]:SetArmor(amount)
end
sam.player.send_message(nil, "set_armor", {
A = ply, T = targets, V = amount
})
end)
:End()
command.new("ignite")
:SetPermission("ignite", "admin")
:AddArg("player")
:AddArg("number", {hint = "seconds", optional = true, default = 60, round = true})
:Help("ignite_help")
:OnExecute(function(ply, targets, length)
for i = 1, #targets do
local target = targets[i]
if target:IsOnFire() then
target:Extinguish()
end
target:Ignite(length)
end
sam.player.send_message(nil, "ignite", {
A = ply, T = targets, V = length
})
end)
:End()
command.new("unignite")
:Aliases("extinguish")
:SetPermission("ignite", "admin")
:AddArg("player", {optional = true})
:Help("unignite_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:Extinguish()
end
sam.player.send_message(nil, "unignite", {
A = ply, T = targets
})
end)
:End()
command.new("god")
:Aliases("invincible")
:SetPermission("god", "admin")
:AddArg("player", {optional = true})
:Help("god_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local target = targets[i]
target:GodEnable()
target.sam_has_god_mode = true
end
sam.player.send_message(nil, "god", {
A = ply, T = targets
})
end)
:End()
command.new("ungod")
:Aliases("uninvincible")
:SetPermission("ungod", "admin")
:AddArg("player", {optional = true})
:Help("ungod_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local target = targets[i]
target:GodDisable()
target.sam_has_god_mode = nil
end
sam.player.send_message(nil, "ungod", {
A = ply, T = targets
})
end)
:End()
do
command.new("freeze")
:SetPermission("freeze", "admin")
:AddArg("player")
:Help("freeze_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local v = targets[i]
v:ExitVehicle()
if v:sam_get_nwvar("frozen") then
v:UnLock()
end
v:Lock()
v:sam_set_nwvar("frozen", true)
v:sam_set_exclusive("frozen")
end
sam.player.send_message(nil, "freeze", {
A = ply, T = targets
})
end)
:End()
command.new("unfreeze")
:SetPermission("unfreeze", "admin")
:AddArg("player", {optional = true})
:Help("unfreeze_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local v = targets[i]
v:UnLock()
v:sam_set_nwvar("frozen", false)
v:sam_set_exclusive(nil)
end
sam.player.send_message(nil, "unfreeze", {
A = ply, T = targets
})
end)
:End()
local disallow = function(ply)
if ply:sam_get_nwvar("frozen") then
return false
end
end
for _, v in ipairs({"SAM.CanPlayerSpawn", "CanPlayerSuicide", "CanTool"}) do
hook.Add(v, "SAM.FreezePlayer." .. v, disallow)
end
end
command.new("cloak")
:SetPermission("cloak", "admin")
:AddArg("player", {optional = true})
:Help("cloak_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:sam_cloak()
end
sam.player.send_message(nil, "cloak", {
A = ply, T = targets
})
end)
:End()
command.new("uncloak")
:SetPermission("uncloak", "admin")
:AddArg("player", {optional = true})
:Help("uncloak_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:sam_uncloak()
end
sam.player.send_message(nil, "uncloak", {
A = ply, T = targets
})
end)
:End()
do
local jail_props = {
Vector(0, 0, -5), Angle(90, 0, 0);
Vector(0, 0, 97), Angle(90, 0, 0);
Vector(21, 31, 46), Angle(0, 90, 0);
Vector(21, -31, 46), Angle(0, 90, 0);
Vector(-21, 31, 46), Angle(0, 90, 0);
Vector(-21, -31, 46), Angle(0, 90, 0);
Vector(-52, 0, 46), Angle(0, 0, 0);
Vector(52, 0, 46), Angle(0, 0, 0)
}
local remove_jail = function(ply_jail_props)
for _, jail_prop in ipairs(ply_jail_props) do
if IsValid(jail_prop) then
jail_prop:Remove()
end
end
end
local unjail = function(ply)
if not IsValid(ply) then return end
if not ply:sam_get_nwvar("jailed") then return end
remove_jail(ply.sam_jail_props)
ply.sam_jail_props = nil
ply.sam_jail_pos = nil
ply:sam_set_nwvar("jailed", nil)
ply:sam_set_exclusive(nil)
timer.Remove("SAM.Unjail." .. ply:SteamID())
timer.Remove("SAM.Jail.Watch." .. ply:SteamID())
end
local return_false = function()
return false
end
local function jail(ply, time)
if not IsValid(ply) then return end
if not isnumber(time) or time < 0 then
time = 0
end
if ply:sam_get_nwvar("frozen") then
RunConsoleCommand("sam", "unfreeze", "#" .. ply:EntIndex())
end
if not ply:sam_get_nwvar("jailed") or (not ply.sam_jail_props or not IsValid(ply.sam_jail_props[1])) then
ply:ExitVehicle()
ply:SetMoveType(MOVETYPE_WALK)
ply.sam_jail_pos = ply:GetPos()
ply:sam_set_nwvar("jailed", true)
ply:sam_set_exclusive("in jail")
if ply.sam_jail_props then
for k, v in ipairs(ply.sam_jail_props) do
if IsValid(v) then
v:Remove()
end
end
end
local ply_jail_props = {}
for i = 1, #jail_props, 2 do
local jail_prop = ents.Create("prop_physics")
jail_prop:SetModel("models/props_building_details/Storefront_Template001a_Bars.mdl")
jail_prop:SetPos(ply.sam_jail_pos + jail_props[i])
jail_prop:SetAngles(jail_props[i + 1])
jail_prop:SetMoveType(MOVETYPE_NONE)
jail_prop:Spawn()
jail_prop:GetPhysicsObject():EnableMotion(false)
jail_prop.CanTool = return_false
jail_prop.PhysgunPickup = return_false
jail_prop.jailWall = true
table.insert(ply_jail_props, jail_prop)
end
ply.sam_jail_props = ply_jail_props
end
local steamid = ply:SteamID()
if time == 0 then
timer.Remove("SAM.Unjail." .. steamid)
else
timer.Create("SAM.Unjail." .. steamid, time, 1, function()
if IsValid(ply) then
unjail(ply)
end
end)
end
timer.Create("SAM.Jail.Watch." .. steamid, 0.5, 0, function()
if not IsValid(ply) then
return timer.Remove("SAM.Jail.Watch." .. steamid)
end
if ply:GetPos():DistToSqr(ply.sam_jail_pos) > 4900 then
ply:SetPos(ply.sam_jail_pos)
end
if not IsValid(ply.sam_jail_props[1]) then
jail(ply, timer.TimeLeft("SAM.Unjail." .. steamid) or 0)
end
end)
end
command.new("jail")
:SetPermission("jail", "admin")
:AddArg("player")
:AddArg("length", {optional = true, default = 0, min = 0})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("jail_help")
:OnExecute(function(ply, targets, length, reason)
for i = 1, #targets do
jail(targets[i], length * 60)
end
sam.player.send_message(nil, "jail", {
A = ply, T = targets, V = sam.format_length(length), V_2 = reason
})
end)
:End()
command.new("unjail")
:SetPermission("unjail", "admin")
:AddArg("player", {optional = true})
:Help("unjail_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
unjail(targets[i])
end
sam.player.send_message(nil, "unjail", {
A = ply, T = targets
})
end)
:End()
sam.hook_first("CanProperty", "SAM.Jail", function(_, property, ent)
if ent.jailWall and property == "remover" then
return false
end
end)
if SERVER then
hook.Add("PlayerSpawn", "SAM.Jail", function(ply)
if ply:sam_get_nwvar("jailed") or ply:sam_get_pdata("jailed") then
if ply.sam_jail_pos then
ply:SetPos(ply.sam_jail_pos)
else
ply:SetPos(ply:sam_get_pdata("jail_pos"))
jail(ply, ply:sam_get_pdata("jail_time_left"))
ply:sam_set_pdata("jailed", nil)
ply:sam_set_pdata("jail_pos", nil)
ply:sam_set_pdata("jail_time_left", nil)
end
end
end)
hook.Add("PlayerEnteredVehicle", "SAM.Jail", function(ply)
if ply:sam_get_nwvar("jailed") then
ply:ExitVehicle()
end
end)
hook.Add("PlayerDisconnected", "SAM.Jail", function(ply)
if ply:sam_get_nwvar("jailed") then
remove_jail(ply.sam_jail_props)
ply:sam_set_pdata("jailed", true)
ply:sam_set_pdata("jail_pos", ply.sam_jail_pos)
ply:sam_set_pdata("jail_time_left", timer.TimeLeft("SAM.Unjail." .. ply:SteamID()) or 0)
timer.Remove("SAM.Unjail." .. ply:SteamID())
timer.Remove("SAM.Jail.Watch." .. ply:SteamID())
end
end)
end
local disallow = function(ply)
if ply:sam_get_nwvar("jailed") then
return false
end
end
for _, v in ipairs({"PlayerNoClip", "SAM.CanPlayerSpawn", "CanPlayerEnterVehicle", "CanPlayerSuicide", "CanTool"}) do
hook.Add(v, "SAM.Jail", disallow)
end
end
command.new("strip")
:SetPermission("strip", "admin")
:AddArg("player")
:Help("strip_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:StripWeapons()
end
sam.player.send_message(nil, "strip", {
A = ply, T = targets
})
end)
:End()
command.new("respawn")
:SetPermission("respawn", "admin")
:AddArg("player", {optional = true})
:Help("respawn_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i]:Spawn()
end
sam.player.send_message(nil, "respawn", {
A = ply, T = targets
})
end)
:End()
command.new("setmodel")
:SetPermission("setmodel", "superadmin")
:AddArg("player")
:AddArg("text", {hint = "model"})
:Help("setmodel_help")
:OnExecute(function(ply, targets, model)
for i = 1, #targets do
targets[i]:SetModel(model)
end
sam.player.send_message(nil, "setmodel", {
A = ply, T = targets, V = model
})
end)
:End()
command.new("giveammo")
:Aliases("ammo")
:SetPermission("giveammo", "superadmin")
:AddArg("player")
:AddArg("number", {hint = "amount", min = 0, max = 99999})
:Help("giveammo_help")
:OnExecute(function(ply, targets, amount)
if amount == 0 then
amount = 99999
end
for i = 1, #targets do
local target = targets[i]
for _, wep in ipairs(target:GetWeapons()) do
if wep:GetPrimaryAmmoType() ~= -1 then
target:GiveAmmo(amount, wep:GetPrimaryAmmoType(), true)
end
if wep:GetSecondaryAmmoType() ~= -1 then
target:GiveAmmo(amount, wep:GetSecondaryAmmoType(), true)
end
end
end
sam.player.send_message(nil, "giveammo", {
A = ply, T = targets, V = amount
})
end)
:End()
do
command.new("scale")
:SetPermission("scale", "superadmin")
:AddArg("player")
:AddArg("number", {hint = "amount", optional = true, min = 0, max = 2.5, default = 1})
:Help("scale_help")
:OnExecute(function(ply, targets, amount)
for i = 1, #targets do
local v = targets[i]
v:SetModelScale(amount)
-- https://github.com/carz1175/More-ULX-Commands/blob/9b142ee4247a84f16e2dc2ec71c879ab76e145d4/lua/ulx/modules/sh/extended.lua#L313
v:SetViewOffset(Vector(0, 0, 64 * amount))
v:SetViewOffsetDucked(Vector(0, 0, 28 * amount))
v.sam_scaled = true
end
sam.player.send_message(nil, "scale", {
A = ply, T = targets, V = amount
})
end)
:End()
hook.Add("PlayerSpawn", "SAM.Scale", function(ply)
if ply.sam_scaled then
ply.sam_scaled = nil
ply:SetViewOffset(Vector(0, 0, 64))
ply:SetViewOffsetDucked(Vector(0, 0, 28))
end
end)
end
sam.command.new("freezeprops")
:SetPermission("freezeprops", "admin")
:Help("freezeprops_help")
:OnExecute(function(ply)
for _, prop in ipairs(ents.FindByClass("prop_physics")) do
local physics_obj = prop:GetPhysicsObject()
if IsValid(physics_obj) then
physics_obj:EnableMotion(false)
end
end
sam.player.send_message(nil, "freezeprops", {
A = ply
})
end)
:End()

224
lua/sam/modules/murder.lua Normal file
View File

@@ -0,0 +1,224 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local add = not GAMEMODE and hook.Add or function(_, _, fn)
fn()
end
-- Thanks to https://github.com/boxama/addons/blob/master/addons/ULX_Murder/lua/ulx/modules/sh/murder.lua
add("PostGamemodeLoaded", "SAM.Murder", function()
if GAMEMODE.Author ~= "MechanicalMind" then return end
if not isstring(GAMEMODE.Version) or GAMEMODE.Version < "28" then return end
local sam, command = sam, sam.command
command.set_category("Murder")
local autoslain_players = {}
command.new("slaynr")
:SetPermission("slaynr", "admin")
:AddArg("player")
:AddArg("number", {hint = "rounds", optional = true, default = 1, min = 1, max = 100, round = true})
:Help("Slays the target(s) at the beggining of the next round.")
:OnExecute(function(ply, targets, rounds)
for i = 1, #targets do
local v = targets[i]
v.MurdererChance = 0
if not v:IsBot() then
autoslain_players[v:AccountID()] = rounds
end
end
sam.player.send_message(nil, "{A} set {T} to be autoslain for {V} round(s)", {
A = ply, T = targets, V = rounds
})
end)
:End()
command.new("unslaynr")
:SetPermission("unslaynr", "admin")
:AddArg("player")
:Help("Remove target(s) autoslays.")
:OnExecute(function(ply, targets)
for i = 1, #targets do
local v = targets[i]
v.MurdererChance = 1
if not v:IsBot() then
autoslain_players[v:AccountID()] = nil
end
end
sam.player.send_message(nil, "Removed all autoslays for {T} ", {
A = ply, T = targets
})
end)
:End()
hook.Add("OnStartRound", "SAM.Murder", function()
timer.Simple(3, function()
local players = team.GetPlayers(2)
local targets = {admin = sam.console}
for i = 1, #players do
local v = players[i]
if not v:IsBot() then continue end
local slays = autoslain_players[v:AccountID()]
if not slays then continue end
v:Kill()
slays = slays - 1
targets[1] = v
sam.player.send_message(nil, "{A} autoslayed {T}, autoslays left: {V}.", {
A = sam.console, T = targets, V = slays
})
autoslain_players[v:AccountID()] = slays > 0 and slays or nil
end
end)
end)
hook.Add("PlayerInitialSpawn", "SAM.Murder", function(ply)
if autoslain_players[ply:AccountID()] then
ply.MurdererChance = 0
end
end)
command.new("respawn")
:SetPermission("respawn", "admin")
:AddArg("player", {single_target = true})
:Help("Respawn a target.")
:OnExecute(function(ply, targets)
local target = targets[1]
if target:Team() ~= 2 then
return ply:sam_add_text("You cannot respawn a spectator!")
end
target:Spectate(OBS_MODE_NONE)
target:Spawn()
sam.player.send_message(nil, "respawn", {
A = ply, T = targets
})
end)
:End()
local get_admins = function()
local admins = {}
local players = player.GetHumans()
for i = 1, #players do
local v = players[i]
if v:IsAdmin() then
table.insert(admins, v)
end
end
return admins
end
command.new("givemagnum")
:SetPermission("givemagnum", "superadmin")
:AddArg("player", {single_target = true, optional = true})
:Help("Give the target a magnum.")
:OnExecute(function(ply, targets)
local target = targets[1]
if target:Team() ~= 2 then
return ply:sam_add_text("You cannot give spectator a magnum!")
end
target:Give("weapon_mu_magnum")
sam.player.send_message(get_admins(), "{A} gave {T} a {V}", {
A = ply, T = targets, V = "magnum"
})
end)
:End()
command.new("giveknife")
:SetPermission("giveknife", "superadmin")
:AddArg("player", {single_target = true, optional = true})
:Help("Give the target a knife.")
:OnExecute(function(ply, targets)
local target = targets[1]
if target:Team() ~= 2 then
return ply:sam_add_text("You cannot give spectator a knife!")
end
target:Give("weapon_mu_knife")
sam.player.send_message(get_admins(), "{A} gave {T} a {V}", {
A = ply, T = targets, V = "knife"
})
end)
:End()
command.new("forcemurderer")
:SetPermission("forcemurderer", "admin")
:AddArg("player", {single_target = true, optional = true})
:Help("Force the target to me a murderer next round.")
:OnExecute(function(ply, targets)
GAMEMODE.ForceNextMurderer = targets[1]
sam.player.send_message(get_admins(), "{A} set {T} to be the Murderer next round!", {
A = ply, T = targets
})
end)
:End()
command.new("getmurderers")
:SetPermission("getmurderers", "admin")
:Help("Print all murderers in chat.")
:OnExecute(function(ply)
local murderers = {admin = ply}
local players = team.GetPlayers(2)
for i = 1, #players do
local v = players[i]
if v:GetMurderer() then
table.insert(murderers, v)
end
end
sam.player.send_message(ply, "Murderers are: {T}", {
T = murderers
})
end)
:End()
end)

View File

@@ -0,0 +1,136 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local ranks_loaded
if SERVER then
ranks_loaded = sam.ranks.ranks_loaded()
else
ranks_loaded = sam.ranks.get_ranks() ~= nil
end
do
local load_ranks = function()
for name, rank in pairs(sam.ranks.get_ranks()) do
if not sam.ranks.is_default_rank(name) then
CAMI.RegisterUsergroup({Name = name, Inherits = rank.inherit}, "SAM")
end
end
end
if ranks_loaded then
load_ranks()
else
hook.Add("SAM.LoadedRanks", "SAM.CAMI.LoadRanksToCAMI", load_ranks)
end
end
hook.Add("SAM.AddedRank", "SAM.CAMI.AddedRank", function(name, rank)
if not sam.ranks.is_default_rank(name) then
CAMI.RegisterUsergroup({Name = name, Inherits = rank.inherit}, "SAM")
end
end)
hook.Add("SAM.RemovedRank", "SAM.CAMI.RemovedRank", function(name)
CAMI.UnregisterUsergroup(name, "SAM")
end)
hook.Add("SAM.RankNameChanged", "SAM.CAMI.RankNameChanged", function(old, new)
CAMI.UnregisterUsergroup(old, "SAM")
CAMI.RegisterUsergroup({Name = new, Inherits = sam.ranks.get_rank(new).inherit}, "SAM")
end)
hook.Add("SAM.ChangedPlayerRank", "SAM.CAMI.ChangedPlayerRank", function(ply, new_rank, old_rank)
CAMI.SignalUserGroupChanged(ply, old_rank, new_rank, "SAM")
end)
hook.Add("SAM.ChangedSteamIDRank", "SAM.CAMI.ChangedSteamIDRank", function(steamid, new_rank, old_rank)
CAMI.SignalSteamIDUserGroupChanged(steamid, old_rank, new_rank, "SAM")
end)
----------------------------------------------------------------------------------------------------------------------------------------------------------
if SERVER then
do
local on_user_group_registered = function(rank, source)
if source ~= "SAM" then
sam.ranks.add_rank(rank.Name, sam.ranks.is_rank(rank.Inherits) and rank.Inherits or "user")
end
end
local load_ranks = function()
for _, rank in pairs(CAMI.GetUsergroups()) do
on_user_group_registered(rank, "CAMI")
end
hook.Add("CAMI.OnUsergroupRegistered", "SAM.CAMI.OnUsergroupRegistered", on_user_group_registered)
end
if ranks_loaded then
load_ranks()
else
hook.Add("SAM.LoadedRanks", "SAM.CAMI.LoadRanksFromCAMI", load_ranks)
end
end
hook.Add("CAMI.OnUsergroupUnregistered", "SAM.CAMI.OnUsergroupUnregistered", function(rank, source)
if source ~= "SAM" then
sam.ranks.remove_rank(rank.Name)
end
end)
hook.Add("CAMI.PlayerUsergroupChanged", "SAM.CAMI.PlayerUsergroupChanged", function(ply, _, new_rank, source)
if ply and IsValid(ply) and source ~= "SAM" then
sam.player.set_rank(ply, new_rank)
end
end)
hook.Add("CAMI.SteamIDUsergroupChanged", "SAM.CAMI.SteamIDUsergroupChanged", function(steamid, _, new_rank, source)
if sam.is_steamid(steamid) and source ~= "SAM" then
sam.player.set_rank_id(steamid, new_rank)
end
end)
end
do
local on_privilege_registered = function(privilege)
sam.permissions.add(privilege.Name, "CAMI", privilege.MinAccess)
end
local load_privileges = function()
for _, privilege in pairs(CAMI.GetPrivileges()) do
on_privilege_registered(privilege)
end
hook.Add("CAMI.OnPrivilegeRegistered", "SAM.CAMI.OnPrivilegeRegistered", on_privilege_registered)
end
if ranks_loaded then
load_privileges()
else
hook.Add("SAM.LoadedRanks", "SAM.CAMI.LoadPrivileges", load_privileges)
end
end
hook.Add("CAMI.OnPrivilegeUnregistered", "SAM.CAMI.OnPrivilegeUnregistered", function(privilege)
sam.permissions.remove(privilege.Name)
end)
hook.Add("CAMI.PlayerHasAccess", "SAM.CAMI.PlayerHasAccess", function(ply, privilege, callback, target)
if sam.type(ply) ~= "Player" then return end
local has_permission = ply:HasPermission(privilege)
if sam.type(target) == "Player" then
callback(has_permission and ply:CanTarget(target))
else
callback(has_permission)
end
return true
end)

View File

@@ -0,0 +1,61 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
--
-- This checks if a player joined your server using a lent account that is banned
-- eg. player got banned so he decided to make an alt account and used https://store.steampowered.com/promotion/familysharing
--
--
-- Whitelisted players from checking if they have family sharing or not
-- You can have steamid/steamid64 here
--
local Whitelisted_SteamIDs = {
}
local BanMessage = "Bypassing a ban using an alt. (alt: %s)"
--
-- Do you want to kick players using family shared accounts?
--
local BlockFamilySharing = false
local BlockFamilySharingMessage = "This server blocked using shared accounts."
--
--
-- DO NOT TOUCH --
--
--
for k, v in pairs(Whitelisted_SteamIDs) do
Whitelisted_SteamIDs[v] = true
Whitelisted_SteamIDs[k] = nil
end
hook.Add("SAM.AuthedPlayer", "CheckSteamFamily", function(ply)
local ply_steamid = ply:SteamID()
local ply_steamid64 = ply:SteamID64()
if Whitelisted_SteamIDs[ply_steamid] or Whitelisted_SteamIDs[ply_steamid64] then return end
local lender = ply:OwnerSteamID64()
if (ply_steamid64 == lender) then return end
if BlockFamilySharing then
ply:Kick(BlockFamilySharingMessage)
else
lender = util.SteamIDFrom64(lender)
sam.player.is_banned(lender, function(banned)
if banned then
RunConsoleCommand("sam", "banid", ply_steamid, "0", BanMessage:format(lender))
end
end)
end
end)

View File

@@ -0,0 +1,198 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("Teleport")
local find_empty_pos -- https://github.com/FPtje/DarkRP/blob/b147d6fa32799136665a9fd52d35c2fe87cf7f78/gamemode/modules/base/sv_util.lua#L149
do
local is_empty = function(vector, ignore)
local point = util.PointContents(vector)
local a = point ~= CONTENTS_SOLID
and point ~= CONTENTS_MOVEABLE
and point ~= CONTENTS_LADDER
and point ~= CONTENTS_PLAYERCLIP
and point ~= CONTENTS_MONSTERCLIP
if not a then return false end
local ents_found = ents.FindInSphere(vector, 35)
for i = 1, #ents_found do
local v = ents_found[i]
if (v:IsNPC() or v:IsPlayer() or v:GetClass() == "prop_physics" or v.NotEmptyPos) and v ~= ignore then
return false
end
end
return true
end
local distance, step, area = 600, 30, Vector(16, 16, 64)
local north_vec, east_vec, up_vec = Vector(0, 0, 0), Vector(0, 0, 0), Vector(0, 0, 0)
find_empty_pos = function(pos, ignore)
if is_empty(pos, ignore) and is_empty(pos + area, ignore) then
return pos
end
for j = step, distance, step do
for i = -1, 1, 2 do
local k = j * i
-- North/South
north_vec.x = k
if is_empty(pos + north_vec, ignore) and is_empty(pos + north_vec + area, ignore) then
return pos + north_vec
end
-- East/West
east_vec.y = k
if is_empty(pos + east_vec, ignore) and is_empty(pos + east_vec + area, ignore) then
return pos + east_vec
end
-- Up/Down
up_vec.z = k
if is_empty(pos + up_vec, ignore) and is_empty(pos + up_vec + area, ignore) then
return pos + up_vec
end
end
end
return pos
end
end
command.new("bring")
:DisallowConsole()
:SetPermission("bring", "admin")
:AddArg("player", {cant_target_self = true})
:Help("bring_help")
:OnExecute(function(ply, targets)
if not ply:Alive() then
return ply:sam_send_message("dead")
end
if ply:InVehicle() then
return ply:sam_send_message("leave_car")
end
if ply:sam_get_exclusive(ply) then
return ply:sam_send_message(ply:sam_get_exclusive(ply))
end
local teleported = {admin = ply}
local all = targets.input == "*"
for i = 1, #targets do
local target = targets[i]
if target:sam_get_exclusive(ply) then
if not all then
ply:sam_send_message(target:sam_get_exclusive(ply))
end
continue
end
if not target:Alive() then
target:Spawn()
end
target.sam_tele_pos, target.sam_tele_ang = target:GetPos(), target:EyeAngles()
target:ExitVehicle()
target:SetVelocity(Vector(0, 0, 0))
target:SetPos(find_empty_pos(ply:GetPos(), target))
target:SetEyeAngles((ply:EyePos() - target:EyePos()):Angle())
table.insert(teleported, target)
end
if #teleported > 0 then
sam.player.send_message(nil, "bring", {
A = ply, T = teleported
})
end
end)
:End()
command.new("goto")
:DisallowConsole()
:SetPermission("goto", "admin")
:AddArg("player", {single_target = true, allow_higher_target = true, cant_target_self = true})
:Help("goto_help")
:OnExecute(function(ply, targets)
if ply:sam_get_exclusive(ply) then
return ply:sam_send_message(ply:sam_get_exclusive(ply))
end
if not ply:Alive() then
ply:Spawn()
end
local target = targets[1]
ply.sam_tele_pos, ply.sam_tele_ang = ply:GetPos(), ply:EyeAngles()
ply:ExitVehicle()
ply:SetVelocity(Vector(0, 0, 0))
ply:SetPos(find_empty_pos(target:GetPos(), ply))
ply:SetEyeAngles((target:EyePos() - ply:EyePos()):Angle())
sam.player.send_message(nil, "goto", {
A = ply, T = targets
})
end)
:End()
command.new("return")
:SetPermission("return", "admin")
:AddArg("player", {single_target = true, optional = true})
:Help("return_help")
:OnExecute(function(ply, targets)
local target = targets[1]
local last_pos, last_ang = target.sam_tele_pos, target.sam_tele_ang
if not last_pos then
return sam.player.send_message(ply, "no_location", {
T = targets
})
end
if target:sam_get_exclusive(ply) then
return ply:sam_send_message(target:sam_get_exclusive(ply))
end
if not target:Alive() then
return ply:sam_send_message(target:Name() .. " is dead!")
end
target:ExitVehicle()
target:SetVelocity(Vector(0, 0, 0))
target:SetPos(last_pos)
target:SetEyeAngles(last_ang)
target.sam_tele_pos, target.sam_tele_ang = nil, nil
sam.player.send_message(nil, "returned", {
A = ply, T = targets
})
end)
:End()

102
lua/sam/modules/ttt.lua Normal file
View File

@@ -0,0 +1,102 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local run = function(fn)
if not GAMEMODE then
timer.Simple(0, fn)
else
fn()
end
end
run(function()
if engine.ActiveGamemode() ~= "terrortown" then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("TTT")
command.new("setslays")
:SetPermission("setslays", "admin")
:AddArg("player", {single_target = true})
:AddArg("number", {hint = "amount", optional = true, min = 1, default = 1, round = true})
:Help("setslays_help")
:OnExecute(function(ply, targets, amount)
targets[1]:sam_set_pdata("slays_amount", amount)
sam.player.send_message(nil, "setslays", {
A = ply, T = targets, V = amount
})
end)
:End()
command.new("removeslays")
:SetPermission("removeslays", "admin")
:AddArg("player", {single_target = true})
:Help("removeslays_help")
:OnExecute(function(ply, targets, amount)
local target = targets[1]
target:sam_set_pdata("slays_amount", nil)
target:SetForceSpec(false)
sam.player.send_message(nil, "removeslays", {
A = ply, T = targets
})
end)
:End()
OldBeginRound = OldBeginRound or BeginRound
function BeginRound(...)
local players = player.GetAll()
for i = 1, #players do
local ply = players[i]
local slays = ply:sam_get_pdata("slays_amount")
if not slays then continue end
if not ply:IsSpec() then
ply:Kill()
end
GAMEMODE:PlayerSpawnAsSpectator(ply)
ply:SetTeam(TEAM_SPEC)
ply:SetForceSpec(true)
ply:Spawn()
ply:SetRagdollSpec(false) -- dying will enable this, we don't want it here
slays = slays - 1
if slays == 0 then
timer.Simple(0, function()
ply:SetForceSpec(false)
end)
ply:sam_set_pdata("slays_amount", nil)
else
ply:sam_set_pdata("slays_amount", slays)
end
sam.player.send_message(nil, "setslays_slayed", {
T = {ply}, V = slays
})
end
return OldBeginRound(...)
end
end)

273
lua/sam/modules/user.lua Normal file
View File

@@ -0,0 +1,273 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("User Management")
command.new("setrank")
:Aliases("adduser", "changerank", "giverank")
:SetPermission("setrank")
:AddArg("player", {single_target = true})
:AddArg("rank", {check = function(rank, ply)
return ply:CanTargetRank(rank)
end})
:AddArg("length", {optional = true, default = 0})
:Help("setrank_help")
:OnExecute(function(ply, targets, rank, length)
targets[1]:sam_set_rank(rank, length)
sam.player.send_message(nil, "setrank", {
A = ply, T = targets, V = rank, V_2 = sam.format_length(length)
})
end)
:End()
command.new("setrankid")
:Aliases("adduserid", "changerankid", "giverankid")
:SetPermission("setrankid")
:AddArg("steamid")
:AddArg("rank", {check = function(rank, ply)
return ply:CanTargetRank(rank)
end})
:AddArg("length", {optional = true, default = 0})
:Help("setrankid_help")
:OnExecute(function(ply, promise, rank, length)
local a_name = ply:Name()
promise:done(function(data)
local steamid, target = data[1], data[2]
if target then
target:sam_set_rank(rank, length)
sam.player.send_message(nil, "setrank", {
A = ply, T = {target, admin = ply}, V = rank, V_2 = sam.format_length(length)
})
else
sam.player.set_rank_id(steamid, rank, length)
sam.player.send_message(nil, "setrank", {
A = a_name, T = steamid, V = rank, V_2 = sam.format_length(length)
})
end
end)
end)
:End()
command.new("addrank")
:SetPermission("manage_ranks")
:AddArg("text", {hint = "rank name", check = function(rank)
return not sam.ranks.is_rank(rank)
end})
:AddArg("rank", {hint = "inherit from"})
:AddArg("number", {hint = "immunity", min = 2, max = 99, optional = true})
:AddArg("length", {hint = "ban limit", optional = true})
:Help("addrank_help")
:MenuHide()
:OnExecute(function(ply, rank, inherit, immunity, ban_limit)
sam.ranks.add_rank(rank, inherit, immunity, ban_limit)
sam.player.send_message(nil, "addrank", {
A = ply, V = rank
})
end)
:End()
command.new("removerank")
:SetPermission("manage_ranks")
:AddArg("rank", {check = function(rank)
return not sam.ranks.is_default_rank(rank)
end})
:Help("removerank_help")
:MenuHide()
:OnExecute(function(ply, rank)
sam.ranks.remove_rank(rank)
sam.player.send_message(nil, "removerank", {
A = ply, V = rank
})
end)
:End()
command.new("renamerank")
:SetPermission("manage_ranks")
:AddArg("rank", {check = function(rank)
return not sam.ranks.is_default_rank(rank)
end})
:AddArg("text", {hint = "new name", check = function(rank)
return not sam.ranks.is_rank(rank)
end})
:Help("renamerank_help")
:MenuHide()
:OnExecute(function(ply, rank, new_name)
sam.ranks.rename_rank(rank, new_name)
sam.player.send_message(nil, "renamerank", {
A = ply, T = rank, V = new_name
})
end)
:End()
command.new("changeinherit")
:SetPermission("manage_ranks")
:AddArg("rank", {check = function(rank)
return rank ~= "user" and rank ~= "superadmin"
end})
:AddArg("rank", {hint = "inherits from"})
:Help("changeinherit_help")
:MenuHide()
:OnExecute(function(ply, rank, inherit)
if rank == inherit then return end
sam.ranks.change_inherit(rank, inherit)
sam.player.send_message(nil, "changeinherit", {
A = ply, T = rank, V = inherit
})
end)
:End()
command.new("changerankimmunity")
:SetPermission("manage_ranks")
:AddArg("rank", {check = function(rank)
return rank ~= "user" and rank ~= "superadmin"
end})
:AddArg("number", {hint = "new immunity", min = 2, max = 99})
:Help("changerankimmunity_help")
:MenuHide()
:OnExecute(function(ply, rank, new_immunity)
sam.ranks.change_immunity(rank, new_immunity)
sam.player.send_message(nil, "rank_immunity", {
A = ply, T = rank, V = new_immunity
})
end)
:End()
command.new("changerankbanlimit")
:SetPermission("manage_ranks")
:AddArg("rank", {check = function(rank)
return rank ~= "superadmin"
end})
:AddArg("length")
:Help("changerankbanlimit_help")
:MenuHide()
:OnExecute(function(ply, rank, new_limit)
sam.ranks.change_ban_limit(rank, new_limit)
sam.player.send_message(nil, "rank_ban_limit", {
A = ply, T = rank, V = sam.format_length(new_limit)
})
end)
:End()
command.new("givepermission")
:SetPermission("manage_ranks")
:AddArg("rank")
:AddArg("text", {hint = "permission"})
:Help("givepermission_help")
:MenuHide()
:OnExecute(function(ply, rank, permission)
if rank == "superadmin" then
return ply:sam_send_message("super_admin_access")
end
sam.ranks.give_permission(rank, permission)
sam.player.send_message(nil, "giveaccess", {
A = ply, V = permission, T = rank
})
end)
:End()
command.new("takepermission")
:SetPermission("manage_ranks")
:AddArg("rank")
:AddArg("text", {hint = "permission"})
:Help("takepermission_help")
:MenuHide()
:OnExecute(function(ply, rank, permission)
if rank == "superadmin" then
return ply:sam_send_message("super_admin_access")
end
sam.ranks.take_permission(rank, permission)
sam.player.send_message(nil, "takeaccess", {
A = ply, V = permission, T = rank
})
end)
:End()
command.new("changeranklimit")
:SetPermission("manage_ranks")
:AddArg("rank")
:AddArg("text", {hint = "limit"})
:AddArg("number", {hint = "value"})
:Help("changeranklimit_help")
:MenuHide()
:OnExecute(function(ply, rank, limit, value)
if rank == "superadmin" then
return ply:sam_send_message("super_admin_access")
end
sam.ranks.set_limit(rank, limit, value)
sam.player.send_message(nil, "changeranklimit", {
A = ply, T = rank, V = limit, V_2 = value
})
end)
:End()

579
lua/sam/modules/util.lua Normal file
View File

@@ -0,0 +1,579 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local sam, command, language = sam, sam.command, sam.language
command.set_category("Utility")
command.new("map")
:SetPermission("map", "admin")
:AddArg("map")
:AddArg("text", {hint = "gamemode", optional = true, check = sam.is_valid_gamemode})
:Help("map_help")
:OnExecute(function(ply, map, gamemode)
if not gamemode then
sam.player.send_message(nil, "map_change", {
A = ply, V = map
})
else
sam.player.send_message(nil, "map_change2", {
A = ply, V = map, V_2 = gamemode
})
RunConsoleCommand("gamemode", gamemode)
end
if #player.GetHumans() == 0 then
RunConsoleCommand("changelevel", map)
else
timer.Create("SAM.Command.Map", 10, 1, function()
RunConsoleCommand("changelevel", map)
end)
end
end)
:End()
command.new("maprestart")
:SetPermission("maprestart", "admin")
:Help("map_restart_help")
:OnExecute(function(ply)
if #player.GetHumans() == 0 then
RunConsoleCommand("changelevel", game.GetMap())
else
timer.Create("SAM.Command.MapRestart", 10, 1, function()
RunConsoleCommand("changelevel", game.GetMap())
end)
sam.player.send_message(nil, "map_restart", {
A = ply
})
end
end)
:End()
command.new("mapreset")
:SetPermission("mapreset", "admin")
:Help("mapreset_help")
:OnExecute(function(ply)
game.CleanUpMap()
sam.player.send_message(nil, "mapreset", {
A = ply
})
end)
:End()
command.new("kick")
:SetPermission("kick", "admin")
:AddArg("player", {single_target = true})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("kick_help")
:OnExecute(function(ply, targets, reason)
local target = targets[1]
target:Kick(reason)
sam.player.send_message(nil, "kick", {
A = ply, T = target:Name(), V = reason
})
end)
:End()
command.new("ban")
:SetPermission("ban", "admin")
:AddArg("player", {single_target = true})
:AddArg("length", {optional = true, default = 0})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("ban_help")
:OnExecute(function(ply, targets, length, reason)
local target = targets[1]
if ply:GetBanLimit() ~= 0 then
if length == 0 then
length = ply:GetBanLimit()
else
length = math.Clamp(length, 1, ply:GetBanLimit())
end
end
target:sam_ban(length, reason, ply:SteamID())
sam.player.send_message(nil, "ban", {
A = ply, T = target:Name(), V = sam.format_length(length), V_2 = reason
})
end)
:End()
command.new("banid")
:SetPermission("banid", "admin")
:AddArg("steamid")
:AddArg("length", {optional = true, default = 0})
:AddArg("text", {hint = "reason", optional = true, default = sam.language.get("default_reason")})
:GetRestArgs()
:Help("banid_help")
:OnExecute(function(ply, promise, length, reason)
local a_steamid, a_name, a_ban_limit = ply:SteamID(), ply:Name(), ply:GetBanLimit()
promise:done(function(data)
local steamid, target = data[1], data[2]
if a_ban_limit ~= 0 then
if length == 0 then
length = a_ban_limit
else
length = math.Clamp(length, 1, a_ban_limit)
end
end
if target then
target:sam_ban(length, reason, a_steamid)
sam.player.send_message(nil, "ban", {
A = a_name, T = target:Name(), V = sam.format_length(length), V_2 = reason
})
else
sam.player.ban_id(steamid, length, reason, a_steamid)
sam.player.send_message(nil, "banid", {
A = a_name, T = steamid, V = sam.format_length(length), V_2 = reason
})
end
end)
end)
:End()
command.new("unban")
:SetPermission("unban", "admin")
:AddArg("steamid", {allow_higher_target = true})
:Help("unban_help")
:OnExecute(function(ply, steamid, reason)
sam.player.unban(steamid, ply:SteamID())
sam.player.send_message(nil, "unban", {
A = ply, T = steamid
})
end)
:End()
do
command.new("noclip")
:SetPermission("noclip", "admin")
:AddArg("player", {optional = true})
:Help("noclip_help")
:OnExecute(function(ply, targets)
local id
for i = 1, #targets do
local v = targets[i]
v:SetMoveType(v:GetMoveType() == MOVETYPE_WALK and MOVETYPE_NOCLIP or MOVETYPE_WALK)
if v == ply then
id = i
end
end
if id then
table.remove(targets, id)
if #targets == 0 then return end
end
sam.player.send_message(nil, "noclip", {
A = ply, T = targets
})
end)
:End()
sam.permissions.add("can_noclip", nil, "admin")
hook.Add("PlayerNoClip", "SAM.CanNoClip", function(ply)
if ply:HasPermission("can_noclip") then
return true
end
end)
end
do
local config = sam.config
sam.permissions.add("can_physgun_players", nil, "admin")
if CLIENT then
local add_setting = function(body, title, key)
local setting = body:Add("SAM.LabelPanel")
setting:Dock(TOP)
setting:SetLabel(title)
local enable = setting:Add("SAM.ToggleButton")
enable:SetConfig(key, true)
return setting
end
config.add_menu_setting("Physgun", function(body)
local setting_body
do
local p = add_setting(body, "Physgun (Enable/Disable all physgun features except picking up players)", "Physgun.Enabled")
p:DockMargin(8, 6, 8, 0)
end
setting_body = body:Add("Panel")
setting_body:Dock(TOP)
setting_body:DockMargin(8, 6, 8, 0)
setting_body:DockPadding(8, 0, 8, 0)
add_setting(setting_body, "No fall damage on drop", "Physgun.NoFallDamageOnDrop")
add_setting(setting_body, "Right click to freeze players", "Physgun.RightClickToFreeze")
add_setting(setting_body, "Reset Velocity to fix some issues when players fall", "Physgun.ResetVelocity")
function setting_body:PerformLayout()
setting_body:SizeToChildren(false, true)
end
end)
end
local freeze_player = function(ply)
if SERVER then
ply:Lock()
end
ply:SetMoveType(MOVETYPE_NONE)
ply:SetCollisionGroup(COLLISION_GROUP_WORLD)
end
sam.hook_first("PhysgunPickup", "SAM.CanPhysgunPlayer", function(ply, target)
if sam.type(target) == "Player" and ply:HasPermission("can_physgun_players") and ply:CanTarget(target) then
freeze_player(target)
return true
end
end)
local load_phygun_settings = function()
hook.Remove("PhysgunDrop", "SAM.PhysgunDrop")
hook.Remove("OnPlayerHitGround", "SAM.PhysgunDropOnPlayerHitGround")
if config.get("Physgun.Enabled", true) == false then
return
end
local right_click_to_freeze = config.get("Physgun.RightClickToFreeze", true)
local reset_velocity = config.get("Physgun.ResetVelocity", true)
hook.Add("PhysgunDrop", "SAM.PhysgunDrop", function(ply, target)
if sam.type(target) ~= "Player" then return end
if right_click_to_freeze and ply:KeyPressed(IN_ATTACK2) then
freeze_player(target)
if SERVER then
target:sam_set_nwvar("frozen", true)
target:sam_set_exclusive("frozen")
end
else
if reset_velocity then
target:SetLocalVelocity(Vector(0, 0, 0))
end
if SERVER then
target:UnLock()
target:sam_set_nwvar("frozen", false)
target:sam_set_exclusive(nil)
if target.sam_has_god_mode then
target:GodEnable()
end
target.sam_physgun_drop_was_frozen = not target:IsOnGround()
end
target:SetMoveType(MOVETYPE_WALK)
target:SetCollisionGroup(COLLISION_GROUP_PLAYER)
end
end)
if config.get("Physgun.NoFallDamageOnDrop", true) then
hook.Add("OnPlayerHitGround", "SAM.PhysgunDropOnPlayerHitGround", function(ply)
if ply.sam_physgun_drop_was_frozen then
ply.sam_physgun_drop_was_frozen = false
return true
end
end)
end
end
config.hook({"Physgun.Enabled", "Physgun.RightClickToFreeze", "Physgun.ResetVelocity", "Physgun.NoFallDamageOnDrop"}, load_phygun_settings)
end
do
command.new("cleardecals")
:SetPermission("cleardecals", "admin")
:Help("cleardecals_help")
:OnExecute(function(ply)
sam.netstream.Start(nil, "cleardecals")
sam.player.send_message(nil, "cleardecals", {
A = ply
})
end)
:End()
if CLIENT then
sam.netstream.Hook("cleardecals", function()
game.RemoveRagdolls()
RunConsoleCommand("r_cleardecals")
end)
end
end
do
command.new("stopsound")
:SetPermission("stopsound", "admin")
:Help("stopsound_help")
:OnExecute(function(ply)
sam.netstream.Start(nil, "stopsound")
sam.player.send_message(nil, "stopsound", {
A = ply
})
end)
:End()
if CLIENT then
sam.netstream.Hook("stopsound", function()
RunConsoleCommand("stopsound")
end)
end
end
command.new("exit")
:SetPermission("exit_vehicle", "admin")
:AddArg("player", {single_target = true})
:Help("exit_vehicle_help")
:OnExecute(function(ply, targets)
local target = targets[1]
if not target:InVehicle() then
if ply == target then
return ply:sam_send_message("not_in_vehicle")
else
return ply:sam_send_message("not_in_vehicle2", {
S = target:Name()
})
end
end
target:ExitVehicle()
sam.player.send_message(nil, "exit_vehicle", {
A = ply, T = targets
})
end)
:End()
command.new("time")
:SetPermission("time", "user")
:AddArg("player", {single_target = true, optional = true})
:Help("time_help")
:OnExecute(function(ply, targets)
if ply == targets[1] then
sam.player.send_message(ply, "time_your", {
V = sam.reverse_parse_length(targets[1]:sam_get_play_time() / 60)
})
else
sam.player.send_message(ply, "time_player", {
T = targets, V = sam.reverse_parse_length(targets[1]:sam_get_play_time() / 60)
})
end
end)
:End()
command.new("admin")
:SetPermission("admin_mode", "admin")
:Help("admin_help")
:OnExecute(function(ply)
ply:sam_cloak()
ply:GodEnable()
ply:SetMoveType(MOVETYPE_NOCLIP)
end)
:End()
command.new("unadmin")
:SetPermission("admin_mode", "admin")
:Help("unadmin_help")
:OnExecute(function(ply)
ply:sam_uncloak()
ply:GodDisable()
ply:SetMoveType(MOVETYPE_WALK)
end)
:End()
do
command.new("buddha")
:SetPermission("buddha", "admin")
:AddArg("player", {optional = true})
:Help("buddha_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i].sam_buddha = true
end
sam.player.send_message(nil, "buddha", {
A = ply, T = targets
})
end)
:End()
command.new("unbuddha")
:SetPermission("buddha", "admin")
:AddArg("player", {optional = true})
:Help("unbuddha_help")
:OnExecute(function(ply, targets)
for i = 1, #targets do
targets[i].sam_buddha = nil
end
sam.player.send_message(nil, "unbuddha", {
A = ply, T = targets
})
end)
:End()
if SERVER then
hook.Add("EntityTakeDamage", "SAM.BuddhaMode", function(ply, info)
if ply.sam_buddha and ply:Health() - info:GetDamage() <= 0 then
ply:SetHealth(1)
return true
end
end)
end
end
command.new("give")
:SetPermission("give", "superadmin")
:AddArg("player")
:AddArg("text", {hint = "weapon/entity"})
:Help("give_help")
:OnExecute(function(ply, targets, weapon)
for i = 1, #targets do
targets[i]:Give(weapon)
end
sam.player.send_message(nil, "give", {
A = ply, T = targets, V = weapon
})
end)
:End()
-- do
-- if CLIENT then
-- sam.netstream.Hook("GetFriends", function()
-- local friends = {}
-- local humans = player.GetHumans()
-- for i = 1, #humans do
-- local human = humans[i]
-- if human:GetFriendStatus() == "friend" then
-- table.insert(friends, human)
-- end
-- end
-- netstream.Start("GetFriends", friends)
-- end)
-- else
-- hook.Add("SAM.AuthedPlayer", "GetPlayerFriends", function(ply)
-- timer.Simple(0, function()
-- ply.sam_requesting_friends = true
-- netstream.Start(ply, "GetFriends")
-- end)
-- end)
-- local invalid_friends = function(ply, friends, new_list)
-- if not sam.istable(friends) then return true end
-- local count = #friends
-- local max_players = game.MaxPlayers()
-- for k, friend in pairs(friends) do
-- if not sam.isnumber(k) then return true end
-- if not sam.isentity(friend) then return true end
-- if k > max_players then return true end
-- if k > count then return true end
-- if IsValid(friend) then
-- table.insert(new_list, friend)
-- end
-- end
-- end
-- sam.netstream.Hook("GetFriends", function(ply, friends)
-- local new_list = {}
-- if invalid_friends(ply, friends, new_list) then
-- ply.sam_friends_invalid = true
-- return
-- end
-- ply.sam_friends = new_list
-- end, function()
-- return ply.sam_requesting_friends
-- end)
-- end
-- command.new("friends")
-- :SetPermission("friends", "superadmin")
-- :AddArg("player", {single_target = true})
-- :Help(language.get("friends_help"))
-- :OnExecute(function(ply, targets)
-- local target = targets[1]
-- target.sam_friends_requests = target.sam_friends_requests or {}
-- target.sam_friends_requests[ply] = true
-- end)
-- :End()
-- end

44
lua/sam/modules/utime.lua Normal file
View File

@@ -0,0 +1,44 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
local PLAYER = FindMetaTable("Player")
function PLAYER:GetUTime()
return self:sam_get_nwvar("TotalUTime")
end
function PLAYER:SetUTime(time)
self:sam_set_nwvar("TotalUTime", time)
end
function PLAYER:GetUTimeStart()
return self:sam_get_nwvar("UTimeStart")
end
function PLAYER:SetUTimeStart(time)
self:sam_set_nwvar("UTimeStart", time)
end
function PLAYER:GetUTimeSessionTime()
return CurTime() - self:GetUTimeStart()
end
function PLAYER:GetUTimeTotalTime()
return self:GetUTime() + CurTime() - self:GetUTimeStart()
end
if SERVER then
hook.Add("SAM.AuthedPlayer", "SAM.UTime", function(ply)
ply:SetUTime(ply:sam_get_play_time())
ply:SetUTimeStart(CurTime())
end)
end

486
lua/sam/modules/vote.lua Normal file
View File

@@ -0,0 +1,486 @@
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
if SAM_LOADED then return end
-- DONT EVER TALK TO ME ABOUT THIS CODE
local sam, command = sam, sam.command
command.set_category("Voting")
local start_vote, end_vote
if SERVER then
local vote_on = false
local options, players_voted
local shuffle = function(tbl) -- https://gist.github.com/Uradamus/10323382
for i = #tbl, 2, -1 do
local j = math.random(i)
tbl[i], tbl[j] = tbl[j], tbl[i]
end
return tbl
end
end_vote = function(ply, callback)
if not vote_on then
return ply:sam_add_text(color_white, "There is no vote to end.")
end
vote_on = false
sam.set_global("Vote", nil)
if callback then
local tbl = {}
local total_count = 0
for i = 1, #options do
local count = sam.get_global("Votings" .. i)
total_count = total_count + count
table.insert(tbl, {i, count})
sam.set_global("Votings" .. i, nil)
end
if total_count == 0 then
return sam.player.add_text(nil, color_white, "The vote have been canceled because nobody voted.")
end
table.sort(shuffle(tbl), function(a,b) return a[2] > b[2] end)
local v = tbl[1]
local winner, count = v[1], v[2]
callback(winner, options[winner], count, total_count)
else
for i = 1, #options do
sam.set_global("Votings" .. i, nil)
end
end
options, players_voted = nil, nil
timer.Remove("SAM.Vote")
end
start_vote = function(ply, callback, title, ...)
if vote_on then
return ply:sam_add_text(color_white, "There is an active vote, wait for it to finish.")
end
vote_on = true
options, players_voted = {}, {}
local args, n = {...}, select("#", ...)
for i = 1, n do
local v = args[i]
if v then
table.insert(options, v)
end
end
sam.set_global("Vote", {title, options, CurTime()})
for k in ipairs(options) do
sam.set_global("Votings" .. k, 0)
end
timer.Create("SAM.Vote", 25, 1, function()
end_vote(ply, callback)
end)
return true
end
sam.netstream.Hook("Vote", function(ply, index)
if not sam.isnumber(index) or index > 5 then return end
local votings = sam.get_global("Votings" .. index)
if not votings then return end
local old_index = players_voted[ply:AccountID()]
if old_index == index then return end
if old_index then
sam.set_global("Votings" .. old_index, sam.get_global("Votings" .. old_index) - 1)
end
sam.set_global("Votings" .. index, votings + 1)
players_voted[ply:AccountID()] = index
end)
end
if CLIENT then
local SUI = sam.SUI
-- https://github.com/Facepunch/garrysmod/blob/master/garrysmod/lua/includes/extensions/client/player.lua
local VOTING_TITLE = SUI.CreateFont("VotingTitle", "Roboto Bold", 15)
local VOTING_OPTION = SUI.CreateFont("VotingTitle", "Roboto Medium", 14)
local bind_translation = {}
for i = 0, 9 do
bind_translation["slot" .. i] = i
end
local voting_frame
end_vote = function()
if IsValid(voting_frame) then
voting_frame:Remove()
end
hook.Remove("PlayerBindPress", "SAM.Voting")
hook.Remove("SAM.ChangedGlobalVar", "SAM.VotingCount")
end
hook.Add("SAM.ChangedGlobalVar", "Voting", function(key, value)
if key ~= "Vote" then return end
if not value then
end_vote()
return
end
local title, options, start_time = value[1], value[2], value[3]
sui.TDLib.Start()
voting_frame = vgui.Create("EditablePanel")
voting_frame:SetSize(SUI.Scale(165), SUI.Scale(230))
voting_frame:SetPos(5, ScrH() * 0.25)
voting_frame:DockPadding(4, 4, 4, 4)
voting_frame:Blur()
:Background(Color(30, 30, 30, 240))
local voting_title = voting_frame:Add("SAM.Label")
voting_title:Dock(TOP)
voting_title:SetFont(VOTING_TITLE)
voting_title:TextColor(Color(220, 220, 220))
voting_title:SetText(title)
voting_title:SetWrap(true)
voting_title:SetAutoStretchVertical(true)
local line = voting_frame:Add("SAM.Label")
line:Dock(TOP)
line:TextColor(Color(220, 220, 220))
line:SetText("-")
local options_added = {}
for i, v in ipairs(options) do
local option = voting_frame:Add("SAM.Label")
option:Dock(TOP)
option:SetFont(VOTING_OPTION)
option:TextColor(Color(220, 220, 220), true)
option:SetText(i .. ". " .. v .. " (0)")
option:SetWrap(true)
option:SetAutoStretchVertical(true)
options_added[i] = option
end
function voting_frame:Think() -- fucking gmod
self:SizeToChildren(false, true)
local time_left = math.floor(25 - (CurTime() - start_time))
if time_left <= 0 then
end_vote()
voting_frame.Think = nil
return
end
voting_title:SetText(title .. " (" .. time_left .. ")")
end
line = voting_frame:Add("SAM.Label")
line:Dock(TOP)
line:TextColor(Color(220, 220, 220))
line:SetText("-")
local option = voting_frame:Add("SAM.Label")
option:Dock(TOP)
option:SetFont(VOTING_OPTION)
option:TextColor(Color(220, 220, 220), true)
option:SetText("0. Close")
option:SetWrap(true)
option:SetAutoStretchVertical(true)
sui.TDLib.End()
local current_index
hook.Add("PlayerBindPress", "SAM.Voting", function(_, bind, down)
if not down then return end
local index = bind_translation[bind]
if not index then return end
if index == 0 then
end_vote()
return true
end
if not options[index] then return true end
if current_index then
options_added[current_index]:TextColor(Color(220, 220, 220), true)
end
options_added[index]:TextColor(Color(65, 185, 255), true)
current_index = index
sam.netstream.Start("Vote", index)
return true
end)
hook.Add("SAM.ChangedGlobalVar", "SAM.VotingCount", function(key2, count)
if key2:sub(1, 7) ~= "Votings" then return end
if not count then return end
local index = tonumber(key2:sub(8))
options_added[index]:SetText(index .. ". " .. options[index] .. " (" .. count .. ")")
end)
end)
end
local vote_check = function(str)
return str:match("%S") ~= nil
end
command.new("vote")
:SetPermission("vote", "admin")
:AddArg("text", {hint = "title", check = vote_check})
:AddArg("text", {hint = "option", check = vote_check})
:AddArg("text", {hint = "option", check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:AddArg("text", {hint = "option", optional = true, check = vote_check})
:Help("Start a vote!")
:OnExecute(function(ply, title, ...)
local callback = function(_, option, count, total_count)
sam.player.send_message(nil, "Vote {V} for {V_2} has been passed. ({V_3}/{V_4})", {
V = title, V_2 = option, V_3 = count, V_4 = total_count
})
end
if start_vote(ply, callback, title, ...) then
sam.player.send_message(nil, "{A} started a vote with title {V}.", {
A = ply, V = title
})
end
end)
:End()
command.new("endvote")
:SetPermission("endvote", "admin")
:Help("End current vote.")
:OnExecute(function(ply)
end_vote(ply)
end)
:End()
command.new("votekick")
:SetPermission("votekick", "admin")
:AddArg("player", {single_target = true})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to kick a player.")
:OnExecute(function(ply, targets, reason)
local target = targets[1]
local target_name = target:Name()
local callback = function(index, option, count, total_count)
if not IsValid(ply) then
sam.player.send_message(nil, "Vote was canceled because {T} left.", {
T = target_name
})
return
end
if index == 1 then
target:Kick("Vote was successful (" .. (reason or "none") .. ")")
sam.player.send_message(nil, "Vote was successful, {T} has been kicked. ({V})", {
T = targets, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be kicked.", {
T = target_name
})
end
end
local title = "Kick " .. target_name .. "?"
if reason then
title = title .. " (" .. reason .. ")"
end
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a votekick against {T} ({V})", {
A = ply, T = targets, V = reason
})
else
sam.player.send_message(nil, "{A} started a votekick against {T}", {
A = ply, T = targets
})
end
end
end)
:End()
command.new("voteban")
:SetPermission("voteban", "admin")
:AddArg("player", {single_target = true})
:AddArg("length", {optional = true, default = 60, min = 30, max = 120})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to ban a player.")
:OnExecute(function(ply, targets, length, reason)
local target = targets[1]
local target_steamid, target_name = target:SteamID(), target:Name()
local ply_steamid = ply:SteamID()
local callback = function(index, option, count, total_count)
if index == 1 then
sam.player.ban_id(target_steamid, length, "Vote was successful (" .. (reason or "none") .. ")", ply_steamid)
sam.player.send_message(nil, "Vote was successful, {T} has been banned. ({V})", {
T = target_name, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be banned.", {
T = target_name
})
end
end
local title = "Ban " .. target_name .. "?"
if reason then
title = title .. " (" .. reason .. ")"
end
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a voteban against {T} for {V} ({V_2})", {
A = ply, T = targets, V = sam.format_length(length), V_2 = reason
})
else
sam.player.send_message(nil, "{A} started a voteban against {T} for {V}", {
A = ply, T = targets, V = sam.format_length(length)
})
end
end
end)
:End()
command.new("votemute")
:SetPermission("votemute", "admin")
:AddArg("player", {single_target = true})
:AddArg("text", {hint = "reason", optional = true})
:GetRestArgs()
:Help("Start a vote to mute and gag a player.")
:OnExecute(function(ply, targets, reason)
local _reason = reason and (" (" .. reason .. ")") or ""
local target = targets[1]
local target_name = target:Name()
local callback = function(index, option, count, total_count)
if not IsValid(target) then
sam.player.send_message(nil, "Vote was canceled because {T} left.", {
T = target_name
})
return
end
if index == 1 then
RunConsoleCommand("sam", "mute", "#" .. target:EntIndex(), 0, "votemute" .. _reason)
RunConsoleCommand("sam", "gag", "#" .. target:EntIndex(), 0, "votemute" .. _reason)
sam.player.send_message(nil, "Vote was successful, {T} has been muted. ({V})", {
T = target_name, V = reason
})
else
sam.player.send_message(nil, "Vote was unsuccessful, {T} won't be muted.", {
T = target_name
})
end
end
local title = "Mute " .. target_name .. "?" .. _reason
if start_vote(ply, callback, title, "Yes", "No") then
if reason then
sam.player.send_message(nil, "{A} started a votemute against {T} ({V}).", {
A = ply, T = targets, V = reason
})
else
sam.player.send_message(nil, "{A} started a votemute against {T}.", {
A = ply, T = targets
})
end
end
end)
:End()
command.new("votemap")
:SetPermission("votemap", "admin")
:AddArg("map", {exclude_current = true})
:AddArg("map", {optional = true, exclude_current = true})
:AddArg("map", {optional = true, exclude_current = true})
:GetRestArgs()
:Help("Start a vote to change map.")
:OnExecute(function(ply, ...)
local callback = function(_, option, count, total_count)
sam.player.send_message(nil, "Map vote for {V} has been passed. ({V_2}/{V_3})", {
V = option, V_2 = count, V_3 = total_count
})
if sam.is_valid_map(option) then
RunConsoleCommand("sam", "map", option)
end
end
local args = {...}
for i = select("#", ...), 1, -1 do
if args[i] == "None" then
args[i] = nil
end
end
table.insert(args, "Extend Current Map")
if start_vote(ply, callback, "Vote for the next map!", unpack(args)) then
sam.player.send_message(nil, "{A} started a map change vote.", {
A = ply
})
end
end)
:End()