This commit is contained in:
lifestorm
2024-08-05 18:40:29 +03:00
parent 9f505a0646
commit c6d9b6f580
8044 changed files with 1853472 additions and 21 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,672 @@
--[[
| 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/
--]]
function GM:PlayerNoClip(client)
return client:IsAdmin()
end
-- luacheck: globals HOLDTYPE_TRANSLATOR
HOLDTYPE_TRANSLATOR = {}
HOLDTYPE_TRANSLATOR[""] = "normal"
HOLDTYPE_TRANSLATOR["physgun"] = "smg"
HOLDTYPE_TRANSLATOR["ar2"] = "smg"
HOLDTYPE_TRANSLATOR["crossbow"] = "shotgun"
HOLDTYPE_TRANSLATOR["rpg"] = "shotgun"
HOLDTYPE_TRANSLATOR["slam"] = "normal"
HOLDTYPE_TRANSLATOR["grenade"] = "grenade"
HOLDTYPE_TRANSLATOR["fist"] = "normal"
HOLDTYPE_TRANSLATOR["melee2"] = "melee"
HOLDTYPE_TRANSLATOR["passive"] = "normal"
HOLDTYPE_TRANSLATOR["knife"] = "melee"
HOLDTYPE_TRANSLATOR["duel"] = "pistol"
HOLDTYPE_TRANSLATOR["camera"] = "smg"
HOLDTYPE_TRANSLATOR["magic"] = "normal"
HOLDTYPE_TRANSLATOR["revolver"] = "pistol"
-- luacheck: globals PLAYER_HOLDTYPE_TRANSLATOR
PLAYER_HOLDTYPE_TRANSLATOR = {}
PLAYER_HOLDTYPE_TRANSLATOR[""] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["fist"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["pistol"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["grenade"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["melee"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["slam"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["melee2"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["passive"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["knife"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["duel"] = "normal"
PLAYER_HOLDTYPE_TRANSLATOR["bugbait"] = "normal"
local PLAYER_HOLDTYPE_TRANSLATOR = PLAYER_HOLDTYPE_TRANSLATOR
local HOLDTYPE_TRANSLATOR = HOLDTYPE_TRANSLATOR
local animationFixOffset = Vector(16.5438, -0.1642, -20.5493)
function GM:TranslateActivity(client, act)
local clientInfo = client:GetTable()
local modelClass = clientInfo.ixAnimModelClass or "player"
local bRaised = client:IsWepRaised()
if (modelClass == "player") then
local weapon = client:GetActiveWeapon()
local bAlwaysRaised = ix.config.Get("weaponAlwaysRaised")
weapon = IsValid(weapon) and weapon or nil
if (!bAlwaysRaised and weapon and !bRaised and client:OnGround()) then
local model = string.lower(client:GetModel())
if (string.find(model, "zombie")) then
local tree = ix.anim.zombie
if (string.find(model, "fast")) then
tree = ix.anim.fastZombie
end
if (tree[act]) then
return tree[act]
end
end
local holdType = weapon and (weapon.HoldType or weapon:GetHoldType()) or "normal"
if (!bAlwaysRaised and weapon and !bRaised and client:OnGround()) then
holdType = PLAYER_HOLDTYPE_TRANSLATOR[holdType] or "passive"
end
local tree = ix.anim.player[holdType]
if (tree and tree[act]) then
if (isstring(tree[act])) then
clientInfo.CalcSeqOverride = client:LookupSequence(tree[act])
return
else
return tree[act]
end
end
end
return self.BaseClass:TranslateActivity(client, act)
end
if (clientInfo.ixAnimTable) then
local glide = clientInfo.ixAnimGlide
if (client:InVehicle()) then
act = clientInfo.ixAnimTable[1]
local fixVector = clientInfo.ixAnimTable[2]
if (isvector(fixVector)) then
client:SetLocalPos(animationFixOffset)
end
if (isstring(act)) then
clientInfo.CalcSeqOverride = client:LookupSequence(act)
else
return act
end
elseif (client:OnGround()) then
if (clientInfo.ixAnimTable[act]) then
local act2 = clientInfo.ixAnimTable[act][bRaised and 2 or 1]
if (isstring(act2)) then
clientInfo.CalcSeqOverride = client:LookupSequence(act2)
else
return act2
end
end
elseif (glide) then
if (isstring(glide)) then
clientInfo.CalcSeqOverride = client:LookupSequence(glide)
else
return clientInfo.ixAnimGlide
end
end
end
end
function GM:CanPlayerUseBusiness(client, uniqueID)
local itemTable = ix.item.list[uniqueID]
if (!client:GetCharacter()) then
return false
end
if (itemTable.noBusiness) then
return false
end
if (itemTable.factions) then
local allowed = false
if (istable(itemTable.factions)) then
for _, v in pairs(itemTable.factions) do
if (client:Team() == v) then
allowed = true
break
end
end
elseif (client:Team() != itemTable.factions) then
allowed = false
end
if (!allowed) then
return false
end
end
if (itemTable.classes) then
local allowed = false
if (istable(itemTable.classes)) then
for _, v in pairs(itemTable.classes) do
if (client:GetCharacter():GetClass() == v) then
allowed = true
break
end
end
elseif (client:GetCharacter():GetClass() == itemTable.classes) then
allowed = true
end
if (!allowed) then
return false
end
end
if (itemTable.flag) then
if (!client:GetCharacter():HasFlags(itemTable.flag)) then
return false
end
end
return true
end
function GM:DoAnimationEvent(client, event, data)
local class = client.ixAnimModelClass
if (class == "player") then
return self.BaseClass:DoAnimationEvent(client, event, data)
else
local weapon = client:GetActiveWeapon()
if (IsValid(weapon)) then
local animation = client.ixAnimTable
if (event == PLAYERANIMEVENT_ATTACK_PRIMARY) then
client:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, animation.attack or ACT_GESTURE_RANGE_ATTACK_SMG1, true)
return ACT_VM_PRIMARYATTACK
elseif (event == PLAYERANIMEVENT_ATTACK_SECONDARY) then
client:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, animation.attack or ACT_GESTURE_RANGE_ATTACK_SMG1, true)
return ACT_VM_SECONDARYATTACK
elseif (event == PLAYERANIMEVENT_RELOAD) then
client:AnimRestartGesture(GESTURE_SLOT_ATTACK_AND_RELOAD, animation.reload or ACT_GESTURE_RELOAD_SMG1, true)
return ACT_INVALID
elseif (event == PLAYERANIMEVENT_JUMP) then
client:AnimRestartMainSequence()
return ACT_INVALID
elseif (event == PLAYERANIMEVENT_CANCEL_RELOAD) then
client:AnimResetGestureSlot(GESTURE_SLOT_ATTACK_AND_RELOAD)
return ACT_INVALID
end
end
end
return ACT_INVALID
end
function GM:EntityEmitSound(data)
if (data.Entity.ixIsMuted) then
return false
end
end
function GM:EntityRemoved(entity)
if (SERVER) then
entity:ClearNetVars()
elseif (entity:IsWeapon()) then
local owner = entity:GetOwner()
-- GetActiveWeapon is the player's new weapon at this point so we'll assume
-- that the player switched away from this weapon
if (IsValid(owner) and owner:IsPlayer()) then
hook.Run("PlayerWeaponChanged", owner, owner:GetActiveWeapon())
end
end
end
local function UpdatePlayerHoldType(client, weapon)
weapon = weapon or client:GetActiveWeapon()
local holdType = "normal"
if (IsValid(weapon)) then
holdType = weapon.HoldType or weapon:GetHoldType()
holdType = HOLDTYPE_TRANSLATOR[holdType] or holdType
end
client.ixAnimHoldType = holdType
end
local function UpdateAnimationTable(client, vehicle)
local baseTable = ix.anim[client.ixAnimModelClass] or {}
if (IsValid(client) and IsValid(vehicle)) then
local vehicleClass = vehicle:IsChair() and "chair" or vehicle:GetClass()
if (baseTable.vehicle and baseTable.vehicle[vehicleClass]) then
client.ixAnimTable = baseTable.vehicle[vehicleClass]
else
client.ixAnimTable = baseTable.normal[ACT_MP_CROUCH_IDLE]
end
else
client.ixAnimTable = baseTable[client.ixAnimHoldType]
end
client.ixAnimGlide = baseTable["glide"]
end
function GM:PlayerWeaponChanged(client, weapon)
UpdatePlayerHoldType(client, weapon)
UpdateAnimationTable(client)
if (CLIENT) then
return
end
-- update weapon raise state
if (weapon.IsAlwaysRaised or ALWAYS_RAISED[weapon:GetClass()]) then
client:SetWepRaised(true, weapon)
return
elseif (weapon.IsAlwaysLowered or weapon.NeverRaised) then
client:SetWepRaised(false, weapon)
return
end
-- If the player has been forced to have their weapon lowered.
if (client:IsRestricted()) then
client:SetWepRaised(false, weapon)
return
end
-- Let the config decide before actual results.
if (ix.config.Get("weaponAlwaysRaised")) then
client:SetWepRaised(true, weapon)
return
end
client:SetWepRaised(false, weapon)
end
function GM:PlayerSwitchWeapon(client, oldWeapon, weapon)
if (!IsFirstTimePredicted()) then
return
end
-- the player switched weapon themself (i.e not through SelectWeapon), so we have to network it here
if (SERVER) then
net.Start("PlayerSelectWeapon")
net.WriteEntity(client)
net.WriteString(weapon:GetClass())
net.Broadcast()
end
hook.Run("PlayerWeaponChanged", client, weapon)
end
function GM:PlayerModelChanged(client, model)
client.ixAnimModelClass = ix.anim.GetModelClass(model)
UpdateAnimationTable(client)
end
do
local vectorAngle = FindMetaTable("Vector").Angle
local normalizeAngle = math.NormalizeAngle
function GM:CalcMainActivity(client, velocity)
local clientInfo = client:GetTable()
local forcedSequence = client:GetNetVar("forcedSequence")
if (forcedSequence) then
if (client:GetSequence() != forcedSequence) then
client:SetCycle(0)
end
return -1, forcedSequence
end
client:SetPoseParameter("move_yaw", normalizeAngle(vectorAngle(velocity)[2] - client:EyeAngles()[2]))
local sequenceOverride = clientInfo.CalcSeqOverride
clientInfo.CalcSeqOverride = -1
clientInfo.CalcIdeal = ACT_MP_STAND_IDLE
-- we could call the baseclass function, but it's faster to do it this way
local BaseClass = self.BaseClass
if (BaseClass:HandlePlayerNoClipping(client, velocity) or
BaseClass:HandlePlayerDriving(client) or
BaseClass:HandlePlayerVaulting(client, velocity) or
BaseClass:HandlePlayerJumping(client, velocity) or
BaseClass:HandlePlayerSwimming(client, velocity) or
BaseClass:HandlePlayerDucking(client, velocity)) then -- luacheck: ignore 542
else
local length = velocity:Length2DSqr()
if (length > 22500) then
clientInfo.CalcIdeal = ACT_MP_RUN
elseif (length > 0.25) then
clientInfo.CalcIdeal = ACT_MP_WALK
end
end
clientInfo.m_bWasOnGround = client:OnGround()
clientInfo.m_bWasNoclipping = (client:GetMoveType() == MOVETYPE_NOCLIP and !client:InVehicle())
return clientInfo.CalcIdeal, sequenceOverride or clientInfo.CalcSeqOverride or -1
end
end
do
local KEY_BLACKLIST = IN_ATTACK + IN_ATTACK2
function GM:StartCommand(client, command)
if (!client:CanShootWeapon()) then
command:RemoveKey(KEY_BLACKLIST)
end
end
end
function GM:CharacterVarChanged(char, varName, oldVar, newVar)
if (ix.char.varHooks[varName]) then
for _, v in pairs(ix.char.varHooks[varName]) do
v(char, oldVar, newVar)
end
end
end
function GM:CanPlayerThrowPunch(client)
if (!client:IsWepRaised()) then
return false
end
return true
end
function GM:OnCharacterCreated(client, character)
local faction = ix.faction.Get(character:GetFaction())
if (faction and faction.OnCharacterCreated) then
faction:OnCharacterCreated(client, character)
end
end
function GM:GetDefaultCharacterName(client, faction)
local info = ix.faction.indices[faction]
if (info and info.GetDefaultName) then
return info:GetDefaultName(client)
end
end
function GM:CanPlayerUseCharacter(client, character)
local banned = character:GetData("banned")
if (banned) then
if (isnumber(banned)) then
if (banned < os.time()) then
return
end
return false, "@charBannedTemp"
end
return false, "@charBanned"
end
local bHasWhitelist = client:HasWhitelist(character:GetFaction())
if (!bHasWhitelist) then
return false, "@noWhitelist"
end
end
function GM:CanProperty(client, property, entity)
if (client:IsAdmin()) then
return true
end
if (CLIENT and (property == "remover" or property == "collision")) then
return true
end
return false
end
function GM:PhysgunPickup(client, entity)
local bPickup = self.BaseClass:PhysgunPickup(client, entity)
if (!bPickup and entity:IsPlayer() and (client:IsSuperAdmin() or client:IsAdmin() and !entity:IsSuperAdmin())) then
bPickup = true
end
if (bPickup) then
if (entity:IsPlayer()) then
entity:SetMoveType(MOVETYPE_NONE)
elseif (!entity.ixCollisionGroup) then
entity.ixCollisionGroup = entity:GetCollisionGroup()
entity:SetCollisionGroup(COLLISION_GROUP_WEAPON)
end
end
return bPickup
end
function GM:PhysgunDrop(client, entity)
if (entity:IsPlayer()) then
entity:SetMoveType(MOVETYPE_WALK)
elseif (entity.ixCollisionGroup) then
entity:SetCollisionGroup(entity.ixCollisionGroup)
entity.ixCollisionGroup = nil
end
end
do
local TOOL_DANGEROUS = {}
TOOL_DANGEROUS["dynamite"] = true
TOOL_DANGEROUS["duplicator"] = true
function GM:CanTool(client, trace, tool)
if (client:IsAdmin()) then
return true
end
if (TOOL_DANGEROUS[tool]) then
return false
end
return self.BaseClass:CanTool(client, trace, tool)
end
end
function GM:Move(client, moveData)
local char = client:GetCharacter()
if (char) then
if (client:GetNetVar("actEnterAngle")) then
moveData:SetForwardSpeed(0)
moveData:SetSideSpeed(0)
moveData:SetVelocity(vector_origin)
end
if (client:GetMoveType() == MOVETYPE_WALK and moveData:KeyDown(IN_WALK)) then
local mf, ms = 0, 0
local speed = client:GetWalkSpeed()
local ratio = ix.config.Get("walkRatio")
if (moveData:KeyDown(IN_FORWARD)) then
mf = ratio
elseif (moveData:KeyDown(IN_BACK)) then
mf = -ratio
end
if (moveData:KeyDown(IN_MOVELEFT)) then
ms = -ratio
elseif (moveData:KeyDown(IN_MOVERIGHT)) then
ms = ratio
end
moveData:SetForwardSpeed(mf * speed)
moveData:SetSideSpeed(ms * speed)
end
end
end
-- I'm sorry. ~Aspect
--[[
function GM:CanTransferItem(itemObject, curInv, inventory)
if (SERVER) then
local client = itemObject.GetOwner and itemObject:GetOwner() or nil
if (IsValid(client) and curInv.GetReceivers) then
local bAuthorized = false
for _, v in ipairs(curInv:GetReceivers()) do
if (client == v) then
bAuthorized = true
break
end
end
if (!bAuthorized) then
return false
end
end
end
-- we can transfer anything that isn't a bag
if (!itemObject or !itemObject.isBag) then
return
end
-- don't allow bags to be put inside bags
if (inventory.id != 0 and curInv.id != inventory.id) then
if (inventory.vars and inventory.vars.isBag) then
local owner = itemObject:GetOwner()
if (IsValid(owner)) then
owner:NotifyLocalized("nestedBags")
end
return false
end
elseif (inventory.id != 0 and curInv.id == inventory.id) then
-- we are simply moving items around if we're transferring to the same inventory
return
end
inventory = ix.item.inventories[itemObject:GetData("id")]
-- don't allow transferring items that are in use
if (inventory) then
for _, v in pairs(inventory:GetItems()) do
if (v:GetData("equip") == true) then
local owner = itemObject:GetOwner()
if (owner and IsValid(owner)) then
owner:NotifyLocalized("equippedBag")
end
return false
end
end
end
end
--]]
function GM:CanPlayerEquipItem(client, item)
local slots = ix.plugin.list["inventoryslots"]
if slots then return slots:CanEquipOrUnequip(client, item, true) end
return item.invID == client:GetCharacter():GetInventory():GetID()
end
function GM:CanPlayerUnequipItem(client, item)
local slots = ix.plugin.list["inventoryslots"]
if slots then return slots:CanEquipOrUnequip(client, item, false) end
return item.invID == client:GetCharacter():GetInventory():GetID()
end
function GM:OnItemTransferred(item, curInv, inventory)
local bagInventory = item.GetInventory and item:GetInventory()
if (!bagInventory) then
return
end
-- we need to retain the receiver if the owner changed while viewing as storage
if (inventory.storageInfo and isfunction(curInv.GetOwner)) then
bagInventory:AddReceiver(curInv:GetOwner())
end
end
function GM:ShowHelp() end
function GM:PreGamemodeLoaded()
hook.Remove("PostDrawEffects", "RenderWidgets")
hook.Remove("PlayerTick", "TickWidgets")
hook.Remove("RenderScene", "RenderStereoscopy")
end
function GM:PostGamemodeLoaded()
baseclass.Set("ix_character", ix.meta.character)
baseclass.Set("ix_inventory", ix.meta.inventory)
baseclass.Set("ix_item", ix.meta.item)
end
if (SERVER) then
util.AddNetworkString("PlayerVehicle")
function GM:PlayerEnteredVehicle(client, vehicle, role)
UpdateAnimationTable(client)
net.Start("PlayerVehicle")
net.WriteEntity(client)
net.WriteEntity(vehicle)
net.WriteBool(true)
net.Broadcast()
end
function GM:PlayerLeaveVehicle(client, vehicle)
UpdateAnimationTable(client)
net.Start("PlayerVehicle")
net.WriteEntity(client)
net.WriteEntity(vehicle)
net.WriteBool(false)
net.Broadcast()
end
else
net.Receive("PlayerVehicle", function(length)
local client = net.ReadEntity()
local vehicle = net.ReadEntity()
local bEntered = net.ReadBool()
UpdateAnimationTable(client, bEntered and vehicle or false)
end)
end

View File

@@ -0,0 +1,951 @@
--[[
| 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/
--]]
function GM:PlayerInitialSpawn(client)
client.ixJoinTime = RealTime()
if (client:IsBot()) then
local botID = os.time() + client:EntIndex()
local index = math.random(1, table.Count(ix.faction.indices))
local faction = ix.faction.indices[index]
local model = faction and table.Random(faction:GetModels(client)) or "models/gman.mdl"
if (istable(model)) then
model = table.Random(model)
end
local character = ix.char.New({
name = client:Name(),
faction = faction and faction.uniqueID or "unknown",
model = model,
}, botID, client, client:SteamID64())
character.isBot = true
local inventory = ix.inventory.Create(ix.config.Get("inventoryWidth"), ix.config.Get("inventoryHeight"), botID)
inventory:SetOwner(botID)
inventory.noSave = true
character.vars.inv = {inventory}
ix.char.loaded[botID] = character
character:Setup()
client:Spawn()
ix.chat.Send(nil, "connect", client:SteamName())
return
end
ix.config.Send(client)
ix.date.Send(client)
client:LoadData(function(data)
if (!IsValid(client)) then return end
-- Don't use the character cache if they've connected to another server using the same database
local address = ix.util.GetAddress()
local bNoCache = client:GetData("lastIP", address) != address
client:SetData("lastIP", address)
net.Start("ixDataSync")
net.WriteTable(data or {})
net.WriteUInt(client.ixPlayTime or 0, 32)
net.Send(client)
ix.char.Restore(client, function(charList)
if (!IsValid(client)) then return end
MsgN("Loaded (" .. table.concat(charList, ", ") .. ") for " .. client:Name())
for _, v in ipairs(charList) do
ix.char.loaded[v]:Sync(client)
end
client.ixCharList = charList
net.Start("ixCharacterMenu")
net.WriteUInt(#charList, 6)
for _, v in ipairs(charList) do
net.WriteUInt(v, 32)
end
net.Send(client)
client.ixLoaded = true
client:SetData("intro", true)
for _, v in ipairs(player.GetAll()) do
if (v:GetCharacter()) then
v:GetCharacter():Sync(client)
end
end
end, bNoCache)
ix.chat.Send(nil, "connect", client:SteamName())
end)
client:SetNoDraw(true)
client:SetNotSolid(true)
client:Lock()
client:SyncVars()
timer.Simple(1, function()
if (!IsValid(client)) then
return
end
client:KillSilent()
client:StripAmmo()
end)
end
function GM:PlayerUse(client, entity)
if (client:IsRestricted() or (isfunction(entity.GetEntityMenu) and entity:GetClass() != "ix_item")) then
return false
end
return true
end
function GM:KeyPress(client, key)
if (key == IN_RELOAD) then
timer.Create("ixToggleRaise"..client:SteamID(), ix.config.Get("weaponRaiseTime"), 1, function()
if (IsValid(client)) then
client:ToggleWepRaised()
end
end)
elseif (key == IN_USE) then
local data = {}
data.start = client:GetShootPos()
data.endpos = data.start + client:GetAimVector() * 96
data.filter = client
local entity = util.TraceLine(data).Entity
if (IsValid(entity) and hook.Run("PlayerUse", client, entity)) then
if (entity:IsDoor()) then
local result = hook.Run("CanPlayerUseDoor", client, entity)
if (result != false) then
hook.Run("PlayerUseDoor", client, entity)
end
end
end
end
end
function GM:KeyRelease(client, key)
if (key == IN_RELOAD) then
timer.Remove("ixToggleRaise" .. client:SteamID())
elseif (key == IN_USE) then
timer.Remove("ixCharacterInteraction" .. client:SteamID())
end
end
function GM:CanPlayerInteractItem(client, action, item)
if (client:IsRestricted()) then
return false
end
if (IsValid(client.ixRagdoll)) then
client:NotifyLocalized("notNow")
return false
end
if (action == "drop" and hook.Run("CanPlayerDropItem", client, item) == false) then
return false
end
if (action == "take" and hook.Run("CanPlayerTakeItem", client, item) == false) then
return false
end
if (isentity(item) and item.ixSteamID and item.ixCharID
and item.ixSteamID == client:SteamID() and item.ixCharID != client:GetCharacter():GetID()
and !item:GetItemTable().bAllowMultiCharacterInteraction) then
client:NotifyLocalized("itemOwned")
return false
end
return client:Alive()
end
function GM:CanPlayerDropItem(client, item)
end
function GM:CanPlayerTakeItem(client, item)
end
function GM:PlayerShouldTakeDamage(client, attacker)
return client:GetCharacter() != nil
end
function GM:GetFallDamage(client, speed)
return (speed - 580) * (100 / 444)
end
function GM:EntityTakeDamage(entity, dmgInfo)
local inflictor = dmgInfo:GetInflictor()
if (IsValid(inflictor) and inflictor:GetClass() == "ix_item") then
dmgInfo:SetDamage(0)
return
end
if (IsValid(entity.ixPlayer)) then
if (IsValid(entity.ixHeldOwner)) then
dmgInfo:SetDamage(0)
return
end
if (dmgInfo:IsDamageType(DMG_CRUSH)) then
if ((entity.ixFallGrace or 0) < CurTime()) then
if (dmgInfo:GetDamage() <= 10) then
dmgInfo:SetDamage(0)
end
entity.ixFallGrace = CurTime() + 0.5
else
return
end
end
entity.ixPlayer:TakeDamageInfo(dmgInfo)
end
end
function GM:PrePlayerLoadedCharacter(client, character, lastChar)
-- Reset all bodygroups
client:ResetBodygroups()
-- Remove all skins
client:SetSkin(0)
end
function GM:PlayerLoadedCharacter(client, character, lastChar)
local query = mysql:Update("ix_characters")
query:Where("id", character:GetID())
query:Update("last_join_time", math.floor(os.time()))
query:Execute()
if (lastChar) then
local charEnts = lastChar:GetVar("charEnts") or {}
for _, v in ipairs(charEnts) do
if (v and IsValid(v)) then
v:Remove()
end
end
lastChar:SetVar("charEnts", nil)
end
if (character) then
for _, v in pairs(ix.class.list) do
if (v.faction == client:Team() and v.isDefault) then
character:SetClass(v.index)
break
end
end
end
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll.ixNoReset = true
client.ixRagdoll.ixIgnoreDelete = true
client.ixRagdoll:Remove()
end
local faction = ix.faction.indices[character:GetFaction()]
local uniqueID = "ixSalary" .. client:SteamID64()
if (faction and faction.pay and faction.pay > 0) then
timer.Create(uniqueID, faction.payTime or 300, 0, function()
if (IsValid(client)) then
if (hook.Run("CanPlayerEarnSalary", client, faction) != false) then
local pay = hook.Run("GetSalaryAmount", client, faction) or faction.pay
character:GiveMoney(pay)
client:NotifyLocalized("salary", ix.currency.Get(pay))
end
else
timer.Remove(uniqueID)
end
end)
elseif (timer.Exists(uniqueID)) then
timer.Remove(uniqueID)
end
hook.Run("PlayerLoadout", client)
end
function GM:CharacterLoaded(character)
local client = character:GetPlayer()
if (IsValid(client)) then
local uniqueID = "ixSaveChar"..client:SteamID()
timer.Create(uniqueID, ix.config.Get("saveInterval"), 0, function()
if (IsValid(client) and client:GetCharacter()) then
client:GetCharacter():Save()
else
timer.Remove(uniqueID)
end
end)
end
end
function GM:PlayerSay(client, text)
local chatType, message, anonymous = ix.chat.Parse(client, text, true)
if (chatType == "ic") then
if (ix.command.Parse(client, message)) then
return ""
end
end
text = ix.chat.Send(client, chatType, message, anonymous)
if (isstring(text)) then
ix.log.Add(client, "chat", chatType and chatType:utf8upper() or "??", text)
end
hook.Run("PostPlayerSay", client, chatType, message, anonymous)
return ""
end
function GM:CanAutoFormatMessage(client, chatType, message)
return chatType == "ic" or chatType == "w" or chatType == "y"
end
function GM:PlayerSpawn(client)
client:SetNoDraw(false)
client:UnLock()
client:SetNotSolid(false)
client:SetMoveType(MOVETYPE_WALK)
client:SetRagdolled(false)
client:SetAction()
client:SetDSP(1)
hook.Run("PlayerLoadout", client)
end
-- Shortcuts for (super)admin only things.
local function IsAdmin(_, client)
return client:IsAdmin()
end
-- Set the gamemode hooks to the appropriate shortcuts.
GM.PlayerGiveSWEP = IsAdmin
GM.PlayerSpawnEffect = IsAdmin
GM.PlayerSpawnSENT = IsAdmin
function GM:PlayerSpawnNPC(client, npcType, weapon)
return client:IsAdmin() or client:GetCharacter():HasFlags("n")
end
function GM:PlayerSpawnSWEP(client, weapon, info)
return client:IsAdmin()
end
function GM:PlayerSpawnProp(client)
if (client:GetCharacter() and client:GetCharacter():HasFlags("e")) then
return true
end
return false
end
function GM:PlayerSpawnRagdoll(client)
if (client:GetCharacter() and client:GetCharacter():HasFlags("r")) then
return true
end
return false
end
function GM:PlayerSpawnVehicle(client, model, name, data)
if (client:GetCharacter()) then
if (data.Category == "Chairs") then
return client:GetCharacter():HasFlags("c")
else
return client:GetCharacter():HasFlags("C")
end
end
return false
end
function GM:PlayerSpawnedEffect(client, model, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedNPC(client, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedProp(client, model, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedRagdoll(client, model, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedSENT(client, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedSWEP(client, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
function GM:PlayerSpawnedVehicle(client, entity)
entity:SetNetVar("owner", client:GetCharacter():GetID())
end
ix.allowedHoldableClasses = {
["ix_item"] = true,
["ix_money"] = true,
["ix_shipment"] = true,
["prop_physics"] = true,
["prop_physics_override"] = true,
["prop_physics_multiplayer"] = true,
["prop_ragdoll"] = true
}
function GM:CanPlayerHoldObject(client, entity)
if (ix.allowedHoldableClasses[entity:GetClass()]) then
return true
end
end
local voiceDistance = 360000
local function CalcPlayerCanHearPlayersVoice(listener)
if (!IsValid(listener)) then
return
end
listener.ixVoiceHear = listener.ixVoiceHear or {}
local eyePos = listener:EyePos()
for _, speaker in ipairs(player.GetAll()) do
local speakerEyePos = speaker:EyePos()
listener.ixVoiceHear[speaker] = eyePos:DistToSqr(speakerEyePos) < voiceDistance
end
end
function GM:InitializedConfig()
ix.date.Initialize()
voiceDistance = ix.config.Get("voiceDistance")
voiceDistance = voiceDistance * voiceDistance
end
function GM:VoiceToggled(bAllowVoice)
for _, v in ipairs(player.GetAll()) do
local uniqueID = v:SteamID64() .. "ixCanHearPlayersVoice"
if (bAllowVoice) then
timer.Create(uniqueID, 0.5, 0, function()
CalcPlayerCanHearPlayersVoice(v)
end)
else
timer.Remove(uniqueID)
v.ixVoiceHear = nil
end
end
end
function GM:VoiceDistanceChanged(distance)
voiceDistance = distance * distance
end
-- Called when weapons should be given to a player.
function GM:PlayerLoadout(client)
if (client.ixSkipLoadout) then
client.ixSkipLoadout = nil
return
end
client:SetWeaponColor(Vector(client:GetInfo("cl_weaponcolor")))
client:StripWeapons()
client:StripAmmo()
client:SetLocalVar("blur", nil)
local character = client:GetCharacter()
-- Check if they have loaded a character.
if (character) then
client:SetupHands()
-- Set their player model to the character's model.
client:SetModel(character:GetModel())
client:Give("ix_hands")
client:SetWalkSpeed(ix.config.Get("walkSpeed"))
client:SetRunSpeed(ix.config.Get("runSpeed"))
client:SetJumpPower(ix.config.Get("jumpPower"))
client:SetHealth(character:GetData("health", client:GetMaxHealth()))
local faction = ix.faction.indices[client:Team()]
if (faction) then
-- If their faction wants to do something when the player spawns, let it.
if (faction.OnSpawn) then
faction:OnSpawn(client)
end
-- @todo add docs for player:Give() failing if player already has weapon - which means if a player is given a weapon
-- here due to the faction weapons table, the weapon's :Give call in the weapon base will fail since the player
-- will already have it by then. This will cause issues for weapons that have pac data since the parts are applied
-- only if the weapon returned by :Give() is valid
-- If the faction has default weapons, give them to the player.
if (faction.weapons) then
for _, v in ipairs(faction.weapons) do
client:Give(v)
end
end
end
-- Ditto, but for classes.
local class = ix.class.list[client:GetCharacter():GetClass()]
if (class) then
if (class.OnSpawn) then
class:OnSpawn(client)
end
if (class.weapons) then
for _, v in ipairs(class.weapons) do
client:Give(v)
end
end
end
-- Apply any flags as needed.
ix.flag.OnSpawn(client)
ix.attributes.Setup(client)
hook.Run("PostPlayerLoadout", client)
client:SelectWeapon("ix_hands")
else
client:SetNoDraw(true)
client:Lock()
client:SetNotSolid(true)
end
end
function GM:PostPlayerLoadout(client)
-- Reload All Attrib Boosts
local character = client:GetCharacter()
if (character:GetInventory()) then
for _, v in pairs(character:GetInventory():GetItems()) do
v:Call("OnLoadout", client)
if (v:GetData("equip") and v.attribBoosts) then
for attribKey, attribValue in pairs(v.attribBoosts) do
character:AddBoost(v.uniqueID, attribKey, attribValue)
end
end
end
end
if (ix.config.Get("allowVoice")) then
timer.Create(client:SteamID64() .. "ixCanHearPlayersVoice", 0.5, 0, function()
CalcPlayerCanHearPlayersVoice(client)
end)
end
end
local deathSounds = {
Sound("vo/npc/male01/pain07.wav"),
Sound("vo/npc/male01/pain08.wav"),
Sound("vo/npc/male01/pain09.wav")
}
function GM:DoPlayerDeath(client, attacker, damageinfo)
client:AddDeaths(1)
if (hook.Run("ShouldSpawnClientRagdoll", client) != false) then
client:CreateRagdoll()
end
if (IsValid(attacker) and attacker:IsPlayer()) then
if (client == attacker) then
attacker:AddFrags(-1)
else
attacker:AddFrags(1)
end
end
client:SetDSP(31)
end
function GM:PlayerDeath(client, inflictor, attacker)
local character = client:GetCharacter()
if (character) then
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll.ixIgnoreDelete = true
client:SetLocalVar("blur", nil)
if (hook.Run("ShouldRemoveRagdollOnDeath", client) != false) then
client.ixRagdoll:Remove()
end
end
client:SetNetVar("deathStartTime", CurTime())
client:SetNetVar("deathTime", CurTime() + ix.config.Get("spawnTime", 5))
character:SetData("health", nil)
local deathSound = hook.Run("GetPlayerDeathSound", client)
if (deathSound != false) then
deathSound = deathSound or deathSounds[math.random(1, #deathSounds)]
if (client:IsFemale() and !deathSound:find("female")) then
deathSound = deathSound:gsub("male", "female")
end
client:EmitSound(deathSound)
end
local weapon = attacker:IsPlayer() and attacker:GetActiveWeapon()
ix.log.Add(client, "playerDeath",
attacker:GetName() ~= "" and attacker:GetName() or attacker:GetClass(), IsValid(weapon) and weapon:GetClass())
end
end
local painSounds = {
Sound("vo/npc/male01/pain01.wav"),
Sound("vo/npc/male01/pain02.wav"),
Sound("vo/npc/male01/pain03.wav"),
Sound("vo/npc/male01/pain04.wav"),
Sound("vo/npc/male01/pain05.wav"),
Sound("vo/npc/male01/pain06.wav")
}
local drownSounds = {
Sound("player/pl_drown1.wav"),
Sound("player/pl_drown2.wav"),
Sound("player/pl_drown3.wav"),
}
function GM:GetPlayerPainSound(client)
if (client:WaterLevel() >= 3) then
return drownSounds[math.random(1, #drownSounds)]
end
end
function GM:PlayerHurt(client, attacker, health, damage)
if ((client.ixNextPain or 0) < CurTime() and health > 0) then
local painSound = hook.Run("GetPlayerPainSound", client) or painSounds[math.random(1, #painSounds)]
if (client:IsFemale() and !painSound:find("female")) then
painSound = painSound:gsub("male", "female")
end
client:EmitSound(painSound)
client.ixNextPain = CurTime() + 0.33
end
ix.log.Add(client, "playerHurt", damage, attacker:GetName() ~= "" and attacker:GetName() or attacker:GetClass())
end
function GM:PlayerDeathThink(client)
if (client:GetCharacter()) then
local deathTime = client:GetNetVar("deathTime")
if (deathTime and deathTime <= CurTime()) then
client:Spawn()
end
end
return false
end
function GM:PlayerDisconnected(client)
client:SaveData()
local character = client:GetCharacter()
if (character) then
local charEnts = character:GetVar("charEnts") or {}
for _, v in ipairs(charEnts) do
if (v and IsValid(v)) then
v:Remove()
end
end
hook.Run("OnCharacterDisconnect", client, character)
character:Save()
ix.chat.Send(nil, "disconnect", client:SteamName())
end
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll:Remove()
end
client:ClearNetVars()
if (!client.ixVoiceHear) then
return
end
for _, v in ipairs(player.GetAll()) do
if (!v.ixVoiceHear) then
continue
end
v.ixVoiceHear[client] = nil
end
timer.Remove(client:SteamID64() .. "ixCanHearPlayersVoice")
end
function GM:InitPostEntity()
local doors = ents.FindByClass("prop_door_rotating")
for _, v in ipairs(doors) do
local parent = v:GetOwner()
if (IsValid(parent)) then
v.ixPartner = parent
parent.ixPartner = v
else
for _, v2 in ipairs(doors) do
if (v2:GetOwner() == v) then
v2.ixPartner = v
v.ixPartner = v2
break
end
end
end
end
timer.Simple(2, function()
ix.entityDataLoaded = true
end)
end
function GM:SaveData()
ix.date.Save()
end
function GM:ShutDown()
ix.shuttingDown = true
ix.config.Save()
hook.Run("SaveData")
for _, v in ipairs(player.GetAll()) do
v:SaveData()
if (v:GetCharacter()) then
v:GetCharacter():Save()
end
end
end
function GM:GetGameDescription()
return "IX: "..(Schema and Schema.name or "Unknown")
end
function GM:OnPlayerUseBusiness(client, item)
-- You can manipulate purchased items with this hook.
-- does not requires any kind of return.
-- ex) item:SetData("businessItem", true)
-- then every purchased item will be marked as Business Item.
end
function GM:PlayerDeathSound()
return true
end
function GM:InitializedSchema()
game.ConsoleCommand("sbox_persist ix_"..Schema.folder.."\n")
end
function GM:PlayerCanHearPlayersVoice(listener, speaker)
if (!speaker:Alive()) then
return false
end
local bCanHear = listener.ixVoiceHear and listener.ixVoiceHear[speaker]
return bCanHear, true
end
function GM:PlayerCanPickupWeapon(client, weapon)
local data = {}
data.start = client:GetShootPos()
data.endpos = data.start + client:GetAimVector() * 96
data.filter = client
local trace = util.TraceLine(data)
if (trace.Entity == weapon and client:KeyDown(IN_USE)) then
return true
end
return client.ixWeaponGive
end
function GM:OnPhysgunFreeze(weapon, physObj, entity, client)
-- Object is already frozen (!?)
if (entity.scaledSize) then return true end
if (!physObj:IsMoveable()) then return false end
if (entity:GetUnFreezable()) then return false end
physObj:EnableMotion(false)
-- With the jeep we need to pause all of its physics objects
-- to stop it spazzing out and killing the server.
if (entity:GetClass() == "prop_vehicle_jeep") then
local objects = entity:GetPhysicsObjectCount()
for i = 0, objects - 1 do
entity:GetPhysicsObjectNum(i):EnableMotion(false)
end
end
-- Add it to the player's frozen props
client:AddFrozenPhysicsObject(entity, physObj)
client:SendHint("PhysgunUnfreeze", 0.3)
client:SuppressHint("PhysgunFreeze")
return true
end
function GM:CanPlayerSuicide(client)
return false
end
function GM:AllowPlayerPickup(client, entity)
return false
end
function GM:PreCleanupMap()
hook.Run("SaveData")
hook.Run("PersistenceSave")
end
function GM:PostCleanupMap()
ix.plugin.RunLoadData()
end
function GM:CharacterPreSave(character)
local client = character:GetPlayer()
for _, v in pairs(character:GetInventory():GetItems()) do
if (v.OnSave) then
v:Call("OnSave", client)
end
end
character:SetData("health", client:Alive() and client:Health() or nil)
end
timer.Create("ixLifeGuard", 1, 0, function()
for _, v in ipairs(player.GetAll()) do
if (v:GetCharacter() and v:Alive() and hook.Run("ShouldPlayerDrowned", v) != false) then
if (v:WaterLevel() >= 3) then
if (!v.drowningTime) then
v.drowningTime = CurTime() + 30
v.nextDrowning = CurTime()
v.drownDamage = v.drownDamage or 0
end
if (v.drowningTime < CurTime()) then
if (v.nextDrowning < CurTime()) then
v:ScreenFade(1, Color(0, 0, 255, 100), 1, 0)
v:TakeDamage(10)
v.drownDamage = v.drownDamage + 10
v.nextDrowning = CurTime() + 1
end
end
else
if (v.drowningTime) then
v.drowningTime = nil
v.nextDrowning = nil
v.nextRecover = CurTime() + 2
end
if (v.nextRecover and v.nextRecover < CurTime() and v.drownDamage > 0) then
v.drownDamage = v.drownDamage - 10
v:SetHealth(math.Clamp(v:Health() + 10, 0, v:GetMaxHealth()))
v.nextRecover = CurTime() + 1
end
end
end
end
end)
net.Receive("ixStringRequest", function(length, client)
local time = net.ReadUInt(32)
local text = net.ReadString()
if (client.ixStrReqs and client.ixStrReqs[time]) then
client.ixStrReqs[time](text)
client.ixStrReqs[time] = nil
end
end)
net.Receive("ixConfirmationRequest", function(length, client)
local time = net.ReadUInt(32)
local confirmation = net.ReadBool()
if (client.ixConfReqs and client.ixConfReqs[time]) then
client.ixConfReqs[time](confirmation)
client.ixConfReqs[time] = nil
end
end)
function GM:GetPreferredCarryAngles(entity)
if (entity:GetClass() == "ix_item") then
local itemTable = entity:GetItemTable()
if (itemTable) then
local preferedAngle = itemTable.preferedAngle
if (preferedAngle) then -- I don't want to return something
return preferedAngle
end
end
end
end
function GM:PluginShouldLoad(uniqueID)
return !ix.plugin.unloaded[uniqueID]
end
function GM:DatabaseConnected()
-- Create the SQL tables if they do not exist.
ix.db.LoadTables()
ix.log.LoadTables()
MsgC(Color(0, 255, 0), "Database Type: " .. ix.db.config.adapter .. ".\n")
timer.Create("ixDatabaseThink", 0.5, 0, function()
mysql:Think()
end)
ix.plugin.RunLoadData()
end