Files
BarotraumaModServer/LocalMods/Neurotrauma/Lua/Scripts/helperfunctions.lua
2026-06-09 00:42:10 +03:00

1219 lines
40 KiBLFS
Lua
Executable File

-- This file contains a bunch of useful functions that see heavy use in the other scripts.
LuaUserData.RegisterType("Barotrauma.ModUtils+Logging")
local Logging = LuaUserData.CreateStatic("Barotrauma.ModUtils+Logging")
local function TraceError(errorMessage)
if errorMessage then
errorMessage = "Neurotrauma Error: " .. errorMessage
else
errorMessage = "Neurotrauma Error"
end
--second argument means traceback level, 2 means we exclude topmoost aka this function
Logging.PrintError(debug.traceback(errorMessage, 2))
end
local LimbNames = {}
for key, value in pairs(LimbType) do
LimbNames[value] = key
end
-- Neurotrauma functions
function NT.DislocateLimb(character, limbtype, strength)
strength = strength or 1
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "dislocation1"
limbtoaffliction[LimbType.LeftLeg] = "dislocation2"
limbtoaffliction[LimbType.RightArm] = "dislocation3"
limbtoaffliction[LimbType.LeftArm] = "dislocation4"
if limbtoaffliction[limbtype] == nil then return end
HF.AddAffliction(character, limbtoaffliction[limbtype], strength)
end
function NT.BreakLimb(character, limbtype, strength)
strength = strength or 5
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "rl_fracture"
limbtoaffliction[LimbType.LeftLeg] = "ll_fracture"
limbtoaffliction[LimbType.RightArm] = "ra_fracture"
limbtoaffliction[LimbType.LeftArm] = "la_fracture"
limbtoaffliction[LimbType.Head] = "h_fracture"
limbtoaffliction[LimbType.Torso] = "t_fracture"
if limbtoaffliction[limbtype] == nil then return end
HF.AddAffliction(character, limbtoaffliction[limbtype], strength)
if strength > 0 and NTConfig.Get("NT_fracturesRemoveCasts", true) then
HF.SetAfflictionLimb(character, "gypsumcast", limbtype, 0)
end
end
function NT.SurgicallyAmputateLimbAndGenerateItem(usingCharacter, targetCharacter, limbtype)
-- drop previously worn headgear item
local previtem = HF.GetHeadWear(targetCharacter)
if previtem ~= nil and limbtype == LimbType.Head then previtem.Drop(usingCharacter, true) end
local droplimb = not NT.LimbIsAmputated(targetCharacter, limbtype)
and not HF.HasAfflictionLimb(targetCharacter, "gangrene", limbtype, 15)
NT.SurgicallyAmputateLimb(targetCharacter, limbtype)
if droplimb then
local limbtoitem = {}
limbtoitem[LimbType.RightLeg] = "rleg"
limbtoitem[LimbType.LeftLeg] = "lleg"
limbtoitem[LimbType.RightArm] = "rarm"
limbtoitem[LimbType.LeftArm] = "larm"
limbtoitem[LimbType.Head] = "headsa"
if limbtoitem[limbtype] ~= nil then
HF.GiveItem(usingCharacter, limbtoitem[limbtype])
HF.GiveSurgerySkill(usingCharacter, 0.5)
end
end
end
function NT.SurgicallyAmputateLimb(character, limbtype, strength, traumampstrength)
strength = strength or 100
traumampstrength = traumampstrength or 0
limbtype = HF.NormalizeLimbType(limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "srl_amputation"
limbtoaffliction[LimbType.LeftLeg] = "sll_amputation"
limbtoaffliction[LimbType.RightArm] = "sra_amputation"
limbtoaffliction[LimbType.LeftArm] = "sla_amputation"
limbtoaffliction[LimbType.Head] = "sh_amputation"
if limbtoaffliction[limbtype] == nil then return end
HF.SetAffliction(character, limbtoaffliction[limbtype], strength)
limbtoaffliction[LimbType.RightLeg] = "trl_amputation"
limbtoaffliction[LimbType.LeftLeg] = "tll_amputation"
limbtoaffliction[LimbType.RightArm] = "tra_amputation"
limbtoaffliction[LimbType.LeftArm] = "tla_amputation"
limbtoaffliction[LimbType.Head] = "th_amputation"
HF.SetAffliction(character, limbtoaffliction[limbtype], traumampstrength)
HF.SetAfflictionLimb(character, "gangrene", limbtype, 0)
end
function NT.TraumamputateLimb(character, limbtype, attacker)
limbtype = HF.NormalizeLimbType(limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "gate_ta_rl"
limbtoaffliction[LimbType.LeftLeg] = "gate_ta_ll"
limbtoaffliction[LimbType.RightArm] = "gate_ta_ra"
limbtoaffliction[LimbType.LeftArm] = "gate_ta_la"
limbtoaffliction[LimbType.Head] = "gate_ta_h"
if limbtoaffliction[limbtype] == nil then return end
local limbtoitem = {}
limbtoitem[LimbType.RightLeg] = "rleg"
limbtoitem[LimbType.LeftLeg] = "lleg"
limbtoitem[LimbType.RightArm] = "rarm"
limbtoitem[LimbType.LeftArm] = "larm"
limbtoitem[LimbType.Head] = "headta"
-- (optional parameter) if attacker is a monster with free inventory slot, give them the limb instead
if limbtoitem[limbtype] ~= nil then
if attacker ~= nil and not attacker.IsHuman and not attacker.Inventory.IsFull() then
HF.GiveItem(attacker, limbtoitem[limbtype])
HF.AddAfflictionLimb(character, limbtoaffliction[limbtype] .. "_2", limbtype, 10)
else
HF.AddAfflictionLimb(character, limbtoaffliction[limbtype], limbtype, 10)
end
end
end
function NT.TraumamputateLimbMinusItem(character, limbtype)
limbtype = HF.NormalizeLimbType(limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "gate_ta_rl_2"
limbtoaffliction[LimbType.LeftLeg] = "gate_ta_ll_2"
limbtoaffliction[LimbType.RightArm] = "gate_ta_ra_2"
limbtoaffliction[LimbType.LeftArm] = "gate_ta_la_2"
limbtoaffliction[LimbType.Head] = "gate_ta_h_2"
if limbtoaffliction[limbtype] == nil then return end
HF.AddAfflictionLimb(character, limbtoaffliction[limbtype], limbtype, 10)
end
function NT.ArteryCutLimb(character, limbtype, strength)
strength = strength or 5
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "rl_arterialcut"
limbtoaffliction[LimbType.LeftLeg] = "ll_arterialcut"
limbtoaffliction[LimbType.RightArm] = "ra_arterialcut"
limbtoaffliction[LimbType.LeftArm] = "la_arterialcut"
limbtoaffliction[LimbType.Head] = "h_arterialcut"
limbtoaffliction[LimbType.Torso] = "t_arterialcut"
if limbtoaffliction[limbtype] == nil then return end
HF.AddAffliction(character, limbtoaffliction[limbtype], strength)
end
function NT.LimbIsDislocated(character, limbtype, isarm)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "dislocation1"
limbtoaffliction[LimbType.LeftLeg] = "dislocation2"
limbtoaffliction[LimbType.RightArm] = "dislocation3"
limbtoaffliction[LimbType.LeftArm] = "dislocation4"
if limbtoaffliction[limbtype] == nil then return false end
if isarm then
return HF.HasAffliction(character, limbtoaffliction[limbtype], 100)
else
return HF.HasAffliction(character, limbtoaffliction[limbtype], 1)
end
end
function NT.LimbIsBroken(character, limbtype, isarm)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "rl_fracture"
limbtoaffliction[LimbType.LeftLeg] = "ll_fracture"
limbtoaffliction[LimbType.RightArm] = "ra_fracture"
limbtoaffliction[LimbType.LeftArm] = "la_fracture"
if limbtoaffliction[limbtype] == nil then return false end
if isarm then
return HF.HasAffliction(character, limbtoaffliction[limbtype], 100)
else
return HF.HasAffliction(character, limbtoaffliction[limbtype], 1)
end
end
function NT.LimbIsArterialCut(character, limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "rl_arterialcut"
limbtoaffliction[LimbType.LeftLeg] = "ll_arterialcut"
limbtoaffliction[LimbType.RightArm] = "ra_arterialcut"
limbtoaffliction[LimbType.LeftArm] = "la_arterialcut"
limbtoaffliction[LimbType.Head] = "h_arterialcut"
limbtoaffliction[LimbType.Torso] = "t_arterialcut"
if limbtoaffliction[limbtype] == nil then return false end
return HF.HasAffliction(character, limbtoaffliction[limbtype], 1)
end
function NT.LimbIsAmputated(character, limbtype)
return NT.LimbIsTraumaticallyAmputated(character, limbtype) or NT.LimbIsSurgicallyAmputated(character, limbtype)
end
function NT.LimbIsTraumaticallyAmputated(character, limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "trl_amputation"
limbtoaffliction[LimbType.LeftLeg] = "tll_amputation"
limbtoaffliction[LimbType.RightArm] = "tra_amputation"
limbtoaffliction[LimbType.LeftArm] = "tla_amputation"
limbtoaffliction[LimbType.Head] = "th_amputation"
if limbtoaffliction[limbtype] == nil then return false end
return HF.HasAffliction(character, limbtoaffliction[limbtype], 0.1)
end
function NT.LimbIsSurgicallyAmputated(character, limbtype)
local limbtoaffliction = {}
limbtoaffliction[LimbType.RightLeg] = "srl_amputation"
limbtoaffliction[LimbType.LeftLeg] = "sll_amputation"
limbtoaffliction[LimbType.RightArm] = "sra_amputation"
limbtoaffliction[LimbType.LeftArm] = "sla_amputation"
limbtoaffliction[LimbType.Head] = "sh_amputation"
if limbtoaffliction[limbtype] == nil then return false end
return HF.HasAffliction(character, limbtoaffliction[limbtype], 0.1)
end
function NT.Fibrillate(character, amount)
-- tachycardia (increased heartrate) ->
-- fibrillation (irregular heartbeat) ->
-- cardiacarrest
-- fetch values
local tachycardia = HF.GetAfflictionStrength(character, "tachycardia", 0)
local fibrillation = HF.GetAfflictionStrength(character, "fibrillation", 0)
local cardiacarrest = HF.GetAfflictionStrength(character, "cardiacarrest", 0)
-- already in cardiac arrest? don't do anything
if cardiacarrest > 0 then return end
-- determine total amount of fibrillation, then determine afflictions from that
local previousAmount = tachycardia / 5
if fibrillation > 0 then previousAmount = 20 + fibrillation end
local newAmount = previousAmount + amount
-- 0-20: 0-100% tachycardia
-- 20-120: 0-100% fibrillation
-- >120: cardiac arrest
if newAmount < 20 then
-- 0-20: 0-100% tachycardia
tachycardia = newAmount * 5
fibrillation = 0
elseif newAmount < 120 then
-- 20-120: 0-100% fibrillation
tachycardia = 0
fibrillation = newAmount - 20
else
-- >120: cardiac arrest
tachycardia = 0
fibrillation = 0
HF.SetAffliction(character, "cardiacarrest", 10)
end
HF.SetAffliction(character, "tachycardia", tachycardia)
HF.SetAffliction(character, "fibrillation", fibrillation)
end
HF = {} -- Helperfunctions
function HF.Lerp(a, b, t)
return a + (b - a) * t
end
function HF.Round(num, numDecimalPlaces)
local mult = 10 ^ (numDecimalPlaces or 0)
return math.floor(num * mult + 0.5) / mult
end
function HF.Clamp(num, min, max)
if num < min then
num = min
elseif num > max then
num = max
end
return num
end
-- returns num if num > min, else defaultvalue
function HF.Minimum(num, min, defaultvalue)
if num < min then num = (defaultvalue or 0) end
return num
end
function HF.DistanceBetween(point1, point2)
local xd = point1.X - point2.X
local yd = point1.Y - point2.Y
return math.sqrt(xd * xd + yd * yd)
end
function HF.FindDepth(item)
if SERVER then
return Level.Loaded.GetRealWorldDepth(item.WorldPosition.Y)
else
return item.WorldPosition.Y * Physics.DisplayToRealWorldRatio
end
end
-- /// affliction magic ///
------------------------------
function HF.GetAfflictionStrength(character, identifier, defaultvalue)
if character == nil or character.CharacterHealth == nil then return defaultvalue end
local aff = character.CharacterHealth.GetAffliction(identifier)
local res = defaultvalue or 0
if aff ~= nil then res = aff.Strength end
return res
end
function HF.GetAfflictionStrengthLimb(character, limbtype, identifier, defaultvalue)
if character == nil or character.CharacterHealth == nil or character.AnimController == nil then
return defaultvalue
end
local limb = character.AnimController.GetLimb(limbtype)
if limb == nil then return defaultvalue end
local aff = character.CharacterHealth.GetAffliction(identifier, limb)
local res = defaultvalue or 0
if aff ~= nil then res = aff.Strength end
return res
end
function HF.HasAffliction(character, identifier, minamount)
if character == nil or character.CharacterHealth == nil then return false end
local aff = character.CharacterHealth.GetAffliction(identifier)
local res = false
if aff ~= nil then res = aff.Strength >= (minamount or 0.5) end
return res
end
function HF.HasAfflictionLimb(character, identifier, limbtype, minamount)
local limb = character.AnimController.GetLimb(limbtype)
if limb == nil then return false end
local aff = character.CharacterHealth.GetAffliction(identifier, limb)
local res = false
if aff ~= nil then res = aff.Strength >= (minamount or 0.5) end
return res
end
-- this might be overkill, but a lot of people have reported dislocation fixing issues
function HF.HasAfflictionExtremity(character, identifier, limbtype, minamount)
local aff = nil
if limbtype == LimbType.LeftArm or limbtype == LimbType.LeftForearm or limbtype == LimbType.LeftHand then
aff = character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.LeftArm))
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.LeftForearm)
)
end
if aff == nil then
aff =
character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.LeftHand))
end
elseif limbtype == LimbType.RightArm or limbtype == LimbType.RightForearm or limbtype == LimbType.RightHand then
aff = character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.RightArm))
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.RightForearm)
)
end
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.RightHand)
)
end
elseif limbtype == LimbType.LeftLeg or limbtype == LimbType.LeftThigh or limbtype == LimbType.LeftFoot then
aff = character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.LeftLeg))
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.LeftThigh)
)
end
if aff == nil then
aff =
character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.LeftFoot))
end
elseif limbtype == LimbType.RightLeg or limbtype == LimbType.RightThigh or limbtype == LimbType.RightFoot then
aff = character.CharacterHealth.GetAffliction(identifier, character.AnimController.GetLimb(LimbType.RightLeg))
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.RightThigh)
)
end
if aff == nil then
aff = character.CharacterHealth.GetAffliction(
identifier,
character.AnimController.GetLimb(LimbType.RightFoot)
)
end
end
local res = false
if aff ~= nil then res = aff.Strength >= (minamount or 0.5) end
return res
end
function HF.SetAffliction(character, identifier, strength, aggressor, prevstrength)
HF.SetAfflictionLimb(character, identifier, LimbType.Torso, strength, aggressor, prevstrength)
end
-- the main "mess with afflictions" function
function HF.SetAfflictionLimb(character, identifier, limbtype, strength, aggressor, prevstrength)
local _, prefab = AfflictionPrefab.Prefabs.TryGet(identifier)
if not character or not limbtype or not prefab then
TraceError(
string.format(
"Can't apply affliction to character limb\ncharacter = %s, limbtype = %s, affliction = %s, strength = %s",
character and tostring(character.Name) or "nil",
limbtype and LimbNames[limbtype] or limbtype or "nil",
prefab and string.format("%s (%s)", tostring(prefab.Name), tostring(prefab.Identifier))
or tostring(identifier)
or "nil",
strength and string.format("%.3f", strength) or "nil"
)
)
return
end
local resistance = character.CharacterHealth.GetResistance(prefab, limbtype)
if resistance >= 1 then return end
-- We need to reverse the resistance effect so that proper values are given in our CharacterHealth.ApplyAffliction, as we are using this command for our internal affliction updates and functions, that do not account for resistance in the first place.
local strength = strength * character.CharacterHealth.MaxVitality / 100 / (1 - resistance)
local affliction = prefab.Instantiate(strength, aggressor)
local recalculateVitality = NTC.AfflictionsAffectingVitality[identifier] ~= nil
character.CharacterHealth.ApplyAffliction(
character.AnimController.GetLimb(limbtype),
affliction,
false,
false,
recalculateVitality
)
-- turn target aggressive if damaging
-- if(aggressor ~= nil and character~=aggressor) then
-- if prevstrength == nil then prevstrength = 0 end
--
-- local dmg = affliction.GetVitalityDecrease(character.CharacterHealth,strength-prevstrength)
--
-- if (dmg ~= nil and dmg > 0) then
-- MakeAggressive(aggressor,character,dmg)
-- end
-- end
end
function HF.ApplyAfflictionChange(character, identifier, strength, prevstrength, minstrength, maxstrength)
strength = HF.Clamp(strength, minstrength, maxstrength)
prevstrength = HF.Clamp(prevstrength, minstrength, maxstrength)
if prevstrength ~= strength then HF.SetAffliction(character, identifier, strength) end
end
function HF.ApplyAfflictionChangeLimb(character, limbtype, identifier, strength, prevstrength, minstrength, maxstrength)
strength = HF.Clamp(strength, minstrength, maxstrength)
prevstrength = HF.Clamp(prevstrength, minstrength, maxstrength)
if prevstrength ~= strength then HF.SetAfflictionLimb(character, identifier, limbtype, strength) end
end
function HF.ApplySymptom(character, identifier, hassymptom, removeifnot)
if not hassymptom and not removeifnot then return end
local strength = 0
if hassymptom then strength = 100 end
if removeifnot or hassymptom then HF.SetAffliction(character, identifier, strength) end
end
function HF.ApplySymptomLimb(character, limbtype, identifier, hassymptom, removeifnot)
if not hassymptom and not removeifnot then return end
local strength = 0
if hassymptom then strength = 100 end
if removeifnot or hassymptom then HF.SetAfflictionLimb(character, identifier, limbtype, strength) end
end
function HF.AddAfflictionLimb(character, identifier, limbtype, strength, aggressor)
if strength < 0 then
character.CharacterHealth.ReduceAfflictionOnLimb(
character.AnimController.GetLimb(limbtype),
identifier,
-strength,
nil,
aggressor
)
return
end
local prevstrength = HF.GetAfflictionStrengthLimb(character, limbtype, identifier, 0)
HF.SetAfflictionLimb(character, identifier, limbtype, strength + prevstrength, aggressor, prevstrength)
end
function HF.AddAffliction(character, identifier, strength, aggressor)
local prevstrength = HF.GetAfflictionStrength(character, identifier, 0)
HF.SetAffliction(character, identifier, strength + prevstrength, aggressor, prevstrength)
end
function HF.AddAfflictionResisted(character, identifier, strength, aggressor)
local prevstrength = HF.GetAfflictionStrength(character, identifier, 0)
strength = strength * (1 - HF.GetResistance(character, identifier))
HF.SetAffliction(character, identifier, strength + prevstrength, aggressor, prevstrength)
end
function HF.GetResistance(character, identifier, limbtype)
local limbtype = limbtype or LimbType.None
local prefab = AfflictionPrefab.Prefabs[identifier]
if character == nil or character.CharacterHealth == nil or prefab == nil then return 0 end
return character.CharacterHealth.GetResistance(prefab, limbtype)
end
-- /// misc ///
function PrintChat(msg)
if SERVER then
-- use server method
Game.SendMessage(msg, ChatMessageType.Server)
else
-- use client method
Game.ChatBox.AddMessage(ChatMessage.Create("", msg, ChatMessageType.Server, nil))
end
end
function HF.DMClient(client, msg, color)
if SERVER then
if client == nil then return end
local chatMessage = ChatMessage.Create("", msg, ChatMessageType.Server, nil)
if color ~= nil then chatMessage.Color = color end
Game.SendDirectChatMessage(chatMessage, client)
else
PrintChat(msg)
end
end
function HF.Chance(chance)
return math.random() < chance
end
function HF.BoolToNum(val, trueoutput)
if val then return trueoutput or 1 end
return 0
end
function HF.GetSkillLevel(character, skilltype)
return character.GetSkillLevel(Identifier(skilltype))
end
function HF.GetBaseSkillLevel(character, skilltype)
if character == nil or character.Info == nil or character.Info.Job == nil then return 0 end
return character.Info.Job.GetSkillLevel(Identifier(skilltype))
end
function HF.GetSkillRequirementMet(character, skilltype, requiredamount)
local skilllevel = HF.GetSkillLevel(character, skilltype)
if NTConfig.Get("NT_vanillaSkillCheck", false) then
return HF.Chance(HF.Clamp((100 - (requiredamount - skilllevel)) / 100, 0, 1))
end
return HF.Chance(HF.Clamp(skilllevel / requiredamount, 0, 1))
end
function HF.GetSurgerySkillRequirementMet(character, requiredamount)
local skilllevel = HF.GetSurgerySkill(character)
if NTConfig.Get("NT_vanillaSkillCheck", false) then
return HF.Chance(HF.Clamp((100 - (requiredamount - skilllevel)) / 100, 0, 1))
end
return HF.Chance(HF.Clamp(skilllevel / requiredamount, 0, 1))
end
function HF.GetSurgerySkill(character)
if NTSP ~= nil and NTConfig.Get("NTSP_enableSurgerySkill", false) then
return math.max(5, HF.GetSkillLevel(character, "surgery"), HF.GetSkillLevel(character, "medical") / 4)
end
return HF.GetSkillLevel(character, "medical")
end
function HF.GiveSkill(character, skilltype, amount)
if character ~= nil and character.Info ~= nil then
character.Info.IncreaseSkillLevel(Identifier(skilltype), amount)
end
end
function HF.GiveSurgerySkill(character, amount)
if NTSP ~= nil and NTConfig.Get("NTSP_enableSurgerySkill", true) then
HF.GiveSkill(character, "surgery", amount)
else
HF.GiveSkill(character, "medical", amount / 4)
end
end
-- amount = vitality healed
function HF.GiveSkillScaled(character, skilltype, amount)
if character ~= nil and character.Info ~= nil then
HF.GiveSkill(character, skilltype, amount * 0.001 / math.max(HF.GetSkillLevel(character, skilltype), 1))
end
end
function HF.GiveItem(character, identifier)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
-- XXX: this is a workaround for a race condition where `Entity.Spawner` is
-- initialized after Luatrauma invokes our `<LuaHook>`s.
if not Entity.Spawner then
-- Reschedule it to run on the next frame... hopefully it will be initialized then
Timer.Wait(function()
HF.GiveItem(character, identifier)
end, 35)
return
end
-- This needs to be done on the next tick because Barotrauma processes
-- the spawn queue before the remove queue, which could result in the
-- item container overflowing.
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, character.WorldPosition, nil, nil, function(item)
character.Inventory.TryPutItem(item, nil, { InvSlotType.Any })
end)
end, 35)
end
function HF.GiveItemAtCondition(character, identifier, condition)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.GiveItemAtCondition(character, identifier, condition)
end, 35)
return
end
-- use server spawn method
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, character.WorldPosition, nil, nil, function(item)
item.Condition = condition
character.Inventory.TryPutItem(item, nil, { InvSlotType.Any })
end)
end, 35)
end
-- for use with items
function HF.SpawnItemPlusFunction(identifier, func, params, inventory, targetslot, position)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.SpawnItemPlusFunction(identifier, func, params, inventory, targetslot, position)
end, 35)
return
end
if params == nil then params = {} end
-- use server spawn method
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
if tostring(inventory) == "Barotrauma.CharacterInventory" then
Entity.Spawner.AddItemToSpawnQueue(
prefab,
position or inventory.Owner.AnimController.WorldPosition,
nil,
nil,
function(newitem)
if inventory ~= nil then inventory.TryPutItem(newitem, targetslot, true, true, nil) end
params["item"] = newitem
if func ~= nil then func(params) end
end
)
else
Entity.Spawner.AddItemToSpawnQueue(
prefab,
position or inventory.Container.Item.WorldPosition,
nil,
nil,
function(newitem)
if inventory ~= nil then
if targetslot ~= nil then
inventory.TryPutItem(newitem, targetslot, true, true, nil)
else
inventory.TryPutItem(newitem, nil, { 0 }, true, true)
end
end
params["item"] = newitem
if func ~= nil then func(params) end
end
)
end
end, 35)
end
-- for use with characters
function HF.GiveItemPlusFunction(identifier, func, params, character)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
HF.GiveItemPlusFunction(identifier, func, params, character)
end, 35)
return
end
if params == nil then params = {} end
-- use server spawn method
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, character.WorldPosition, nil, nil, function(newitem)
if character.Inventory ~= nil then character.Inventory.TryPutItem(newitem, nil, { InvSlotType.Any }) end
params["item"] = newitem
if func ~= nil then func(params) end
end)
end, 35)
end
function HF.SpawnItemAt(identifier, position)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.SpawnItemAt(identifier, position)
end, 35)
return
end
local prefab = ItemPrefab.GetItemPrefab(identifier)
-- use server spawn method
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, position, nil, nil, nil)
end, 35)
end
function HF.ForceArmLock(character, identifier)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.ForceArmLock(character, identifier)
end, 35)
return
end
local handindex = 6
if identifier == "armlock2" then handindex = 5 end
-- drop previously held item
local previtem = character.Inventory.GetItemAt(handindex)
if previtem ~= nil then previtem.Drop(character, true) end
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, character.WorldPosition, nil, nil, function(newitem)
if character.Inventory ~= nil and identifier == "armlock1" then
character.Inventory.TryPutItem(newitem, nil, { InvSlotType.RightHand })
elseif character.Inventory ~= nil and identifier == "armlock2" then
character.Inventory.TryPutItem(newitem, nil, { InvSlotType.LeftHand })
end
end)
end, 35)
end
function HF.RemoveItem(item)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if item == nil or item.Removed then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.RemoveItem(item)
end, 35)
return
end
-- use server remove method
Entity.Spawner.AddEntityToRemoveQueue(item)
end
function HF.RemoveCharacter(character)
-- this is the entirely same function as RemoveItem right now
HF.RemoveItem(character)
--[[
if character == nil or character.Removed then return end
if SERVER then
-- use server remove method
Entity.Spawner.AddEntityToRemoveQueue(character)
else
-- use client remove method
character.Remove()
end
]]
end
function HF.StartsWith(String, Start)
return string.sub(String, 1, string.len(Start)) == Start
end
function HF.SplitString(inputstr, sep)
if sep == nil then sep = "%s" end
local t = {}
for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
table.insert(t, str)
end
return t
end
-- this function is dumb and you shouldn't use it
function HF.TableSize(table)
return #table
end
function HF.HasAbilityFlag(character, flagtype)
return character.HasAbilityFlag(flagtype)
end
function HF.MakeAggressive(aggressor, target, damage)
-- this shit isnt working!!!!
-- why is this shit not working!?!?!?!
-- if(aggressor==nil) then print("no aggressor") else print("aggressor: "..aggressor.Name) end
-- if(target==nil) then print("no target") else print("target: "..target.Name) end
-- if(damage==nil) then print("no damage") else print("damage: "..damage) end
--
-- if ((damage ~= nil and damage <= 0.5) or target==nil or aggressor==nil or target.AIController==nil or aggressor==target) then return end
--
-- if damage == nil then damage = 5 end
--
-- local AttackResult = LuaUserData.CreateStatic("Barotrauma.AttackResult")
-- local res = AttackResult.__new(Round(damage),nil)
-- target.AIController.OnAttacked(aggressor,res)
end
function HF.CharacterToClient(character)
if not SERVER then return nil end
for key, client in pairs(Client.ClientList) do
if client.Character == character then return client end
end
return nil
end
function HF.ClientFromName(name)
if not SERVER then return nil end
for key, client in pairs(Client.ClientList) do
if client.Name == name then return client end
end
return nil
end
function HF.LimbTypeToString(type)
if type == LimbType.Torso then return "Torso" end
if type == LimbType.Head then return "Head" end
if type == LimbType.LeftArm or type == LimbType.LeftForearm or type == LimbType.LeftHand then return "Left Arm" end
if type == LimbType.RightArm or type == LimbType.RightForearm or type == LimbType.RightHand then
return "Right Arm"
end
if type == LimbType.LeftLeg or type == LimbType.LeftThigh or type == LimbType.LeftFoot then return "Left Leg" end
if type == LimbType.RightLeg or type == LimbType.RightThigh or type == LimbType.RightFoot then
return "Right Leg"
end
return "???"
end
function HF.GameIsPaused()
if SERVER then return false end
return Game.Paused
end
function HF.TableContains(table, value)
if not table then return end
for i, v in ipairs(table) do
if v == value then return true end
end
return false
end
function HF.PutItemInsideItem(container, identifier, index)
-- hostside only
if Game.IsMultiplayer and CLIENT then return end
if not Entity.Spawner then
Timer.Wait(function()
HF.PutItemInsideItem(container, identifier, index)
end, 35)
return
end
if index == nil then index = 0 end
local inv = container.OwnInventory
if inv == nil then return end
local previtem = inv.GetItemAt(index)
if previtem ~= nil then
inv.ForceRemoveFromSlot(previtem, index)
previtem.Drop()
end
-- use server spawn method
Timer.Wait(function()
local prefab = ItemPrefab.GetItemPrefab(identifier)
Entity.Spawner.AddItemToSpawnQueue(prefab, container.WorldPosition, nil, nil, function(item)
inv.TryPutItem(item, nil, { index }, true, true)
end)
end, 35)
end
function HF.CanPerformSurgeryOn(character)
return HF.HasAffliction(character, "analgesia", 1) or HF.HasAffliction(character, "sym_unconsciousness", 0.1)
end
-- converts thighs, feet, forearms and hands into legs and arms
function HF.NormalizeLimbType(limbtype)
if
limbtype == LimbType.Head
or limbtype == LimbType.Torso
or limbtype == LimbType.RightArm
or limbtype == LimbType.LeftArm
or limbtype == LimbType.RightLeg
or limbtype == LimbType.LeftLeg
then
return limbtype
end
if limbtype == LimbType.LeftForearm or limbtype == LimbType.LeftHand then return LimbType.LeftArm end
if limbtype == LimbType.RightForearm or limbtype == LimbType.RightHand then return LimbType.RightArm end
if limbtype == LimbType.LeftThigh or limbtype == LimbType.LeftFoot then return LimbType.LeftLeg end
if limbtype == LimbType.RightThigh or limbtype == LimbType.RightFoot then return LimbType.RightLeg end
if limbtype == LimbType.Waist then return LimbType.Torso end
return limbtype
end
-- returns an unrounded random number
function HF.RandomRange(min, max)
return min + math.random() * (max - min)
end
function HF.LimbIsExtremity(limbtype)
return limbtype ~= LimbType.Torso and limbtype ~= LimbType.Head
end
function HF.HasTalent(character, talentidentifier)
local talents = character.Info.UnlockedTalents
for value in talents do
if value.Value == talentidentifier then return true end
end
return false
end
function HF.CharacterDistance(char1, char2)
return HF.Distance(char1.WorldPosition, char2.WorldPosition)
end
function HF.Distance(v1, v2)
return Vector2.Distance(v1, v2)
end
function HF.GetOuterWearIdentifier(character)
return HF.GetCharacterInventorySlotIdentifer(character, 4)
end
function HF.GetInnerWearIdentifier(character)
return HF.GetCharacterInventorySlotIdentifer(character, 3)
end
function HF.GetHeadWearIdentifier(character)
return HF.GetCharacterInventorySlotIdentifer(character, 2)
end
function HF.GetCharacterInventorySlotIdentifer(character, slot)
local item = character.Inventory.GetItemAt(slot)
if item == nil then return nil end
return item.Prefab.Identifier.Value
end
function HF.GetItemInRightHand(character)
return HF.GetCharacterInventorySlot(character, 6)
end
function HF.GetItemInLeftHand(character)
return HF.GetCharacterInventorySlot(character, 5)
end
function HF.GetOuterWear(character)
return HF.GetCharacterInventorySlot(character, 4)
end
function HF.GetInnerWear(character)
return HF.GetCharacterInventorySlot(character, 3)
end
function HF.GetHeadWear(character)
return HF.GetCharacterInventorySlot(character, 2)
end
function HF.GetCharacterInventorySlot(character, slot)
return character.Inventory.GetItemAt(slot)
end
function HF.ItemHasTag(item, tag)
if item == nil then return false end
return item.HasTag(tag)
end
function HF.CauseOfDeathToString(cod)
local res = nil
if
cod.Affliction ~= nil -- from affliction
and cod.Affliction.CauseOfDeathDescription ~= nil
then
res = cod.Affliction.CauseOfDeathDescription
else -- from type
res = tostring(cod.Type)
end
return res or ""
end
function HF.CombineArrays(arr1, arr2)
local res = {}
for _, v in ipairs(arr1) do
table.insert(res, v)
end
for _, v in ipairs(arr2) do
table.insert(res, v)
end
return res
end
HF.EndocrineTalents = {
"aggressiveengineering",
"crisismanagement",
"cannedheat",
"doubleduty",
"firemanscarry",
"fieldmedic",
"multitasker",
"aceofalltrades",
"stillkicking",
"drunkensailor",
"trustedcaptain",
"downwiththeship",
"physicalconditioning",
"beatcop",
"commando",
"justascratch",
"intheflow",
"collegeathletics",
}
function HF.ApplyEndocrineBoost(character, talentlist)
talentlist = talentlist or HF.EndocrineTalents
-- gee i sure do love translating c# into lua
local targetCharacter = character
if targetCharacter.Info == nil then return end
local talentTree = TalentTree.JobTalentTrees[character.Info.Job.Prefab.Identifier.Value]
if talentTree == nil then return end
-- for the sake of technical simplicity, for now do not allow talents to be given if the character could unlock them in their talent tree as well
local disallowedTalents = {}
for subtree in talentTree.TalentSubTrees do
for stage in subtree.TalentOptionStages do
for talent in stage.Talents do
table.insert(disallowedTalents, talent.Identifier.Value)
end
end
end
local characterTalents = {}
for talent in targetCharacter.Info.UnlockedTalents do
table.insert(characterTalents, talent.Value)
end
local viableTalents = {}
for talent in talentlist do
if not HF.TableContains(disallowedTalents, talent) and not HF.TableContains(characterTalents, talent) then
table.insert(viableTalents, talent)
end
end
if #viableTalents <= 0 then return end
local talent = viableTalents[math.random(#viableTalents)]
targetCharacter.GiveTalent(Identifier(talent), true)
end
function HF.JobMemberCount(jobidentifier)
local res = 0
for _, character in pairs(Character.CharacterList) do
if character.IsHuman and not character.IsDead and character.Info.Job ~= nil then
if character.Info.Job.Prefab.Identifier.Value == jobidentifier then res = res + 1 end
end
end
return res
end
function HF.SendTextBox(header, msg, client)
if SERVER then
Game.SendDirectChatMessage(header, msg, nil, 7, client)
else
GUI.MessageBox(header, msg)
end
end
function HF.ReplaceString(original, find, replace)
return string.gsub(original, find, replace)
end
function HF.Explode(entity, range, force, damage, structureDamage, itemDamage, empStrength, ballastFloraStrength)
range = range or 0
force = force or 0
damage = damage or 0
structureDamage = structureDamage or 0
itemDamage = itemDamage or 0
empStrength = empStrength or 0
ballastFloraStrength = ballastFloraStrength or 0
Game.Explode(
entity.WorldPosition,
range,
force,
damage,
structureDamage,
itemDamage,
empStrength,
ballastFloraStrength
)
HF.SpawnItemAt("ntvfx_explosion", entity.WorldPosition)
end
function HF.GetText(identifier)
local text = TextManager.Get(identifier)
if text ~= nil then return text.Value end
return identifier
end
function HF.Magnitude(vector)
return ((vector.X ^ 2) + (vector.Y ^ 2)) ^ 0.5
end
function HF.Clone(object)
return json.parse(json.serialize(object))
end
function HF.ReplaceItemIdentifier(item, newIdentifier, keepCondition)
-- keep track of where to put the new item
local previousSpot = nil
local previousInventory = item.ParentInventory
if previousInventory then previousSpot = previousInventory.FindIndex(item) end
-- make sure to transfer over contained items into the new item
local containedItems = {}
if item.OwnInventory ~= nil then
for containedItem in item.OwnInventory.AllItems do
table.insert(containedItems, { item = containedItem, slot = item.OwnInventory.FindIndex(containedItem) })
end
end
local funcParams = { containedItems = containedItems }
if keepCondition then funcParams.condition = item.Condition end
Timer.Wait(function()
HF.SpawnItemPlusFunction(newIdentifier, function(params)
for containedItem in params.containedItems do
params.item.OwnInventory.TryPutItem(containedItem.item, containedItem.slot, true, false, nil)
end
if params.condition ~= nil then params.item.Condition = params.condition end
end, funcParams, previousInventory, previousSpot, item.WorldPosition)
HF.RemoveItem(item)
end, 1)
end
function HF.GetVelocity(character)
if
not character
or not character.AnimController
or not character.AnimController.MainLimb
or not character.AnimController.MainLimb.body
then
return Vector2(0, 0)
end
return character.AnimController.MainLimb.body.LinearVelocity
end
function HF.DynamicUnavailableItems()
local blockedItems = {}
-- Hardmode Aortic Rupture; enable/disable stent + balloon
if NTConfig.Get("NT_HardmodeAorticRupture", false) == false then
blockedItems["medstent"] = true
blockedItems["endovascballoon"] = true
end
-- Sodium Nitroprusside
if NTConfig.Get("NT_DoNitroprusside", false) == false then blockedItems["pressuremeds"] = true end
-- Antiseptic (sprayer)
if NTConfig.Get("NT_DoAntisepticSprayer", false) == false then
blockedItems["antisepticspray"] = true
blockedItems["antiseptic"] = true
end
-- Organ scalpels
if NTConfig.Get("NT_DoOrganScalpels", false) == false then
blockedItems["organscalpel_liver"] = true
blockedItems["organscalpel_kidneys"] = true
blockedItems["organscalpel_heart"] = true
blockedItems["organscalpel_lungs"] = true
blockedItems["organscalpel_brain"] = true
blockedItems["surgerytoolboxsetscalpel"] = true
end
return blockedItems
end