add sborka

This commit is contained in:
2026-03-31 10:27:04 +03:00
commit f5e5f56c84
2345 changed files with 382127 additions and 0 deletions

View File

@@ -0,0 +1,993 @@
function GM:ForceDermaSkin()
return "helix"
end
function GM:ScoreboardShow()
if (LocalPlayer():GetCharacter()) then
vgui.Create("ixMenu")
end
end
function GM:ScoreboardHide()
end
function GM:LoadFonts(font, genericFont)
surface.CreateFont("ix3D2DFont", {
font = font,
size = 128,
extended = true,
weight = 100
})
surface.CreateFont("ix3D2DMediumFont", {
font = font,
size = 48,
extended = true,
weight = 100
})
surface.CreateFont("ix3D2DSmallFont", {
font = font,
size = 24,
extended = true,
weight = 400
})
surface.CreateFont("ixTitleFont", {
font = font,
size = ScreenScale(30),
extended = true,
weight = 100
})
surface.CreateFont("ixSubTitleFont", {
font = font,
size = ScreenScale(16),
extended = true,
weight = 100
})
surface.CreateFont("ixMenuMiniFont", {
font = "Roboto",
size = math.max(ScreenScale(4), 18),
weight = 300,
})
surface.CreateFont("ixMenuButtonFont", {
font = "Roboto Th",
size = ScreenScale(14),
extended = true,
weight = 100
})
surface.CreateFont("ixMenuButtonFontSmall", {
font = "Roboto Th",
size = ScreenScale(10),
extended = true,
weight = 100
})
surface.CreateFont("ixMenuButtonFontThick", {
font = "Roboto",
size = ScreenScale(14),
extended = true,
weight = 300
})
surface.CreateFont("ixMenuButtonLabelFont", {
font = "Roboto Th",
size = 28,
extended = true,
weight = 100
})
surface.CreateFont("ixMenuButtonHugeFont", {
font = "Roboto Th",
size = ScreenScale(24),
extended = true,
weight = 100
})
surface.CreateFont("ixToolTipText", {
font = font,
size = 20,
extended = true,
weight = 500
})
surface.CreateFont("ixMonoSmallFont", {
font = "Consolas",
size = 12,
extended = true,
weight = 800
})
surface.CreateFont("ixMonoMediumFont", {
font = "Consolas",
size = 22,
extended = true,
weight = 800
})
-- The more readable font.
font = genericFont
surface.CreateFont("ixBigFont", {
font = font,
size = 36,
extended = true,
weight = 1000
})
surface.CreateFont("ixMediumFont", {
font = font,
size = 25,
extended = true,
weight = 1000
})
surface.CreateFont("ixNoticeFont", {
font = font,
size = math.max(ScreenScale(8), 18),
weight = 100,
extended = true,
antialias = true
})
surface.CreateFont("ixMediumLightFont", {
font = font,
size = 25,
extended = true,
weight = 200
})
surface.CreateFont("ixMediumLightBlurFont", {
font = font,
size = 25,
extended = true,
weight = 200,
blursize = 4
})
surface.CreateFont("ixGenericFont", {
font = font,
size = 20,
extended = true,
weight = 1000
})
surface.CreateFont("ixChatFont", {
font = font,
size = math.max(ScreenScale(7), 17) * ix.option.Get("chatFontScale", 1),
extended = true,
weight = 600,
antialias = true
})
surface.CreateFont("ixChatFontItalics", {
font = font,
size = math.max(ScreenScale(7), 17) * ix.option.Get("chatFontScale", 1),
extended = true,
weight = 600,
antialias = true,
italic = true
})
surface.CreateFont("ixSmallTitleFont", {
font = "Roboto Th",
size = math.max(ScreenScale(12), 24),
extended = true,
weight = 100
})
surface.CreateFont("ixMinimalTitleFont", {
font = "Roboto",
size = math.max(ScreenScale(8), 22),
extended = true,
weight = 800
})
surface.CreateFont("ixSmallFont", {
font = font,
size = math.max(ScreenScale(6), 17),
extended = true,
weight = 500
})
surface.CreateFont("ixItemDescFont", {
font = font,
size = math.max(ScreenScale(6), 17),
extended = true,
shadow = true,
weight = 500
})
surface.CreateFont("ixSmallBoldFont", {
font = font,
size = math.max(ScreenScale(8), 20),
extended = true,
weight = 800
})
surface.CreateFont("ixItemBoldFont", {
font = font,
shadow = true,
size = math.max(ScreenScale(8), 20),
extended = true,
weight = 800
})
-- Introduction fancy font.
font = "Roboto Th"
surface.CreateFont("ixIntroTitleFont", {
font = font,
size = math.min(ScreenScale(128), 128),
extended = true,
weight = 100
})
surface.CreateFont("ixIntroTitleBlurFont", {
font = font,
size = math.min(ScreenScale(128), 128),
extended = true,
weight = 100,
blursize = 4
})
surface.CreateFont("ixIntroSubtitleFont", {
font = font,
size = ScreenScale(24),
extended = true,
weight = 100
})
surface.CreateFont("ixIntroSmallFont", {
font = font,
size = ScreenScale(14),
extended = true,
weight = 100
})
surface.CreateFont("ixIconsSmall", {
font = "fontello",
size = 22,
extended = true,
weight = 500
})
surface.CreateFont("ixSmallTitleIcons", {
font = "fontello",
size = math.max(ScreenScale(11), 23),
extended = true,
weight = 100
})
surface.CreateFont("ixIconsMedium", {
font = "fontello",
extended = true,
size = 28,
weight = 500
})
surface.CreateFont("ixIconsMenuButton", {
font = "fontello",
size = ScreenScale(14),
extended = true,
weight = 100
})
surface.CreateFont("ixIconsBig", {
font = "fontello",
extended = true,
size = 48,
weight = 500
})
end
function GM:OnCharacterMenuCreated(panel)
if (IsValid(ix.gui.notices)) then
ix.gui.notices:Clear()
end
end
local LOWERED_ANGLES = Angle(30, 0, -25)
function GM:CalcViewModelView(weapon, viewModel, oldEyePos, oldEyeAngles, eyePos, eyeAngles)
if (!IsValid(weapon)) then
return
end
local client = LocalPlayer()
local bWepRaised = client:IsWepRaised()
-- update tween if the raised state is out of date
if (client.ixWasWeaponRaised != bWepRaised) then
local fraction = bWepRaised and 0 or 1
client.ixRaisedFraction = 1 - fraction
client.ixRaisedTween = ix.tween.new(0.75, client, {
ixRaisedFraction = fraction
}, "outQuint")
client.ixWasWeaponRaised = bWepRaised
end
local fraction = client.ixRaisedFraction
local rotation = weapon.LowerAngles or LOWERED_ANGLES
if (ix.option.Get("altLower", true) and weapon.LowerAngles2) then
rotation = weapon.LowerAngles2
end
eyeAngles:RotateAroundAxis(eyeAngles:Up(), rotation.p * fraction)
eyeAngles:RotateAroundAxis(eyeAngles:Forward(), rotation.y * fraction)
eyeAngles:RotateAroundAxis(eyeAngles:Right(), rotation.r * fraction)
viewModel:SetAngles(eyeAngles)
return self.BaseClass:CalcViewModelView(weapon, viewModel, oldEyePos, oldEyeAngles, eyePos, eyeAngles)
end
function GM:LoadIntro()
if (!IsValid(ix.gui.intro)) then
vgui.Create("ixIntro")
end
end
function GM:CharacterLoaded()
local menu = ix.gui.characterMenu
if (IsValid(menu)) then
menu:Close((LocalPlayer().GetCharacter and LocalPlayer():GetCharacter()) and true or nil)
end
end
function GM:InitializedConfig()
local color = ix.config.Get("color")
hook.Run("LoadFonts", ix.config.Get("font"), ix.config.Get("genericFont"))
hook.Run("ColorSchemeChanged", color)
if (!ix.config.loaded and !IsValid(ix.gui.loading)) then
local loader = vgui.Create("EditablePanel")
loader:ParentToHUD()
loader:Dock(FILL)
loader.Paint = function(this, w, h)
surface.SetDrawColor(0, 0, 0)
surface.DrawRect(0, 0, w, h)
end
local statusLabel = loader:Add("DLabel")
statusLabel:Dock(FILL)
statusLabel:SetText(L"loading")
statusLabel:SetFont("ixTitleFont")
statusLabel:SetContentAlignment(5)
statusLabel:SetTextColor(color_white)
timer.Simple(5, function()
if (IsValid(ix.gui.loading)) then
local fault = GetNetVar("dbError")
if (fault) then
statusLabel:SetText(fault and L"dbError" or L"loading")
local label = loader:Add("DLabel")
label:DockMargin(0, 64, 0, 0)
label:Dock(TOP)
label:SetFont("ixSubTitleFont")
label:SetText(fault)
label:SetContentAlignment(5)
label:SizeToContentsY()
label:SetTextColor(Color(255, 50, 50))
end
end
end)
ix.gui.loading = loader
ix.config.loaded = true
if (ix.config.Get("intro", true) and ix.option.Get("showIntro", true)) then
hook.Run("LoadIntro")
end
end
end
function GM:InitPostEntity()
ix.joinTime = RealTime() - 0.9716
ix.option.Sync()
ix.gui.bars = vgui.Create("ixInfoBarManager")
end
function GM:NetworkEntityCreated(entity)
if (entity:IsPlayer()) then
entity:SetIK(false)
-- we've just discovered a new player, so we need to update their animation state
if (entity != LocalPlayer()) then
-- we don't need to call the PlayerWeaponChanged hook here since it'll be handled below,
-- when this player's weapon has been discovered
hook.Run("PlayerModelChanged", entity, entity:GetModel())
end
elseif (entity:IsWeapon()) then
local owner = entity:GetOwner()
if (IsValid(owner) and owner:IsPlayer() and entity == owner:GetActiveWeapon()) then
hook.Run("PlayerWeaponChanged", owner, entity)
end
end
end
local vignette = ix.util.GetMaterial("helix/gui/vignette.png")
local vignetteAlphaGoal = 0
local vignetteAlphaDelta = 0
local vignetteTraceHeight = Vector(0, 0, 768)
local blurGoal = 0
local blurDelta = 0
local hasVignetteMaterial = !vignette:IsError()
timer.Create("ixVignetteChecker", 1, 0, function()
local client = LocalPlayer()
if (IsValid(client)) then
local data = {}
data.start = client:GetPos()
data.endpos = data.start + vignetteTraceHeight
data.filter = client
local trace = util.TraceLine(data)
-- this timer could run before InitPostEntity is called, so we have to check for the validity of the trace table
if (trace and trace.Hit) then
vignetteAlphaGoal = 80
else
vignetteAlphaGoal = 0
end
end
end)
function GM:CalcView(client, origin, angles, fov)
local view = self.BaseClass:CalcView(client, origin, angles, fov) or {}
local entity = Entity(client:GetLocalVar("ragdoll", 0))
local ragdoll = IsValid(client:GetRagdollEntity()) and client:GetRagdollEntity() or entity
if ((!client:ShouldDrawLocalPlayer() and IsValid(entity) and entity:IsRagdoll())
or (!LocalPlayer():Alive() and IsValid(ragdoll))) then
local ent = LocalPlayer():Alive() and entity or ragdoll
local index = ent:LookupAttachment("eyes")
if (index) then
local data = ent:GetAttachment(index)
if (data) then
view.origin = data.Pos
view.angles = data.Ang
end
return view
end
end
local menu = ix.gui.menu
local entityMenu = ix.menu.panel
if (IsValid(menu) and menu:IsVisible() and menu:GetCharacterOverview()) then
local newOrigin, newAngles, newFOV, bDrawPlayer = menu:GetOverviewInfo(origin, angles, fov)
view.drawviewer = bDrawPlayer
view.fov = newFOV
view.origin = newOrigin
view.angles = newAngles
elseif (IsValid(entityMenu)) then
view.angles = entityMenu:GetOverviewInfo(origin, angles)
end
return view
end
local hookRun = hook.Run
do
local aimLength = 0.35
local aimTime = 0
local aimEntity
local lastEntity
local lastTrace = {}
timer.Create("ixCheckTargetEntity", 0.1, 0, function()
local client = LocalPlayer()
local time = SysTime()
if (!IsValid(client)) then
return
end
local character = client:GetCharacter()
if (!character) then
return
end
lastTrace.start = client:GetShootPos()
lastTrace.endpos = lastTrace.start + client:GetAimVector(client) * 160
lastTrace.filter = client
lastTrace.mask = MASK_SHOT_HULL
lastEntity = util.TraceHull(lastTrace).Entity
if (lastEntity != aimEntity) then
aimTime = time + aimLength
aimEntity = lastEntity
end
local panel = ix.gui.entityInfo
local bShouldShow = time >= aimTime and (!IsValid(ix.gui.menu) or ix.gui.menu.bClosing) and
(!IsValid(ix.gui.characterMenu) or ix.gui.characterMenu.bClosing)
local bShouldPopulate = lastEntity.OnShouldPopulateEntityInfo and lastEntity:OnShouldPopulateEntityInfo() or true
if (bShouldShow and IsValid(lastEntity) and hookRun("ShouldPopulateEntityInfo", lastEntity) != false and
(lastEntity.PopulateEntityInfo or bShouldPopulate)) then
if (!IsValid(panel) or (IsValid(panel) and panel:GetEntity() != lastEntity)) then
if (IsValid(ix.gui.entityInfo)) then
ix.gui.entityInfo:Remove()
end
local infoPanel = vgui.Create(ix.option.Get("minimalTooltips", false) and "ixTooltipMinimal" or "ixTooltip")
local entityPlayer = lastEntity:GetNetVar("player")
if (entityPlayer) then
infoPanel:SetEntity(entityPlayer)
infoPanel.entity = lastEntity
else
infoPanel:SetEntity(lastEntity)
end
infoPanel:SetDrawArrow(true)
ix.gui.entityInfo = infoPanel
end
elseif (IsValid(panel)) then
panel:Remove()
end
end)
end
local mathApproach = math.Approach
local surface = surface
function GM:HUDPaintBackground()
local client = LocalPlayer()
if (!client:GetCharacter()) then
return
end
local frameTime = FrameTime()
local scrW, scrH = ScrW(), ScrH()
if (hasVignetteMaterial and ix.config.Get("vignette")) then
vignetteAlphaDelta = mathApproach(vignetteAlphaDelta, vignetteAlphaGoal, frameTime * 30)
surface.SetDrawColor(0, 0, 0, 175 + vignetteAlphaDelta)
surface.SetMaterial(vignette)
surface.DrawTexturedRect(0, 0, scrW, scrH)
end
blurGoal = client:GetLocalVar("blur", 0) + (hookRun("AdjustBlurAmount", blurGoal) or 0)
if (blurDelta != blurGoal) then
blurDelta = mathApproach(blurDelta, blurGoal, frameTime * 20)
end
if (blurDelta > 0 and !client:ShouldDrawLocalPlayer()) then
ix.util.DrawBlurAt(0, 0, scrW, scrH, blurDelta)
end
self.BaseClass:PaintWorldTips()
local weapon = client:GetActiveWeapon()
if (IsValid(weapon) and hook.Run("CanDrawAmmoHUD", weapon) != false and weapon.DrawAmmo != false) then
local clip = weapon:Clip1()
local clipMax = weapon:GetMaxClip1()
local count = client:GetAmmoCount(weapon:GetPrimaryAmmoType())
local secondary = client:GetAmmoCount(weapon:GetSecondaryAmmoType())
local x, y = scrW - 80, scrH - 80
if (secondary > 0) then
ix.util.DrawBlurAt(x, y, 64, 64)
surface.SetDrawColor(255, 255, 255, 5)
surface.DrawRect(x, y, 64, 64)
surface.SetDrawColor(255, 255, 255, 3)
surface.DrawOutlinedRect(x, y, 64, 64)
ix.util.DrawText(secondary, x + 32, y + 32, nil, 1, 1, "ixBigFont")
end
if (weapon:GetClass() != "weapon_slam" and clip > 0 or count > 0) then
x = x - (secondary > 0 and 144 or 64)
ix.util.DrawBlurAt(x, y, 128, 64)
surface.SetDrawColor(255, 255, 255, 5)
surface.DrawRect(x, y, 128, 64)
surface.SetDrawColor(255, 255, 255, 3)
surface.DrawOutlinedRect(x, y, 128, 64)
ix.util.DrawText((clip == -1 or clipMax == -1) and count or clip.."/"..count, x + 64, y + 32, nil, 1, 1, "ixBigFont")
end
end
if (client:GetLocalVar("restricted") and !client:GetLocalVar("restrictNoMsg")) then
ix.util.DrawText(L"restricted", scrW * 0.5, scrH * 0.33, nil, 1, 1, "ixBigFont")
end
end
function GM:PostDrawOpaqueRenderables(bDepth, bSkybox)
if (bDepth or bSkybox or #ix.blurRenderQueue == 0) then
return
end
ix.util.ResetStencilValues()
render.SetStencilEnable(true)
render.SetStencilWriteMask(27)
render.SetStencilTestMask(27)
render.SetStencilFailOperation(STENCILOPERATION_KEEP)
render.SetStencilZFailOperation(STENCILOPERATION_KEEP)
render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_ALWAYS)
render.SetStencilReferenceValue(27)
for i = 1, #ix.blurRenderQueue do
ix.blurRenderQueue[i]()
end
render.SetStencilReferenceValue(34)
render.SetStencilCompareFunction(STENCILCOMPARISONFUNCTION_EQUAL)
render.SetStencilPassOperation(STENCILOPERATION_REPLACE)
render.SetStencilReferenceValue(27)
cam.Start2D()
ix.util.DrawBlurAt(0, 0, ScrW(), ScrH())
cam.End2D()
render.SetStencilEnable(false)
ix.blurRenderQueue = {}
end
function GM:PostDrawHUD()
cam.Start2D()
ix.hud.DrawAll()
if (!IsValid(ix.gui.deathScreen) and (!IsValid(ix.gui.characterMenu) or ix.gui.characterMenu:IsClosing())) then
ix.bar.DrawAction()
end
cam.End2D()
end
function GM:ShouldPopulateEntityInfo(entity)
local client = LocalPlayer()
local ragdoll = Entity(client:GetLocalVar("ragdoll", 0))
local entityPlayer = entity:GetNetVar("player")
if (vgui.CursorVisible() or !client:Alive() or IsValid(ragdoll) or entity == client or entityPlayer == client) then
return false
end
end
local injTextTable = {
[.3] = {"injMajor", Color(192, 57, 43)},
[.6] = {"injLittle", Color(231, 76, 60)},
}
function GM:GetInjuredText(client)
local health = client:Health()
for k, v in pairs(injTextTable) do
if ((health / client:GetMaxHealth()) < k) then
return v[1], v[2]
end
end
end
function GM:PopulateImportantCharacterInfo(client, character, container)
local color = team.GetColor(client:Team())
container:SetArrowColor(color)
-- name
local name = container:AddRow("name")
name:SetImportant()
name:SetText(hookRun("GetCharacterName", client) or character:GetName())
name:SetBackgroundColor(color)
name:SizeToContents()
-- injured text
local injureText, injureTextColor = hookRun("GetInjuredText", client)
if (injureText) then
local injure = container:AddRow("injureText")
injure:SetText(L(injureText))
injure:SetBackgroundColor(injureTextColor)
injure:SizeToContents()
end
end
function GM:PopulateCharacterInfo(client, character, container)
-- description
local descriptionText = character:GetDescription()
descriptionText = (descriptionText:utf8len() > 128 and
string.format("%s...", descriptionText:utf8sub(1, 125)) or
descriptionText)
if (descriptionText != "") then
local description = container:AddRow("description")
description:SetText(descriptionText)
description:SizeToContents()
end
end
function GM:KeyRelease(client, key)
if (!IsFirstTimePredicted()) then
return
end
if (key == IN_USE) then
if (!ix.menu.IsOpen()) 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 isfunction(entity.GetEntityMenu)) then
hook.Run("ShowEntityMenu", entity)
end
end
timer.Remove("ixItemUse")
client.ixInteractionTarget = nil
client.ixInteractionStartTime = nil
end
end
function GM:PlayerBindPress(client, bind, pressed)
bind = bind:lower()
if (bind:find("use") and pressed) then
local pickupTime = ix.config.Get("itemPickupTime", 0.5)
if (pickupTime > 0) 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 entity.ShowPlayerInteraction and !ix.menu.IsOpen()) then
client.ixInteractionTarget = entity
client.ixInteractionStartTime = SysTime()
timer.Create("ixItemUse", pickupTime, 1, function()
client.ixInteractionTarget = nil
client.ixInteractionStartTime = nil
end)
end
end
elseif (bind:find("jump")) then
local entity = Entity(client:GetLocalVar("ragdoll", 0))
if (IsValid(entity)) then
ix.command.Send("CharGetUp")
end
elseif (bind:find("speed") and client:KeyDown(IN_WALK) and pressed) then
if (LocalPlayer():Crouching()) then
RunConsoleCommand("-duck")
else
RunConsoleCommand("+duck")
end
end
end
function GM:CreateMove(command)
if ((IsValid(ix.gui.characterMenu) and !ix.gui.characterMenu.bClosing) or
(IsValid(ix.gui.menu) and !ix.gui.menu.bClosing and ix.gui.menu:GetActiveTab() == "you")) then
command:ClearButtons()
command:ClearMovement()
end
end
-- Called when use has been pressed on an item.
function GM:ShowEntityMenu(entity)
local options = entity:GetEntityMenu(LocalPlayer())
if (istable(options) and !table.IsEmpty(options)) then
ix.menu.Open(options, entity)
end
end
local hidden = {}
hidden["CHudHealth"] = true
hidden["CHudBattery"] = true
hidden["CHudAmmo"] = true
hidden["CHudSecondaryAmmo"] = true
hidden["CHudCrosshair"] = true
hidden["CHudHistoryResource"] = true
hidden["CHudPoisonDamageIndicator"] = true
hidden["CHudSquadStatus"] = true
hidden["CHUDQuickInfo"] = true
function GM:HUDShouldDraw(element)
if (hidden[element]) then
return false
end
return true
end
function GM:ShouldDrawLocalPlayer(client)
if (IsValid(ix.gui.characterMenu) and ix.gui.characterMenu:IsVisible()) then
return false
end
end
function GM:PostProcessPermitted(class)
return false
end
function GM:RenderScreenspaceEffects()
local menu = ix.gui.menu
if (IsValid(menu) and menu:GetCharacterOverview()) then
local client = LocalPlayer()
local target = client:GetObserverTarget()
local weapon = client:GetActiveWeapon()
cam.Start3D()
ix.util.ResetStencilValues()
render.SetStencilEnable(true)
render.SuppressEngineLighting(true)
cam.IgnoreZ(true)
render.SetColorModulation(1, 1, 1)
render.SetStencilWriteMask(28)
render.SetStencilTestMask(28)
render.SetStencilReferenceValue(28)
render.SetStencilCompareFunction(STENCIL_ALWAYS)
render.SetStencilPassOperation(STENCIL_REPLACE)
render.SetStencilFailOperation(STENCIL_KEEP)
render.SetStencilZFailOperation(STENCIL_KEEP)
if (IsValid(target)) then
target:DrawModel()
else
client:DrawModel()
end
if (IsValid(weapon)) then
weapon:DrawModel()
end
hook.Run("DrawCharacterOverview")
render.SetStencilCompareFunction(STENCIL_NOTEQUAL)
render.SetStencilPassOperation(STENCIL_KEEP)
cam.Start2D()
derma.SkinFunc("DrawCharacterStatusBackground", menu, menu.overviewFraction)
cam.End2D()
cam.IgnoreZ(false)
render.SuppressEngineLighting(false)
render.SetStencilEnable(false)
cam.End3D()
end
end
function GM:ShowPlayerOptions(client, options)
options["viewProfile"] = {"icon16/user.png", function()
if (IsValid(client)) then
client:ShowProfile()
end
end}
options["Copy Steam ID"] = {"icon16/user.png", function()
if (IsValid(client)) then
SetClipboardText(client:SteamID())
end
end}
end
function GM:DrawHelixModelView(panel, ent)
if (ent.weapon and IsValid(ent.weapon)) then
ent.weapon:DrawModel()
end
end
net.Receive("ixStringRequest", function()
local time = net.ReadUInt(32)
local title, subTitle = net.ReadString(), net.ReadString()
local default = net.ReadString()
if (title:sub(1, 1) == "@") then
title = L(title:sub(2))
end
if (subTitle:sub(1, 1) == "@") then
subTitle = L(subTitle:sub(2))
end
Derma_StringRequest(title, subTitle, default or "", function(text)
net.Start("ixStringRequest")
net.WriteUInt(time, 32)
net.WriteString(text)
net.SendToServer()
end)
end)
net.Receive("ixPlayerDeath", function()
if (IsValid(ix.gui.deathScreen)) then
ix.gui.deathScreen:Remove()
end
ix.gui.deathScreen = vgui.Create("ixDeathScreen")
end)
function GM:Think()
local client = LocalPlayer()
if (IsValid(client) and client:Alive() and client.ixRaisedTween) then
client.ixRaisedTween:update(FrameTime())
end
end
function GM:ScreenResolutionChanged(oldW, oldH)
hook.Run("LoadFonts", ix.config.Get("font"), ix.config.Get("genericFont"))
if (IsValid(ix.gui.notices)) then
ix.gui.notices:Remove()
ix.gui.notices = vgui.Create("ixNoticeManager")
end
if (IsValid(ix.gui.bars)) then
ix.gui.bars:Remove()
ix.gui.bars = vgui.Create("ixInfoBarManager")
end
end
function GM:DrawDeathNotice()
return false
end
function GM:HUDAmmoPickedUp()
return false
end
function GM:HUDDrawPickupHistory()
return false
end
function GM:HUDDrawTargetID()
return false
end
function GM:BuildBusinessMenu()
if (!ix.config.Get("allowBusiness", true)) then
return false
end
end
gameevent.Listen("player_spawn")
hook.Add("player_spawn", "ixPlayerSpawn", function(data)
local client = Player(data.userid)
if (IsValid(client)) then
-- GetBoneName returns __INVALIDBONE__ for everything the first time you use it, so we'll force an update to make them valid
client:SetupBones()
client:SetIK(false)
if (client == LocalPlayer() and (IsValid(ix.gui.deathScreen) and !ix.gui.deathScreen:IsClosing())) then
ix.gui.deathScreen:Close()
end
end
end)

View File

@@ -0,0 +1,657 @@
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)
if (!ix.config.Get("allowBusiness", true)) then
return false
end
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() and !IsValid(client:GetHoldingEntity())) 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
return false, "@charBanned"
else
if (banned > os.time()) then
return false, "@charBannedTemp"
end
end
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
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 k, _ in inventory:Iter() do
if (k: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)
return item.invID == client:GetCharacter():GetInventory():GetID()
end
function GM:CanPlayerUnequipItem(client, item)
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,910 @@
util.AddNetworkString("ixPlayerDeath")
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 character = ix.char.New({
name = client:Name(),
faction = faction and faction.uniqueID or "unknown",
model = faction and table.Random(faction:GetModels(client)) or "models/gman.mdl"
}, 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 player.Iterator() 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, data)
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 (action == "combine") then
local other = data[1]
if (hook.Run("CanPlayerCombineItem", client, item, other) == false) then
return false
end
local combineItem = ix.item.instances[other]
if (combineItem and combineItem.invID != 0) then
local combineInv = ix.item.inventories[combineItem.invID]
if (!combineInv:OnCheckAccess(client)) then
return false
end
else
return false
end
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:CanPlayerCombineItem(client, item, other)
end
function GM:PlayerShouldTakeDamage(client, attacker)
return client:GetCharacter() != nil
end
function GM:GetFallDamage(client, speed)
return math.max(0, (speed - 526.5) * 0.75)
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:UniqueID()
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) and chatType != "ic") 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
return hook.Run("CanPlayerPickupEntity", client, entity) == true
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 player.Iterator() 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 player.Iterator() 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: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) then return end
local inventory = character:GetInventory()
if (inventory and !isnumber(inventory)) then
for k, _ in inventory:Iter() do
k:Call("OnLoadout", client)
if (k:GetData("equip") and k.attribBoosts) then
for attribKey, attribValue in pairs(k.attribBoosts) do
character:AddBoost(k.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 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
hook.Add("PlayerDeath", "SyncDeathTimeWithScreen", function(ply)
local duration = ix.config.Get("deathScreenDuration", 5.5)
ply:SetNetVar("deathTime", CurTime() + duration)
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 player.Iterator() 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 player.Iterator() do
v:SaveData()
if (v:GetCharacter()) then
v:GetCharacter():Save()
end
end
end
function GM:GetGameDescription()
return (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)
-- Validate the physObj, to prevent errors on entities who have no physics object
if (!IsValid(physObj)) then return false end
-- Object is already frozen (!?)
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)
if (ix.allowedHoldableClasses[entity:GetClass()]) then
return true
end
return hook.Run("CanPlayerPickupEntity", client, entity) == true
end
function GM:PreCleanupMap()
hook.Run("SaveData")
hook.Run("PersistenceSave")
end
function GM:PostCleanupMap()
ix.plugin.RunLoadData()
end
function GM:CharacterPreSave(character)
if (!character) then return end
local client = character:GetPlayer()
local inventory = character:GetInventory()
if (inventory and !isnumber(inventory)) then
for k, _ in inventory:Iter() do
if (k.OnSave) then
k:Call("OnSave", client)
end
end
end
character:SetData("health", client:Alive() and client:Health() or nil)
end
timer.Create("ixLifeGuard", 1, 0, function()
for _, v in player.Iterator() 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)
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