mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
367 lines
9.3 KiB
Lua
367 lines
9.3 KiB
Lua
--[[
|
|
| 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/
|
|
--]]
|
|
|
|
|
|
-- serverside extensions to player table
|
|
|
|
local plymeta = FindMetaTable( "Player" )
|
|
if not plymeta then Error("FAILED TO FIND PLAYER TABLE") return end
|
|
|
|
function plymeta:SetRagdollSpec(s)
|
|
if s then
|
|
self.spec_ragdoll_start = CurTime()
|
|
end
|
|
self.spec_ragdoll = s
|
|
end
|
|
function plymeta:GetRagdollSpec() return self.spec_ragdoll end
|
|
|
|
AccessorFunc(plymeta, "force_spec", "ForceSpec", FORCE_BOOL)
|
|
|
|
--- Karma
|
|
|
|
-- The base/start karma is determined once per round and determines the player's
|
|
-- damage penalty. It is networked and shown on clients.
|
|
function plymeta:SetBaseKarma(k)
|
|
self:SetNWFloat("karma", k)
|
|
end
|
|
|
|
-- The live karma starts equal to the base karma, but is updated "live" as the
|
|
-- player damages/kills others. When another player damages/kills this one, the
|
|
-- live karma is used to determine his karma penalty.
|
|
AccessorFunc(plymeta, "live_karma", "LiveKarma", FORCE_NUMBER)
|
|
|
|
-- The damage factor scales how much damage the player deals, so if it is .9
|
|
-- then the player only deals 90% of his original damage.
|
|
AccessorFunc(plymeta, "dmg_factor", "DamageFactor", FORCE_NUMBER)
|
|
|
|
-- If a player does not damage team members in a round, he has a "clean" round
|
|
-- and gets a bonus for it.
|
|
AccessorFunc(plymeta, "clean_round", "CleanRound", FORCE_BOOL)
|
|
|
|
function plymeta:InitKarma()
|
|
KARMA.InitPlayer(self)
|
|
end
|
|
|
|
--- Equipment credits
|
|
function plymeta:SetCredits(amt)
|
|
self.equipment_credits = amt
|
|
self:SendCredits()
|
|
end
|
|
|
|
function plymeta:AddCredits(amt)
|
|
self:SetCredits(self:GetCredits() + amt)
|
|
end
|
|
function plymeta:SubtractCredits(amt) self:AddCredits(-amt) end
|
|
|
|
function plymeta:SetDefaultCredits()
|
|
if self:GetTraitor() then
|
|
local c = GetConVar("ttt_credits_starting"):GetInt()
|
|
if CountTraitors() == 1 then
|
|
c = c + GetConVar("ttt_credits_alonebonus"):GetInt()
|
|
end
|
|
self:SetCredits(c)
|
|
elseif self:GetDetective() then
|
|
self:SetCredits(GetConVar("ttt_det_credits_starting"):GetInt())
|
|
else
|
|
self:SetCredits(0)
|
|
end
|
|
end
|
|
|
|
function plymeta:SendCredits()
|
|
net.Start("TTT_Credits")
|
|
net.WriteUInt(self:GetCredits(), 8)
|
|
net.Send(self)
|
|
end
|
|
|
|
--- Equipment items
|
|
function plymeta:AddEquipmentItem(id)
|
|
id = tonumber(id)
|
|
if id then
|
|
self.equipment_items = bit.bor(self.equipment_items, id)
|
|
self:SendEquipment()
|
|
end
|
|
end
|
|
|
|
-- We do this instead of an NW var in order to limit the info to just this ply
|
|
function plymeta:SendEquipment()
|
|
net.Start("TTT_Equipment")
|
|
net.WriteUInt(self.equipment_items, 16)
|
|
net.Send(self)
|
|
end
|
|
|
|
function plymeta:ResetEquipment()
|
|
self.equipment_items = EQUIP_NONE
|
|
self:SendEquipment()
|
|
end
|
|
|
|
function plymeta:SendBought()
|
|
-- Send all as string, even though equipment are numbers, for simplicity
|
|
net.Start("TTT_Bought")
|
|
net.WriteUInt(#self.bought, 8)
|
|
for k, v in pairs(self.bought) do
|
|
net.WriteString(v)
|
|
end
|
|
net.Send(self)
|
|
end
|
|
|
|
local function ResendBought(ply)
|
|
if IsValid(ply) then ply:SendBought() end
|
|
end
|
|
concommand.Add("ttt_resend_bought", ResendBought)
|
|
|
|
function plymeta:ResetBought()
|
|
self.bought = {}
|
|
self:SendBought()
|
|
end
|
|
|
|
function plymeta:AddBought(id)
|
|
if not self.bought then self.bought = {} end
|
|
|
|
table.insert(self.bought, tostring(id))
|
|
|
|
self:SendBought()
|
|
end
|
|
|
|
|
|
-- Strips player of all equipment
|
|
function plymeta:StripAll()
|
|
-- standard stuff
|
|
self:StripAmmo()
|
|
self:StripWeapons()
|
|
|
|
-- our stuff
|
|
self:ResetEquipment()
|
|
self:SetCredits(0)
|
|
end
|
|
|
|
-- Sets all flags (force_spec, etc) to their default
|
|
function plymeta:ResetStatus()
|
|
self:SetRole(ROLE_INNOCENT)
|
|
self:SetRagdollSpec(false)
|
|
self:SetForceSpec(false)
|
|
|
|
self:ResetRoundFlags()
|
|
end
|
|
|
|
-- Sets round-based misc flags to default position. Called at PlayerSpawn.
|
|
function plymeta:ResetRoundFlags()
|
|
-- equipment
|
|
self:ResetEquipment()
|
|
self:SetCredits(0)
|
|
|
|
self:ResetBought()
|
|
|
|
-- equipment stuff
|
|
self.bomb_wire = nil
|
|
self.radar_charge = 0
|
|
self.decoy = nil
|
|
|
|
-- corpse
|
|
self:SetNWBool("body_found", false)
|
|
|
|
self.kills = {}
|
|
|
|
self.dying_wep = nil
|
|
self.was_headshot = false
|
|
|
|
-- communication
|
|
self.mute_team = -1
|
|
self.traitor_gvoice = false
|
|
|
|
self:SetNWBool("disguised", false)
|
|
|
|
-- karma
|
|
self:SetCleanRound(true)
|
|
|
|
self:Freeze(false)
|
|
end
|
|
|
|
function plymeta:GiveEquipmentItem(id)
|
|
if self:HasEquipmentItem(id) then
|
|
return false
|
|
elseif id and id > EQUIP_NONE then
|
|
self:AddEquipmentItem(id)
|
|
return true
|
|
end
|
|
end
|
|
|
|
-- Forced specs and latejoin specs should not get points
|
|
function plymeta:ShouldScore()
|
|
if self:GetForceSpec() then
|
|
return false
|
|
elseif self:IsSpec() and self:Alive() then
|
|
return false
|
|
else
|
|
return true
|
|
end
|
|
end
|
|
|
|
function plymeta:RecordKill(victim)
|
|
if not IsValid(victim) then return end
|
|
|
|
if not self.kills then
|
|
self.kills = {}
|
|
end
|
|
|
|
table.insert(self.kills, victim:SteamID64())
|
|
end
|
|
|
|
|
|
function plymeta:SetSpeed(slowed)
|
|
-- For player movement prediction to work properly, ply:SetSpeed turned out
|
|
-- to be a bad idea. It now uses GM:SetupMove, and the TTTPlayerSpeedModifier
|
|
-- hook is provided to let you change player speed without messing up
|
|
-- prediction. It needs to be hooked on both client and server and return the
|
|
-- same results (ie. same implementation).
|
|
error "Player:SetSpeed has been removed - please remove this call and use the TTTPlayerSpeedModifier hook in both CLIENT and SERVER environments"
|
|
end
|
|
|
|
function plymeta:ResetLastWords()
|
|
if not IsValid(self) then return end -- timers are dangerous things
|
|
self.last_words_id = nil
|
|
end
|
|
|
|
function plymeta:SendLastWords(dmginfo)
|
|
-- Use a pseudo unique id to prevent people from abusing the concmd
|
|
self.last_words_id = math.floor(CurTime() + math.random(500))
|
|
|
|
-- See if the damage was interesting
|
|
local dtype = KILL_NORMAL
|
|
if dmginfo:GetAttacker() == self or dmginfo:GetInflictor() == self then
|
|
dtype = KILL_SUICIDE
|
|
elseif dmginfo:IsDamageType(DMG_BURN) then
|
|
dtype = KILL_BURN
|
|
elseif dmginfo:IsFallDamage() then
|
|
dtype = KILL_FALL
|
|
end
|
|
|
|
self.death_type = dtype
|
|
|
|
net.Start("TTT_InterruptChat")
|
|
net.WriteUInt(self.last_words_id, 32)
|
|
net.Send(self)
|
|
|
|
-- any longer than this and you're out of luck
|
|
local ply = self
|
|
timer.Simple(2, function() ply:ResetLastWords() end)
|
|
end
|
|
|
|
|
|
function plymeta:ResetViewRoll()
|
|
local ang = self:EyeAngles()
|
|
if ang.r != 0 then
|
|
ang.r = 0
|
|
self:SetEyeAngles(ang)
|
|
end
|
|
end
|
|
|
|
|
|
function plymeta:ShouldSpawn()
|
|
-- do not spawn players who have not been through initspawn
|
|
if (not self:IsSpec()) and (not self:IsTerror()) then return false end
|
|
-- do not spawn forced specs
|
|
if self:IsSpec() and self:GetForceSpec() then return false end
|
|
|
|
return true
|
|
end
|
|
|
|
-- Preps a player for a new round, spawning them if they should. If dead_only is
|
|
-- true, only spawns if player is dead, else just makes sure he is healed.
|
|
function plymeta:SpawnForRound(dead_only)
|
|
hook.Call("PlayerSetModel", GAMEMODE, self)
|
|
hook.Call("TTTPlayerSetColor", GAMEMODE, self)
|
|
|
|
-- wrong alive status and not a willing spec who unforced after prep started
|
|
-- (and will therefore be "alive")
|
|
if dead_only and self:Alive() and (not self:IsSpec()) then
|
|
-- if the player does not need respawn, make sure he has full health
|
|
self:SetHealth(self:GetMaxHealth())
|
|
return false
|
|
end
|
|
|
|
if not self:ShouldSpawn() then return false end
|
|
|
|
-- reset propspec state that they may have gotten during prep
|
|
PROPSPEC.Clear(self)
|
|
|
|
-- respawn anyone else
|
|
if self:Team() == TEAM_SPEC then
|
|
self:UnSpectate()
|
|
end
|
|
|
|
self:StripAll()
|
|
self:SetTeam(TEAM_TERROR)
|
|
self:Spawn()
|
|
|
|
-- tell caller that we spawned
|
|
return true
|
|
end
|
|
|
|
function plymeta:InitialSpawn()
|
|
self.has_spawned = false
|
|
|
|
-- The team the player spawns on depends on the round state
|
|
self:SetTeam(GetRoundState() == ROUND_PREP and TEAM_TERROR or TEAM_SPEC)
|
|
|
|
-- Change some gmod defaults
|
|
self:SetCanZoom(false)
|
|
self:SetJumpPower(160)
|
|
self:SetCrouchedWalkSpeed(0.3)
|
|
self:SetRunSpeed(220)
|
|
self:SetWalkSpeed(220)
|
|
self:SetMaxSpeed(220)
|
|
|
|
-- Always spawn innocent initially, traitor will be selected later
|
|
self:ResetStatus()
|
|
|
|
-- Start off with clean, full karma (unless it can and should be loaded)
|
|
self:InitKarma()
|
|
|
|
-- We never have weapons here, but this inits our equipment state
|
|
self:StripAll()
|
|
end
|
|
|
|
function plymeta:KickBan(length, reason)
|
|
-- see admin.lua
|
|
PerformKickBan(self, length, reason)
|
|
end
|
|
|
|
local oldSpectate = plymeta.Spectate
|
|
function plymeta:Spectate(type)
|
|
oldSpectate(self, type)
|
|
|
|
-- NPCs should never see spectators. A workaround for the fact that gmod NPCs
|
|
-- do not ignore them by default.
|
|
self:SetNoTarget(true)
|
|
|
|
if type == OBS_MODE_ROAMING then
|
|
self:SetMoveType(MOVETYPE_NOCLIP)
|
|
end
|
|
end
|
|
|
|
local oldSpectateEntity = plymeta.SpectateEntity
|
|
function plymeta:SpectateEntity(ent)
|
|
oldSpectateEntity(self, ent)
|
|
|
|
if IsValid(ent) and ent:IsPlayer() then
|
|
self:SetupHands(ent)
|
|
end
|
|
end
|
|
|
|
local oldUnSpectate = plymeta.UnSpectate
|
|
function plymeta:UnSpectate()
|
|
oldUnSpectate(self)
|
|
self:SetNoTarget(false)
|
|
end
|
|
|
|
function plymeta:GetAvoidDetective()
|
|
return self:GetInfoNum("ttt_avoid_detective", 0) > 0
|
|
end
|