Files
barotrauma-localmods/Neurotrauma/Lua/Scripts/helperfunctions.lua
2025-03-31 13:19:47 +02:00

1253 lines
35 KiB
Lua

-- This file contains a bunch of useful functions that see heavy use in the other scripts.
-- 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.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)
end
function NT.TraumamputateLimb(character, 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
HF.AddAfflictionLimb(character, limbtoaffliction[limbtype], limbtype, 10)
end
function NT.TraumamputateLimbMinusItem(character, 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"
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)
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
return HF.HasAffliction(character, limbtoaffliction[limbtype], 1)
end
function NT.LimbIsBroken(character, limbtype)
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
return HF.HasAffliction(character, limbtoaffliction[limbtype], 1)
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[identifier]
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,
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)
Entity.Spawner.AddItemToSpawnQueue(
prefab,
position or inventory.Container.Item.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
)
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
func(params)
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