Add other mods
This commit is contained in:
100
Neurotrauma/Lua/Autorun/init.lua
Normal file
100
Neurotrauma/Lua/Autorun/init.lua
Normal file
@@ -0,0 +1,100 @@
|
||||
--if Game.IsMultiplayer and CLIENT then return end
|
||||
|
||||
NT = {} -- Neurotrauma
|
||||
NT.Name = "Neurotrauma"
|
||||
NT.Version = "A1.12.1"
|
||||
NT.VersionNum = 01120100
|
||||
NT.Path = table.pack(...)[1]
|
||||
|
||||
dofile(NT.Path .. "/Lua/Scripts/helperfunctions.lua")
|
||||
|
||||
-- all things config
|
||||
dofile(NT.Path .. "/Lua/Scripts/configdata.lua")
|
||||
|
||||
-- server-side code (also run in singleplayer)
|
||||
if (Game.IsMultiplayer and SERVER) or not Game.IsMultiplayer then
|
||||
-- Version and expansion display
|
||||
Timer.Wait(function()
|
||||
Timer.Wait(function()
|
||||
local runstring = "\n/// Running Neurotrauma V " .. NT.Version .. " ///\n"
|
||||
|
||||
-- add dashes
|
||||
local linelength = string.len(runstring) + 4
|
||||
local i = 0
|
||||
while i < linelength do
|
||||
runstring = runstring .. "-"
|
||||
i = i + 1
|
||||
end
|
||||
local hasAddons = #NTC.RegisteredExpansions > 0
|
||||
|
||||
-- add expansions
|
||||
for val in NTC.RegisteredExpansions do
|
||||
runstring = runstring .. "\n+ " .. (val.Name or "Unnamed expansion") .. " V " .. (val.Version or "???")
|
||||
if val.MinNTVersion ~= nil and NT.VersionNum < (val.MinNTVersionNum or 1) then
|
||||
runstring = runstring
|
||||
.. "\n-- WARNING! Neurotrauma version "
|
||||
.. val.MinNTVersion
|
||||
.. " or higher required!"
|
||||
end
|
||||
end
|
||||
|
||||
-- No expansions
|
||||
runstring = runstring .. "\n"
|
||||
if not hasAddons then
|
||||
runstring = runstring .. "- Not running any expansions\n"
|
||||
end
|
||||
|
||||
print(runstring)
|
||||
end, 1)
|
||||
end, 1)
|
||||
|
||||
--dofile(NT.Path .. "/Lua/Scripts/Server/characterpatches.lua")
|
||||
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/ntcompat.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/blood.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/humanupdate.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/ondamaged.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/items.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/onfire.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/cpr.lua")
|
||||
--dofile(NT.Path.."/Lua/Scripts/Server/surgerytable.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/fuckbots.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/lootcrates.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/multiscalpel.lua") -- its important for this to run after items.lua
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/falldamage.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/screams.lua")
|
||||
dofile(NT.Path .. "/Lua/Scripts/Server/modconflict.lua")
|
||||
|
||||
dofile(NT.Path .. "/Lua/Scripts/testing.lua")
|
||||
end
|
||||
|
||||
-- server-side code only
|
||||
if SERVER then
|
||||
Networking.Receive("NT.ConfigUpdate", function(msg, sender)
|
||||
if not sender.HasPermission(ClientPermissions.ManageSettings) then
|
||||
return
|
||||
end
|
||||
NTConfig.ReceiveConfig(msg)
|
||||
NTConfig.SaveConfig()
|
||||
end)
|
||||
|
||||
Networking.Receive("NT.ConfigRequest", function(msg, sender)
|
||||
if not sender then
|
||||
return
|
||||
end
|
||||
NTConfig.SendConfig(sender)
|
||||
end)
|
||||
end
|
||||
|
||||
-- client-side code
|
||||
if CLIENT then
|
||||
dofile(NT.Path .. "/Lua/Scripts/Client/configgui.lua")
|
||||
end
|
||||
|
||||
-- Shared and singleplayer code
|
||||
dofile(NT.Path .. "/Lua/Scripts/Shared/surgerytable.lua") -- Heelge: fix for https://github.com/OlegBSTU/Neurotrauma/issues/15
|
||||
--dofile(NT.Path .. "/Lua/Scripts/Shared/pronecolliderfix.lua") -- Heelge: fix collider on prone (thx Lua man), but it has 2 ms perf drop so commented out
|
||||
|
||||
-- Consent Required Extended with adjustments
|
||||
-- mod page: https://steamcommunity.com/sharedfiles/filedetails/?id=2892602084
|
||||
dofile(NT.Path .. "/Lua/ConsentRequiredExtended/init.lua")
|
146
Neurotrauma/Lua/ConsentRequiredExtended/Api.lua
Normal file
146
Neurotrauma/Lua/ConsentRequiredExtended/Api.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
-- Consent Required API
|
||||
-- Any Lua script can access this API by adding this line:
|
||||
-- local Api = require "com.github.cintique.ConsentRequired.Api"
|
||||
local Environment = require("ConsentRequiredExtended.Util.Environment")
|
||||
local Barotrauma = require("ConsentRequiredExtended.Util.Barotrauma")
|
||||
|
||||
local _ENV = Environment.PrepareEnvironment(_ENV)
|
||||
|
||||
-- Table of identifiers (strings) of items that when used
|
||||
-- as a treatment on an NPC from a different team,
|
||||
-- causes that NPC (and their allies) to become hostile
|
||||
-- towards the player.
|
||||
local affectedItems = {}
|
||||
|
||||
---Adds an item (by identifier string) to `affectedItems`.
|
||||
---@param identifier string
|
||||
function AddAffectedItem(identifier)
|
||||
table.insert(affectedItems, identifier)
|
||||
end
|
||||
|
||||
LuaUserData.MakeFieldAccessible(Descriptors["Barotrauma.AbandonedOutpostMission"], "requireRescue")
|
||||
|
||||
-- Character type doesn't have tags we can assign a custom "rescuetarget" tag to
|
||||
-- So instead we just hold characters which need rescue in a table and compare their entity IDs
|
||||
-- This table is only resfreshed on roundstart
|
||||
local rescuetargets = {}
|
||||
|
||||
---Returns a boolean indicating whether a given item is affected or not.
|
||||
---@param identifier string The identifier of the item that we are testing.
|
||||
---@return boolean isAffected True if the item is affected, false otherwise.
|
||||
function IsItemAffected(identifier)
|
||||
for _, item in pairs(affectedItems) do
|
||||
if item == identifier or HF.StartsWith(identifier, item) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local ADD_ATTACKER_DAMAGE = 130 -- Heelge: this used to max out negative rep gain, now only around 4 negative rep, any less negative rep is too forgiving.
|
||||
|
||||
---@param aiChar Barotrauma_Character The AI character to be made hostile.
|
||||
---@param instigator Barotrauma_Character The character to be the target of the AI's wrath.
|
||||
function makeHostile(aiChar, instigator)
|
||||
aiChar.AIController.OnAttacked(instigator, Barotrauma.AttackResult.NewAttackResultFromDamage(ADD_ATTACKER_DAMAGE))
|
||||
aiChar.AddAttacker(instigator, ADD_ATTACKER_DAMAGE)
|
||||
end
|
||||
|
||||
---@param char1 Barotrauma_Character Character one.
|
||||
---@param char2 Barotrauma_Character Character two.
|
||||
---@return boolean charactersAreOnSameTeam True if characters one & two are on the same team, false otherwise.
|
||||
function isOnSameTeam(char1, char2)
|
||||
local team1 = char1.TeamID
|
||||
local team2 = char2.TeamID
|
||||
return team1 == team2
|
||||
end
|
||||
|
||||
---Updates current rescue targets list, separate so we dont cycle thru all missions every time we apply item to chacter. Use IsRescueTarget(target) after this.
|
||||
function UpdateRescueTargets()
|
||||
rescuetargets = {}
|
||||
for mission in Game.GameSession.Missions do
|
||||
if LuaUserData.IsTargetType(mission.Prefab.MissionClass, "Barotrauma.AbandonedOutpostMission") then
|
||||
for character in mission.requireRescue do
|
||||
rescuetargets[character.ID] = character
|
||||
--table.insert(rescuetargets, character)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- print('rescue targets =')
|
||||
-- for char in rescuetargets do print(char.Name) end
|
||||
end
|
||||
|
||||
---@param target Barotrauma_Character The character we want to confirm as being rescued
|
||||
---@return boolean consent True if target is rescue mission target, false otherwise
|
||||
function IsRescueTarget(target)
|
||||
-- for char in rescuetargets do
|
||||
-- if target.ID == char.ID then return true end
|
||||
-- end
|
||||
if rescuetargets[target.ID] ~= nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param user Barotrauma_Character The character who desires consent.
|
||||
---@param target Barotrauma_Character The character who gives consent
|
||||
---@return boolean consent True if consent is given, false otherwise.
|
||||
function hasConsent(user, target)
|
||||
return isOnSameTeam(user, target) or target.IsEscorted or IsRescueTarget(target) -- No longer needs to be shared.
|
||||
end
|
||||
|
||||
---@param aiChar Barotrauma_Character The (AI but not necessarily) character whose sight is being tested.
|
||||
---@param target Barotrauma_Character The character to be seen.
|
||||
---@return boolean aiCanSeeTarget True if the AI can see the target character.
|
||||
function canAiSeeTarget(aiChar, target)
|
||||
-- I'll just use what Barotrauma uses for witness line of sight
|
||||
local aiVisibleHulls = aiChar.GetVisibleHulls()
|
||||
local targetCurrentHull = target.CurrentHull
|
||||
for _, visibleHull in pairs(aiVisibleHulls) do
|
||||
if targetCurrentHull == visibleHull then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
---@param user Barotrauma_Character The character of the instigator being witnessed.
|
||||
---@param victim Barotrauma_Character The character of the victim of the crime being witnessed.
|
||||
---@return Barotrauma_Character[] Characters that have witnessed the crime.
|
||||
function getWitnessesToCrime(user, victim)
|
||||
local witnesses = {}
|
||||
for _, char in pairs(Character.CharacterList) do
|
||||
if
|
||||
not char.Removed
|
||||
and not char.IsUnconscious
|
||||
and char.IsBot
|
||||
and char.IsHuman
|
||||
and isOnSameTeam(char, victim)
|
||||
then
|
||||
local isWitnessingUser = canAiSeeTarget(char, user)
|
||||
if isWitnessingUser then
|
||||
table.insert(witnesses, char)
|
||||
end
|
||||
end
|
||||
end
|
||||
return witnesses
|
||||
end
|
||||
|
||||
---@param user Barotrauma_Character The character that is applying the affected item.
|
||||
---@param target Barotrauma_Character The character of the target of the affected item's application.
|
||||
function onAffectedItemApplied(user, target)
|
||||
if not hasConsent(user, target) and target.IsBot and target.IsHuman then
|
||||
if not target.IsIncapacitated and target.Stun <= 10 then
|
||||
makeHostile(target, user)
|
||||
else
|
||||
-- Vanilla Barotrauma Human AI doesn't care what you do to their unconscious teammates, even shooting them in the head
|
||||
-- Let's fix that for this particular case of mistreatment
|
||||
local witnesses = getWitnessesToCrime(user, target)
|
||||
for _, witness in pairs(witnesses) do
|
||||
makeHostile(witness, user)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return Environment.Export(_ENV)
|
64
Neurotrauma/Lua/ConsentRequiredExtended/Config.lua
Normal file
64
Neurotrauma/Lua/ConsentRequiredExtended/Config.lua
Normal file
@@ -0,0 +1,64 @@
|
||||
-- User edited configuration file.
|
||||
local Environment = require("ConsentRequiredExtended.Util.Environment")
|
||||
|
||||
local _ENV = Environment.PrepareEnvironment(_ENV)
|
||||
|
||||
--------- Start editing here ---------
|
||||
|
||||
AffectedItems = {
|
||||
-- Neurotrauma
|
||||
-- "healthscanner", --健康扫描仪 -- whats a tiny bit of radiation damage between friends?
|
||||
"bloodanalyzer", --血液分析仪
|
||||
"opium", --药用鸦片
|
||||
"antidama1", --吗啡
|
||||
"antidama2", --芬太尼
|
||||
"antibleeding3", --抗生素凝膠
|
||||
"propofol", -- 异丙酚
|
||||
"mannitol", -- 甘露醇
|
||||
"pressuremeds", -- 压力药物
|
||||
"multiscalpel", -- 多功能手术刀
|
||||
"advscalpel", -- 手术刀
|
||||
"advhemostat", -- 止血钳
|
||||
"advretractors", -- 皮肤牵引器
|
||||
"tweezers", -- 镊子
|
||||
"surgicaldrill", -- 骨钻
|
||||
"surgerysaw", -- 手术锯
|
||||
"organscalpel_liver", -- 器官切割刀:肝脏
|
||||
"organscalpel_lungs", -- 器官切割刀:肺
|
||||
"organscalpel_kidneys", -- 器官切割刀:肾脏
|
||||
"organscalpel_heart", -- 器官切割刀:心脏
|
||||
"organscalpel_brain", -- 器官切割刀:大脑
|
||||
"emptybloodpack", -- 空血袋
|
||||
"bloodpack",
|
||||
"alienblood", -- 异星血浆
|
||||
"tourniquet", -- 止血带
|
||||
"defibrillator", -- 手动除颤器
|
||||
"aed", -- 智能除颤器
|
||||
"bvm", -- 人工呼吸器
|
||||
"antibiotics", -- 广谱抗生素
|
||||
"sulphuricacid", -- 硫酸
|
||||
"divingknife", -- 潜水刀
|
||||
"divingknifedementonite", -- 攝魂潛水刀
|
||||
"divingknifehardened", -- 硬化潛水刀
|
||||
"crowbar", -- 潜水刀
|
||||
"crowbardementonite", -- 攝魂撬棍
|
||||
"crowbarhardened", -- 硬化撬棍
|
||||
"stasisbag", -- 冷藏袋
|
||||
"autocpr", -- 全自动CPR
|
||||
-- NeuroEyes
|
||||
"organscalpel_eyes", -- 器官切割刀:眼睛
|
||||
-- blahaj 布罗艾鲨鱼
|
||||
-- "blahaj", -- 布罗艾鲨鱼 -- Blahaj never hurt anyone
|
||||
-- "blahajplus", -- 大鲨鲨
|
||||
"blahajplusplus", -- 超大鲨鲨
|
||||
-- Pharmacy 制药大师
|
||||
"custompill", -- 自制药丸
|
||||
"custompill_horsepill", -- 大药丸
|
||||
"custompill_tablets", -- 药片
|
||||
-- vanilla 原版
|
||||
"toyhammer", -- 玩具锤子
|
||||
}
|
||||
|
||||
--------- Stop editing here ---------
|
||||
|
||||
return Environment.Export(_ENV)
|
31
Neurotrauma/Lua/ConsentRequiredExtended/Main.lua
Normal file
31
Neurotrauma/Lua/ConsentRequiredExtended/Main.lua
Normal file
@@ -0,0 +1,31 @@
|
||||
-- Do not take my blood or organs without my consent, thanks.
|
||||
-- Causes AI to get angry at you if you use certain medical items on them.
|
||||
-- These items are those related to organ and blood removal.
|
||||
-- This mod is meant to be accompanied by Neurotrauma, and aims to
|
||||
-- resolve the issue of being freely able to steal blood/organs from
|
||||
-- neutral NPCs (e.g. outposts, VIPs) without them getting mad at you.
|
||||
local Api = require("ConsentRequiredExtended.Api")
|
||||
local OnItemApplied = require("ConsentRequiredExtended.OnItemApplied")
|
||||
local onMeleeWeaponHandleImpact = require("ConsentRequiredExtended.onMeleeWeaponHandleImpact")
|
||||
local Config = require("ConsentRequiredExtended.Config")
|
||||
|
||||
local LUA_EVENT_ITEM_APPLYTREATMENT = "item.ApplyTreatment"
|
||||
local HOOK_NAME_ITEM_APPLYTREATMENT = "ConsentRequiredExtended.onItemApplyTreatment"
|
||||
|
||||
local LUA_EVENT_MELEEWEAPON_HANDLEIMPACT = "meleeWeapon.handleImpact"
|
||||
local HOOK_NAME_MELEEWEAPON_HANDLEIMPACT = "ConsentRequiredExtended.onMeleeWeaponHandleImpact"
|
||||
|
||||
local LUA_EVENT_ROUNDSTART = "roundStart"
|
||||
local HOOK_NAME_UPDATE_RESCUETARGETS = "ConsentRequiredExtended.onUpdateRescueTargets"
|
||||
|
||||
-- Set up affected items from config.
|
||||
for _, affectedItem in pairs(Config.AffectedItems) do
|
||||
Api.AddAffectedItem(affectedItem)
|
||||
end
|
||||
|
||||
Hook.Add(LUA_EVENT_ITEM_APPLYTREATMENT, HOOK_NAME_ITEM_APPLYTREATMENT, OnItemApplied)
|
||||
|
||||
-- damn meleeWeapon
|
||||
Hook.Add(LUA_EVENT_MELEEWEAPON_HANDLEIMPACT, HOOK_NAME_MELEEWEAPON_HANDLEIMPACT, onMeleeWeaponHandleImpact)
|
||||
|
||||
Hook.Add(LUA_EVENT_ROUNDSTART, HOOK_NAME_UPDATE_RESCUETARGETS, Api.UpdateRescueTargets)
|
20
Neurotrauma/Lua/ConsentRequiredExtended/OnItemApplied.lua
Normal file
20
Neurotrauma/Lua/ConsentRequiredExtended/OnItemApplied.lua
Normal file
@@ -0,0 +1,20 @@
|
||||
local Api = require("ConsentRequiredExtended.Api")
|
||||
|
||||
local function isItemAffected(identifier)
|
||||
return Api.IsItemAffected(identifier)
|
||||
end
|
||||
|
||||
---@param item Barotrauma_Item Item being applied.
|
||||
---@param user Barotrauma_Character The character that is applying the item.
|
||||
---@param target Barotrauma_Character The character of the target of the item's application.
|
||||
local function OnItemApplied(item, user, target)
|
||||
if not NTConfig.Get("NTCRE_ConsentRequired", true) then
|
||||
return
|
||||
end
|
||||
local itemIdentifier = item.Prefab.Identifier.Value
|
||||
if isItemAffected(itemIdentifier) then
|
||||
Api.onAffectedItemApplied(user, target)
|
||||
end
|
||||
end
|
||||
|
||||
return OnItemApplied
|
90
Neurotrauma/Lua/ConsentRequiredExtended/Util/Barotrauma.lua
Normal file
90
Neurotrauma/Lua/ConsentRequiredExtended/Util/Barotrauma.lua
Normal file
@@ -0,0 +1,90 @@
|
||||
-- Functions for interfacing with Barotrauma.
|
||||
|
||||
local Environment = require 'ConsentRequiredExtended.Util.Environment'
|
||||
local _ENV = Environment.PrepareEnvironment(_ENV)
|
||||
|
||||
-- local Clr = require 'ConsentRequiredExtended.Util.Clr'
|
||||
-- local UserData = require 'ConsentRequiredExtended.Util.UserData'
|
||||
|
||||
---Functions related to working with Barotrauma.AttackResult.
|
||||
AttackResult = {}
|
||||
|
||||
---Initialise AttackResults.
|
||||
-- local function Init_AttackResult()
|
||||
-- -- Registrations.
|
||||
-- UserData.RegisterStandardType("System.Reflection.FieldInfo")
|
||||
|
||||
-- -- Construct a List<Affliction> generic type.
|
||||
-- local afflictionsListClrType = Clr.CreateConstructedGenericType("System.Collections.Generic.List`1", "Barotrauma.Affliction")
|
||||
-- local attackResultAfflictionsField = Clr.GetRawClrType("Barotrauma.AttackResult").GetField("Afflictions")
|
||||
|
||||
-- ---Instantiates a new AttackResult with damage and empty afflictions.
|
||||
-- ---@param damage number An amount of damage.
|
||||
-- function AttackResult.NewAttackResultFromDamage(damage)
|
||||
-- -- Instantiate a new AttackResult.
|
||||
-- local attackResult = _G.AttackResult(damage, nil)
|
||||
|
||||
-- -- Instantiate an empty List<Afflictions> (this is to prevent NREs),
|
||||
-- -- and set it to attackResult.Afflictions. This is a readonly field,
|
||||
-- -- hence the use of reflection.
|
||||
-- local afflictionsList = UserData.FromClrType({}, afflictionsListClrType)
|
||||
-- attackResultAfflictionsField.SetValue(attackResult, afflictionsList)
|
||||
|
||||
-- return attackResult
|
||||
-- end
|
||||
-- end
|
||||
|
||||
---Initialise AttackResults without needing to register system.type and reflections
|
||||
local function Init_AttackResult()
|
||||
-- Registrations.
|
||||
LuaUserData.MakePropertyAccessible(Descriptors['Barotrauma.AttackResult'], 'Damage')
|
||||
|
||||
---Instantiates a new AttackResult with damage and empty afflictions.
|
||||
---@param damage number An amount of damage.
|
||||
function AttackResult.NewAttackResultFromDamage(damage)
|
||||
-- I have not noticed any NREs from affliction list being null
|
||||
-- but just in case here is version which intializes with empty list
|
||||
-- Also uncomment MakePropertyAccessible Damage above
|
||||
local attackResult = _G.AttackResult({}, nil, {})
|
||||
attackResult.Damage = damage
|
||||
|
||||
--local attackResult = _G.AttackResult(damage)
|
||||
|
||||
return attackResult
|
||||
end
|
||||
end
|
||||
|
||||
---Runs at start-up, handles registrations, etc.
|
||||
function Init()
|
||||
Init_AttackResult()
|
||||
end
|
||||
|
||||
function Test()
|
||||
local errors = {}
|
||||
local function AssertEquals(testDescription, expected, got)
|
||||
if expected ~= got then
|
||||
local errorString = string.format(
|
||||
"Test Error: %s\n\texpected = %s\n\tgot = %s",
|
||||
testDescription,
|
||||
tostring(expected),
|
||||
tostring(got)
|
||||
)
|
||||
table.insert(errors, errorString)
|
||||
end
|
||||
end
|
||||
local atkRes = AttackResult.NewAttackResultFromDamage(10)
|
||||
AssertEquals("atkRes.Damage", 10, atkRes.Damage)
|
||||
AssertEquals("atkRes.Afflictions is null", true, atkRes.Afflictions ~= nil)
|
||||
AssertEquals("#atkRes.Afflictions is non-zero", 0, #atkRes.Afflictions)
|
||||
|
||||
if #errors == 0 then
|
||||
print("Tests successful")
|
||||
else
|
||||
for _, err in pairs(errors) do
|
||||
print(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Init()
|
||||
return Environment.Export(_ENV)
|
74
Neurotrauma/Lua/ConsentRequiredExtended/Util/Clr.lua
Normal file
74
Neurotrauma/Lua/ConsentRequiredExtended/Util/Clr.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
-- Functions for working with CLR types.
|
||||
|
||||
local Environment = require 'ConsentRequiredExtended.Util.Environment'
|
||||
local _ENV = Environment.PrepareEnvironment(_ENV)
|
||||
|
||||
local UserData = require 'ConsentRequiredExtended.Util.UserData'
|
||||
|
||||
---Construct ClrType wrapper table for CLR types.
|
||||
---@param underlyingType userdata The underlying type (CLR type: System.Type).
|
||||
---@return ClrType Wrapper table for working with CLR types.
|
||||
local function New(underlyingType)
|
||||
---@class ClrType
|
||||
local clrType = {}
|
||||
|
||||
---Instantiate an object for the given CLR type.
|
||||
---@return any An instance of the CLR type. Actual Lua type depends on MoonSharp conversions.
|
||||
function clrType:Instantiate()
|
||||
-- TODO: Implement args.
|
||||
return underlyingType.Assembly.CreateInstance(underlyingType.FullName)
|
||||
end
|
||||
|
||||
---Get the underlying type as a raw CLR type object.
|
||||
---@return userdata The raw underlying type (CLR type: System.Type).
|
||||
function clrType:GetUnderlyingType()
|
||||
return underlyingType
|
||||
end
|
||||
|
||||
---Get the full name of the CLR type.
|
||||
---@return string The full name of the type.
|
||||
function clrType:GetFullName()
|
||||
return underlyingType.FullName
|
||||
end
|
||||
|
||||
return clrType
|
||||
end
|
||||
|
||||
---Create a constructed generic type.
|
||||
---@param genericTypeName string The name of the generic type to construct and register.
|
||||
---@vararg string
|
||||
---@return ClrType The constructed generic type.
|
||||
function CreateConstructedGenericType(genericTypeName, ...)
|
||||
local genericTypeArgumentsString = table.pack(...)
|
||||
|
||||
local genericTypeArgumentsType = {}
|
||||
for _, typeString in pairs(genericTypeArgumentsString) do
|
||||
table.insert(genericTypeArgumentsType, GetRawClrType(typeString))
|
||||
end
|
||||
|
||||
local genericTypeDefinition = GetRawClrType(genericTypeName)
|
||||
local constructedGenericType = genericTypeDefinition.MakeGenericType(table.unpack(genericTypeArgumentsType))
|
||||
return New(constructedGenericType)
|
||||
end
|
||||
|
||||
---Get a System.Type object from a type name.
|
||||
---@param typeName string Name of the type.
|
||||
---@return userdata The type object (CLR type: System.Type).
|
||||
function GetRawClrType(typeName)
|
||||
return LuaUserData.GetType(typeName)
|
||||
end
|
||||
|
||||
---Get a ClrType instance wrapping a Type object that matches the type name.
|
||||
---@param typeName string Name of the type.
|
||||
---@return ClrType The CLR type.
|
||||
function GetClrType(typeName)
|
||||
return New(GetRawClrType(typeName))
|
||||
end
|
||||
|
||||
local function Init()
|
||||
UserData.RegisterStandardType("System.Type")
|
||||
UserData.RegisterStandardType("System.Reflection.RuntimeAssembly")
|
||||
end
|
||||
|
||||
Init()
|
||||
return Environment.Export(_ENV)
|
32
Neurotrauma/Lua/ConsentRequiredExtended/Util/Environment.lua
Normal file
32
Neurotrauma/Lua/ConsentRequiredExtended/Util/Environment.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- Functions for managing the mod's environment.
|
||||
|
||||
---Isolate a function or module's environment from Global.
|
||||
---@param env table The _ENV table.
|
||||
local function prepareEnvironment(env)
|
||||
return setmetatable(
|
||||
{},
|
||||
{
|
||||
__index = _G,
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
local _ENV = prepareEnvironment(_ENV)
|
||||
|
||||
PrepareEnvironment = prepareEnvironment
|
||||
|
||||
---Create an empty table whose metatable indexes non-local variables declared within
|
||||
---a function/module's environment, and is immutable to any changes.
|
||||
---@param env table The _ENV table.
|
||||
---@return table Empty table that interfaces with _ENV.
|
||||
function Export(env)
|
||||
return setmetatable(
|
||||
{},
|
||||
{
|
||||
__index = function(t, k) return env[k] end,
|
||||
__newindex = function() error("Attempted to modify a protected table.") end
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
return Export(_ENV)
|
35
Neurotrauma/Lua/ConsentRequiredExtended/Util/UserData.lua
Normal file
35
Neurotrauma/Lua/ConsentRequiredExtended/Util/UserData.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
-- Functions for creating userdata.
|
||||
|
||||
local Environment = require 'ConsentRequiredExtended.Util.Environment'
|
||||
local _ENV = Environment.PrepareEnvironment(_ENV)
|
||||
|
||||
---Create a userdata that references the type in a static context.
|
||||
---@param clrTypeName string The name of the type to point to.
|
||||
---@return userdata A userdata that references the type in a static context.
|
||||
function FromStringStatic(clrTypeName)
|
||||
LuaUserData.CreateStatic(clrTypeName)
|
||||
end
|
||||
|
||||
---Create a userdata that references the type described by a ClrType in a static context.
|
||||
---@param clrType ClrType ClrType that describes the type being referenced.
|
||||
---@return userdata A userdata that references the type in a static context.
|
||||
function FromClrTypeStatic(clrType)
|
||||
return FromStringStatic(clrType:GetFullName())
|
||||
end
|
||||
|
||||
---Create a userdata that references an instance of a CLR type with conversion.
|
||||
---@param value any A Lua value to convert to a CLR object of the given type and wrap up in a userdata.
|
||||
---@param clrType ClrType The CLR type to instantiate and wrap in the userdata.
|
||||
---@return userdata A userdata that references the an instance of the CLR type.
|
||||
function FromClrType(value, clrType)
|
||||
return LuaUserData.CreateUserDataFromType(value, clrType:GetUnderlyingType())
|
||||
end
|
||||
|
||||
---Register standard types with MoonSharp. For generics use RegisterClrType.ConstructedGenericType.
|
||||
---@param typeName string Name of the type to register.
|
||||
function RegisterStandardType(typeName)
|
||||
local desc = LuaUserData.RegisterType(typeName)
|
||||
_G.Descriptors[typeName] = desc
|
||||
end
|
||||
|
||||
return Environment.Export(_ENV)
|
16
Neurotrauma/Lua/ConsentRequiredExtended/init.lua
Normal file
16
Neurotrauma/Lua/ConsentRequiredExtended/init.lua
Normal file
@@ -0,0 +1,16 @@
|
||||
local SRC_NAMESPACE = "ConsentRequiredExtended."
|
||||
local MAIN = "Main"
|
||||
local LUA_EVENT_LOADED = "loaded"
|
||||
local HOOK_NAME_ON_LOADED = "ConsentRequiredExtended.onLoaded"
|
||||
|
||||
local function onLoaded()
|
||||
-- Only run client side if not multiplayer
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
-- if Game.IsMultiplayer and CLIENT then return end
|
||||
|
||||
local requireStr = SRC_NAMESPACE .. MAIN
|
||||
|
||||
require(requireStr)
|
||||
end
|
||||
|
||||
Hook.Add(LUA_EVENT_LOADED, HOOK_NAME_ON_LOADED, onLoaded)
|
@@ -0,0 +1,38 @@
|
||||
local Api = require("ConsentRequiredExtended.Api")
|
||||
|
||||
local function isItemAffected(identifier)
|
||||
return Api.IsItemAffected(identifier)
|
||||
end
|
||||
|
||||
---@param meleeweapon Weapon target
|
||||
---@param target The target of the hit could be a limb or just a character.
|
||||
local function onMeleeWeaponHandleImpact(meleeweapon, target)
|
||||
if not NTConfig.Get("NTCRE_ConsentRequired", true) then
|
||||
return
|
||||
end
|
||||
if meleeweapon == nil or target == nil then
|
||||
return
|
||||
end
|
||||
local itemIdentifier = meleeweapon.item.Prefab.Identifier.Value
|
||||
if isItemAffected(itemIdentifier) then
|
||||
local user = meleeweapon.picker
|
||||
if user == nil then
|
||||
return
|
||||
end
|
||||
local targetUserData = target.UserData
|
||||
if targetUserData == nil then
|
||||
return
|
||||
end
|
||||
local targetUser = nil
|
||||
if LuaUserData.IsTargetType(targetUserData, "Barotrauma.Limb") then
|
||||
targetUser = targetUserData.character
|
||||
elseif LuaUserData.IsTargetType(targetUserData, "Barotrauma.Character") then
|
||||
targetUser = targetUserData
|
||||
end
|
||||
if targetUser ~= nil then
|
||||
Api.onAffectedItemApplied(user, targetUser)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return onMeleeWeaponHandleImpact
|
56
Neurotrauma/Lua/Scripts/Client/MultiLineTextBox.lua
Normal file
56
Neurotrauma/Lua/Scripts/Client/MultiLineTextBox.lua
Normal file
@@ -0,0 +1,56 @@
|
||||
-- why barotrauma's GUI libraries don't have this implemented by default? this is stupid
|
||||
|
||||
local function updateServerMessageScrollBasedOnCaret(textBox, listBox)
|
||||
local caretY = textBox.CaretScreenPos.Y
|
||||
local bottomCaretExtent = textBox.Font.LineHeight * 1.5
|
||||
local topCaretExtent = -textBox.Font.LineHeight * 0.5
|
||||
|
||||
if caretY + bottomCaretExtent > listBox.Rect.Bottom then
|
||||
listBox.ScrollBar.BarScroll = (caretY - textBox.Rect.Top - listBox.Rect.Height + bottomCaretExtent)
|
||||
/ (textBox.Rect.Height - listBox.Rect.Height)
|
||||
elseif caretY + topCaretExtent < listBox.Rect.Top then
|
||||
listBox.ScrollBar.BarScroll = (caretY - textBox.Rect.Top + topCaretExtent)
|
||||
/ (textBox.Rect.Height - listBox.Rect.Height)
|
||||
end
|
||||
end
|
||||
|
||||
local function CreateMultiLineTextBox(rectransform, text, size)
|
||||
local multineListBox = GUI.ListBox(GUI.RectTransform(Vector2(1, size or 0.2), rectransform))
|
||||
|
||||
local textBox = GUI.TextBox(
|
||||
GUI.RectTransform(Vector2(1, 1), multineListBox.Content.RectTransform),
|
||||
text,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
true,
|
||||
"GUITextBoxNoBorder"
|
||||
)
|
||||
|
||||
textBox.add_OnSelected(function()
|
||||
updateServerMessageScrollBasedOnCaret(textBox, multineListBox)
|
||||
end)
|
||||
|
||||
textBox.OnTextChangedDelegate = function()
|
||||
local textSize = textBox.Font.MeasureString(textBox.WrappedText)
|
||||
textBox.RectTransform.NonScaledSize =
|
||||
Point(textBox.RectTransform.NonScaledSize.X, math.max(multineListBox.Content.Rect.Height, textSize.Y + 10))
|
||||
multineListBox.UpdateScrollBarSize()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
textBox.OnEnterPressed = function()
|
||||
local str = textBox.Text
|
||||
local caretIndex = textBox.CaretIndex
|
||||
|
||||
textBox.Text = str:sub(1, caretIndex) .. "\n" .. str:sub(caretIndex + 1)
|
||||
textBox.CaretIndex = caretIndex + 1
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return textBox
|
||||
end
|
||||
|
||||
return CreateMultiLineTextBox
|
242
Neurotrauma/Lua/Scripts/Client/configgui.lua
Normal file
242
Neurotrauma/Lua/Scripts/Client/configgui.lua
Normal file
@@ -0,0 +1,242 @@
|
||||
--easysettings by Evil Factory
|
||||
local easySettings = dofile(NT.Path .. "/Lua/Scripts/Client/easysettings.lua")
|
||||
local MultiLineTextBox = dofile(NT.Path .. "/Lua/Scripts/Client/MultiLineTextBox.lua")
|
||||
local GUIComponent = LuaUserData.CreateStatic("Barotrauma.GUIComponent")
|
||||
local configUI
|
||||
|
||||
local function CommaStringToTable(str)
|
||||
local tbl = {}
|
||||
|
||||
for word in string.gmatch(str, "([^,]+)") do
|
||||
table.insert(tbl, word)
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
--calculate difficulty
|
||||
local function DetermineDifficulty()
|
||||
local difficulty = 0
|
||||
local defaultDifficulty = 0
|
||||
local res = ""
|
||||
|
||||
for key, entry in pairs(NTConfig.Entries) do
|
||||
if entry.difficultyCharacteristics then
|
||||
local entryValue = entry.value
|
||||
local entryValueDefault = entry.default
|
||||
local diffMultiplier = 1
|
||||
if entry.type == "bool" then
|
||||
entryValue = HF.BoolToNum(entry.value)
|
||||
entryValueDefault = HF.BoolToNum(entry.default)
|
||||
end
|
||||
if entry.difficultyCharacteristics.multiplier then
|
||||
diffMultiplier = entry.difficultyCharacteristics.multiplier
|
||||
end
|
||||
|
||||
defaultDifficulty = defaultDifficulty + entryValueDefault * diffMultiplier
|
||||
difficulty = difficulty + math.min(entryValue * diffMultiplier, entry.difficultyCharacteristics.max or 1)
|
||||
end
|
||||
end
|
||||
|
||||
-- normalize to 10
|
||||
difficulty = difficulty / defaultDifficulty * 10
|
||||
|
||||
if difficulty > 23 then
|
||||
res = "Impossible"
|
||||
elseif difficulty > 16 then
|
||||
res = "Very hard"
|
||||
elseif difficulty > 11 then
|
||||
res = "Hard"
|
||||
elseif difficulty > 8 then
|
||||
res = "Normal"
|
||||
elseif difficulty > 6 then
|
||||
res = "Easy"
|
||||
elseif difficulty > 4 then
|
||||
res = "Very easy"
|
||||
elseif difficulty > 2 then
|
||||
res = "Barely different"
|
||||
else
|
||||
res = "Vanilla but sutures"
|
||||
end
|
||||
|
||||
res = res .. " (" .. HF.Round(difficulty, 1) .. ")"
|
||||
return res
|
||||
end
|
||||
|
||||
--bulk of the GUI code
|
||||
local function ConstructUI(parent)
|
||||
local list = easySettings.BasicList(parent)
|
||||
|
||||
--info text
|
||||
local userBlock = GUI.TextBlock(
|
||||
GUI.RectTransform(Vector2(1, 0.2), list.Content.RectTransform),
|
||||
"Server config can be changed by owner or a client with manage settings permission. If the server doesn't allow writing into the config folder, then it must be edited manually.",
|
||||
Color(200, 255, 255),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
local difficultyBlock = GUI.TextBlock(
|
||||
GUI.RectTransform(Vector2(1, 0.1), list.Content.RectTransform),
|
||||
"",
|
||||
Color(200, 255, 255),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
|
||||
--set difficulty text (why does this even exist in the first place)
|
||||
local function OnChanged()
|
||||
difficultyRate = "Calculated difficulty rating: " .. DetermineDifficulty()
|
||||
difficultyBlock.Text = difficultyRate
|
||||
end
|
||||
OnChanged()
|
||||
|
||||
--empty space
|
||||
--GUI.TextBlock(GUI.RectTransform(Vector2(0.2, 0.1), list.Content.RectTransform), "", Color(255,255,255), nil, GUI.Alignment.Center, true, nil, Color(0,0,0))
|
||||
|
||||
-- procedurally construct config UI
|
||||
for key, entry in pairs(NTConfig.Entries) do
|
||||
if entry.type == "float" then
|
||||
-- scalar value
|
||||
--grab range
|
||||
local minrange = ""
|
||||
local maxrange = ""
|
||||
local count = 0
|
||||
for _, rangegrab in pairs(entry.range) do
|
||||
if count == 0 then
|
||||
minrange = rangegrab
|
||||
end
|
||||
if count == 1 then
|
||||
maxrange = rangegrab
|
||||
end
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
local rect = GUI.RectTransform(Vector2(1, 0.05), list.Content.RectTransform)
|
||||
local textBlock = GUI.TextBlock(
|
||||
rect,
|
||||
entry.name .. " (" .. minrange .. "-" .. maxrange .. ")",
|
||||
Color(230, 230, 170),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
if entry.description then
|
||||
textBlock.ToolTip = entry.description
|
||||
end
|
||||
local scalar =
|
||||
GUI.NumberInput(GUI.RectTransform(Vector2(1, 0.08), list.Content.RectTransform), NumberType.Float)
|
||||
local key2 = key
|
||||
scalar.valueStep = 0.1
|
||||
scalar.MinValueFloat = 0
|
||||
scalar.MaxValueFloat = 100
|
||||
if entry.range then
|
||||
scalar.MinValueFloat = entry.range[1]
|
||||
scalar.MaxValueFloat = entry.range[2]
|
||||
end
|
||||
scalar.FloatValue = NTConfig.Get(key2, 1)
|
||||
scalar.OnValueChanged = function()
|
||||
NTConfig.Set(key2, scalar.FloatValue)
|
||||
OnChanged()
|
||||
end
|
||||
elseif entry.type == "string" then
|
||||
--user string input
|
||||
local style = ""
|
||||
--get custom style
|
||||
if entry.style ~= nil then
|
||||
style = " (" .. entry.style .. ")"
|
||||
end
|
||||
|
||||
local rect = GUI.RectTransform(Vector2(1, 0.05), list.Content.RectTransform)
|
||||
local textBlock = GUI.TextBlock(
|
||||
rect,
|
||||
entry.name .. style,
|
||||
Color(230, 230, 170),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
if entry.description then
|
||||
textBlock.ToolTip = entry.description
|
||||
end
|
||||
|
||||
local stringinput = MultiLineTextBox(list.Content.RectTransform, "", entry.boxsize)
|
||||
|
||||
stringinput.Text = table.concat(entry.value, ",")
|
||||
|
||||
stringinput.OnTextChangedDelegate = function(textBox)
|
||||
entry.value = CommaStringToTable(textBox.Text)
|
||||
end
|
||||
elseif entry.type == "bool" then
|
||||
-- toggle
|
||||
local rect = GUI.RectTransform(Vector2(1, 0.2), list.Content.RectTransform)
|
||||
local toggle = GUI.TickBox(rect, entry.name)
|
||||
if entry.description then
|
||||
toggle.ToolTip = entry.description
|
||||
end
|
||||
local key2 = key
|
||||
toggle.Selected = NTConfig.Get(key2, false)
|
||||
toggle.OnSelected = function()
|
||||
NTConfig.Set(key2, toggle.State == GUIComponent.ComponentState.Selected)
|
||||
OnChanged()
|
||||
end
|
||||
elseif entry.type == "category" then
|
||||
-- visual separation
|
||||
GUI.TextBlock(
|
||||
GUI.RectTransform(Vector2(1, 0.05), list.Content.RectTransform),
|
||||
entry.name,
|
||||
Color(255, 255, 255),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
--empty space as last tickbox was getting cutoff
|
||||
GUI.TextBlock(
|
||||
GUI.RectTransform(Vector2(1, 0.05), list.Content.RectTransform),
|
||||
"",
|
||||
Color(255, 255, 255),
|
||||
nil,
|
||||
GUI.Alignment.Center,
|
||||
true,
|
||||
nil,
|
||||
Color(0, 0, 0)
|
||||
)
|
||||
|
||||
if Game.IsMultiplayer and not Game.Client.HasPermission(ClientPermissions.ManageSettings) then
|
||||
for guicomponent in list.GetAllChildren() do
|
||||
guicomponent.enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
return list
|
||||
end
|
||||
|
||||
Networking.Receive("NT.ConfigUpdate", function(msg)
|
||||
NTConfig.ReceiveConfig(msg)
|
||||
local parent = configUI.Parent.Parent
|
||||
configUI.RectTransform.Parent = nil
|
||||
configUI = nil
|
||||
configUI = ConstructUI(parent)
|
||||
end)
|
||||
|
||||
easySettings.AddMenu("Neurotrauma", function(parent)
|
||||
if Game.IsMultiplayer then
|
||||
local msg = Networking.Start("NT.ConfigRequest")
|
||||
Networking.Send(msg)
|
||||
end
|
||||
configUI = ConstructUI(parent)
|
||||
end)
|
170
Neurotrauma/Lua/Scripts/Client/easysettings.lua
Normal file
170
Neurotrauma/Lua/Scripts/Client/easysettings.lua
Normal file
@@ -0,0 +1,170 @@
|
||||
--original code by Evil Factory,
|
||||
--adapted to NT
|
||||
local easySettings = {}
|
||||
|
||||
easySettings.Settings = {}
|
||||
|
||||
local GUIComponent = LuaUserData.CreateStatic("Barotrauma.GUIComponent")
|
||||
|
||||
local function GetChildren(comp)
|
||||
local tbl = {}
|
||||
for value in comp.GetAllChildren() do
|
||||
table.insert(tbl, value)
|
||||
end
|
||||
return tbl
|
||||
end
|
||||
|
||||
Hook.Patch("Barotrauma.GUI", "TogglePauseMenu", {}, function()
|
||||
if GUI.GUI.PauseMenuOpen then
|
||||
local frame = GUI.GUI.PauseMenu
|
||||
|
||||
local list = GetChildren(GetChildren(frame)[2])[1]
|
||||
|
||||
for key, value in pairs(easySettings.Settings) do
|
||||
local button = GUI.Button(
|
||||
GUI.RectTransform(Vector2(1, 0.1), list.RectTransform),
|
||||
value.Name,
|
||||
GUI.Alignment.Center,
|
||||
"GUIButtonSmall"
|
||||
)
|
||||
|
||||
button.OnClicked = function()
|
||||
value.OnOpen(frame)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, Hook.HookMethodType.After)
|
||||
|
||||
easySettings.SaveTable = function(path, tbl)
|
||||
File.Write(path, json.serialize(tbl))
|
||||
end
|
||||
easySettings.LoadTable = function(path)
|
||||
if not File.Exists(path) then
|
||||
return {}
|
||||
end
|
||||
|
||||
return json.parse(File.Read(path))
|
||||
end
|
||||
|
||||
easySettings.AddMenu = function(name, onOpen)
|
||||
table.insert(easySettings.Settings, { Name = name, OnOpen = onOpen })
|
||||
end
|
||||
|
||||
easySettings.BasicList = function(parent, size)
|
||||
local menuContent = GUI.Frame(GUI.RectTransform(size or Vector2(0.3, 0.6), parent.RectTransform, GUI.Anchor.Center))
|
||||
local menuList = GUI.ListBox(GUI.RectTransform(Vector2(1, 0.95), menuContent.RectTransform, GUI.Anchor.TopCenter))
|
||||
|
||||
easySettings.SaveButton(menuContent)
|
||||
easySettings.CloseButton(menuContent)
|
||||
easySettings.ResetButton(menuContent)
|
||||
|
||||
return menuList
|
||||
end
|
||||
|
||||
easySettings.TickBox = function(parent, text, onSelected, state)
|
||||
if state == nil then
|
||||
state = true
|
||||
end
|
||||
|
||||
local tickBox = GUI.TickBox(GUI.RectTransform(Vector2(1, 0.2), parent.RectTransform), text)
|
||||
tickBox.Selected = state
|
||||
tickBox.OnSelected = function()
|
||||
onSelected(tickBox.State == GUIComponent.ComponentState.Selected)
|
||||
end
|
||||
|
||||
return tickBox
|
||||
end
|
||||
|
||||
easySettings.Slider = function(parent, min, max, onSelected, value)
|
||||
local scrollBar = GUI.ScrollBar(GUI.RectTransform(Vector2(1, 0.1), parent.RectTransform), 0.1, nil, "GUISlider")
|
||||
scrollBar.Range = Vector2(min, max)
|
||||
scrollBar.BarScrollValue = value or max / 2
|
||||
scrollBar.OnMoved = function()
|
||||
onSelected(scrollBar.BarScrollValue)
|
||||
end
|
||||
|
||||
return scrollBar
|
||||
end
|
||||
|
||||
--save and exit
|
||||
easySettings.SaveButton = function(parent)
|
||||
local button = GUI.Button(
|
||||
GUI.RectTransform(Vector2(0.33, 0.05), parent.RectTransform, GUI.Anchor.BottomLeft),
|
||||
"Save and Exit",
|
||||
GUI.Alignment.Center,
|
||||
"GUIButton"
|
||||
)
|
||||
|
||||
button.OnClicked = function()
|
||||
if Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings) then
|
||||
NTConfig.SendConfig()
|
||||
elseif Game.IsSingleplayer then
|
||||
NTConfig.SaveConfig()
|
||||
end
|
||||
GUI.GUI.TogglePauseMenu()
|
||||
end
|
||||
|
||||
return button
|
||||
end
|
||||
|
||||
--discard and exit
|
||||
easySettings.CloseButton = function(parent)
|
||||
local button = GUI.Button(
|
||||
GUI.RectTransform(Vector2(0.33, 0.05), parent.RectTransform, GUI.Anchor.BottomCenter),
|
||||
"Discard and Exit",
|
||||
GUI.Alignment.Center,
|
||||
"GUIButton"
|
||||
)
|
||||
|
||||
button.OnClicked = function()
|
||||
GUI.GUI.TogglePauseMenu()
|
||||
NTConfig.LoadConfig()
|
||||
end
|
||||
|
||||
return button
|
||||
end
|
||||
|
||||
--reset and exit
|
||||
easySettings.ResetButton = function(parent)
|
||||
local button = GUI.Button(
|
||||
GUI.RectTransform(Vector2(0.33, 0.05), parent.RectTransform, GUI.Anchor.BottomRight),
|
||||
"Reset Config",
|
||||
GUI.Alignment.Center,
|
||||
"GUIButton"
|
||||
)
|
||||
|
||||
button.OnClicked = function()
|
||||
if
|
||||
Game.IsSingleplayer or (Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings))
|
||||
then
|
||||
easySettings.ResetMessage(parent)
|
||||
end
|
||||
end
|
||||
return button
|
||||
end
|
||||
|
||||
easySettings.ResetMessage = function(parent)
|
||||
local ResetMessage = GUI.MessageBox(
|
||||
"Reset neurotrauma settings",
|
||||
"Are you sure you want to reset neurotrauma settings to default values?",
|
||||
{ "Yes", "No" }
|
||||
)
|
||||
ResetMessage.DrawOnTop = true
|
||||
ResetMessage.Text.TextAlignment = GUI.Alignment.Center
|
||||
ResetMessage.Buttons[1].OnClicked = function()
|
||||
NTConfig.ResetConfig()
|
||||
if Game.IsMultiplayer and Game.Client.HasPermission(ClientPermissions.ManageSettings) then
|
||||
NTConfig.SendConfig()
|
||||
elseif Game.IsSingleplayer then
|
||||
NTConfig.SaveConfig()
|
||||
end
|
||||
GUI.GUI.TogglePauseMenu()
|
||||
ResetMessage.Close()
|
||||
end
|
||||
ResetMessage.Buttons[2].OnClicked = function()
|
||||
ResetMessage.Close()
|
||||
end
|
||||
return ResetMessage
|
||||
end
|
||||
|
||||
return easySettings
|
182
Neurotrauma/Lua/Scripts/Server/blood.lua
Normal file
182
Neurotrauma/Lua/Scripts/Server/blood.lua
Normal file
@@ -0,0 +1,182 @@
|
||||
-- Neurotrauma blood types functions
|
||||
-- Hooks Lua event "characterCreated" to create a randomized blood type for spawned character and sets their immunity to 100
|
||||
---@diagnostic disable: lowercase-global, undefined-global
|
||||
NT.BLOODTYPE = { -- blood types and chance in percent
|
||||
{ "ominus", 7 },
|
||||
{ "oplus", 37 },
|
||||
{ "aminus", 6 },
|
||||
{ "aplus", 36 },
|
||||
{ "bminus", 2 },
|
||||
{ "bplus", 8 },
|
||||
{ "abminus", 1 },
|
||||
{ "abplus", 3 },
|
||||
}
|
||||
NT.setBlood = {}
|
||||
NT.foundAny = false
|
||||
|
||||
-- Insert all blood types in one table for RandomizeBlood()
|
||||
for index, value in ipairs(NT.BLOODTYPE) do
|
||||
-- print(index," : ",value[1],", ",value[2],"%")
|
||||
table.insert(NT.setBlood, index, { value[2], value[1] })
|
||||
end
|
||||
|
||||
-- Applies math.random() blood type.
|
||||
-- returns the applied bloodtype as an affliction identifier
|
||||
function NT.RandomizeBlood(character)
|
||||
rand = math.random(0, 99)
|
||||
local i = 0
|
||||
for index, value in ipairs(NT.setBlood) do
|
||||
i = i + value[1]
|
||||
if i > rand then
|
||||
HF.SetAffliction(character, value[2], 100)
|
||||
return value[2]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Hook.Add("characterCreated", "NT.BloodAndImmunity", function(createdCharacter)
|
||||
Timer.Wait(function()
|
||||
if createdCharacter.IsHuman and not createdCharacter.IsDead then
|
||||
NT.TryRandomizeBlood(createdCharacter)
|
||||
|
||||
-- add immunity
|
||||
local conditional2 = createdCharacter.CharacterHealth.GetAffliction("immunity")
|
||||
if conditional2 == nil then
|
||||
HF.SetAffliction(createdCharacter, "immunity", 100)
|
||||
end
|
||||
end
|
||||
end, 1000)
|
||||
end)
|
||||
|
||||
-- applies a new bloodtype only if the character doesnt already have one
|
||||
function NT.TryRandomizeBlood(character)
|
||||
NT.GetBloodtype(character)
|
||||
end
|
||||
|
||||
-- returns the bloodtype of the character as an affliction identifier string
|
||||
-- generates blood type if none present
|
||||
function NT.GetBloodtype(character)
|
||||
for index, affliction in ipairs(NT.BLOODTYPE) do
|
||||
local conditional = character.CharacterHealth.GetAffliction(affliction[1])
|
||||
|
||||
if conditional ~= nil and conditional.Strength > 0 then
|
||||
return affliction[1] -- TODO: give out abplus (AB+) to enemy team for blood infusions
|
||||
end
|
||||
end
|
||||
|
||||
return NT.RandomizeBlood(character)
|
||||
end
|
||||
|
||||
function NT.HasBloodtype(character)
|
||||
for index, affliction in ipairs(NT.BLOODTYPE) do
|
||||
local conditional = character.CharacterHealth.GetAffliction(affliction[1])
|
||||
|
||||
if conditional ~= nil and conditional.Strength > 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
Hook.Add("OnInsertedIntoBloodAnalyzer", "NT.BloodAnalyzer", function(effect, deltaTime, item, targets, position)
|
||||
-- Hematology Analyzer (bloodanalyzer) can scan inserted blood bags
|
||||
local owner = item.GetRootInventoryOwner()
|
||||
if owner == nil then return end
|
||||
if not LuaUserData.IsTargetType(owner, "Barotrauma.Character") then return end
|
||||
if not owner.IsPlayer then return end
|
||||
|
||||
local character = owner
|
||||
local contained = item.OwnInventory.GetItemAt(0)
|
||||
|
||||
local BaseColor = "127,255,255"
|
||||
local NameColor = "127,255,255"
|
||||
local LowColor = "127,255,255"
|
||||
local HighColor = "127,255,255"
|
||||
local VitalColor = "127,255,255"
|
||||
|
||||
if NTConfig.Get("NTSCAN_enablecoloredscanner", 1) then
|
||||
BaseColor = table.concat(NTConfig.Get("NTSCAN_basecolor", 1), ",")
|
||||
NameColor = table.concat(NTConfig.Get("NTSCAN_namecolor", 1), ",")
|
||||
LowColor = table.concat(NTConfig.Get("NTSCAN_lowcolor", 1), ",")
|
||||
HighColor = table.concat(NTConfig.Get("NTSCAN_highcolor", 1), ",")
|
||||
VitalColor = table.concat(NTConfig.Get("NTSCAN_vitalcolor", 1), ",")
|
||||
end
|
||||
|
||||
-- NT adds bloodbag; NT Blood Work or 'Real Sonar Medical Item Recipes Patch for Neurotrauma' add allblood, lets check for either
|
||||
if contained ~= nil and (contained.HasTag("bloodbag") or contained.HasTag("allblood")) then
|
||||
HF.GiveItem(character, "ntsfx_syringe")
|
||||
Timer.Wait(function()
|
||||
if item == nil or character == nil or item.OwnInventory.GetItemAt(0) ~= contained then
|
||||
return
|
||||
end
|
||||
|
||||
local identifier = contained.Prefab.Identifier.Value
|
||||
local packtype = "o-"
|
||||
if identifier ~= "antibloodloss2" then
|
||||
packtype = string.sub(identifier, string.len("bloodpack") + 1)
|
||||
end
|
||||
local bloodTypeDisplay = string.gsub(packtype, "abc", "c")
|
||||
bloodTypeDisplay = string.gsub(bloodTypeDisplay, "plus", "+")
|
||||
bloodTypeDisplay = string.gsub(bloodTypeDisplay, "minus", "-")
|
||||
bloodTypeDisplay = string.upper(bloodTypeDisplay)
|
||||
|
||||
local readoutString = "‖color:"
|
||||
.. BaseColor
|
||||
.. "‖"
|
||||
.. "Bloodpack: "
|
||||
.. "‖color:end‖"
|
||||
.. "‖color:"
|
||||
.. NameColor
|
||||
.. "‖"
|
||||
.. bloodTypeDisplay
|
||||
.. "‖color:end‖"
|
||||
-- check if acidosis, alkalosis or sepsis
|
||||
local tags = HF.SplitString(contained.Tags, ",")
|
||||
local defects = ""
|
||||
for tag in tags do
|
||||
if tag == "sepsis" then
|
||||
defects = defects .. "‖color:" .. VitalColor .. "‖" .. "\nSepsis detected" .. "‖color:end‖"
|
||||
end
|
||||
|
||||
if HF.StartsWith(tag, "acid") then
|
||||
local split = HF.SplitString(tag, ":")
|
||||
if split[2] ~= nil then
|
||||
defects = defects
|
||||
.. "‖color:"
|
||||
.. HighColor
|
||||
.. "‖"
|
||||
.. "\nAcidosis: "
|
||||
.. tonumber(split[2])
|
||||
.. "%"
|
||||
.. "‖color:end‖"
|
||||
end
|
||||
elseif HF.StartsWith(tag, "alkal") then
|
||||
local split = HF.SplitString(tag, ":")
|
||||
if split[2] ~= nil then
|
||||
defects = defects
|
||||
.. "‖color:"
|
||||
.. HighColor
|
||||
.. "‖"
|
||||
.. "\nAlkalosis: "
|
||||
.. tonumber(split[2])
|
||||
.. "%"
|
||||
.. "‖color:end‖"
|
||||
end
|
||||
end
|
||||
end
|
||||
if defects ~= "" then
|
||||
readoutString = readoutString .. defects
|
||||
else
|
||||
readoutString = readoutString
|
||||
.. "‖color:"
|
||||
.. LowColor
|
||||
.. "‖"
|
||||
.. "\nNo blood defects"
|
||||
.. "‖color:end‖"
|
||||
end
|
||||
|
||||
HF.DMClient(HF.CharacterToClient(character), readoutString, Color(127, 255, 255, 255))
|
||||
end, 1500)
|
||||
end
|
||||
end)
|
32
Neurotrauma/Lua/Scripts/Server/characterpatches.lua
Normal file
32
Neurotrauma/Lua/Scripts/Server/characterpatches.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
-- Hooks CalculateMovementPenalty method of Barotrauma.Character
|
||||
-- when painless enough, disable weapon sway / movement hindrance limb penalties
|
||||
-- !!! Lags the game, skipping this file, and there is no Lua perf tracker to potentially fix, screw it for now
|
||||
|
||||
-- Disable movement penalties for painless characters
|
||||
-- Has about 2 ms performance drop on a many character save
|
||||
Hook.Patch("Barotrauma.Character", "CalculateMovementPenalty", function(instance, ptable)
|
||||
if HF.HasAffliction(instance, "analgesia", 20) then
|
||||
ptable.PreventExecution = true
|
||||
return 0
|
||||
end
|
||||
end, Hook.HookMethodType.Before)
|
||||
|
||||
-- Disable aim penalties for painless characters
|
||||
Hook.Patch("Barotrauma.AnimController", "GetAimWobble", function(instance, ptable)
|
||||
if HF.HasAffliction(instance.Character, "analgesia", 20) then
|
||||
ptable.PreventExecution = true
|
||||
return 0
|
||||
end
|
||||
end, Hook.HookMethodType.Before)
|
||||
|
||||
-- Patch to cause unconscious from the game rather than stun
|
||||
-- Lags the game by 6 times (on the same save)
|
||||
Hook.Patch("Barotrauma.CharacterHealth", "get_IsUnconscious", function(instance, ptable)
|
||||
local isUnconscious = HF.HasAffliction(instance.Character, "sym_unconsciousness")
|
||||
ptable.PreventExecution = true
|
||||
return instance.Character.IsDead
|
||||
or (
|
||||
(instance.Character.Vitality <= 0.0 or isUnconscious)
|
||||
and not instance.Character.HasAbilityFlag(AbilityFlags.AlwaysStayConscious)
|
||||
)
|
||||
end, Hook.HookMethodType.After)
|
112
Neurotrauma/Lua/Scripts/Server/convertbloodpacks.lua
Normal file
112
Neurotrauma/Lua/Scripts/Server/convertbloodpacks.lua
Normal file
@@ -0,0 +1,112 @@
|
||||
-- THIS FILE IS NO LONGER IN USE
|
||||
-- the defunct item in question has been removed from the mod
|
||||
-- i'm keeping it here for...safekeeping i guess
|
||||
|
||||
LuaUserData.RegisterTypeBarotrauma("PurchasedItem")
|
||||
LuaUserData.RegisterType("System.Xml.Linq.XElement")
|
||||
|
||||
local VANILLA_PREFAB_ID = "antibloodloss2"
|
||||
local DEFUNCT_PREFAB_ID = "bloodpackominus"
|
||||
|
||||
-- Removes vanilla bloodpacks from cached stores in case the user installed
|
||||
-- this mod mid-campaign.
|
||||
-- NOTE: stores that had their stocks generated before installing this mod
|
||||
-- won't have any new medical items added.
|
||||
Hook.HookMethod("Barotrauma.Location", "LoadStores", function(instance, ptable)
|
||||
if instance.Stores == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for storeId, store in pairs(instance.Stores) do
|
||||
for _, purchasedItem in pairs(store.Stock) do
|
||||
local itemId = purchasedItem.ItemPrefabIdentifier
|
||||
if itemId == DEFUNCT_PREFAB_ID then
|
||||
-- print("Removing defunct bloodpack (qty " .. purchasedItem.Quantity .. ") from " .. tostring(storeId))
|
||||
store.RemoveStock({ purchasedItem })
|
||||
end
|
||||
end
|
||||
end
|
||||
end, Hook.HookMethodType.After)
|
||||
|
||||
-- Replaces all vanilla bloodpack items with O- blood
|
||||
local function replaceItems()
|
||||
local ntBloodPrefab = ItemPrefab.Prefabs[DEFUNCT_PREFAB_ID]
|
||||
local vanillaBloodPrefab = ItemPrefab.Prefabs[VANILLA_PREFAB_ID]
|
||||
if ntBloodPrefab == nil then
|
||||
print("ERROR: couldn't find " .. DEFUNCT_PREFAB_ID)
|
||||
return
|
||||
end
|
||||
|
||||
for _, item in pairs(Item.ItemList) do
|
||||
local id = tostring(item.Prefab.Identifier)
|
||||
if id == DEFUNCT_PREFAB_ID then
|
||||
-- Don't replace decorative blood packs
|
||||
if item.NonInteractable then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = item.WorldPosition
|
||||
local inv = item.ParentInventory
|
||||
local condition = item.ConditionPercentage
|
||||
local quality = item.Quality
|
||||
-- print("replacing blood pack (pos=" .. tostring(pos) .. ", inv=" .. tostring(inv) .. ")")
|
||||
|
||||
local slotIdx = -1
|
||||
if inv ~= nil then
|
||||
slotIdx = inv.FindIndex(item)
|
||||
if slotIdx < 0 then
|
||||
print(
|
||||
"ERROR: couldn't find item ("
|
||||
.. tostring(item)
|
||||
.. ", pos "
|
||||
.. tostring(pos)
|
||||
.. ") in inventory ("
|
||||
.. tostring(inv)
|
||||
.. ")"
|
||||
)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- We call `Drop()` first in case the inventory is full because
|
||||
-- `AddEntityToRemoveQueue` may not remove the item before we
|
||||
-- insert the new one, causing the inventory to overflow.
|
||||
item.Drop()
|
||||
Entity.Spawner.AddEntityToRemoveQueue(item)
|
||||
|
||||
Entity.Spawner.AddItemToSpawnQueue(vanillaBloodPrefab, pos, condition, quality, function(newItem)
|
||||
newItem.Rotation = item.Rotation
|
||||
-- Stolen items stay stolen
|
||||
newItem.AllowStealing = item.AllowStealing
|
||||
newItem.OriginalOutpost = item.OriginalOutpost
|
||||
|
||||
if inv ~= nil then
|
||||
if not inv.TryPutItem(newItem, slotIdx, false, true, nil) then
|
||||
print(
|
||||
"ERROR: failed to replace neurotrauma bloodpack ("
|
||||
.. tostring(item)
|
||||
.. ", pos "
|
||||
.. tostring(pos)
|
||||
.. ", slotIdx "
|
||||
.. tostring(slotIdx)
|
||||
.. ", inv "
|
||||
.. tostring(inv)
|
||||
.. ") with new item: "
|
||||
.. tostring(newItem)
|
||||
)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Hook.Add("roundStart", "NT.ConvertBloodPacks", function()
|
||||
replaceItems()
|
||||
end)
|
||||
|
||||
-- Hook.Add("chatMessage", "NT.BloodPackTesting", function(msg, client)
|
||||
-- if (msg == "convertblood") then
|
||||
-- replaceItems()
|
||||
-- end
|
||||
-- end)
|
41
Neurotrauma/Lua/Scripts/Server/cpr.lua
Normal file
41
Neurotrauma/Lua/Scripts/Server/cpr.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
-- Hooks Lua event "human.CPRSuccess" to prevent fractures from ragdoll jank, and
|
||||
-- apply NT affliction cpr_buff or cause rib fractures in Hooked Lua event "human.CPRFailed"
|
||||
Hook.Add("human.CPRSuccess", "NT.CPRSuccess", function(animcontroller)
|
||||
if
|
||||
animcontroller == nil
|
||||
or animcontroller.Character == nil
|
||||
or animcontroller.Character.SelectedCharacter == nil
|
||||
then
|
||||
return
|
||||
end
|
||||
local character = animcontroller.Character.SelectedCharacter
|
||||
|
||||
if not HF.HasAffliction(character, "cpr_buff_auto") then
|
||||
HF.AddAffliction(character, "cpr_buff", 2)
|
||||
end
|
||||
HF.AddAffliction(character, "cpr_fracturebuff", 2) -- prevent fractures during CPR (fuck baro physics)
|
||||
end)
|
||||
|
||||
Hook.Add("human.CPRFailed", "NT.CPRFailed", function(animcontroller)
|
||||
if
|
||||
animcontroller == nil
|
||||
or animcontroller.Character == nil
|
||||
or animcontroller.Character.SelectedCharacter == nil
|
||||
then
|
||||
return
|
||||
end
|
||||
local character = animcontroller.Character.SelectedCharacter
|
||||
|
||||
HF.AddAffliction(character, "cpr_fracturebuff", 2) -- prevent fractures during CPR (fuck baro physics)
|
||||
HF.AddAfflictionLimb(character, "blunttrauma", LimbType.Torso, 0.3)
|
||||
if
|
||||
HF.Chance(
|
||||
NTConfig.Get("NT_fractureChance", 1)
|
||||
* NTConfig.Get("NT_CPRFractureChance", 1)
|
||||
* 0.2
|
||||
/ HF.GetSkillLevel(animcontroller.Character, "medical")
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "t_fracture", 1)
|
||||
end
|
||||
end)
|
312
Neurotrauma/Lua/Scripts/Server/falldamage.lua
Normal file
312
Neurotrauma/Lua/Scripts/Server/falldamage.lua
Normal file
@@ -0,0 +1,312 @@
|
||||
-- Hooks Lua event "changeFallDamage" to cause more damage and NT afflictions like fractures and artery cuts on extremities depending on severity
|
||||
local limbtypes = {
|
||||
LimbType.Torso,
|
||||
LimbType.Head,
|
||||
LimbType.LeftArm,
|
||||
LimbType.RightArm,
|
||||
LimbType.LeftLeg,
|
||||
LimbType.RightLeg,
|
||||
}
|
||||
local function HasLungs(c)
|
||||
return not HF.HasAffliction(c, "lungremoved")
|
||||
end
|
||||
|
||||
local function getCalculatedReductionSuit(armor, strength, limbtype)
|
||||
if armor == nil then
|
||||
return 0
|
||||
end
|
||||
local reduction = 0
|
||||
|
||||
if armor.HasTag("deepdivinglarge") or armor.HasTag("deepdiving") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "blunttrauma") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
elseif armor.HasTag("clothing") and armor.HasTag("smallitem") and limbtype == LimbType.Torso then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "blunttrauma") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
return reduction
|
||||
end
|
||||
local function getCalculatedReductionClothes(armor, strength, limbtype)
|
||||
if armor == nil then
|
||||
return 0
|
||||
end
|
||||
local reduction = 0
|
||||
if armor.HasTag("deepdiving") or armor.HasTag("diving") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "blunttrauma") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
elseif armor.HasTag("clothing") and armor.HasTag("smallitem") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "blunttrauma") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
return reduction
|
||||
end
|
||||
local function getCalculatedReductionHelmet(armor, strength)
|
||||
if armor == nil then
|
||||
return 0
|
||||
end
|
||||
local reduction = 0
|
||||
|
||||
if armor.HasTag("smallitem") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "blunttrauma") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
return reduction
|
||||
end
|
||||
local function getCalculatedConcussionReduction(armor, strength)
|
||||
if armor == nil then
|
||||
return 0
|
||||
end
|
||||
local reduction = 0
|
||||
|
||||
if armor.HasTag("deepdiving") or armor.HasTag("deepdivinglarge") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "concussion") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
elseif armor.HasTag("smallitem") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "concussion") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
return reduction
|
||||
end
|
||||
Hook.Add("changeFallDamage", "NT.falldamage", function(impactDamage, character, impactPos, velocity)
|
||||
-- dont bother with creatures
|
||||
if not character.IsHuman then
|
||||
return
|
||||
end
|
||||
|
||||
-- dont apply fall damage in water
|
||||
if character.InWater then
|
||||
return 0
|
||||
end
|
||||
|
||||
-- dont apply fall damage when dragged by someone
|
||||
if character.SelectedBy ~= nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
local velocityMagnitude = HF.Magnitude(velocity)
|
||||
velocityMagnitude = velocityMagnitude ^ 1.5
|
||||
|
||||
-- apply fall damage to all limbs based on fall direction
|
||||
local mainlimbPos = character.AnimController.MainLimb.WorldPosition
|
||||
|
||||
local limbDotResults = {}
|
||||
local minDotRes = 1000
|
||||
|
||||
for limb in character.AnimController.Limbs do
|
||||
for type in limbtypes do
|
||||
if limb.type == type then
|
||||
-- fetch the direction of each limb relative to the torso
|
||||
local limbPosition = limb.WorldPosition
|
||||
local posDif = limbPosition - mainlimbPos
|
||||
posDif.X = posDif.X / 100
|
||||
posDif.Y = posDif.Y / 100
|
||||
local posDifMagnitude = HF.Magnitude(posDif)
|
||||
if posDifMagnitude > 1 then
|
||||
posDif.Normalize()
|
||||
end
|
||||
|
||||
local normalizedVelocity = Vector2(velocity.X, velocity.Y)
|
||||
normalizedVelocity.Normalize()
|
||||
|
||||
-- compare those directions to the direction we're moving
|
||||
-- this will later be used to hurt the limbs facing impact more than the others
|
||||
local limbDot = Vector2.Dot(posDif, normalizedVelocity)
|
||||
limbDotResults[type] = limbDot
|
||||
if minDotRes > limbDot then
|
||||
minDotRes = limbDot
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- shift all weights out of the negatives
|
||||
-- increase the weight of all limbs if speed is high
|
||||
-- the effect of this is that, at higher speeds, all limbs take damage instead of mainly the ones facing the impact site
|
||||
for type, dotResult in pairs(limbDotResults) do
|
||||
limbDotResults[type] = dotResult - minDotRes + math.max(0, (velocityMagnitude - 30) / 10)
|
||||
end
|
||||
|
||||
-- count weight so we're able to distribute the damage fractionally
|
||||
local weightsum = 0
|
||||
for dotResult in limbDotResults do
|
||||
weightsum = weightsum + dotResult
|
||||
end
|
||||
|
||||
for type, dotResult in pairs(limbDotResults) do
|
||||
local relativeWeight = dotResult / weightsum
|
||||
|
||||
-- lets limit the numbers to the max value of blunttrauma so that resistances make sense
|
||||
local damageInflictedToThisLimb = math.min(
|
||||
relativeWeight * math.max(0, velocityMagnitude - 10) ^ 1.5 * NTConfig.Get("NT_falldamage", 1) * 0.5,
|
||||
200
|
||||
)
|
||||
NT.CauseFallDamage(character, type, damageInflictedToThisLimb)
|
||||
end
|
||||
|
||||
-- make the normal damage not run
|
||||
return 0
|
||||
end)
|
||||
NT.CauseFallDamage = function(character, limbtype, strength)
|
||||
local armor1 = character.Inventory.GetItemInLimbSlot(InvSlotType.OuterClothes)
|
||||
local armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.InnerClothes)
|
||||
if limbtype ~= LimbType.Head then
|
||||
strength = math.max(
|
||||
strength
|
||||
- getCalculatedReductionSuit(armor1, strength, limbtype)
|
||||
- getCalculatedReductionClothes(armor2, strength, limbtype),
|
||||
0
|
||||
)
|
||||
else
|
||||
armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.Head)
|
||||
strength = math.max(
|
||||
strength
|
||||
- getCalculatedReductionSuit(armor1, strength, limbtype)
|
||||
- getCalculatedReductionHelmet(armor2, strength, limbtype),
|
||||
0
|
||||
)
|
||||
end
|
||||
|
||||
-- additionally calculate the affliction reduced damage
|
||||
local prefab = AfflictionPrefab.Prefabs["blunttrauma"]
|
||||
local resistance = character.CharacterHealth.GetResistance(prefab, limbtype)
|
||||
if resistance >= 1 then
|
||||
return
|
||||
end
|
||||
strength = strength * (1 - resistance)
|
||||
HF.AddAfflictionLimb(character, "blunttrauma", limbtype, strength)
|
||||
|
||||
-- return earlier if the strength value is not high enough for damage checks
|
||||
if strength < 1 then
|
||||
return
|
||||
end
|
||||
|
||||
local fractureImmune = false
|
||||
|
||||
local injuryChanceMultiplier = NTConfig.Get("NT_falldamageSeriousInjuryChance", 1)
|
||||
|
||||
-- torso
|
||||
if not fractureImmune and strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 15)
|
||||
/ 100
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
* injuryChanceMultiplier
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
strength
|
||||
/ 70
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if not fractureImmune and strength >= 1 and limbtype == LimbType.Head then
|
||||
if strength >= 15 and HF.Chance(math.min(strength / 100, 0.7)) then
|
||||
HF.AddAfflictionResisted(
|
||||
character,
|
||||
"concussion",
|
||||
math.max(
|
||||
10
|
||||
- getCalculatedConcussionReduction(armor1, 10, limbtype)
|
||||
- getCalculatedConcussionReduction(armor2, 10, limbtype),
|
||||
0
|
||||
)
|
||||
)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 15) / 100, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
* injuryChanceMultiplier
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
strength >= 55
|
||||
and HF.Chance(
|
||||
math.min((strength - 55) / 100, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
* injuryChanceMultiplier
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "n_fracture", 5)
|
||||
end
|
||||
if strength >= 5 and HF.Chance(0.7) then
|
||||
HF.AddAffliction(character, "cerebralhypoxia", strength * HF.RandomRange(0.1, 0.4))
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if not fractureImmune and strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 15)
|
||||
/ 100
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
* injuryChanceMultiplier
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
if HF.Chance((strength - 2) / 60) then
|
||||
-- this is here to simulate open fractures
|
||||
NT.ArteryCutLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
HF.Clamp((strength - 5) / 120, 0, 0.5)
|
||||
* NTC.GetMultiplier(character, "dislocationchance")
|
||||
* NTConfig.Get("NT_dislocationChance", 1)
|
||||
* injuryChanceMultiplier
|
||||
) and not NT.LimbIsAmputated(character, limbtype)
|
||||
then
|
||||
NT.DislocateLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
23
Neurotrauma/Lua/Scripts/Server/fuckbots.lua
Normal file
23
Neurotrauma/Lua/Scripts/Server/fuckbots.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
-- hopefully this stops bots from doing any rescuing at all.
|
||||
-- and also hopefully my assumption that this very specific thing
|
||||
-- about bots is what is causing them to eat frames is correct.
|
||||
|
||||
if NTConfig.Get("NT_disableBotAlgorithms", true) then
|
||||
Hook.Patch("Barotrauma.AIObjectiveRescueAll", "IsValidTarget", {
|
||||
"Barotrauma.Character",
|
||||
"Barotrauma.Character",
|
||||
"out System.Boolean",
|
||||
}, function(instance, ptable)
|
||||
-- TODO: some bot behavior
|
||||
-- make it hostile act if:
|
||||
-- surgery without corresponding ailments
|
||||
-- treatment without ailments
|
||||
|
||||
-- basic self treatments:
|
||||
-- find items to treat each other for blood loss or bleeding or suturable damage or fractures and dislocations
|
||||
-- ^ would possibly need items to have proper suitable treatments too, and yk bots dont spawn with enough meds...
|
||||
|
||||
ptable.PreventExecution = true
|
||||
return false
|
||||
end, Hook.HookMethodType.Before)
|
||||
end
|
2053
Neurotrauma/Lua/Scripts/Server/humanupdate.lua
Normal file
2053
Neurotrauma/Lua/Scripts/Server/humanupdate.lua
Normal file
File diff suppressed because it is too large
Load Diff
2304
Neurotrauma/Lua/Scripts/Server/items.lua
Normal file
2304
Neurotrauma/Lua/Scripts/Server/items.lua
Normal file
File diff suppressed because it is too large
Load Diff
101
Neurotrauma/Lua/Scripts/Server/lootcrates.lua
Normal file
101
Neurotrauma/Lua/Scripts/Server/lootcrates.lua
Normal file
@@ -0,0 +1,101 @@
|
||||
-- Spawns items inside medstartercrate
|
||||
-- Hooks XML Lua event "NT.medstartercrate.spawn" to create medstartercrate items and put them inside it
|
||||
Hook.Add(
|
||||
"NT.medstartercrate.spawn",
|
||||
"NT.medstartercrate.spawn",
|
||||
function(effect, deltaTime, item, targets, worldPosition)
|
||||
Timer.Wait(function()
|
||||
if item == nil then
|
||||
return
|
||||
end
|
||||
|
||||
-- check if the item already got populated before
|
||||
-- got broken somehow and is no longer needed, handled with oneshot="true" for the StatusEffect inside the medstartercrate item that calls this hook on spawn
|
||||
|
||||
-- local populated = item.HasTag("used")
|
||||
-- if populated then return end
|
||||
|
||||
-- add used tag
|
||||
|
||||
-- local tags = HF.SplitString(item.Tags,",")
|
||||
-- table.insert(tags,"used")
|
||||
-- local tagstring = ""
|
||||
-- for index, value in ipairs(tags) do
|
||||
-- tagstring = tagstring..value
|
||||
-- if index < #tags then tagstring=tagstring.."," end
|
||||
-- end
|
||||
-- item.Tags = tagstring
|
||||
|
||||
-- populate with goodies!!
|
||||
|
||||
if item.Scale == 0.5 then
|
||||
return
|
||||
end
|
||||
item.Scale = 0.5
|
||||
HF.SpawnItemPlusFunction("medtoolbox", function(params)
|
||||
HF.SpawnItemPlusFunction("defibrillator", nil, nil, params.item.OwnInventory, 0)
|
||||
HF.SpawnItemPlusFunction("autocpr", nil, nil, params.item.OwnInventory, 1)
|
||||
for i = 1, 2, 1 do
|
||||
HF.SpawnItemPlusFunction("tourniquet", nil, nil, params.item.OwnInventory, 2)
|
||||
end
|
||||
for i = 1, 2, 1 do
|
||||
HF.SpawnItemPlusFunction("ringerssolution", nil, nil, params.item.OwnInventory, 3)
|
||||
end
|
||||
HF.SpawnItemPlusFunction("surgicaldrill", nil, nil, params.item.OwnInventory, 4)
|
||||
HF.SpawnItemPlusFunction("surgerysaw", nil, nil, params.item.OwnInventory, 5)
|
||||
end, nil, item.OwnInventory, 0)
|
||||
|
||||
HF.SpawnItemPlusFunction("medtoolbox", function(params)
|
||||
HF.SpawnItemPlusFunction("antibleeding1", nil, nil, params.item.OwnInventory, 0)
|
||||
HF.SpawnItemPlusFunction("gypsum", nil, nil, params.item.OwnInventory, 1)
|
||||
HF.SpawnItemPlusFunction("opium", nil, nil, params.item.OwnInventory, 2)
|
||||
HF.SpawnItemPlusFunction("antibiotics", nil, nil, params.item.OwnInventory, 3)
|
||||
HF.SpawnItemPlusFunction("ointment", nil, nil, params.item.OwnInventory, 4)
|
||||
HF.SpawnItemPlusFunction("antisepticspray", function(params2)
|
||||
HF.SpawnItemPlusFunction("antiseptic", nil, nil, params2.item.OwnInventory, 0)
|
||||
end, nil, params.item.OwnInventory, 5)
|
||||
end, nil, item.OwnInventory, 1)
|
||||
|
||||
HF.SpawnItemPlusFunction("surgerytoolbox", function(params)
|
||||
HF.SpawnItemPlusFunction("advscalpel", nil, nil, params.item.OwnInventory, 0)
|
||||
HF.SpawnItemPlusFunction("advhemostat", nil, nil, params.item.OwnInventory, 1)
|
||||
HF.SpawnItemPlusFunction("advretractors", nil, nil, params.item.OwnInventory, 2)
|
||||
for i = 1, 16, 1 do
|
||||
HF.SpawnItemPlusFunction("suture", nil, nil, params.item.OwnInventory, 3)
|
||||
end
|
||||
HF.SpawnItemPlusFunction("tweezers", nil, nil, params.item.OwnInventory, 4)
|
||||
HF.SpawnItemPlusFunction("traumashears", nil, nil, params.item.OwnInventory, 5)
|
||||
HF.SpawnItemPlusFunction("drainage", nil, nil, params.item.OwnInventory, 6)
|
||||
HF.SpawnItemPlusFunction("needle", nil, nil, params.item.OwnInventory, 7)
|
||||
HF.SpawnItemPlusFunction("organscalpel_kidneys", nil, nil, params.item.OwnInventory, 8)
|
||||
HF.SpawnItemPlusFunction("organscalpel_liver", nil, nil, params.item.OwnInventory, 9)
|
||||
HF.SpawnItemPlusFunction("organscalpel_lungs", nil, nil, params.item.OwnInventory, 10)
|
||||
HF.SpawnItemPlusFunction("organscalpel_heart", nil, nil, params.item.OwnInventory, 11)
|
||||
end, nil, item.OwnInventory, 3)
|
||||
|
||||
HF.SpawnItemPlusFunction("bloodanalyzer", nil, nil, item.OwnInventory, 6)
|
||||
HF.SpawnItemPlusFunction("healthscanner", function(params)
|
||||
local prefab = ItemPrefab.GetItemPrefab("batterycell")
|
||||
Entity.Spawner.AddItemToSpawnQueue(prefab, params["item"].WorldPosition, nil, nil, function(batteryItem)
|
||||
params["item"].OwnInventory.TryPutItem(batteryItem)
|
||||
end)
|
||||
end, nil, item.OwnInventory, 7)
|
||||
end, 35)
|
||||
end
|
||||
)
|
||||
|
||||
Hook.Add("character.giveJobItems", "NT.giveHealthScannersBatteries", function(character)
|
||||
Timer.Wait(function()
|
||||
for item in character.Inventory.AllItems do
|
||||
local thisIdentifier = item.Prefab.Identifier.Value
|
||||
if thisIdentifier == "healthscanner" then
|
||||
if item.OwnInventory ~= nil and item.OwnInventory.GetItemAt(0) == nil then
|
||||
local prefab = ItemPrefab.GetItemPrefab("batterycell")
|
||||
Entity.Spawner.AddItemToSpawnQueue(prefab, character.WorldPosition, nil, nil, function(batteryItem)
|
||||
item.OwnInventory.TryPutItem(batteryItem, character)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
end, 1000)
|
||||
end)
|
36
Neurotrauma/Lua/Scripts/Server/modconflict.lua
Normal file
36
Neurotrauma/Lua/Scripts/Server/modconflict.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
-- Modders, please use ModDir:Neurotrauma when taking dependencies, and
|
||||
-- name your patches with the word "neurotrauma" (letter case doesnt matter)
|
||||
|
||||
-- sets NT.modconflict to true if incompatible mod detected
|
||||
-- this applies meta affliction "modconflict" every round
|
||||
-- prints out the warning and incompatible mod on server startup
|
||||
-- Hooks Lua event "roundStart" to do the above each round
|
||||
NT.modconflict = false
|
||||
function NT.CheckModConflicts()
|
||||
NT.modconflict = false
|
||||
if NTConfig.Get("NT_ignoreModConflicts", false) then
|
||||
return
|
||||
end
|
||||
|
||||
local itemsToCheck = { "antidama2", "opdeco_hospitalbed" }
|
||||
|
||||
for prefab in ItemPrefab.Prefabs do
|
||||
if HF.TableContains(itemsToCheck, prefab.Identifier.Value) then
|
||||
local mod = prefab.ConfigElement.ContentPackage.Name
|
||||
if not string.find(string.lower(mod), "neurotrauma") then
|
||||
NT.modconflict = true
|
||||
print("Found Neurotrauma incompatibility with mod: ", mod)
|
||||
print("WARNING! mod conflict detected! Neurotrauma may not function correctly and requires a patch!")
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Timer.Wait(function()
|
||||
NT.CheckModConflicts()
|
||||
end, 1000)
|
||||
Hook.Add("roundStart", "NT.RoundStart.modconflicts", function()
|
||||
Timer.Wait(function()
|
||||
NT.CheckModConflicts()
|
||||
end, 10000)
|
||||
end)
|
302
Neurotrauma/Lua/Scripts/Server/multiscalpel.lua
Normal file
302
Neurotrauma/Lua/Scripts/Server/multiscalpel.lua
Normal file
@@ -0,0 +1,302 @@
|
||||
-- NT functions for multiscalpel mode setting
|
||||
-- Hooks XML Lua events defined in the multiscalpel item.xml
|
||||
-- Hooks Lua event "roundStart" to RefreshAllMultiscalpels descriptions
|
||||
function NT.SetMultiscalpelFunction(item, func)
|
||||
if func ~= "" then
|
||||
item.Tags = "multiscalpel_" .. func
|
||||
else
|
||||
item.Tags = ""
|
||||
end
|
||||
NT.RefreshScalpelDescription(item)
|
||||
end
|
||||
|
||||
local function GetMultiscalpelMode(item)
|
||||
local functiontag = ""
|
||||
local tags = HF.SplitString(item.Tags, ",")
|
||||
for tag in tags do
|
||||
if HF.StartsWith(tag, "multiscalpel_") then
|
||||
functiontag = HF.SplitString(tag, "_")[2]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return functiontag
|
||||
end
|
||||
|
||||
function NT.RefreshScalpelDescription(item)
|
||||
-- if not HF.ItemHasTag(item,"init") then return end
|
||||
-- hostside only
|
||||
if Game.IsMultiplayer and CLIENT then
|
||||
return
|
||||
end
|
||||
|
||||
if not Entity.Spawner then
|
||||
Timer.Wait(function()
|
||||
NT.RefreshScalpelDescription(item)
|
||||
end, 35)
|
||||
return
|
||||
end
|
||||
|
||||
local functiontag = GetMultiscalpelMode(item)
|
||||
|
||||
local description = ""
|
||||
if functiontag ~= "" then
|
||||
description = HF.GetText("multiscalpel." .. functiontag)
|
||||
end
|
||||
|
||||
if description == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local targetinventory = item.ParentInventory
|
||||
local targetslot = 0
|
||||
if targetinventory ~= nil then
|
||||
targetslot = targetinventory.FindIndex(item)
|
||||
end
|
||||
|
||||
local function SpawnFunc(newscalpelitem, targetinventory)
|
||||
if targetinventory ~= nil then
|
||||
targetinventory.TryPutItem(newscalpelitem, targetslot, true, true, nil)
|
||||
end
|
||||
newscalpelitem.Description = description
|
||||
newscalpelitem.Tags = "multiscalpel_" .. functiontag
|
||||
end
|
||||
HF.RemoveItem(item)
|
||||
Timer.Wait(function()
|
||||
local prefab = item.Prefab
|
||||
Entity.Spawner.AddItemToSpawnQueue(prefab, item.WorldPosition, nil, nil, function(newscalpelitem)
|
||||
SpawnFunc(newscalpelitem, targetinventory)
|
||||
end)
|
||||
end, 35)
|
||||
end
|
||||
|
||||
Hook.Add("roundStart", "NT.RoundStart.Multiscalpels", function()
|
||||
Timer.Wait(function()
|
||||
NT.RefreshAllMultiscalpels()
|
||||
end, 10000) -- maybe 10 seconds is enough?
|
||||
end)
|
||||
|
||||
function NT.RefreshAllMultiscalpels()
|
||||
-- descriptions dont get serialized, so i have to respawn
|
||||
-- every scalpel every round to keep their descriptions (big oof)
|
||||
|
||||
-- fetch scalpel items
|
||||
local scalpelItems = {}
|
||||
for item in Item.ItemList do
|
||||
if item.Prefab.Identifier.Value == "multiscalpel" then
|
||||
table.insert(scalpelItems, item)
|
||||
end
|
||||
end
|
||||
-- refresh items
|
||||
for scalpel in scalpelItems do
|
||||
NT.RefreshScalpelDescription(scalpel)
|
||||
end
|
||||
end
|
||||
Timer.Wait(function()
|
||||
NT.RefreshAllMultiscalpels()
|
||||
end, 50)
|
||||
|
||||
Hook.Add(
|
||||
"NT.multiscalpel.incision",
|
||||
"NT.multiscalpel.incision",
|
||||
function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "incision")
|
||||
end
|
||||
)
|
||||
Hook.Add("NT.multiscalpel.kidneys", "NT.multiscalpel.kidneys", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "kidneys")
|
||||
end)
|
||||
Hook.Add("NT.multiscalpel.liver", "NT.multiscalpel.liver", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "liver")
|
||||
end)
|
||||
Hook.Add("NT.multiscalpel.lungs", "NT.multiscalpel.lungs", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "lungs")
|
||||
end)
|
||||
Hook.Add("NT.multiscalpel.heart", "NT.multiscalpel.heart", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "heart")
|
||||
end)
|
||||
Hook.Add("NT.multiscalpel.brain", "NT.multiscalpel.brain", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "brain")
|
||||
end)
|
||||
Hook.Add("NT.multiscalpel.bandage", "NT.multiscalpel.bandage", function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "bandage")
|
||||
end)
|
||||
Hook.Add(
|
||||
"NT.multiscalpel.speedflex",
|
||||
"NT.multiscalpel.speedflex",
|
||||
function(effect, deltaTime, item, targets, worldPosition)
|
||||
NT.SetMultiscalpelFunction(item, "speedflex")
|
||||
end
|
||||
)
|
||||
|
||||
NT.ItemMethods.multiscalpel = function(item, usingCharacter, targetCharacter, limb)
|
||||
local limbtype = HF.NormalizeLimbType(limb.type)
|
||||
|
||||
local mode = GetMultiscalpelMode(item)
|
||||
if mode == "" then
|
||||
mode = "none"
|
||||
end
|
||||
|
||||
local modeFunctions = {
|
||||
none = function(item, usingCharacter, targetCharacter, limb) end,
|
||||
incision = NT.ItemMethods.advscalpel,
|
||||
kidneys = NT.ItemMethods.organscalpel_kidneys,
|
||||
liver = NT.ItemMethods.organscalpel_liver,
|
||||
lungs = NT.ItemMethods.organscalpel_lungs,
|
||||
heart = NT.ItemMethods.organscalpel_heart,
|
||||
brain = NT.ItemMethods.organscalpel_brain,
|
||||
bandage = function(item, usingCharacter, targetCharacter, limb)
|
||||
-- remove casts, bandages, and if none of those apply, cause some damage
|
||||
|
||||
-- code snippet taken from NT.ItemMethods.traumashears
|
||||
-- does the target have any cuttable afflictions?
|
||||
local cuttables = HF.CombineArrays(NT.CuttableAfflictions, NT.TraumashearsAfflictions)
|
||||
local canCut = false
|
||||
for val in cuttables do
|
||||
local prefab = AfflictionPrefab.Prefabs[val]
|
||||
if prefab ~= nil then
|
||||
if prefab.LimbSpecific then
|
||||
if HF.HasAfflictionLimb(targetCharacter, val, limbtype, 0.1) then
|
||||
canCut = true
|
||||
break
|
||||
end
|
||||
elseif limbtype == prefab.IndicatorLimb then
|
||||
if HF.HasAffliction(targetCharacter, val, 0.1) then
|
||||
canCut = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if canCut then
|
||||
NT.ItemMethods.traumashears(item, usingCharacter, targetCharacter, limb)
|
||||
else
|
||||
-- malpractice time!!!!
|
||||
local open = HF.HasAfflictionLimb(targetCharacter, "retractedskin", limbtype, 1)
|
||||
local istorso = limbtype == LimbType.Torso
|
||||
local ishead = limbtype == LimbType.Head
|
||||
|
||||
if not open then
|
||||
HF.AddAfflictionLimb(targetCharacter, "bleeding", limbtype, 6 + math.random() * 4, usingCharacter)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"lacerations",
|
||||
limbtype,
|
||||
2.5 + math.random() * 5,
|
||||
usingCharacter
|
||||
)
|
||||
HF.GiveItem(targetCharacter, "ntsfx_slash")
|
||||
else
|
||||
if istorso then
|
||||
-- stabbing an open torso (not good for the organs therein!)
|
||||
|
||||
HF.AddAffliction(targetCharacter, "internalbleeding", 6 + math.random() * 12, usingCharacter)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"lacerations",
|
||||
limbtype,
|
||||
4 + math.random() * 6,
|
||||
usingCharacter
|
||||
)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"internaldamage",
|
||||
limbtype,
|
||||
4 + math.random() * 6,
|
||||
usingCharacter
|
||||
)
|
||||
|
||||
local case = math.random()
|
||||
local casecount = 4
|
||||
if case < 1 / casecount then
|
||||
HF.AddAffliction(targetCharacter, "kidneydamage", 10 + math.random() * 10, usingCharacter)
|
||||
elseif case < 2 / casecount then
|
||||
HF.AddAffliction(targetCharacter, "liverdamage", 10 + math.random() * 10, usingCharacter)
|
||||
elseif case < 3 / casecount then
|
||||
HF.AddAffliction(targetCharacter, "lungdamage", 10 + math.random() * 10, usingCharacter)
|
||||
elseif case < 4 / casecount then
|
||||
HF.AddAffliction(targetCharacter, "heartdamage", 10 + math.random() * 10, usingCharacter)
|
||||
end
|
||||
elseif ishead then
|
||||
-- stabbing an open head (brain surgery done right!)
|
||||
|
||||
HF.AddAffliction(targetCharacter, "cerebralhypoxia", 15 + math.random() * 15, usingCharacter)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"internaldamage",
|
||||
limbtype,
|
||||
10 + math.random() * 10,
|
||||
usingCharacter
|
||||
)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"bleeding",
|
||||
limbtype,
|
||||
6 + math.random() * 12,
|
||||
usingCharacter
|
||||
)
|
||||
else
|
||||
-- stabbing an open arm or leg (how to cause fractures)
|
||||
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"bleeding",
|
||||
limbtype,
|
||||
6 + math.random() * 6,
|
||||
usingCharacter
|
||||
)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"lacerations",
|
||||
limbtype,
|
||||
4 + math.random() * 6,
|
||||
usingCharacter
|
||||
)
|
||||
HF.AddAfflictionLimb(
|
||||
targetCharacter,
|
||||
"internaldamage",
|
||||
limbtype,
|
||||
4 + math.random() * 6,
|
||||
usingCharacter
|
||||
)
|
||||
if HF.Chance(0.1) then
|
||||
NT.BreakLimb(targetCharacter, limbtype)
|
||||
end
|
||||
end
|
||||
|
||||
HF.GiveItem(targetCharacter, "ntsfx_slash")
|
||||
end
|
||||
end
|
||||
end,
|
||||
speedflex = function(item, usingCharacter, targetCharacter, limb)
|
||||
local animcontroller = targetCharacter.AnimController
|
||||
local torsoLimb = limb
|
||||
if animcontroller ~= nil then
|
||||
torsoLimb = animcontroller.MainLimb
|
||||
end
|
||||
|
||||
if limbtype == LimbType.Head then
|
||||
NT.ItemMethods.organscalpel_brain(item, usingCharacter, targetCharacter, limb)
|
||||
elseif limbtype == LimbType.LeftArm then
|
||||
NT.ItemMethods.organscalpel_kidneys(item, usingCharacter, targetCharacter, torsoLimb)
|
||||
elseif limbtype == LimbType.Torso then
|
||||
NT.ItemMethods.organscalpel_liver(item, usingCharacter, targetCharacter, torsoLimb)
|
||||
elseif limbtype == LimbType.RightArm then
|
||||
NT.ItemMethods.organscalpel_heart(item, usingCharacter, targetCharacter, torsoLimb)
|
||||
elseif limbtype == LimbType.LeftLeg then
|
||||
NT.ItemMethods.organscalpel_lungs(item, usingCharacter, targetCharacter, torsoLimb)
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
if modeFunctions[mode] ~= nil then
|
||||
modeFunctions[mode](item, usingCharacter, targetCharacter, limb)
|
||||
end
|
||||
|
||||
if mode ~= "none" then
|
||||
Timer.Wait(function()
|
||||
item.Tags = "multiscalpel_" .. mode
|
||||
end, 50)
|
||||
end
|
||||
end
|
311
Neurotrauma/Lua/Scripts/Server/ntcompat.lua
Normal file
311
Neurotrauma/Lua/Scripts/Server/ntcompat.lua
Normal file
@@ -0,0 +1,311 @@
|
||||
NTC = {} -- a class containing compatibility functions for other mods to make use of neurotraumas symptom system
|
||||
|
||||
-- use this function to register your expansion mod to be displayed by the
|
||||
-- console lua startup readout of neurotrauma expansions
|
||||
|
||||
-- check surgery plus or cybernetics for an example
|
||||
-- example of code for registering your expansion in init.lua:
|
||||
|
||||
-- MyExp = {} -- Example Expansions
|
||||
-- MyExp.Name="My Expansion"
|
||||
-- MyExp.Version = "A1.0"
|
||||
-- MyExp.VersionNum = 01000000 -- split into two digits (01->1.; 00->0.; 00->0h; 00->0) -> 1.0.0h0
|
||||
-- MyExp.MinNTVersion = "A1.7.1"
|
||||
-- MyExp.MinNTVersionNum = 01070100 -- 01.07.01.00 -> A1.7.1h0
|
||||
-- Timer.Wait(function() if NT ~= nil then NTC.RegisterExpansion(MyExp) end end,1)
|
||||
|
||||
NTC.RegisteredExpansions = {}
|
||||
function NTC.RegisterExpansion(expansionMainObject)
|
||||
table.insert(NTC.RegisteredExpansions, expansionMainObject)
|
||||
end
|
||||
|
||||
-- a table of tables, each character that has some custom data has an entry
|
||||
NTC.CharacterData = {}
|
||||
|
||||
-- use this function to induce symptoms temporarily
|
||||
-- duration is in humanupdates (~2 seconds), should at least be 2 to prevent symptom flickering
|
||||
function NTC.SetSymptomTrue(character, symptomidentifer, duration)
|
||||
if duration == nil then
|
||||
duration = 2
|
||||
end
|
||||
|
||||
NTC.AddEmptyCharacterData(character)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
data[symptomidentifer] = duration
|
||||
|
||||
NTC.CharacterData[character.ID] = data
|
||||
end
|
||||
|
||||
-- use this function to suppress symptoms temporarily. this takes precedence over NTC.SetSymptomTrue.
|
||||
-- duration is in humanupdates (~2 seconds), should at least be 2 to prevent symptom flickering
|
||||
function NTC.SetSymptomFalse(character, symptomidentifer, duration)
|
||||
if duration == nil then
|
||||
duration = 2
|
||||
end
|
||||
|
||||
NTC.AddEmptyCharacterData(character)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
data["!" .. symptomidentifer] = duration
|
||||
|
||||
NTC.CharacterData[character.ID] = data
|
||||
end
|
||||
|
||||
-- usage example: anywhere in your lua code, cause 4 seconds (2 humanupdates) of pale skin with this:
|
||||
-- NTC.SetSymptomTrue(targetCharacter,"sym_paleskin",2)
|
||||
|
||||
-- a list of possible symptom identifiers:
|
||||
|
||||
-- sym_unconsciousness
|
||||
-- tachycardia
|
||||
-- hyperventilation
|
||||
-- hypoventilation
|
||||
-- dyspnea
|
||||
-- sym_cough
|
||||
-- sym_paleskin
|
||||
-- sym_lightheadedness
|
||||
-- sym_blurredvision
|
||||
-- sym_confusion
|
||||
-- sym_headache
|
||||
-- sym_legswelling
|
||||
-- sym_weakness
|
||||
-- sym_wheezing
|
||||
-- sym_vomiting
|
||||
-- sym_nausea
|
||||
-- sym_hematemesis
|
||||
-- sym_fever
|
||||
-- sym_abdomdiscomfort
|
||||
-- sym_bloating
|
||||
-- sym_jaundice
|
||||
-- sym_sweating
|
||||
-- sym_palpitations
|
||||
-- sym_craving
|
||||
-- pain_abdominal
|
||||
-- pain_chest
|
||||
-- lockleftarm
|
||||
-- lockrightarm
|
||||
-- lockleftleg
|
||||
-- lockrightleg
|
||||
|
||||
-- with the following identifiers you can either cause things or prevent them.
|
||||
-- i recommend setting the duration when using these to cause things to 1.
|
||||
|
||||
-- triggersym_seizure
|
||||
-- triggersym_coma
|
||||
-- triggersym_stroke
|
||||
-- triggersym_heartattack
|
||||
-- triggersym_cardiacarrest
|
||||
-- triggersym_respiratoryarrest
|
||||
|
||||
-- prints all of the current compatibility data in the chat
|
||||
-- might be useful for debugging
|
||||
function NTC.DebugPrintAllData()
|
||||
local res = "neurotrauma compatibility data:\n"
|
||||
for key, value in pairs(NTC.CharacterData) do
|
||||
res = res .. "\n" .. value["character"].Name
|
||||
for key2, value2 in pairs(value) do
|
||||
res = res .. "\n " .. tostring(key2) .. " : " .. tostring(value2)
|
||||
end
|
||||
end
|
||||
|
||||
PrintChat(res)
|
||||
end
|
||||
|
||||
NTC.PreHumanUpdateHooks = {}
|
||||
-- use this function to add a function to be executed before humanupdate with a character parameter
|
||||
function NTC.AddPreHumanUpdateHook(func)
|
||||
NTC.PreHumanUpdateHooks[#NTC.PreHumanUpdateHooks + 1] = func
|
||||
end
|
||||
|
||||
NTC.HumanUpdateHooks = {}
|
||||
-- use this function to add a function to be executed after humanupdate with a character parameter
|
||||
function NTC.AddHumanUpdateHook(func)
|
||||
NTC.HumanUpdateHooks[#NTC.HumanUpdateHooks + 1] = func
|
||||
end
|
||||
|
||||
NTC.OnDamagedHooks = {}
|
||||
-- use this function to add a function to be executed after ondamaged
|
||||
-- with a characterhealth, attack result and limb parameter
|
||||
function NTC.AddOnDamagedHook(func)
|
||||
NTC.OnDamagedHooks[#NTC.OnDamagedHooks + 1] = func
|
||||
end
|
||||
|
||||
NTC.ModifyingOnDamagedHooks = {}
|
||||
-- use this function to add a function to be executed before ondamaged
|
||||
-- with a characterhealth, afflictions and limb parameter, and afflictions return type
|
||||
function NTC.AddModifyingOnDamagedHook(func)
|
||||
NTC.ModifyingOnDamagedHooks[#NTC.ModifyingOnDamagedHooks + 1] = func
|
||||
end
|
||||
|
||||
NTC.CharacterSpeedMultipliers = {}
|
||||
-- use this function to multiply a characters speed for one human update.
|
||||
-- should always be called from within a prehumanupdate hook
|
||||
function NTC.MultiplySpeed(character, multiplier)
|
||||
if NTC.CharacterSpeedMultipliers[character] == nil then
|
||||
NTC.CharacterSpeedMultipliers[character] = multiplier
|
||||
else
|
||||
NTC.CharacterSpeedMultipliers[character] = NTC.CharacterSpeedMultipliers[character] * multiplier
|
||||
end
|
||||
end
|
||||
|
||||
-- use this function to register an affliction to be detected by the hematology analyzer
|
||||
function NTC.AddHematologyAffliction(identifier)
|
||||
Timer.Wait(function()
|
||||
if not HF.TableContains(NT.HematologyDetectable, identifier) then
|
||||
table.insert(NT.HematologyDetectable, identifier)
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
|
||||
-- use this function to register an affliction to be healed by sutures
|
||||
-- identifier: the identifier of the affliction to be healed
|
||||
-- surgeryskillgain: how much surgery skill is gained by healing this affliction (optional, default: 0)
|
||||
-- requiredaffliction: what affliction has to be present alongside the healed affliction for it to get healed (optional, default: none)
|
||||
-- func: a function that gets run if the affliction is present. if provided, doesnt heal the affliction automatically (optional, default: none)
|
||||
-- func(item, usingCharacter, targetCharacter, limb)
|
||||
function NTC.AddSuturedAffliction(identifier, surgeryskillgain, requiredaffliction, func)
|
||||
Timer.Wait(function()
|
||||
if not HF.TableContains(NT.SutureAfflictions, identifier) then
|
||||
NT.SutureAfflictions[identifier] = {
|
||||
xpgain = surgeryskillgain,
|
||||
case = requiredaffliction,
|
||||
func = func,
|
||||
}
|
||||
end
|
||||
end, 1)
|
||||
end
|
||||
|
||||
NTC.AfflictionsAffectingVitality = {
|
||||
bleeding = true,
|
||||
bleedingnonstop = true,
|
||||
burn = true,
|
||||
acidburn = true,
|
||||
lacerations = true,
|
||||
gunshotwound = true,
|
||||
bitewounds = true,
|
||||
explosiondamage = true,
|
||||
blunttrauma = true,
|
||||
internaldamage = true,
|
||||
organdamage = true,
|
||||
cerebralhypoxia = true,
|
||||
gangrene = true,
|
||||
th_amputation = true,
|
||||
sh_amputation = true,
|
||||
suturedw = true,
|
||||
alcoholaddiction = true,
|
||||
opiateaddiction = true,
|
||||
}
|
||||
function NTC.AddAfflictionAffectingVitality(identifier)
|
||||
NTC.AfflictionsAffectingVitality[identifier] = true
|
||||
end
|
||||
|
||||
-- these functions are used by neurotrauma to check for symptom overrides
|
||||
function NTC.GetSymptom(character, symptomidentifer)
|
||||
local chardata = NTC.GetCharacterData(character)
|
||||
if chardata == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local durationleft = chardata[symptomidentifer]
|
||||
|
||||
if durationleft == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
function NTC.GetSymptomFalse(character, symptomidentifer)
|
||||
local chardata = NTC.GetCharacterData(character)
|
||||
if chardata == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
local durationleft = chardata["!" .. symptomidentifer]
|
||||
|
||||
if durationleft == nil then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- sets multiplier data for one humanupdate, should be called from within a humanupdate hook
|
||||
function NTC.SetMultiplier(character, multiplieridentifier, multiplier)
|
||||
NTC.AddEmptyCharacterData(character)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
data["mult_" .. multiplieridentifier] = NTC.GetMultiplier(character, multiplieridentifier) * multiplier
|
||||
NTC.CharacterData[character.ID] = data
|
||||
end
|
||||
function NTC.GetMultiplier(character, multiplieridentifier)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
if data == nil or data["mult_" .. multiplieridentifier] == nil then
|
||||
return 1
|
||||
end
|
||||
return data["mult_" .. multiplieridentifier]
|
||||
end
|
||||
|
||||
-- sets tag data for one humanupdate, should be called from within a humanupdate hook
|
||||
function NTC.SetTag(character, tagidentifier)
|
||||
NTC.AddEmptyCharacterData(character)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
data["tag_" .. tagidentifier] = 1
|
||||
end
|
||||
function NTC.HasTag(character, tagidentifier)
|
||||
local data = NTC.GetCharacterData(character)
|
||||
if data == nil or data["tag_" .. tagidentifier] == nil then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- don't concern yourself with these
|
||||
function NTC.AddEmptyCharacterData(character)
|
||||
if NTC.GetCharacterData(character) ~= nil then
|
||||
return
|
||||
end
|
||||
local newdat = {}
|
||||
newdat["character"] = character
|
||||
NTC.CharacterData[character.ID] = newdat
|
||||
end
|
||||
function NTC.CheckChardataEmpty(character)
|
||||
local chardat = NTC.GetCharacterData(character)
|
||||
if chardat == nil or HF.TableSize(chardat) > 1 then
|
||||
return
|
||||
end
|
||||
|
||||
-- remove entry from data
|
||||
NTC.CharacterData[character.ID] = nil
|
||||
end
|
||||
function NTC.GetCharacterData(character)
|
||||
return NTC.CharacterData[character.ID]
|
||||
end
|
||||
function NTC.TickCharacter(character)
|
||||
local chardata = NTC.GetCharacterData(character)
|
||||
if chardata == nil then
|
||||
return
|
||||
end
|
||||
|
||||
for key, value in pairs(chardata) do
|
||||
if key ~= "character" then
|
||||
if HF.StartsWith(key, "mult_") then -- multipliers
|
||||
chardata[key] = nil
|
||||
NTC.CheckChardataEmpty(character)
|
||||
else -- symptoms
|
||||
local durationleft = value
|
||||
if durationleft ~= nil and durationleft > 1 then
|
||||
chardata[key] = durationleft - 1
|
||||
else
|
||||
chardata[key] = nil
|
||||
NTC.CheckChardataEmpty(character)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
NTC.CharacterData[character.ID] = chardata
|
||||
end
|
||||
function NTC.GetSpeedMultiplier(character)
|
||||
if NTC.CharacterSpeedMultipliers[character] ~= nil then
|
||||
return NTC.CharacterSpeedMultipliers[character]
|
||||
end
|
||||
return 1
|
||||
end
|
671
Neurotrauma/Lua/Scripts/Server/ondamaged.lua
Normal file
671
Neurotrauma/Lua/Scripts/Server/ondamaged.lua
Normal file
@@ -0,0 +1,671 @@
|
||||
-- Hooks Lua event "character.applyDamage" to cause NT afflictions after attacks depending on the damaging affliction defined here in NT.OnDamagedMethods
|
||||
local function getCalculatedConcussionReduction(armor, strength)
|
||||
if armor == nil then
|
||||
return 0
|
||||
end
|
||||
local reduction = 0
|
||||
|
||||
if armor.HasTag("deepdiving") or armor.HasTag("deepdivinglarge") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "concussion") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
elseif armor.HasTag("smallitem") then
|
||||
local modifiers = armor.GetComponentString("Wearable").DamageModifiers
|
||||
for modifier in modifiers do
|
||||
if string.find(modifier.AfflictionIdentifiers, "concussion") ~= nil then
|
||||
reduction = strength - strength * modifier.DamageMultiplier
|
||||
end
|
||||
end
|
||||
end
|
||||
return reduction
|
||||
end
|
||||
Hook.Add("character.applyDamage", "NT.ondamaged", function(characterHealth, attackResult, hitLimb)
|
||||
--print(hitLimb.HealthIndex or hitLimb ~= nil)
|
||||
|
||||
if -- invalid attack data, don't do anything
|
||||
characterHealth == nil
|
||||
or characterHealth.Character == nil
|
||||
or characterHealth.Character.IsDead
|
||||
or not characterHealth.Character.IsHuman
|
||||
or attackResult == nil
|
||||
or attackResult.Afflictions == nil
|
||||
or #attackResult.Afflictions <= 0
|
||||
or hitLimb == nil
|
||||
or hitLimb.IsSevered
|
||||
then
|
||||
return
|
||||
end
|
||||
|
||||
local afflictions = attackResult.Afflictions
|
||||
|
||||
-- ntc
|
||||
-- modifying ondamaged hooks
|
||||
for key, val in pairs(NTC.ModifyingOnDamagedHooks) do
|
||||
afflictions = val(characterHealth, afflictions, hitLimb)
|
||||
end
|
||||
|
||||
local identifier = ""
|
||||
local methodtorun = nil
|
||||
for value in afflictions do
|
||||
-- execute fitting method, if available
|
||||
identifier = value.Prefab.Identifier.Value
|
||||
methodtorun = NT.OnDamagedMethods[identifier]
|
||||
if methodtorun ~= nil then
|
||||
-- make resistance from afflictions apply
|
||||
local resistance = HF.GetResistance(characterHealth.Character, identifier, hitLimb.type)
|
||||
local strength = value.Strength * (1 - resistance)
|
||||
|
||||
methodtorun(characterHealth.Character, strength, hitLimb.type)
|
||||
end
|
||||
end
|
||||
|
||||
-- ntc
|
||||
-- ondamaged hooks
|
||||
for key, val in pairs(NTC.OnDamagedHooks) do
|
||||
val(characterHealth, attackResult, hitLimb)
|
||||
end
|
||||
end)
|
||||
|
||||
NT.OnDamagedMethods = {}
|
||||
|
||||
local function HasLungs(c)
|
||||
return not HF.HasAffliction(c, "lungremoved")
|
||||
end
|
||||
local function HasHeart(c)
|
||||
return not HF.HasAffliction(c, "heartremoved")
|
||||
end
|
||||
|
||||
-- cause foreign bodies, rib fractures, pneumothorax, tamponade, internal bleeding, fractures, neurotrauma
|
||||
NT.OnDamagedMethods.gunshotwound = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
local causeFullForeignBody = false
|
||||
|
||||
-- torso specific
|
||||
if strength >= 1 and limbtype == LimbType.Torso then
|
||||
local hitOrgan = false
|
||||
if
|
||||
HF.Chance(
|
||||
HF.Clamp(strength * 0.02, 0, 0.3)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
causeFullForeignBody = true
|
||||
end
|
||||
if
|
||||
HasLungs(character)
|
||||
and HF.Chance(
|
||||
0.3 * NTC.GetMultiplier(character, "pneumothoraxchance") * NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
HF.AddAffliction(character, "lungdamage", strength)
|
||||
HF.AddAffliction(character, "organdamage", strength / 4)
|
||||
hitOrgan = true
|
||||
end
|
||||
if
|
||||
HasHeart(character)
|
||||
and hitOrgan == false
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
strength / 50 * NTC.GetMultiplier(character, "tamponadechance") * NTConfig.Get("NT_tamponadeChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "tamponade", 5)
|
||||
HF.AddAffliction(character, "heartdamage", strength)
|
||||
HF.AddAffliction(character, "organdamage", strength / 4)
|
||||
hitOrgan = true
|
||||
end
|
||||
if strength >= 5 then
|
||||
HF.AddAffliction(character, "internalbleeding", strength * HF.RandomRange(0.3, 0.6))
|
||||
end
|
||||
|
||||
-- liver and kidney damage
|
||||
if hitOrgan == false and strength >= 2 and HF.Chance(0.5) then
|
||||
HF.AddAfflictionLimb(character, "organdamage", limbtype, strength / 4)
|
||||
if HF.Chance(0.5) then
|
||||
HF.AddAffliction(character, "liverdamage", strength)
|
||||
else
|
||||
HF.AddAffliction(character, "kidneydamage", strength)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if strength >= 1 and limbtype == LimbType.Head then
|
||||
if
|
||||
HF.Chance(
|
||||
strength / 90 * NTC.GetMultiplier(character, "anyfracturechance") * NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
causeFullForeignBody = true
|
||||
end
|
||||
if strength >= 5 and HF.Chance(0.7) then
|
||||
HF.AddAffliction(character, "cerebralhypoxia", strength * HF.RandomRange(0.1, 0.4))
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance(strength / 60 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
strength / 60 * NTC.GetMultiplier(character, "anyfracturechance") * NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
causeFullForeignBody = true
|
||||
end
|
||||
end
|
||||
|
||||
-- foreign bodies
|
||||
if causeFullForeignBody then
|
||||
HF.AddAfflictionLimb(
|
||||
character,
|
||||
"foreignbody",
|
||||
limbtype,
|
||||
HF.Clamp(strength, 0, 30) * NTC.GetMultiplier(character, "foreignbodymultiplier")
|
||||
)
|
||||
else
|
||||
if HF.Chance(0.75) then
|
||||
HF.AddAfflictionLimb(
|
||||
character,
|
||||
"foreignbody",
|
||||
limbtype,
|
||||
HF.Clamp(strength / 4, 0, 20) * NTC.GetMultiplier(character, "foreignbodymultiplier")
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cause foreign bodies, rib fractures, pneumothorax, internal bleeding, concussion, fractures
|
||||
NT.OnDamagedMethods.explosiondamage = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
if HF.Chance(0.75) then
|
||||
HF.AddAfflictionLimb(
|
||||
character,
|
||||
"foreignbody",
|
||||
limbtype,
|
||||
strength / 2 * NTC.GetMultiplier(character, "foreignbodymultiplier")
|
||||
)
|
||||
end
|
||||
|
||||
-- torso specific
|
||||
if strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
strength >= 10
|
||||
and HF.Chance(
|
||||
strength / 50 * NTC.GetMultiplier(character, "anyfracturechance") * NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
strength
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
if strength >= 5 then
|
||||
HF.AddAffliction(character, "internalbleeding", strength * HF.RandomRange(0.2, 0.5))
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if strength >= 1 and limbtype == LimbType.Head then
|
||||
local armor1 = character.Inventory.GetItemInLimbSlot(InvSlotType.OuterClothes)
|
||||
local armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.Head)
|
||||
local reduceddmg = math.max(
|
||||
10
|
||||
- getCalculatedConcussionReduction(armor1, 10, limbtype)
|
||||
- getCalculatedConcussionReduction(armor2, 10, limbtype),
|
||||
0
|
||||
)
|
||||
if strength >= 15 and HF.Chance(math.min(strength / 60, 0.7)) then
|
||||
HF.AddAfflictionResisted(character, "concussion", reduceddmg)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min(strength / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min(strength / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "n_fracture", 5)
|
||||
end
|
||||
if strength >= 25 and HF.Chance(0.25) then
|
||||
-- drop previously held item
|
||||
local previtem = HF.GetHeadWear(character)
|
||||
if previtem ~= nil then
|
||||
previtem.Drop(character, true)
|
||||
end
|
||||
HF.AddAfflictionLimb(character, "gate_ta_h", limbtype, 5)
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance(strength / 60 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
strength / 60 * NTC.GetMultiplier(character, "anyfracturechance") * NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
0.35 * NTC.GetMultiplier(character, "dislocationchance") * NTConfig.Get("NT_dislocationChance", 1)
|
||||
) and not NT.LimbIsAmputated(character, limbtype)
|
||||
then
|
||||
NT.DislocateLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cause rib fractures, pneumothorax, internal bleeding, concussion, fractures
|
||||
NT.OnDamagedMethods.bitewounds = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
-- torso specific
|
||||
if strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
strength >= 10
|
||||
and HF.Chance(
|
||||
(strength - 10)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
(strength - 5)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
if strength >= 5 then
|
||||
HF.AddAffliction(character, "internalbleeding", strength * HF.RandomRange(0.2, 0.5))
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if strength >= 1 and limbtype == LimbType.Head then
|
||||
local armor1 = character.Inventory.GetItemInLimbSlot(InvSlotType.OuterClothes)
|
||||
local armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.Head)
|
||||
local reduceddmg = math.max(
|
||||
10
|
||||
- getCalculatedConcussionReduction(armor1, 10, limbtype)
|
||||
- getCalculatedConcussionReduction(armor2, 10, limbtype),
|
||||
0
|
||||
)
|
||||
if strength >= 15 and HF.Chance(math.min(strength / 60, 0.7)) then
|
||||
HF.AddAfflictionResisted(character, "concussion", reduceddmg)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 10) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance((strength - 5) / 60 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 5)
|
||||
/ 60
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cause rib fractures, pneumothorax, tamponade, internal bleeding, fractures
|
||||
NT.OnDamagedMethods.lacerations = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
-- torso specific
|
||||
if strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
strength >= 10
|
||||
and HF.Chance(
|
||||
(strength - 10)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
(strength - 5)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
if
|
||||
HasHeart(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
(strength - 5)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "tamponadechance")
|
||||
* NTConfig.Get("NT_tamponadeChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "tamponade", 5)
|
||||
end
|
||||
if strength >= 5 then
|
||||
HF.AddAffliction(character, "internalbleeding", strength * HF.RandomRange(0.2, 0.5))
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if strength >= 1 and limbtype == LimbType.Head then
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 15) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance(strength / 60 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 5)
|
||||
/ 60
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cause rib fractures, organ damage, pneumothorax, concussion, fractures, neurotrauma
|
||||
NT.OnDamagedMethods.blunttrauma = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
local fractureImmune = HF.HasAffliction(character, "cpr_fracturebuff")
|
||||
|
||||
-- torso
|
||||
if not fractureImmune and strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
HF.Chance(
|
||||
strength / 50 * NTC.GetMultiplier(character, "anyfracturechance") * NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
|
||||
HF.AddAffliction(character, "lungdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "heartdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "liverdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "kidneydamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "organdamage", strength * HF.RandomRange(0, 1))
|
||||
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
strength
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if not fractureImmune and strength >= 1 and limbtype == LimbType.Head then
|
||||
local armor1 = character.Inventory.GetItemInLimbSlot(InvSlotType.OuterClothes)
|
||||
local armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.Head)
|
||||
local reduceddmg = math.max(
|
||||
10
|
||||
- getCalculatedConcussionReduction(armor1, 10, limbtype)
|
||||
- getCalculatedConcussionReduction(armor2, 10, limbtype),
|
||||
0
|
||||
)
|
||||
if strength >= 15 and HF.Chance(math.min(strength / 60, 0.7)) then
|
||||
HF.AddAfflictionResisted(character, "concussion", reduceddmg)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 10) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 10) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "n_fracture", 5)
|
||||
end
|
||||
if strength >= 5 and HF.Chance(0.7) then
|
||||
HF.AddAffliction(character, "cerebralhypoxia", strength * HF.RandomRange(0.1, 0.4))
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if not fractureImmune and strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
strength > 15
|
||||
and NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance(strength / 100 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 2)
|
||||
/ 60
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
HF.Clamp((strength - 2) / 80, 0, 0.5)
|
||||
* NTC.GetMultiplier(character, "dislocationchance")
|
||||
* NTConfig.Get("NT_dislocationChance", 1)
|
||||
) and not NT.LimbIsAmputated(character, limbtype)
|
||||
then
|
||||
NT.DislocateLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- cause rib fractures, organ damage, pneumothorax, concussion, fractures
|
||||
NT.OnDamagedMethods.internaldamage = function(character, strength, limbtype)
|
||||
limbtype = HF.NormalizeLimbType(limbtype)
|
||||
|
||||
-- torso
|
||||
if strength >= 1 and limbtype == LimbType.Torso then
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 5)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
|
||||
HF.AddAffliction(character, "lungdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "heartdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "liverdamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "kidneydamage", strength * HF.RandomRange(0, 1))
|
||||
HF.AddAffliction(character, "organdamage", strength * HF.RandomRange(0, 1))
|
||||
|
||||
if
|
||||
HasLungs(character)
|
||||
and strength >= 5
|
||||
and HF.Chance(
|
||||
(strength - 5)
|
||||
/ 50
|
||||
* NTC.GetMultiplier(character, "pneumothoraxchance")
|
||||
* NTConfig.Get("NT_pneumothoraxChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "pneumothorax", 5)
|
||||
end
|
||||
end
|
||||
|
||||
-- head
|
||||
if strength >= 1 and limbtype == LimbType.Head then
|
||||
local armor1 = character.Inventory.GetItemInLimbSlot(InvSlotType.OuterClothes)
|
||||
local armor2 = character.Inventory.GetItemInLimbSlot(InvSlotType.Head)
|
||||
local reduceddmg = math.max(
|
||||
10
|
||||
- getCalculatedConcussionReduction(armor1, 10, limbtype)
|
||||
- getCalculatedConcussionReduction(armor2, 10, limbtype),
|
||||
0
|
||||
)
|
||||
if strength >= 15 and HF.Chance(math.min(strength / 60, 0.7)) then
|
||||
HF.AddAfflictionResisted(character, "concussion", reduceddmg)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 5) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
strength >= 15
|
||||
and HF.Chance(
|
||||
math.min((strength - 5) / 60, 0.7)
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
HF.AddAffliction(character, "n_fracture", 5)
|
||||
end
|
||||
end
|
||||
|
||||
-- extremities
|
||||
if strength >= 1 and HF.LimbIsExtremity(limbtype) then
|
||||
if
|
||||
strength > 10
|
||||
and NT.LimbIsBroken(character, limbtype)
|
||||
and not NT.LimbIsAmputated(character, limbtype)
|
||||
and HF.Chance((strength - 10) / 60 * NTC.GetMultiplier(character, "traumamputatechance"))
|
||||
then
|
||||
NT.TraumamputateLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
(strength - 5)
|
||||
/ 60
|
||||
* NTC.GetMultiplier(character, "anyfracturechance")
|
||||
* NTConfig.Get("NT_fractureChance", 1)
|
||||
)
|
||||
then
|
||||
NT.BreakLimb(character, limbtype)
|
||||
end
|
||||
if
|
||||
HF.Chance(
|
||||
0.25 * NTC.GetMultiplier(character, "dislocationchance") * NTConfig.Get("NT_dislocationChance", 1)
|
||||
) and not NT.LimbIsAmputated(character, limbtype)
|
||||
then
|
||||
NT.DislocateLimb(character, limbtype)
|
||||
end
|
||||
end
|
||||
end
|
19
Neurotrauma/Lua/Scripts/Server/onfire.lua
Normal file
19
Neurotrauma/Lua/Scripts/Server/onfire.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
-- Hooks Lua event "Barotrauma.Character" to apply vanilla burning (formerly NT onfire) affliction and set a human on fire
|
||||
Hook.HookMethod("Barotrauma.Character", "ApplyStatusEffects", function(instance, ptable)
|
||||
if ptable.actionType == ActionType.OnFire then
|
||||
local function ApplyBurn(character, limbtype)
|
||||
HF.AddAfflictionLimb(character, "burning", limbtype, ptable.deltaTime * 3)
|
||||
end
|
||||
|
||||
if instance.IsHuman then
|
||||
ApplyBurn(instance, LimbType.Torso)
|
||||
ApplyBurn(instance, LimbType.Head)
|
||||
ApplyBurn(instance, LimbType.LeftArm)
|
||||
ApplyBurn(instance, LimbType.RightArm)
|
||||
ApplyBurn(instance, LimbType.LeftLeg)
|
||||
ApplyBurn(instance, LimbType.RightLeg)
|
||||
else
|
||||
HF.AddAfflictionLimb(instance, "burning", instance.AnimController.MainLimb.type, ptable.deltaTime * 5)
|
||||
end
|
||||
end
|
||||
end, Hook.HookMethodType.After)
|
9
Neurotrauma/Lua/Scripts/Server/screams.lua
Normal file
9
Neurotrauma/Lua/Scripts/Server/screams.lua
Normal file
@@ -0,0 +1,9 @@
|
||||
-- Hooks XML Lua event "NT.causeScreams" to cause character to scream if config has enabled screaming
|
||||
Hook.Add("NT.causeScreams", "NT.causeScreams", function(...)
|
||||
if not NTConfig.Get("NT_screams", true) then
|
||||
return
|
||||
end
|
||||
|
||||
local character = table.pack(...)[3]
|
||||
HF.SetAffliction(character, "screaming", 10)
|
||||
end)
|
13
Neurotrauma/Lua/Scripts/Shared/pronecolliderfix.lua
Normal file
13
Neurotrauma/Lua/Scripts/Shared/pronecolliderfix.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
Hook.Patch("Barotrauma.Character", "Control", function(instance)
|
||||
if instance.CharacterHealth.GetAfflictionStrengthByIdentifier("forceprone") > 1 then
|
||||
instance.SetInput(InputType.Crouch, false, true)
|
||||
end
|
||||
end)
|
||||
|
||||
Hook.Patch("Barotrauma.Ragdoll", "get_ColliderHeightFromFloor", function(instance, ptable)
|
||||
if instance.Character and instance.Character.CharacterHealth then
|
||||
if instance.Character.CharacterHealth.GetAfflictionStrengthByIdentifier("forceprone") > 1 then
|
||||
return Single(0.1)
|
||||
end
|
||||
end
|
||||
end, Hook.HookMethodType.After)
|
142
Neurotrauma/Lua/Scripts/Shared/surgerytable.lua
Normal file
142
Neurotrauma/Lua/Scripts/Shared/surgerytable.lua
Normal file
@@ -0,0 +1,142 @@
|
||||
-- Hooks a XML Lua event "surgerytable.update" to use for getting
|
||||
-- Neurotrauma and vanilla character data with the surgical table or hospital bed
|
||||
-- lifted and translated from betterhealthui
|
||||
local NormalHeartrate = 60
|
||||
local MaxTachycardiaHeartrate = 180
|
||||
local MaxFibrillationHeartrate = 300
|
||||
local function GetHeartrate(character)
|
||||
if character == nil or character.CharacterHealth == nil or character.IsDead then
|
||||
return 0
|
||||
end
|
||||
|
||||
local rate = NormalHeartrate
|
||||
|
||||
local cardiacarrest = character.CharacterHealth.GetAffliction("cardiacarrest")
|
||||
|
||||
-- return 0 rate if in cardiac arrest
|
||||
if cardiacarrest ~= nil and cardiacarrest.Strength >= 0.5 then
|
||||
return 0
|
||||
end
|
||||
|
||||
local tachycardia = character.CharacterHealth.GetAffliction("tachycardia")
|
||||
local fibrillation = character.CharacterHealth.GetAffliction("fibrillation")
|
||||
|
||||
if fibrillation ~= nil then
|
||||
rate = HF.Lerp(
|
||||
MaxTachycardiaHeartrate,
|
||||
MaxFibrillationHeartrate,
|
||||
fibrillation.Strength / 100 * (1 + math.random() * 0.5)
|
||||
)
|
||||
elseif tachycardia ~= nil then
|
||||
rate = HF.Lerp(NormalHeartrate, MaxTachycardiaHeartrate, tachycardia.Strength / 100)
|
||||
end
|
||||
|
||||
return rate
|
||||
end
|
||||
|
||||
local function GetPH(character)
|
||||
if character == nil or character.CharacterHealth == nil then
|
||||
return 0
|
||||
end
|
||||
|
||||
local acidosis = HF.GetAfflictionStrength(character, "acidosis", 0)
|
||||
local alkalosis = HF.GetAfflictionStrength(character, "alkalosis", 0)
|
||||
|
||||
return alkalosis - acidosis
|
||||
end
|
||||
|
||||
Hook.Add("surgerytable.update", "surgerytable.update", function(effect, deltaTime, item, targets, worldPosition)
|
||||
-- fetch controller component
|
||||
local controllerComponent = item.GetComponentString("Controller")
|
||||
if controllerComponent == nil then
|
||||
item.SendSignal("0", "state_out")
|
||||
return
|
||||
end
|
||||
|
||||
-- check if targets present
|
||||
-- laying on the table
|
||||
local target = controllerComponent.User
|
||||
-- noone one the table? check the targets array for the one with the least vitality
|
||||
if target == nil or not target.IsHuman then
|
||||
local minVitality = 999
|
||||
for index, value in ipairs(targets) do
|
||||
if value.Name ~= nil and value.IsHuman and (value.Vitality < minVitality) then
|
||||
minVitality = value.Vitality
|
||||
target = value
|
||||
end
|
||||
end
|
||||
end
|
||||
-- no target found
|
||||
if target == nil or not target.IsHuman then
|
||||
item.SendSignal("0", "state_out")
|
||||
return
|
||||
end
|
||||
|
||||
-- send signals
|
||||
item.SendSignal("1", "state_out")
|
||||
if target.IsDead then
|
||||
item.SendSignal("0", "alive_out")
|
||||
else
|
||||
item.SendSignal("1", "alive_out")
|
||||
end
|
||||
if target.IsDead or HF.HasAffliction(target, "sym_unconsciousness", 0.1) then
|
||||
item.SendSignal("0", "conscious_out")
|
||||
else
|
||||
item.SendSignal("1", "conscious_out")
|
||||
end
|
||||
item.SendSignal(target.Name, "name_out")
|
||||
item.SendSignal(tostring(HF.Round(target.Vitality)), "vitality_out")
|
||||
if target.IsDead then
|
||||
item.SendSignal("0", "bloodpressure_out")
|
||||
else
|
||||
item.SendSignal(tostring(HF.Round(HF.GetAfflictionStrength(target, "bloodpressure", 100))), "bloodpressure_out")
|
||||
end
|
||||
item.SendSignal(tostring(HF.Round(100 - HF.GetAfflictionStrength(target, "hypoxemia", 0))), "bloodoxygen_out")
|
||||
item.SendSignal(tostring(HF.Round(HF.GetAfflictionStrength(target, "cerebralhypoxia", 0))), "neurotrauma_out")
|
||||
item.SendSignal(tostring(HF.Round(HF.GetAfflictionStrength(target, "organdamage", 0))), "organdamage_out")
|
||||
|
||||
local heartrate = HF.Round(GetHeartrate(target))
|
||||
item.SendSignal(tostring(heartrate), "heartrate_out")
|
||||
|
||||
local breathingrate = math.random(15, 18)
|
||||
if HF.HasAffliction(target, "respiratoryarrest") or target.IsDead then
|
||||
breathingrate = 0
|
||||
elseif HF.HasAffliction(target, "hyperventilation") then
|
||||
breathingrate = breathingrate + math.random(6, 8)
|
||||
elseif HF.HasAffliction(target, "hypoventilation") then
|
||||
breathingrate = breathingrate - math.random(6, 8)
|
||||
end
|
||||
item.SendSignal(tostring(breathingrate), "breathingrate_out")
|
||||
|
||||
item.SendSignal(tostring(HF.BoolToNum(HF.HasAffliction(target, "surgeryincision"), 1)), "insurgery_out")
|
||||
|
||||
if target.IsDead and target.causeOfDeath ~= nil then
|
||||
item.SendSignal(HF.CauseOfDeathToString(target.causeOfDeath), "causeofdeath_out")
|
||||
end
|
||||
|
||||
local bloodph = HF.Round(GetPH(target))
|
||||
item.SendSignal(tostring(bloodph), "bloodph_out")
|
||||
end)
|
||||
|
||||
--Hook.Add("surgerytable.forceon", "surgerytable.forceon", function (effect, deltaTime, item, targets, worldPosition)
|
||||
-- -- fetch controller component
|
||||
-- local controllerComponent = item.GetComponentString("Controller")
|
||||
-- if controllerComponent == nil or controllerComponent.IsActive then return end
|
||||
--
|
||||
-- -- check if targets present
|
||||
-- if targets == nil or #targets <= 0 then return end
|
||||
-- local target = nil
|
||||
-- for index, value in ipairs(targets) do
|
||||
-- target=value
|
||||
-- if target ~=nil then break end
|
||||
-- end
|
||||
-- if target == nil then return end
|
||||
--
|
||||
-- -- was experimenting with forcing the patient into laying down here, sort of worked... until 0 vitality.
|
||||
-- -- it's too janky to be released.
|
||||
--
|
||||
-- -- target.Stun = 0
|
||||
-- -- HF.SetAffliction(target,"givein",0)
|
||||
-- -- controllerComponent.Select(target)
|
||||
-- -- target.SelectedConstruction = item
|
||||
--end)
|
408
Neurotrauma/Lua/Scripts/configdata.lua
Normal file
408
Neurotrauma/Lua/Scripts/configdata.lua
Normal file
@@ -0,0 +1,408 @@
|
||||
NTConfig = { Entries = {}, Expansions = {} } -- contains all config options, their default, type, valid ranges, difficulty influence
|
||||
|
||||
local configDirectoryPath = Game.SaveFolder .. "/ModConfigs"
|
||||
local configFilePath = configDirectoryPath .. "/Neurotrauma.json"
|
||||
|
||||
-- this is the function that gets used in other mods to add their own settings to the config
|
||||
function NTConfig.AddConfigOptions(expansion)
|
||||
table.insert(NTConfig.Expansions, expansion)
|
||||
|
||||
for key, entry in pairs(expansion.ConfigData) do
|
||||
NTConfig.Entries[key] = entry
|
||||
NTConfig.Entries[key].value = entry.default
|
||||
end
|
||||
end
|
||||
|
||||
function NTConfig.SaveConfig()
|
||||
--prevent both owner client and server saving config at the same time and potentially erroring from file access
|
||||
if Game.IsMultiplayer and CLIENT and Game.Client.MyClient.IsOwner then
|
||||
return
|
||||
end
|
||||
|
||||
local tableToSave = {}
|
||||
for key, entry in pairs(NTConfig.Entries) do
|
||||
tableToSave[key] = entry.value
|
||||
end
|
||||
|
||||
File.CreateDirectory(configDirectoryPath)
|
||||
File.Write(configFilePath, json.serialize(tableToSave))
|
||||
end
|
||||
|
||||
function NTConfig.ResetConfig()
|
||||
local tableToSave = {}
|
||||
for key, entry in pairs(NTConfig.Entries) do
|
||||
tableToSave[key] = entry.default
|
||||
NTConfig.Entries[key] = entry
|
||||
NTConfig.Entries[key].value = entry.default
|
||||
end
|
||||
|
||||
-- File.CreateDirectory(configDirectoryPath)
|
||||
-- File.Write(configFilePath, json.serialize(tableToSave))
|
||||
end
|
||||
|
||||
function NTConfig.LoadConfig()
|
||||
if not File.Exists(configFilePath) then
|
||||
return
|
||||
end
|
||||
|
||||
local readConfig = json.parse(File.Read(configFilePath))
|
||||
|
||||
for key, value in pairs(readConfig) do
|
||||
if NTConfig.Entries[key] then
|
||||
NTConfig.Entries[key].value = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function NTConfig.Get(key, default)
|
||||
if NTConfig.Entries[key] then
|
||||
return NTConfig.Entries[key].value
|
||||
end
|
||||
return default
|
||||
end
|
||||
|
||||
function NTConfig.Set(key, value)
|
||||
if NTConfig.Entries[key] then
|
||||
NTConfig.Entries[key].value = value
|
||||
end
|
||||
end
|
||||
|
||||
function NTConfig.SendConfig(reciverClient)
|
||||
local tableToSend = {}
|
||||
for key, entry in pairs(NTConfig.Entries) do
|
||||
tableToSend[key] = entry.value
|
||||
end
|
||||
|
||||
local msg = Networking.Start("NT.ConfigUpdate")
|
||||
msg.WriteString(json.serialize(tableToSend))
|
||||
if SERVER then
|
||||
Networking.Send(msg, reciverClient and reciverClient.Connection or nil)
|
||||
else
|
||||
Networking.Send(msg)
|
||||
end
|
||||
end
|
||||
|
||||
function NTConfig.ReceiveConfig(msg)
|
||||
local RecivedTable = {}
|
||||
RecivedTable = json.parse(msg.ReadString())
|
||||
for key, value in pairs(RecivedTable) do
|
||||
NTConfig.Set(key, value)
|
||||
end
|
||||
end
|
||||
|
||||
NT.ConfigData = {
|
||||
NT_header1 = { name = "Neurotrauma", type = "category" },
|
||||
|
||||
NT_dislocationChance = {
|
||||
name = "Dislocation chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { max = 5 },
|
||||
},
|
||||
NT_fractureChance = {
|
||||
name = "Fracture chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 2, max = 5 },
|
||||
},
|
||||
NT_pneumothoraxChance = {
|
||||
name = "Pneumothorax chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { max = 5 },
|
||||
},
|
||||
NT_tamponadeChance = {
|
||||
name = "Tamponade chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { max = 3 },
|
||||
},
|
||||
NT_heartattackChance = {
|
||||
name = "Heart attack chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 1 },
|
||||
},
|
||||
NT_strokeChance = {
|
||||
name = "Stroke chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 1 },
|
||||
},
|
||||
NT_infectionRate = {
|
||||
name = "Infection rate",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 1.5, max = 5 },
|
||||
},
|
||||
NT_CPRFractureChance = {
|
||||
name = "CPR fracture chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 1 },
|
||||
},
|
||||
NT_traumaticAmputationChance = {
|
||||
name = "Traumatic amputation chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { max = 3 },
|
||||
},
|
||||
NT_neurotraumaGain = {
|
||||
name = "Neurotrauma gain",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 3, max = 10 },
|
||||
},
|
||||
NT_organDamageGain = {
|
||||
name = "Organ damage gain",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 2, max = 8 },
|
||||
},
|
||||
NT_fibrillationSpeed = {
|
||||
name = "Fibrillation rate",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 1.5, max = 8 },
|
||||
},
|
||||
NT_gangrenespeed = {
|
||||
name = "Gangrene rate",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 5 },
|
||||
},
|
||||
NT_falldamage = {
|
||||
name = "Falldamage",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 5 },
|
||||
},
|
||||
NT_falldamageSeriousInjuryChance = {
|
||||
name = "Falldamage serious injury chance",
|
||||
default = 1,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
difficultyCharacteristics = { multiplier = 0.5, max = 5 },
|
||||
},
|
||||
NT_vanillaSkillCheck = {
|
||||
name = "Vanilla skill check formula",
|
||||
default = false,
|
||||
type = "bool",
|
||||
description = "Changes the chance to succeed a lua skillcheck from skill/requiredskill to 100-(requiredskill-skill))/100",
|
||||
},
|
||||
NT_disableBotAlgorithms = {
|
||||
name = "Disable bot treatment algorithms",
|
||||
default = true,
|
||||
type = "bool",
|
||||
description = "Prevents bots from attempting to treat afflictions.\nThis is desireable, because bots suck at treating things, and their bad attempts lag out the game immensely.",
|
||||
},
|
||||
NT_screams = { name = "Screams", default = true, type = "bool", description = "Characters scream when in pain." },
|
||||
NT_ignoreModConflicts = {
|
||||
name = "Ignore mod conflicts",
|
||||
default = false,
|
||||
type = "bool",
|
||||
description = "Prevent the mod conflict affliction from showing up.",
|
||||
},
|
||||
NT_organRejection = {
|
||||
name = "Organ rejection",
|
||||
default = false,
|
||||
type = "bool",
|
||||
difficultyCharacteristics = { multiplier = 0.5 },
|
||||
description = "When transplanting an organ, there is a chance that the organ gets rejected.\nThe higher the patients immunity at the time of the transplant, the higher the chance.",
|
||||
},
|
||||
NT_fracturesRemoveCasts = {
|
||||
name = "Fractures remove casts",
|
||||
default = true,
|
||||
type = "bool",
|
||||
difficultyCharacteristics = { multiplier = 0.5 },
|
||||
description = "When receiving damage that would cause a fracture, remove plaster casts on the limb",
|
||||
},
|
||||
|
||||
NTCRE_header1 = { name = "Consent Required", type = "category" },
|
||||
NTCRE_ConsentRequired = {
|
||||
name = "Enable Consent Required",
|
||||
default = true,
|
||||
type = "bool",
|
||||
description = "Integrated consent required mod.\nIf disabled, none of NPCs will get aggravated by medical interactions.",
|
||||
},
|
||||
|
||||
NTSCAN_header1 = { name = "Scanner Settings", type = "category" },
|
||||
|
||||
NTSCAN_enablecoloredscanner = {
|
||||
name = "Enable Colored Scanner",
|
||||
default = true,
|
||||
type = "bool",
|
||||
description = "Enable colored health scanner text messages.",
|
||||
},
|
||||
|
||||
NTSCAN_lowmedThreshold = {
|
||||
name = "Low-Medium Text Threshold",
|
||||
default = 25,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
description = "Where the Low progress color ends and Medium progress color begins.",
|
||||
},
|
||||
|
||||
NT_medhighThreshold = {
|
||||
name = "Medium-High Text Threshold",
|
||||
default = 65,
|
||||
range = { 0, 100 },
|
||||
type = "float",
|
||||
description = "Where the Medium progress color ends and High progress color begins.",
|
||||
},
|
||||
|
||||
NTSCAN_basecolor = {
|
||||
name = "Base Text Color",
|
||||
default = { "100,100,200" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color.",
|
||||
},
|
||||
|
||||
NTSCAN_namecolor = {
|
||||
name = "Name Text Color",
|
||||
default = { "125,125,225" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for player names.",
|
||||
},
|
||||
|
||||
NTSCAN_lowcolor = {
|
||||
name = "Low Priority Color",
|
||||
default = { "100,200,100" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for afflictions that have low progress.",
|
||||
},
|
||||
|
||||
NTSCAN_medcolor = {
|
||||
name = "Medium Priority Color",
|
||||
default = { "200,200,100" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for afflictions that have medium progress.",
|
||||
},
|
||||
|
||||
NTSCAN_highcolor = {
|
||||
name = "High Priority Color",
|
||||
default = { "250,100,100" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for afflictions that have high progress.",
|
||||
},
|
||||
NTSCAN_vitalcolor = {
|
||||
name = "Vital Priority Color",
|
||||
default = { "255,0,0" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for vital afflictions (Arterial bleed, Traumatic amputation).",
|
||||
},
|
||||
NTSCAN_removalcolor = {
|
||||
name = "Removed Organ Color",
|
||||
default = { "0,255,255" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for removed organs (Heart removed, leg amputation).",
|
||||
},
|
||||
NTSCAN_customcolor = {
|
||||
name = "Custom Category Color",
|
||||
default = { "180,50,200" },
|
||||
style = "R,G,B",
|
||||
type = "string",
|
||||
boxsize = 0.05,
|
||||
description = "Scanner text color for the custom category.",
|
||||
},
|
||||
|
||||
NTSCAN_VitalCategory = {
|
||||
name = "Included Vital Afflictions",
|
||||
default = {
|
||||
"cardiacarrest",
|
||||
"ll_arterialcut",
|
||||
"rl_arterialcut",
|
||||
"la_arterialcut",
|
||||
"ra_arterialcut",
|
||||
"t_arterialcut",
|
||||
"h_arterialcut",
|
||||
"tra_amputation",
|
||||
"tla_amputation",
|
||||
"trl_amputation",
|
||||
"tll_amputation",
|
||||
"th_amputation",
|
||||
},
|
||||
style = "identifier,identifier",
|
||||
type = "string",
|
||||
boxsize = 0.1,
|
||||
description = "You can add or remove afflictions to customize this list to your liking.",
|
||||
},
|
||||
|
||||
NTSCAN_RemovalCategory = {
|
||||
name = "Included Removal Affictions",
|
||||
default = {
|
||||
"heartremoved",
|
||||
"brainremoved",
|
||||
"lungremoved",
|
||||
"kidneyremoved",
|
||||
"liverremoved",
|
||||
"sra_amputation",
|
||||
"sla_amputation",
|
||||
"srl_amputation",
|
||||
"sll_amputation",
|
||||
"sh_amputation",
|
||||
},
|
||||
style = "identifier, identifier",
|
||||
type = "string",
|
||||
boxsize = 0.1,
|
||||
description = "You can add or remove afflictions to customize this list to your liking.",
|
||||
},
|
||||
|
||||
NTSCAN_CustomCategory = {
|
||||
name = "Custom Affliction Category",
|
||||
default = {""},
|
||||
style = "identifier,identifier",
|
||||
type = "string",
|
||||
boxsize = 0.1,
|
||||
description = "You can add or remove afflictions to customize this list to your liking.",
|
||||
},
|
||||
|
||||
NTSCAN_IgnoredCategory = {
|
||||
name = "Ignored Afflictions",
|
||||
default = { "" },
|
||||
style = "identifier,identifier",
|
||||
type = "string",
|
||||
boxsize = 0.1,
|
||||
description = "Afflictions added to this category will be ignored by the health scanner.",
|
||||
},
|
||||
}
|
||||
NTConfig.AddConfigOptions(NT)
|
||||
|
||||
-- wait a bit before loading the config so all options have had time to be added
|
||||
-- do note that this unintentionally causes a couple ticks time on load during which the config is always the default
|
||||
-- remember to put default values in your NTConfig.Get calls!
|
||||
Timer.Wait(function()
|
||||
NTConfig.LoadConfig()
|
||||
|
||||
Timer.Wait(function()
|
||||
NTConfig.SaveConfig()
|
||||
end, 1000)
|
||||
end, 50)
|
1252
Neurotrauma/Lua/Scripts/helperfunctions.lua
Normal file
1252
Neurotrauma/Lua/Scripts/helperfunctions.lua
Normal file
File diff suppressed because it is too large
Load Diff
76
Neurotrauma/Lua/Scripts/testing.lua
Normal file
76
Neurotrauma/Lua/Scripts/testing.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
-- set the below variable to true to enable debug and testing features
|
||||
NT.TestingEnabled = false
|
||||
|
||||
Hook.Add("chatMessage", "NT.testing", function(msg, client)
|
||||
if msg == "nt test" then -- a glorified suicide button
|
||||
if client.Character == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
HF.SetAfflictionLimb(client.Character, "gate_ta_ra", LimbType.RightArm, 100)
|
||||
HF.SetAfflictionLimb(client.Character, "gate_ta_la", LimbType.LeftArm, 100)
|
||||
HF.SetAfflictionLimb(client.Character, "gate_ta_rl", LimbType.RightLeg, 100)
|
||||
HF.SetAfflictionLimb(client.Character, "gate_ta_ll", LimbType.LeftLeg, 100)
|
||||
|
||||
return true -- hide message
|
||||
elseif msg == "nt unfuck" then -- a command to remove non-sensical extremity amputations on the head and torso
|
||||
if client.Character == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
HF.SetAfflictionLimb(client.Character, "tll_amputation", LimbType.Head, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "trl_amputation", LimbType.Head, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "tla_amputation", LimbType.Head, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "tra_amputation", LimbType.Head, 0)
|
||||
|
||||
HF.SetAfflictionLimb(client.Character, "tll_amputation", LimbType.Torso, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "trl_amputation", LimbType.Torso, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "tla_amputation", LimbType.Torso, 0)
|
||||
HF.SetAfflictionLimb(client.Character, "tra_amputation", LimbType.Torso, 0)
|
||||
|
||||
return true -- hide message
|
||||
elseif msg == "nt1" then
|
||||
if not NT.TestingEnabled then
|
||||
return
|
||||
end
|
||||
-- insert testing stuff here
|
||||
|
||||
local test = { val = "true" }
|
||||
|
||||
local function testfunc(param)
|
||||
param.val = "false"
|
||||
end
|
||||
|
||||
print(test.val)
|
||||
testfunc(test)
|
||||
print(test.val)
|
||||
|
||||
return true
|
||||
elseif msg == "nt2" then
|
||||
if not NT.TestingEnabled then
|
||||
return
|
||||
end
|
||||
-- insert other testing stuff here
|
||||
local crewenum = Character.GetFriendlyCrew(client.Character)
|
||||
local targetchar = nil
|
||||
local i = 0
|
||||
for char in crewenum do
|
||||
print(char.Name)
|
||||
targetchar = char
|
||||
i = i + 1
|
||||
if i == 2 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
client.SetClientCharacter(nil)
|
||||
|
||||
print(targetchar)
|
||||
|
||||
Timer.Wait(function()
|
||||
client.SetClientCharacter(targetchar)
|
||||
end, 50)
|
||||
|
||||
return true
|
||||
end
|
||||
end)
|
4
Neurotrauma/Lua/todo.md
Normal file
4
Neurotrauma/Lua/todo.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# TODO:
|
||||
- implement body temp
|
||||
- rebalance skill gain amount from existing treatments
|
||||
- rest are probably in .lua files themselves
|
Reference in New Issue
Block a user