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

View File

@@ -0,0 +1,274 @@
--[[
| 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/
--]]
local PLUGIN = PLUGIN
ix.hud.DrawDeath = function() end
do
local healthIcon = ix.util.GetMaterial("willardnetworks/hud/hp.png")
local armorIcon = ix.util.GetMaterial("willardnetworks/hud/armor.png")
function PLUGIN:DrawImportantBars(client, character, alwaysShow, minimalShow, DrawBar)
local maxHealth = client:GetMaxHealth()
local fractionHealth, fractionFakeHealth = client:Health() / maxHealth, character:GetHealing("fakeHealth") / maxHealth
if (alwaysShow or ((fractionHealth < 1 or fractionFakeHealth > 0) and (!minimalShow or (fractionHealth < 0.8 and fractionFakeHealth < 0.2)))) then
-- Health/Fake Health
if (fractionFakeHealth == 0) then
DrawBar(healthIcon, fractionHealth)
else
DrawBar(healthIcon, fractionHealth - fractionFakeHealth, fractionHealth)
end
end
-- Armor
if (alwaysShow or client:Armor() > 0) then
local isOTA = client:Team() == FACTION_OTA
if (alwaysShow or !minimalShow or (isOTA and client:Armor() != 150) or (!isOTA and client:Armor() != 50)) then
local fraction = client:Armor() / (isOTA and 150 or 50)
DrawBar(armorIcon, fraction, nil, (fraction > 1 and (fraction - 1)) or nil)
end
end
end
function PLUGIN:DrawAlertBars(client, character, DrawBar)
if (character:GetBleedout() > 0) then
DrawBar(L("areBleeding"))
end
end
local bleedoutMaterial = ix.util.GetMaterial("willardnetworks/nlrbleedout/bleedout-background.png")
function PLUGIN:DrawHUDOverlays(client, character)
local health = client:Health() * 100 / client:GetMaxHealth()
if (health <= 90) then
surface.SetDrawColor(Color(255, 0, 0, math.Remap(math.max(health, 0), 90, 0, 0, 80)))
surface.SetMaterial(bleedoutMaterial)
surface.DrawTexturedRect(0, 0, ScrW(), ScrH())
end
end
end
function PLUGIN:GetPlayerESPText(client, toDraw, distance, alphaFar, alphaMid, alphaClose)
local character = client:GetCharacter()
if (character:GetBleedout() > 0) then
toDraw[#toDraw + 1] = {alpha = alphaFar, priority = 3, text = "Bleedout: "..character:GetBleedout()}
end
if (character:GetHealing() and
(character:GetHealing("painkillers") > 0 or character:GetHealing("fakeHealth") > 0 or
character:GetHealing("bandage") > 0 or character:GetHealing("disinfectant") > 0)) then
local text1 = string.format("Healing: B:%d/D:%ds",
character:GetHealing("bandage"),
character:GetHealing("disinfectant")
)
toDraw[#toDraw + 1] = {alpha = alphaClose, priority = 22.001, text = text1}
if (character:GetHealing("painkillers") > 0 or character:GetHealing("fakeHealth") > 0) then
local text2 = string.format(" P:%d - %ds/F: %d",
character:GetHealing("painkillers"),
character:GetHealing("painkillersDuration"),
character:GetHealing("fakeHealth")
)
toDraw[#toDraw + 1] = {alpha = alphaClose, priority = 22.002, text = text2}
end
end
end
function PLUGIN:GetInjuredText(client)
if (!client:Alive()) then
return "injDead", self:GetColor(0)
end
local character = client:GetCharacter()
local health = client:Health()
local maxHealth = client:GetMaxHealth()
local bandage = character:GetHealing("bandage")
local disinfectant = character:GetHealing("disinfectant")
local fakeHealth = character:GetHealing("fakeHealth")
-- totalHealthFraction
local thf = math.Clamp((health - fakeHealth) / maxHealth, 0, 1)
if (character:GetBleedout() > 0) then
return "bleedingOut", self:GetColor(thf - 0.1)
end
if (bandage > 0) then
if ((!ix.action or character:CanDoAction("check_sufficient_bandage")) and bandage + (health - fakeHealth) >= maxHealth) then
if (disinfectant > 0) then
return "allBandagedDis", self:GetColor(thf + 0.3)
else
return "allBandaged", self:GetColor(thf + 0.2)
end
else
if (disinfectant > 0) then
return "someBandagedDis", self:GetColor(thf + 0.1)
else
return "someBandaged", self:GetColor(thf)
end
end
end
if (thf < 0) then
return "injWonder", self:GetColor(thf)
elseif (thf < 0.2) then
return "injNearDeath", self:GetColor(thf)
elseif (thf < 0.4) then
return "injCrit", self:GetColor(thf)
elseif (thf < 0.6) then
return "injMaj", self:GetColor(thf)
elseif (thf < 0.8) then
return "injLittle", self:GetColor(thf)
end
end
function PLUGIN:GetColor(totalHealthFraction)
return Color(
math.Clamp(255 * 2 * (1 - totalHealthFraction), 0, 255),
math.Clamp(255 * 2 * totalHealthFraction, 0, 255),
0
)
end
local function textStandard(parent, color, font, topMargin, text)
parent:Dock(TOP)
parent:DockMargin(0, SScaleMin(topMargin / 3), 0, 0)
parent:SetText(text)
parent:SetTextColor(color)
parent:SetFont(font)
parent:SetContentAlignment(5)
parent:SizeToContents()
end
function PLUGIN:HUDPaintBackground()
local client = LocalPlayer()
local character = client:GetCharacter()
if (!character) then return end
if ix.bleedout and ix.bleedout:IsVisible() then return end
if (client:GetLocalVar("blur", 0) > 0 and !client:ShouldDrawLocalPlayer()) and
character.wasBleeding then
if ix.gui.bleedoutTextBackground then
return
end
ix.gui.bleedoutTextBackground = vgui.Create("Panel")
ix.gui.bleedoutTextBackground:SetSize(ScrW(), ScrH())
ix.gui.bleedoutTextBackground.Paint = function(_, w, h)
surface.SetDrawColor(ColorAlpha(color_black, 200))
surface.DrawRect(0, 0, w, h)
end
local bleedoutTextPanel = ix.gui.bleedoutTextBackground:Add("Panel")
local hpInfoText = bleedoutTextPanel:Add("DLabel")
local requiredHealth = math.ceil(client:GetMaxHealth() * ix.config.Get("WakeupTreshold") / 100)
textStandard(hpInfoText, Color(200, 200, 200, 255), "TitlesFontNoBoldNoClamp", 0, L("requiredHealth", requiredHealth))
local currentHPText = bleedoutTextPanel:Add("DLabel")
textStandard(currentHPText, Color(255, 78, 79, 255), "TitlesFontNoBoldNoClamp", 10, L("currentHP", client:Health()))
timer.Create("CurrentHPTextUpdate", 1, 0, function()
if IsValid(currentHPText) then
currentHPText:SetText("Current HP: "..client:Health())
currentHPText:SizeToContents()
else
timer.Remove("CurrentHPTextUpdate")
end
end)
bleedoutTextPanel:SetSize(SScaleMin(520 / 3), hpInfoText:GetTall() + currentHPText:GetTall() + SScaleMin(10 / 3))
bleedoutTextPanel:Center()
local x, y = bleedoutTextPanel:GetPos()
bleedoutTextPanel:SetPos(x, y - SScaleMin(65 / 3)) -- center but with less y position because Atle
else
if ix.gui.bleedoutTextBackground then
ix.gui.bleedoutTextBackground:Remove()
ix.gui.bleedoutTextBackground = nil
end
if timer.Exists("CurrentHPTextUpdate_"..LocalPlayer():SteamID64()) then
timer.Remove("CurrentHPTextUpdate_"..LocalPlayer():SteamID64())
end
end
end
netstream.Hook("BleedoutScreen", function(bWasBleeding)
LocalPlayer():GetCharacter().wasBleeding = bWasBleeding
end)
netstream.Hook("ixDeathScreen", function()
if (IsValid(ix.bleedout)) then
ix.bleedout:Remove()
end
if (IsValid(ix.death)) then
ix.death:Remove()
end
ix.death = vgui.Create("ixDeathScreen")
end)
netstream.Hook("ixBleedoutScreen", function(time)
if (IsValid(ix.bleedout)) then
ix.bleedout:Remove()
end
if (IsValid(ix.death)) then
ix.death:Remove()
end
ix.bleedout = vgui.Create("ixBleedoutScreen")
ix.bleedout:SetTime(time)
end)
PLUGIN.netVars = {"table", "bandage", "disinfectant", "painkillers"}
net.Receive("ixHealingData", function(len)
local id = net.ReadUInt(32)
local character = ix.char.loaded[id]
local data = len > 32 and {} or nil
if (len > 32) then
local healType = PLUGIN.netVars[net.ReadUInt(2) + 1]
if (healType == "table") then
data.bandage = net.ReadUInt(16)
data.disinfectant = net.ReadUInt(16)
data.painkillers = net.ReadUInt(16)
data.painkillersDuration = net.ReadUInt(16)
data.healingAmount = net.ReadFloat()
data.fakeHealth = net.ReadFloat()
else
data[healType] = net.ReadUInt(16)
if (healType == "painkillers") then
data.painkillersDuration = ix.config.Get("HealingPainkillerDuration") * 60
end
end
else
if (character) then
character.vars.healing = nil
end
return
end
if (character) then
if (!character.vars.healing) then
character.vars.healing = data
else
for k, v in pairs(data) do
character.vars.healing[k] = v
end
end
end
end)

View File

@@ -0,0 +1,127 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
self.startTime = CurTime()
self.deathTime = 0
self:SetSize(ScrW(), ScrH())
self.Paint = function(self, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/nlrbleedout/bleedout-background.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
local padding = SScaleMin(5 / 3)
local textPanel = self:Add("Panel")
textPanel:SetSize(SScaleMin(520 / 3), SScaleMin(360 / 3))
textPanel:Center()
local x, y = textPanel:GetPos()
textPanel:SetPos(x, y - SScaleMin(65 / 3)) -- center but with less y position because Atle
textPanel.Paint = function(self, w, h)
surface.SetDrawColor(color_white)
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/nlrbleedout/bleedout-icon.png"))
surface.DrawTexturedRect(w * 0.5 - SScaleMin(42 / 3) * 0.5, 0, SScaleMin(42 / 3), SScaleMin(61 / 3))
end
local function textStandard(parent, color, font, topMargin, text)
parent:Dock(TOP)
parent:DockMargin(0, SScaleMin(topMargin / 3), 0, 0)
parent:SetText(text)
parent:SetTextColor(color)
parent:SetFont(font)
parent:SetContentAlignment(5)
parent:SizeToContents()
end
local bleedingTitle = textPanel:Add("DLabel")
textStandard(bleedingTitle, Color(234, 236, 233, 255), "WNBleedingTitleNoClamp", 61 + padding, string.utf8upper("you are bleeding")) -- 61 icon height
local bleedingText = textPanel:Add("DLabel")
textStandard(bleedingText, Color(200, 200, 200, 255), "WNBleedingTextNoClamp", -padding, "Youre incapacitated and require bandages to stay alive.")
local countdownPanel = textPanel:Add("Panel")
countdownPanel:SetSize(self:GetWide(), SScaleMin(46 / 3))
countdownPanel:Dock(TOP)
countdownPanel:DockMargin(0, padding * 4, 0, 0)
countdownPanel.Paint = function(pnl, w, h)
local curTime = CurTime()
surface.SetDrawColor(Color(0, 0, 0, 178)) -- 70% opacity
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(Color(112, 112, 112, 178)) -- 70% opacity
surface.DrawOutlinedRect(0, 0, w, h)
surface.SetDrawColor(Color(255, 78, 79, 255))
surface.DrawRect(SScaleMin(8 / 3), SScaleMin(8 / 3), (w * (1 - ((curTime - self.startTime) / (self.deathTime - self.startTime)))) - SScaleMin(16 / 3), h - SScaleMin(16 / 3)) -- make config here for countdown
end
self.timeLeftText = textPanel:Add("DLabel")
textStandard(self.timeLeftText, Color(255, 78, 69, 255), "WNBleedingMinutesBoldNoClamp", padding * 3, "")
function self.timeLeftText:SetTime(time)
self:SetText(string.utf8upper(time > 120 and math.Round(time / 60).." minutes" or math.Round(time, 1).." seconds"))
end
local controlText = textPanel:Add("DLabel")
textStandard(controlText, Color(200, 200, 200, 255), "WNBleedingTextNoClamp", -padding, "Hold E to accept your character's death.")
local hpInfoText = textPanel:Add("DLabel")
local requiredHealth = math.ceil(LocalPlayer():GetMaxHealth() * ix.config.Get("WakeupTreshold") / 100)
textStandard(hpInfoText, Color(200, 200, 200, 255), "TitlesFontNoBoldNoClamp", -padding + 15, "You need "..requiredHealth.."HP to get back up.")
local currentHPText = textPanel:Add("DLabel")
textStandard(currentHPText, Color(255, 78, 79, 255), "TitlesFontNoBoldNoClamp", -padding + 5, "Current HP: "..LocalPlayer():Health())
timer.Create("ixBleedout", 0.1, 0, function()
if (!IsValid(self)) then
timer.Remove("ixBleedout")
end
textStandard(currentHPText, Color(255, 78, 79, 255), "TitlesFontNoBoldNoClamp", -padding + 5, "Current HP: "..LocalPlayer():Health())
if (LocalPlayer():GetCharacter()) then
if LocalPlayer():GetCharacter().GetBleedout then
if (LocalPlayer():GetCharacter():GetBleedout() < 0) then
self:Remove()
timer.Remove("ixBleedout")
return
end
end
end
local curTime = CurTime()
if (input.IsKeyDown(KEY_E) and ix.gui.chat.entry:GetText() == "") then -- Make sure the player isn't typing in chat
self.deathTime = self.deathTime - (self.deathTime - self.startTime) * 0.025
end
self.timeLeftText:SetTime(self.deathTime - curTime)
if (self.deathTime <= curTime) then
netstream.Start("ixAcceptDeath")
self:Remove()
end
end)
end
function PANEL:OnRemove()
timer.Remove("ixBleedout")
end
function PANEL:SetTime(time)
self.startTime = CurTime()
self.deathTime = self.startTime + time
end
vgui.Register("ixBleedoutScreen", PANEL, "EditablePanel")

View File

@@ -0,0 +1,79 @@
--[[
| 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/
--]]
local PANEL = {}
function PANEL:Init()
self:SetSize(ScrW(), ScrH())
self:MakePopup()
self.Paint = function(self, w, h)
Derma_DrawBackgroundBlur( self, 1 )
surface.SetDrawColor(Color(255, 255, 255, 80))
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/nlrbleedout/nlr-background.png"))
surface.DrawTexturedRect(0, 0, w, h)
end
Schema:AllowMessage(self)
local padding = 5
local textPanel = self:Add("Panel")
textPanel:SetSize(SScaleMin(520 / 3), SScaleMin(300 / 3))
textPanel:Center()
local x, y = textPanel:GetPos()
textPanel:SetPos(x, y - SScaleMin(65 / 3)) -- center but with less y position because Atle
textPanel.Paint = function(self, w, h)
surface.SetDrawColor(Color(255, 255, 255, 255))
surface.SetMaterial(ix.util.GetMaterial("willardnetworks/nlrbleedout/nlr-icon.png"))
surface.DrawTexturedRect(w * 0.5 - SScaleMin(77 / 3) * 0.5, 0, SScaleMin(77 / 3), SScaleMin(78 / 3))
end
local function textStandard(parent, color, font, topMargin, text)
parent:Dock(TOP)
parent:DockMargin(0, SScaleMin(topMargin / 3), 0, 0)
parent:SetText(text)
parent:SetTextColor(color)
parent:SetFont(font)
parent:SetContentAlignment(5)
parent:SizeToContents()
end
local nlrTitle = textPanel:Add("DLabel")
textStandard(nlrTitle, Color(234, 236, 233, 255), "WNBleedingTitleNoClamp", 78 + padding, string.utf8upper("you are dead")) -- 78 icon height
local nlrText = textPanel:Add("DLabel")
local nlrText2 = textPanel:Add("DLabel")
local nlrText3 = textPanel:Add("DLabel")
textStandard(nlrText, Color(200, 200, 200, 255), "WNBleedingTextNoClamp", -padding, "New life rule applies, your inventory is reset")
textStandard(nlrText2, Color(200, 200, 200, 255), "WNBleedingTextNoClamp", -padding, "and your skill levels are reduced.")
textStandard(nlrText3, Color(200, 200, 200, 255), "WNBleedingTextBold", -padding + 10, "You may perform one final /me action on this screen.")
local okayButton = textPanel:Add("DButton")
okayButton:SetSize(self:GetWide(), SScaleMin(46 / 3))
okayButton:Dock(TOP)
okayButton:SetText("Okay")
okayButton:SetFont("MenuFontNoClamp")
okayButton:DockMargin(SScaleMin(175 / 3), padding * 4, SScaleMin(175 / 3), 0)
okayButton.Paint = function(self, w, h)
surface.SetDrawColor(Color(0, 0, 0, 178))
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(Color(112, 112, 112, 178))
surface.DrawOutlinedRect(0, 0, w, h)
end
okayButton.DoClick = function()
netstream.Start("ixConfirmRespawn")
self:Remove()
end
end
vgui.Register("ixDeathScreen", PANEL, "EditablePanel")

View File

@@ -0,0 +1,299 @@
--[[
| 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/
--]]
ITEM.name = "Medical Item"
ITEM.model = "models/Items/BoxSRounds.mdl"
ITEM.width = 1
ITEM.height = 1
ITEM.description = "A small roll of hand-made gauze."
ITEM.category = "Medical"
ITEM.useSound = "items/medshot4.wav"
ITEM.base = "base_stackable"
ITEM.bInstanceMaxstack = true
ITEM.usableInCombat = false
function ITEM:GetBoostAppend()
local boostAppend = {}
if (ix.special and self.boosts) then
boostAppend[#boostAppend + 1] = "SHORT-TERM BOOSTS:\n"
if (self.boosts.strength) then
boostAppend[#boostAppend + 1] = string.format("Strength: %d\n", self.boosts.strength)
end
if (self.boosts.agility) then
boostAppend[#boostAppend + 1] = string.format("Agility: %d\n", self.boosts.agility)
end
if (self.boosts.intelligence) then
boostAppend[#boostAppend + 1] = string.format("Intelligence: %d\n", self.boosts.intelligence)
end
if (self.boosts.perception) then
boostAppend[#boostAppend + 1] = string.format("Perception: %d", self.boosts.perception)
end
end
return table.concat(boostAppend, "")
end
function ITEM:GetHealingAppend()
local character = LocalPlayer():GetCharacter()
local healingAppend = {}
if (character and self.healing) then
healingAppend[#healingAppend + 1] = "HEALING:\n"
if (self.healing.bandage) then
healingAppend[#healingAppend + 1] = string.format("Bandage: %dHP\n", self.healing.bandage * (1 + character:GetSkillScale("bandage_skill")))
end
if (self.healing.disinfectant) then
healingAppend[#healingAppend + 1] = string.format("Disinfectant: %dHP\n", self.healing.disinfectant * (1 + character:GetSkillScale("disinfectant_skill")))
end
if (self.healing.painkillers) then
healingAppend[#healingAppend + 1] = string.format("Painkillers: %dHP", self.healing.painkillers)
end
end
return table.concat(healingAppend, "")
end
function ITEM:GetColorAppendix()
if (!ix.special) then return false end
if self.boosts and self.healing then
return {["yellow"] = self:GetBoostAppend(), ["green"] = self:GetHealingAppend()}
elseif self.boosts and !self.healing then
return {["yellow"] = self:GetBoostAppend()}
elseif !self.boosts and self.healing then
return {["green"] = self:GetHealingAppend()}
else
return false
end
end
ITEM.action = {
skill = "medicine",
level = function(action, character, skillLevel, target, item, bNotify)
local requiredLevel = -1
if (item.GetLevel) then
requiredLevel = item:GetLevel(action, character, skillLevel, target)
elseif (item.level) then
requiredLevel = item.level
end
if (requiredLevel <= skillLevel) then
return true
else
if (bNotify) then
character:GetPlayer():NotifyLocalized("medicalRequiredLevel", requiredLevel)
end
return false
end
end,
experience = function(action, character, skillLevel, target, item)
if (item.healing) then
local exp = 0
local targetChar = target:GetCharacter()
local healingData = targetChar:GetHealing() or {bandage = 0, disinfectant = 0, fakeHealth = 0, painkillers = 0}
local missingHealth = target:GetMaxHealth() - target:Health()
if (item.healing.bandage) then
local healingLeft = missingHealth - (healingData.bandage or 0) + (healingData.fakeHealth or 0)
exp = exp + math.min(healingLeft, item.healing.bandage) * ix.config.Get("ExperienceBandageScale", 1)
end
if (item.healing.disinfectant) then
local disinfectant = item.healing.disinfectant * (1 + character:GetSkillScale("disinfectant_skill")) * 60 /
(ix.config.Get("HealingRegenRate") * ix.config.Get("HealingRegenBoostFactor"))
if (disinfectant > (healingData.disinfectant or 0)) then
exp = exp + math.min(item.healing.disinfectant, (1 - healingData.disinfectant / disinfectant) * missingHealth) * ix.config.Get("ExperienceDisinfectantScale", 1)
end
end
if (item.healing.painkillers) then
exp = exp + math.min(item.healing.painkillers, missingHealth - (healingData.painkillers or 0)) * ix.config.Get("ExperiencePainkillerScale", 1)
end
return exp
end
end
}
ITEM.functions.use = {
name = "Use on yourself",
tip = "applyTip",
icon = "icon16/user.png",
OnCanRun = function(item)
local character = item.player:GetCharacter()
if (item.player:Health() >= item.player:GetMaxHealth() and !(ix.special and item.boosts)) then
if (character:GetHealing("fakeHealth") == 0 and
(character:GetBleedout() == -1 or !item.healing or !item.healing.bandage)) then
return false
end
end
if (timer.Exists("combattimer" .. item.player:SteamID64()) and !item.usableInCombat) then
item.player:Notify("You cannot use this item while in combat.")
return false
end
if (item.action and ix.action) then
return character:CanDoAction("item_"..item.uniqueID, item.player, item, SERVER)
end
return true
end,
OnRun = function(item)
local character = item.player:GetCharacter()
local player = item.player
item.player:Freeze(true)
item.player:SetAction("Applying medical...", 3, function()
if !IsValid(player) then return end
player:Freeze(false)
end)
if (item.action and ix.action) then
-- Do action before healing is given for exp calculation
character:DoAction("item_"..item.uniqueID, item.player, item)
end
if (item.healing) then
for k, v in pairs(item.healing) do
character:SetHealing(k, v, character)
end
if (item.healing.bandage) then
character:SetBleedout(-1)
end
end
if (ix.special and item.boosts) then
for k, v in pairs(item.boosts) do
character:SetSpecialBoost(k, v, true)
end
end
item.player:EmitSound(item.useSound, 110)
if (item:IsSingleItem()) then
-- Spawn the junk item if it exists
if (item.junk) then
if (!character:GetInventory():Add(item.junk)) then
ix.item.Spawn(item.junk, item.player)
end
end
end
return true
end,
}
-- On player uneqipped the item, Removes a weapon from the player and keep the ammo in the item.
ITEM.functions.give = {
name = "Use on character",
tip = "giveTip",
icon = "icon16/user_go.png",
OnCanRun = function(item)
if (item.entity) then return false end
local trace = item.player:GetEyeTraceNoCursor()
local target = trace.Entity
if (!IsValid(target)) then
return false
end
if (CLIENT and target:GetClass() == "prop_ragdoll") then
return true
end
if (IsValid(target.ixPlayer)) then
target = target.ixPlayer
end
if (!target:IsPlayer() or !target:GetCharacter()) then
return false
end
if (target:Health() >= target:GetMaxHealth() and !(ix.special and item.boosts)) then
local targetChar = target:GetCharacter()
if (targetChar:GetHealing("fakeHealth") == 0 and
(targetChar:GetBleedout() == -1 or !item.healing or !item.healing.bandage)) then
return false
end
end
if (item.action and ix.action) then
local result = item.player:GetCharacter():CanDoAction("item_"..item.uniqueID, item.player, item, SERVER)
return result
end
return true
end,
OnRun = function(item)
local target = item.player:GetEyeTraceNoCursor().Entity
if (!IsValid(target)) then
return false
end
if (IsValid(target.ixPlayer)) then
target = target.ixPlayer
end
local targetChar = target:GetCharacter()
local playerChar = item.player:GetCharacter()
local player = item.player
item.player:Freeze(true)
target:Freeze(true)
item.player:SetAction("Applying medical...", 3, function()
if !IsValid(player) then return end
player:Freeze(false)
target:Freeze(false)
end)
if (item.action and ix.action) then
-- Do action before healing is given for exp calculation
playerChar:DoAction("item_"..item.uniqueID, target, item)
end
if (item.healing) then
for k, v in pairs(item.healing) do
targetChar:SetHealing(k, v, playerChar)
end
if (item.healing.bandage) then
targetChar:SetBleedout(-1)
end
end
if (ix.special and item.boosts) then
for k, v in pairs(item.boosts) do
targetChar:SetSpecialBoost(k, v, true)
end
end
item.player:EmitSound(item.useSound, 110)
if (item:IsSingleItem()) then
-- Spawn the junk item if it exists
if (item.junk) then
if (!playerChar:GetInventory():Add(item.junk)) then
ix.item.Spawn(item.junk, item.player)
end
end
end
return true
end,
}

View File

@@ -0,0 +1,231 @@
--[[
| 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/
--]]
local PLUGIN = PLUGIN
PLUGIN.name = "Medical"
PLUGIN.author = "Gr4Ss"
PLUGIN.description = "Implements a heal-over-time medical system as well as bleedout before death."
-- Round healing to 5 digits
-- This should give at least 3 significant digits for passive health regen
PLUGIN.HEALING_PRECISION = 5
-- How often the medical system should update
-- Existing timers won't update until a charswap when lua refreshing this value
PLUGIN.TIMER_DELAY = PLUGIN.TIMER_DELAY or 5
ix.util.Include("cl_hooks.lua")
ix.util.Include("sv_hooks.lua")
ix.util.Include("sv_plugin.lua")
ix.lang.AddTable("english", {
applyTip = "Apply the item to yourself",
giveTip = "Apply the item to the person you are looking at",
allBandaged = "All wounds are bandaged",
allBandagedDis = "All wounds are cleaned and bandaged",
someBandaged = "Some wounds are bandaged",
someBandagedDis = "Some wounds are cleaned and bandaged",
bleedingOut = "Bleeding to death",
unconscious = "Not responding to anything",
injDead = "They appear to be dead",
injWonder = "They are still alive!? How?",
injNearDeath = "They are near death",
injCrit = "In critical condition",
injMaj = "Has some major wounds",
medicalRequiredLevel = "You need at least level %d medical to do this!",
cmdCharGetHealing = "Prints current healing data for a character.",
healingListEmpty = "%s does not have any healing active.",
healingList = "%s's healing data: %d hp | %.2fHP bandage | %is disinfectant | %.2fHP painkiller | %is painkiller duration | %.2fHP fake health | %.3f fractional HP",
cmdCharStopBleedout = "Stops the bleedout on the given character. Does not give any health.",
bleedoutStopped = "You have stopped %s's bleeding.",
bleedoutStoppedTarget = "%s has stopped your bleeding.",
bleedoutNotActive = "%s is not bleeding out currently.",
areBleeding = "YOU ARE BLEEDING",
currentHP = "Current HP: %d",
requiredHealth = "You need %dHP to get back up.",
cannotChangeCharBleedout = "You cannot change character while bleeding out!"
})
ix.lang.AddTable("spanish", {
giveTip = "Aplica el objeto a la persona que estás mirando",
allBandagedDis = "Todas las heridas son limpiadas y vendadas",
injWonder = "¿¡Todavía está vivo!? ¿Cómo?",
bleedingOut = "Desangrándose hasta la muerte",
injNearDeath = "Está al borde de la muerte",
unconscious = "No responde a nada",
allBandaged = "Todas las heridas están vendadas",
applyTip = "Aplicarte el objeto a ti mismo",
injDead = "Parece estar muerto",
someBandaged = "Algunas heridas están vendadas",
bleedoutStoppedTarget = "%s ha detenido tu hemorragia.",
medicalRequiredLevel = "¡Necesitas al menos nivel %d de medicina para hacer esto!",
healingListEmpty = "%s no tiene ninguna curación activa.",
areBleeding = "TE ESTÁS DESANGRANDO",
cmdCharStopBleedout = "Detiene la hemorragia del personaje. No añade salud.",
injCrit = "En condición crítica",
bleedoutNotActive = "%s no está sangrando actualmente.",
bleedoutStopped = "Has detenido la hemorragia de %s.",
cannotChangeCharBleedout = "¡No puedes cambiar de personaje mientras te desangras!",
injMaj = "Tiene algunas heridas graves",
requiredHealth = "Necesitas %d Puntos de Vida para levantarte.",
currentHP = "Puntos de Vida actuales: %d",
cmdCharGetHealing = "Imprime los datos de curación actuales de un personaje.",
someBandagedDis = "Algunas heridas están limpias y vendadas",
healingList = "Datos de curación de %s: %d hp | %.2fHP de vendaje | %is desinfectando | %.2fHP analgésico | %is duración del analgésico | %.2fHP falso | %3.f HP fraccional"
})
ix.config.Add("HealthRegenTime", 6, "How many hours it takes for someone to passively regain full health.", nil, {
data = {min = 0, max = 24},
category = "Medical"
})
ix.config.Add("HealingRegenRate", 5, "How much health healing items will restore per minute.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("HealingRegenBoostFactor", 2,
"How much faster someone heals when using healing boosters (e.g. disinfectant).", nil, {
data = {min = 0, max = 100, decimals = 1},
category = "Medical"
})
ix.config.Add("HealingPainkillerRate", 30, "How much health per minute painkillers temporarily restore.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("HealingPainkillerDuration", 15, "How long painkillers will last in minutes.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("HealingPainkillerDecayRate", 10,
"How fast painkillers decay after their duration ran out in HP per minute.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("BleedoutTime", 10, "How many minutes it takes for someone to bleedout and die.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("WakeupTreshold", 33,
"How much health someone needs to wake up after being knocked unconscious into bleedout.", nil, {
data = {min = 1, max = 100},
category = "Medical"
})
ix.config.Add("ExperienceBandageScale", 1,
"Scale how much experience is gained from bandaging a wound. 1 means 1 exp per HP healed, 2 is 2 exp per HP healed, etc.", nil, {
data = {min = 0, max = 10, decimals = 1},
category = "Medical"
})
ix.config.Add("ExperienceDisinfectantScale", 1,
"Scale how much experience is gained from speeding up bandage health-regen with disinfectant. 1 means 1 exp per HP sped up, 2 is 2 exp per HP sped up, etc.", nil, {
data = {min = 0, max = 10, decimals = 1},
category = "Medical"
})
ix.config.Add("ExperiencePainkillerScale", 1,
"Scale how much experience is gained from giving painkillers to temporarily replenish health. 1 means 1 exp per HP replenished, 2 is 2 exp per HP replenished, etc.", nil, {
data = {min = 0, max = 10, decimals = 1},
category = "Medical"
})
ix.config.Add("bleedoutGodmode", false,
"Determines if all damage is blocked against players who are ragdolled due to bleedout. This protection stops once the player is no longer ragdolled, or the player's bleedout is stopped (even if they are still ragdolled).", nil, {
category = "Medical"
})
ix.config.Add("AdditionalBleedoutGrace", 30,
"How long the additional bleedout grace timer lasts.", nil, {
data = {min = 0, max = 600},
category = "Medical"
})
ix.command.Add("CharGetHealing", {
description = "@cmdCharGetHealing",
adminOnly = true,
arguments = {
ix.type.character
},
OnRun = function(self, client, target)
local healingData = target:GetHealing()
if (!healingData) then
client:ChatNotifyLocalized("healingListEmpty", target:GetPlayer():Name())
return
end
client:ChatNotifyLocalized(
"healingList",
target:GetPlayer():Name(),
target:GetPlayer():Health(),
healingData.bandage,
healingData.disinfectant,
healingData.painkillers,
healingData.painkillersDuration,
healingData.fakeHealth,
healingData.healingAmount
)
end
})
ix.command.Add("CharStopBleedout", {
description = "@cmdCharStopBleedout",
adminOnly = true,
arguments = {
ix.type.character
},
OnRun = function(self, client, target)
if (target:GetBleedout() > 0) then
target:SetBleedout(-1)
netstream.Start("BleedoutScreen", false)
client:NotifyLocalized("bleedoutStopped", target:GetPlayer():Name())
if (target:GetPlayer() != client) then
target:GetPlayer():NotifyLocalized("bleedoutStoppedTarget", client:Name())
end
else
client:NotifyLocalized("bleedoutNotActive", target:GetPlayer():Name())
end
end
})
ix.char.RegisterVar("bleedout", {
bNoDisplay = true,
default = -1
})
ix.char.RegisterVar("healing", {
default = {},
field = "healing",
fieldType = ix.type.text,
OnSet = PLUGIN.OnSetHealing,
OnGet = function(character, healType)
local healing = character.vars.healing
if (healType) then
return (healing and healing[healType] != nil and healing[healType]) or 0
else
return healing
end
end
})

View File

@@ -0,0 +1,195 @@
--[[
| 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/
--]]
local PLUGIN = PLUGIN
local IsValid = IsValid
local RealTime = RealTime
local ix = ix
local timer = timer
PLUGIN.minHealthLeft = 2
--[[
function PLUGIN:CanPlayerHoldObject(client, entity)
if (entity:GetClass() == "prop_ragdoll" and IsValid(entity.ixPlayer) and entity.bleedoutGetup) then
return entity.ixPlayer:GetCharacter():GetBleedout() <= 0 or !ix.faction.Get(client:Team()).isDefault
end
end
--]]
function PLUGIN:CanPlayerUseCharacter(client, character)
if (IsValid(client.ixRagdoll) and client.ixRagdoll.bleedoutGetup == true) then
return false, "@cannotChangeCharBleedout"
end
end
function PLUGIN:CalculatePlayerDamage(victim, damage)
-- Damage grace for people who just got downed
if (victim.bleedoutDamageGrace and victim.bleedoutDamageGrace > RealTime()) then
damage:SetDamage(0)
return true
end
if (ix.config.Get("bleedoutGodmode") and victim:GetCharacter() and victim:GetCharacter():GetBleedout() != -1 and victim.ixRagdoll and victim.ixRagdoll.bleedoutGetup) then
damage:SetDamage(0)
return true
end
end
function PLUGIN:PlayerHurt(client, attacker, healthRemaining, damageTaken)
if (damageTaken <= 0) then return end
if (IsValid(client.ixScn)) then return end
if (IsValid(attacker) and attacker:GetClass() == "npc_headcrab_black") then return end
local character = client:GetCharacter()
if (!character) then return end
local targetMaxBandage = client:GetMaxHealth() - client:Health() - damageTaken
character:SetHealing("bandage_damage", math.max(damageTaken, character:GetHealing("bandage") - targetMaxBandage))
end
function PLUGIN:HandlePlayerDeath(client, damage)
if (IsValid(client) and client:IsPlayer()) then
local character = client:GetCharacter()
if (!character) then
return
end
hook.Run("PrePlayerBleedout", client)
client:AddFlags(FL_NOTARGET)
local fight = ix.fights and character:GetFight()
if (fight) then
character:SetFight()
end
if (character:GetBleedout() == -1) then
local bleedoutTime = ix.config.Get("BleedoutTime") * 60
client.bleedoutDamageGrace = RealTime() + 0.5 + ix.config.Get("AdditionalBleedoutGrace", 0)
character:SetBleedout(bleedoutTime)
netstream.Start(client, "BleedoutScreen", true)
client:SetHealth(self.minHealthLeft)
if (!IsValid(client.ixRagdoll)) then
client:SetRagdolled(true, nil, bleedoutTime + 60)
elseif (client.ixRagdoll.ixStart) then
client.ixRagdoll.ixStart = nil
client.ixRagdoll.ixFinish = nil
timer.Remove("ixUnRagdoll" .. client:SteamID())
client:SetAction()
end
if (client.ixRagdoll) then
client.ixRagdoll.ixGrace = nil
client.ixRagdoll.bleedoutGetup = true
end
if (client:HasActiveTracker()) then
ix.combineNotify:AddImportantNotification("WRN:// Unit " .. client:GetCombineTag() .. " vital signs critical", nil, client, client:GetPos(), nil, client:GetCombineTag())
end
if ix.plugin.Get("vortigaunts") then
if damage:GetAttacker():IsPlayer() and damage:GetAttacker():IsVortigaunt() then
ix.plugin.Get("vortigaunts"):HandlePlayerKill(client, damage:GetAttacker())
end
end
netstream.Start(client, "ixBleedoutScreen", bleedoutTime)
ix.log.Add(client, "medicalBleedoutKO")
return false
else
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll.ixNoReset = true
end
ix.log.Add(client, "medicalBleedoutKilled")
end
end
end
function PLUGIN:PrePlayerLoadedCharacter(client)
client.ixLoadingChar = true
end
function PLUGIN:PlayerSpawn(client)
if (client.ixLoadingChar == true) then
client.ixLoadingChar = nil
return
end
local character = client:GetCharacter()
if (character) then
character:SetBleedout(-1)
netstream.Start(client, "BleedoutScreen", false)
end
end
local errorFunc = function(msg)
ErrorNoHaltWithStack("[MEDICAL]"..msg.."\n")
end
function PLUGIN:PlayerLoadedCharacter(client, character, lastChar)
local uniqueID = "ixHealing" .. client:SteamID64()
local ticks = self.TIMER_DELAY
timer.Create(uniqueID, ticks, 0, function()
if (IsValid(client)) then
if (ix.fights and client:GetFight() and !client:GetFight().s2kActive) then
return
end
xpcall(PLUGIN.MedicalPlayerTick, errorFunc, PLUGIN, client, ticks)
else
timer.Remove(uniqueID)
end
end)
if (character:GetHealing() and table.IsEmpty(character:GetHealing())) then
character:SetHealing("table", nil)
end
end
function PLUGIN:FirefightTurnEnd(fight, fightInfo, character)
if (!fightInfo.lastMedicalTick or fightInfo.lastMedicalTick < CurTime()) then
self:MedicalPlayerTick(character:GetPlayer(), 5)
fightInfo.lastMedicalTick = CurTime() + 5
end
end
function PLUGIN:PlayerDeath(client, attacker, damageinfo)
local character = client:GetCharacter()
if (character) then
character:SetHealing("table", nil)
character:SetBleedout(-1)
client.lastMeExpended = false
netstream.Start(client, "BleedoutScreen", false)
netstream.Start(client, "ixDeathScreen")
end
end
function PLUGIN:PlayerDeathThink(client)
if (client.confirmRespawn) then
client.confirmRespawn = nil
client:Spawn()
else
return false
end
end
function PLUGIN:PlayerMessageSend(speaker, chatType)
if (chatType == "me" or chatType == "mel" or chatType == "mec" and !speaker:Alive()) then
speaker.lastMeExpended = true
end
end

View File

@@ -0,0 +1,356 @@
--[[
| 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/
--]]
local PLUGIN = PLUGIN
local IsValid = IsValid
local ix = ix
local math = math
util.AddNetworkString("ixHealingData")
ix.log.AddType("medicalBleedoutKO", function(client)
return string.format("%s was knocked unconscious and is bleeding out.", client:GetName())
end, FLAG_DANGER)
ix.log.AddType("medicalBleedoutKilled", function(client)
return string.format("%s was killed while bleeding out.", client:GetName())
end, FLAG_DANGER)
ix.log.AddType("medicalBleedoutStop", function(client)
return string.format("%s is no longer unconscious from critical wounds.", client:GetName())
end)
ix.log.AddType("medicalBleedout", function(client)
return string.format("%s bled out.", client:GetName())
end, FLAG_DANGER)
ix.log.AddType("medicalFullyHealed", function(client)
return string.format("%s is fully healed.", client:GetName())
end)
ix.log.AddType("medicalPainkillersNoHP", function(client)
return string.format("%s ran out of health.", client:GetName())
end, FLAG_DANGER)
ix.log.AddType("medicalPainkillersTooMany", function(client)
return string.format("%s took too many painkillers.", client:GetName())
end, FLAG_DANGER)
ix.log.AddType("medicalBleedoutStoppedBy", function(client, givenBy)
return string.format("%s's bleeding was stopped by %s.", client:Name(), givenBy:GetPlayer():Name())
end)
ix.log.AddType("medicalBandagedBy", function(client, givenBy, amount)
return string.format("%s was bandaged by %s for %d HP.", client:Name(), givenBy:GetPlayer():Name(), amount)
end)
ix.log.AddType("medicalDisinfectedBy", function(client, givenBy, amount)
if (amount) then
return string.format("%s was disinfected by %s for %d seconds.", client:Name(), givenBy:GetPlayer():Name(), amount)
else
return string.format("%s tried to disinfect %s but the wound was already clean.", givenBy:GetPlayer():Name(), client:Name())
end
end)
function PLUGIN:MedicalPlayerTick(client, ticks)
local character = client:GetCharacter()
if (!character) then return end
if (!client:Alive()) then
return
end
local health = client:Health()
local maxHealth = client:GetMaxHealth()
local bMaxHealth = health >= maxHealth
if (!bMaxHealth or character:GetHealing("fakeHealth") > 0) then
local factor = 1
if (character:GetHealing("disinfectant") > 0) then
factor = ix.config.Get("HealingRegenBoostFactor") * 5
end
local passiveHealAmount = ticks * factor * maxHealth / (ix.config.Get("HealthRegenTime") * 3600)
if character:GetConterminous() then
passiveHealAmount = passiveHealAmount * ix.config.Get("ConterminusHealingIncrease", 1)
end
character:SetHealing("passive", passiveHealAmount)
end
if (IsValid(client.ixRagdoll) and client:Alive() and client.ixRagdoll.bleedoutGetup and
(health * 100 / maxHealth) >= ix.config.Get("WakeupTreshold")) then
client:SetRagdolled(false)
netstream.Start("BleedoutScreen", false)
ix.log.Add(client, "medicalBleedoutStop")
client:RemoveFlags(FL_NOTARGET)
end
-- Do bleedout stuff
local bleedout = character:GetBleedout()
if (bleedout > 0) then
bleedout = bleedout - ticks
if (bleedout <= 0) then
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll.ixNoReset = true
end
character:SetBleedout(-1)
client:SetNetVar("deathTime", nil)
client:Kill()
ix.log.Add(client, "medicalBleedout")
return
else
self:BleedoutPainSound(client)
character:SetBleedout(bleedout)
end
end
local healingData = character:GetHealing()
if (!healingData) then
return
end
-- Apply healing from bandages
if (healingData.bandage > 0) then
local healingAmount = ticks * ix.config.Get("HealingRegenRate") / 60
if (healingData.disinfectant > 0) then -- Boost if disinfected
healingAmount = healingAmount * ix.config.Get("HealingRegenBoostFactor")
healingData.disinfectant = math.max(healingData.disinfectant - ticks, 0)
end
-- Give healRate or whatever is left
if (healingData.bandage > healingAmount) then
healingData.healingAmount = math.Round(healingData.healingAmount + healingAmount, self.HEALING_PRECISION)
healingData.bandage = math.Round(healingData.bandage - healingAmount, self.HEALING_PRECISION)
else
healingData.healingAmount = math.Round(healingData.healingAmount + healingData.bandage, self.HEALING_PRECISION)
healingData.bandage = 0
end
elseif (healingData.disinfectant and healingData.disinfectant > 0) then
healingData.disinfectant = math.max(healingData.disinfectant - ticks * 2, 0)
end
-- Apply fake healing from painkillers
if (healingData.painkillers > 0) then
local fakeAmount = ticks * ix.config.Get("HealingPainkillerRate") / 60
if (healingData.painkillers > fakeAmount) then
if (!bMaxHealth) then -- Only actually kill pain if not at max health
healingData.fakeHealth = math.Round(healingData.fakeHealth + fakeAmount, self.HEALING_PRECISION)
healingData.healingAmount = math.Round(healingData.healingAmount + fakeAmount, self.HEALING_PRECISION)
end
healingData.painkillers = math.Round(healingData.painkillers - fakeAmount, self.HEALING_PRECISION)
else
if (!bMaxHealth) then -- Only actually kill pain if not at max health
healingData.healingAmount = math.Round(healingData.healingAmount + healingData.painkillers, self.HEALING_PRECISION)
healingData.fakeHealth = math.Round(healingData.fakeHealth + healingData.painkillers, self.HEALING_PRECISION)
end
healingData.painkillers = 0
end
end
-- Check if painkillers are still working
if (healingData.painkillersDuration > 0) then
-- Reduce duration
healingData.painkillersDuration = math.max(healingData.painkillersDuration - ticks, 0)
end
-- At max health?
if (bMaxHealth) then
-- Check if there is any fake health we can heal
if (healingData.fakeHealth > 0 and healingData.healingAmount > 0) then
if (healingData.fakeHealth > healingData.healingAmount) then
healingData.fakeHealth = healingData.fakeHealth - healingData.healingAmount
healingData.healingAmount = 0
else
healingData.healingAmount = healingData.healingAmount - healingData.fakeHealth
healingData.fakeHealth = 0
end
end
-- At max health and no full health point of fake healing left
if (healingData.fakeHealth - healingData.healingAmount < 1) then
character:SetHealing("table", nil) -- Stop healing!
ix.log.Add(client, "medicalFullyHealed")
return
end
end
-- Uh oh, the painkillers ran out... time to bring back the pain
if (healingData.painkillersDuration == 0 and healingData.fakeHealth > 0) then
local fakeAmount = ticks * ix.config.Get("HealingPainkillerDecayRate") / 60
if (healingData.fakeHealth > fakeAmount) then
healingData.healingAmount = math.Round(healingData.healingAmount - fakeAmount, self.HEALING_PRECISION)
healingData.fakeHealth = math.Round(healingData.fakeHealth - fakeAmount, self.HEALING_PRECISION)
else
healingData.healingAmount = math.Round(healingData.healingAmount - healingData.fakeHealth, self.HEALING_PRECISION)
healingData.fakeHealth = 0
end
end
-- Check if we can heal/damage for at least one point of HP
if ((!bMaxHealth and healingData.healingAmount >= 1) or healingData.healingAmount <= -1) then
if (healingData.healingAmount >= 1 or healingData.healingAmount <= -1) then
-- Source engine can only handle integer values for HP so...
-- Heal as many integer points of HP as we can and save the fraction left for the future
local totalHealing = math.min(math.Truncate(healingData.healingAmount), maxHealth - health)
healingData.healingAmount = healingData.healingAmount - totalHealing
client:SetHealth(math.min(health + totalHealing, maxHealth))
if (client:Health() <= 0) then
client:Kill()
ix.log.Add(client, "medicalPainkillersNoHP")
character:SetHealing("table", nil)
return
end
end
end
if (healingData.fakeHealth - client:Health() > maxHealth * 1.1) then
client:Kill()
ix.log.Add(client, "medicalPainkillersTooMany")
character:SetHealing("table", nil)
return
end
character:SetHealing("table", healingData)
end
function PLUGIN.OnSetHealing(character, healType, value, givenBy)
if (!healType) then
ErrorNoHalt("Attempted to set healing but no type was provided!")
return
end
if (healType == "table") then
character.vars.healing = value
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
if (character.vars.healing) then
net.WriteUInt(0, 2)
net.WriteUInt(value.bandage, 16)
net.WriteUInt(value.disinfectant, 16)
net.WriteUInt(value.painkillers, 16)
net.WriteUInt(value.painkillersDuration, 16)
net.WriteFloat(value.healingAmount)
net.WriteFloat(value.fakeHealth)
end
net.Broadcast()
else
if (!value or value <= 0) then
ErrorNoHalt("Attempted to give '"..healType.."' healing with invalid value ("..(value or "nil")..")!")
return
end
local healingData = character:GetHealing()
if (!healingData or !healingData.bandage) then
healingData = {
bandage = 0,
disinfectant = 0,
painkillers = 0,
painkillersDuration = 0,
healingAmount = 0,
fakeHealth = 0
}
end
if (healType == "bandage") then
value = value * (givenBy and (1 + givenBy:GetSkillScale("bandage_skill")) or 1)
healingData.bandage = healingData.bandage + value
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
net.WriteUInt(1, 2)
net.WriteUInt(healingData.bandage, 16)
net.Broadcast()
if (character:GetBleedout() > 0) then
character:SetBleedout(-1)
ix.log.Add(character:GetPlayer(), "medicalBleedoutStoppedBy", givenBy)
end
if (givenBy) then
ix.log.Add(character:GetPlayer(), "medicalBandagedBy", givenBy, value)
end
elseif (healType == "bandage_damage") then
healingData.bandage = math.max(healingData.bandage - value, 0)
healingData.painkillers = 0
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
net.WriteUInt(1, 2)
net.WriteUInt(healingData.bandage, 16)
net.Broadcast()
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
net.WriteUInt(3, 2)
net.WriteUInt(healingData.painkillers, 16)
net.Broadcast()
elseif (healType == "disinfectant") then
value = value * (1 + givenBy:GetSkillScale("disinfectant_skill")) * 60 /
(ix.config.Get("HealingRegenRate") * ix.config.Get("HealingRegenBoostFactor"))
healingData.disinfectant = math.max(healingData.disinfectant, value)
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
net.WriteUInt(2, 2)
net.WriteUInt(healingData.disinfectant, 16)
net.Broadcast()
if (givenBy) then
ix.log.Add(character:GetPlayer(), "medicalDisinfectedBy", givenBy, healingData.disinfectant == value and value)
end
elseif (healType == "painkillers") then
healingData.painkillers = healingData.painkillers + value
healingData.painkillersDuration = ix.config.Get("HealingPainkillerDuration") * 60
net.Start("ixHealingData")
net.WriteUInt(character:GetID(), 32)
net.WriteUInt(3, 2)
net.WriteUInt(healingData.painkillers, 16)
net.Broadcast()
elseif (healType == "passive") then
healingData.healingAmount = math.Round(healingData.healingAmount + value, PLUGIN.HEALING_PRECISION)
end
character.vars.healing = healingData
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")
}
function PLUGIN:BleedoutPainSound(client)
if ((client.ixNextPain or 0) < CurTime() and math.random() < 0.1) 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() + 5
end
end
netstream.Hook("ixConfirmRespawn", function(client)
client.confirmRespawn = true
end)
netstream.Hook("ixAcceptDeath", function(client)
if (IsValid(client.ixRagdoll)) then
client.ixRagdoll.ixNoReset = true
end
if (!client:GetCharacter()) then return end
client:GetCharacter():SetBleedout(-1)
client:SetNetVar("deathTime", nil)
client:Kill()
ix.log.Add(client, "qolDeathLog", "accepting their death")
end)