mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
367
lua/sam/modules/cami.lua
Normal file
367
lua/sam/modules/cami.lua
Normal 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
238
lua/sam/modules/chat.lua
Normal 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
|
||||
39
lua/sam/modules/commnad_notify_for_ranks.lua
Normal file
39
lua/sam/modules/commnad_notify_for_ranks.lua
Normal 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
324
lua/sam/modules/darkrp.lua
Normal 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
654
lua/sam/modules/fun.lua
Normal 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
224
lua/sam/modules/murder.lua
Normal 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)
|
||||
136
lua/sam/modules/support_cami.lua
Normal file
136
lua/sam/modules/support_cami.lua
Normal 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)
|
||||
61
lua/sam/modules/sv_family_sharing.lua
Normal file
61
lua/sam/modules/sv_family_sharing.lua
Normal 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)
|
||||
198
lua/sam/modules/teleport.lua
Normal file
198
lua/sam/modules/teleport.lua
Normal 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
102
lua/sam/modules/ttt.lua
Normal 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
273
lua/sam/modules/user.lua
Normal 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
579
lua/sam/modules/util.lua
Normal 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
44
lua/sam/modules/utime.lua
Normal 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
486
lua/sam/modules/vote.lua
Normal 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()
|
||||
Reference in New Issue
Block a user