-- 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 ``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