279 lines
7.5 KiB
Lua
279 lines
7.5 KiB
Lua
local IsValid = IsValid
|
|
local PID = SquadMenu.GetPlayerId
|
|
local FindByPID = SquadMenu.FindPlayerById
|
|
|
|
local Squad = SquadMenu.Squad or {}
|
|
SquadMenu.Squad = Squad
|
|
Squad.__index = Squad
|
|
|
|
--- Set the leader of this squad. `ply` can either be
|
|
--- a player entity, a ID string that came from `SquadMenu.GetPlayerId`,
|
|
--- or `nil` if you want to unset the current squad leader.
|
|
function Squad:SetLeader( ply, name )
|
|
if type( ply ) == "string" then
|
|
self.leaderId = ply -- this is a player ID
|
|
self.leaderName = name or "?"
|
|
|
|
elseif IsValid( ply ) then
|
|
self.leaderId = PID( ply )
|
|
self.leaderName = ply:Nick()
|
|
|
|
else
|
|
self.leaderId = nil
|
|
self.leaderName = nil
|
|
|
|
SquadMenu.PrintF( "Removed leader from squad #%d", self.id )
|
|
return
|
|
end
|
|
|
|
SquadMenu.PrintF( "New leader for squad #%d: %s <%s>", self.id, self.leaderName, self.leaderId )
|
|
end
|
|
|
|
--- Get a table containing a list of active squad members.
|
|
--- Returns an array of player entities that are currently on the server.
|
|
function Squad:GetActiveMembers()
|
|
local members, count = {}, 0
|
|
local byId = SquadMenu.AllPlayersById()
|
|
|
|
for id, _ in pairs( self.membersById ) do
|
|
if byId[id] then
|
|
count = count + 1
|
|
members[count] = byId[id]
|
|
end
|
|
end
|
|
|
|
return members, count
|
|
end
|
|
|
|
--- Get a ready-to-be-stringified table containing details from this squad.
|
|
function Squad:GetBasicInfo()
|
|
local info = {
|
|
id = self.id,
|
|
name = self.name,
|
|
icon = self.icon,
|
|
members = {},
|
|
|
|
enableRings = self.enableRings,
|
|
friendlyFire = self.friendlyFire,
|
|
isPublic = self.isPublic,
|
|
|
|
r = self.r,
|
|
g = self.g,
|
|
b = self.b
|
|
}
|
|
|
|
if self.leaderId then
|
|
info.leaderId = self.leaderId
|
|
info.leaderName = self.leaderName
|
|
end
|
|
|
|
local count = 0
|
|
|
|
for id, name in pairs( self.membersById ) do
|
|
count = count + 1
|
|
info.members[count] = { id, name }
|
|
end
|
|
|
|
return info
|
|
end
|
|
|
|
local ValidateString = SquadMenu.ValidateString
|
|
local ValidateNumber = SquadMenu.ValidateNumber
|
|
|
|
--- Set the details of this squad using a table.
|
|
function Squad:SetBasicInfo( info )
|
|
if SquadMenu.GetForceFriendlyFire() then
|
|
info.friendlyFire = true
|
|
end
|
|
|
|
self.name = ValidateString( info.name, "Unnamed", SquadMenu.MAX_NAME_LENGTH )
|
|
self.icon = ValidateString( info.icon, "icon16/flag_blue.png", 256 )
|
|
|
|
self.enableRings = info.enableRings == true
|
|
self.friendlyFire = info.friendlyFire == true
|
|
self.isPublic = info.isPublic == true
|
|
|
|
self.r = ValidateNumber( info.r, 255, 0, 255 )
|
|
self.g = ValidateNumber( info.g, 255, 0, 255 )
|
|
self.b = ValidateNumber( info.b, 255, 0, 255 )
|
|
|
|
SquadMenu.blockDamage[self.id] = Either( self.friendlyFire, nil, true )
|
|
end
|
|
|
|
--- Send details and a list of members to all squad members.
|
|
--- You should never set `immediate` to `true` unless you know what you're doing.
|
|
function Squad:SyncWithMembers( immediate )
|
|
if not immediate then
|
|
-- avoid spamming the networking system
|
|
timer.Remove( "SquadMenu.Sync" .. self.id )
|
|
timer.Create( "SquadMenu.Sync" .. self.id, 0.5, 1, function()
|
|
self:SyncWithMembers( true )
|
|
end )
|
|
|
|
return
|
|
end
|
|
|
|
local members, count = self:GetActiveMembers()
|
|
if count == 0 then return end
|
|
|
|
local data = self:GetBasicInfo()
|
|
|
|
SquadMenu.StartCommand( SquadMenu.SETUP_SQUAD )
|
|
SquadMenu.WriteTable( data )
|
|
net.Send( members )
|
|
end
|
|
|
|
--- Send the requests list to the squad leader.
|
|
function Squad:SyncRequests()
|
|
local leader = FindByPID( self.leaderId )
|
|
if not IsValid( leader ) then return end
|
|
|
|
SquadMenu.StartCommand( SquadMenu.REQUESTS_LIST )
|
|
SquadMenu.WriteTable( self.requestsById )
|
|
net.Send( leader )
|
|
end
|
|
|
|
--- Turns `p` into a id and player entity depending on what `p` is.
|
|
local function ParsePlayerArg( p )
|
|
if type( p ) == "string" then
|
|
return p, FindByPID( p )
|
|
end
|
|
|
|
return PID( p ), p
|
|
end
|
|
|
|
--- Add a player as a new member.
|
|
--- `p` can be a player id from `SquadMenu.GetPlayerId` or a player entity.
|
|
function Squad:AddMember( p )
|
|
local id, ply = ParsePlayerArg( p )
|
|
if self.membersById[id] then return end
|
|
|
|
local count = table.Count( self.membersById )
|
|
if count >= SquadMenu.GetMemberLimit() then return end
|
|
|
|
local name = id
|
|
|
|
if IsValid( ply ) then
|
|
local oldSquad = SquadMenu:GetSquad( ply:GetSquadID() )
|
|
|
|
if oldSquad then
|
|
oldSquad:RemoveMember( ply, SquadMenu.LEAVE_REASON_LEFT )
|
|
end
|
|
|
|
ply:SetNWInt( "squad_menu.id", self.id )
|
|
name = ply:Nick()
|
|
end
|
|
|
|
self.membersById[id] = name
|
|
self:SyncWithMembers()
|
|
|
|
-- We don't send the requests list to the squad leaders (2nd "true" parameter)
|
|
-- because "player_joined_squad" will already tell them to remove
|
|
-- this player from their own copies of the join requests list.
|
|
SquadMenu:CleanupRequests( id, true )
|
|
|
|
SquadMenu.StartEvent( "player_joined_squad", {
|
|
squadId = self.id,
|
|
playerId = id
|
|
} )
|
|
net.Broadcast()
|
|
|
|
hook.Run( "SquadMenu_OnJoinedSquad", self.id, ply, id )
|
|
end
|
|
|
|
--- Remove a player from this squad's members list.
|
|
--- `ply` can be a player id from `SquadMenu.GetPlayerId` or a player entity.
|
|
--- `reasonId` can be `nil` or one of the values from `SquadMenu.LEAVE_REASON_*`.
|
|
function Squad:RemoveMember( p, reasonId )
|
|
local id, ply = ParsePlayerArg( p )
|
|
if not self.membersById[id] then return end
|
|
|
|
if id == self.leaderId then
|
|
pcall( hook.Run, "SquadMenu_OnLeftSquad", self.id, ply, id )
|
|
|
|
self:Delete()
|
|
|
|
return
|
|
end
|
|
|
|
self.membersById[id] = nil
|
|
self:SyncWithMembers()
|
|
|
|
if not IsValid( ply ) then return end
|
|
|
|
ply:SetNWInt( "squad_menu.id", -1 )
|
|
|
|
if reasonId ~= nil then
|
|
SquadMenu.StartCommand( SquadMenu.LEAVE_SQUAD )
|
|
net.WriteUInt( reasonId, 3 )
|
|
net.Send( ply )
|
|
end
|
|
|
|
hook.Run( "SquadMenu_OnLeftSquad", self.id, ply, id )
|
|
end
|
|
|
|
--- Add a player to the list of players that
|
|
--- requested to join and notify the squad leader.
|
|
function Squad:RequestToJoin( ply )
|
|
if self.isPublic then
|
|
self:AddMember( ply )
|
|
return
|
|
end
|
|
|
|
local plyId = PID( ply )
|
|
if self.requestsById[plyId] then return end
|
|
|
|
self.requestsById[plyId] = ply:Nick()
|
|
self:SyncRequests()
|
|
end
|
|
|
|
--- Accept all the join requests from a list of player IDs.
|
|
function Squad:AcceptRequests( ids )
|
|
if not table.IsSequential( ids ) then return end
|
|
|
|
local limit = SquadMenu.GetMemberLimit()
|
|
local count = table.Count( self.membersById )
|
|
|
|
for _, id in ipairs( ids ) do
|
|
if count >= limit then
|
|
break
|
|
|
|
elseif self.requestsById[id] then
|
|
count = count + 1
|
|
|
|
self.requestsById[id] = nil
|
|
self:AddMember( id )
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Remove all members from this squad and delete it.
|
|
function Squad:Delete()
|
|
timer.Remove( "SquadMenu.Sync" .. self.id )
|
|
|
|
local members, count = self:GetActiveMembers()
|
|
|
|
if count > 0 then
|
|
for _, ply in ipairs( members ) do
|
|
ply:SetNWInt( "squad_menu.id", -1 )
|
|
end
|
|
|
|
SquadMenu.StartCommand( SquadMenu.LEAVE_SQUAD )
|
|
net.WriteUInt( SquadMenu.LEAVE_REASON_DELETED, 3 )
|
|
net.Send( members )
|
|
end
|
|
|
|
self.membersById = nil
|
|
self.requestsById = nil
|
|
|
|
local id = self.id
|
|
|
|
SquadMenu.squads[id] = nil
|
|
SquadMenu.blockDamage[id] = nil
|
|
|
|
SquadMenu.PrintF( "Deleted squad #%d", id )
|
|
|
|
SquadMenu.StartEvent( "squad_deleted", { id = id } )
|
|
net.Broadcast()
|
|
end
|