Initial Commit

This commit is contained in:
Elkien3 2020-04-11 11:38:01 -05:00
parent a944ab0ba1
commit 171ea82b84
6 changed files with 314 additions and 0 deletions

33
README.md Normal file
View File

@ -0,0 +1,33 @@
Note: features are subject to change. This mod is WIP and may not be useable in it's current state. Intructions on use will come further in development.
injury types: cuts, fractures, punctures, burns, bruises
complications (injuries brought on from other injuries): obstructed airway, heart stopped, breathing stopped
Injuries are treated linearly, but can have steps removed in they arent applicable.
vitals: temperature, blood pressure/volume, oxygen, pulse, respiratory rate
signs: color, injuries, level of alertness.
symptoms: cold, dizzy, pain, immobility
tools: blood pressure cuff, stethoscope, pulse oximeter, suction, AED, OPA and NPA, BVM, non-rebreather mask, oxygen tank, dressing, saline, c-collar, gloves, splint, triangle bandage, tourniquet, blanket, trauma shears, stopwatch/clock, blood bag, vital monitor, ventilator, oxygen concentrator
perfusion rate is calculated based off breaths per minute, oxygen content of breaths taken, blood volume, and heart rate. also hunger and thirst, if applicable.
as the perfusion rate lowers, the patient will (in chronological order) get dizzy, pale, cold, confused, unconscious, stop breathing and pumping blood, and shortly after die.
perfusion will rapidly decrease if patient stops breathing due to drowning or suffocation.
perfusion will rapidly decrease if patient looses a lot of blood.
if patient has no nutrients (food) or no water, perfusion cannot take place.
patient can also can be dizzy, confused, or unconscious due to blunt force trauma, especially to the head.
oxygen tanks will be able to be attached to bvms, non-rebreathers, and oxygen concentrator machines.
bags can be filled with saline (sterile water and salt) or blood from a donor. they can then be placed above the patient and given to the patient by gravity.
dressings can be used to clean, apply pressure, and bandage a wound. a tourniquet may be needed to stop major bleeding.
blankets can be placed on a patient to lower heat loss.
blood pressure cuff and stethoscope is used to attain a blood pressure.
areobic activity (running, jumping, swimming) will increase pulse and respiratory rate. but also has increased need for perfusion.
BVMing too quickly or with too much volume can cause the patient to vomit and cause an airway obstruction.
need a very flexible api for injuries. would need to allow for special tools, vital sign changes, conditions that cause them, signs and symptoms they show, and be able to omit certain steps if needed.
would also need an api for vital sign management tools.

71
body.lua Normal file
View File

@ -0,0 +1,71 @@
minetest.register_entity("medical:body", {
hp_max = 1,
physical = false,
weight = 5,
collisionbox = {-0.6, 0, -0.6, 0.6, .2, 0.6},
visual = "mesh",
mesh = "character.b3d",
textures = {"character.png"},
is_visible = true,
makes_footstep_sound = false,
automatic_rotate = false,
on_activate = function(self, staticdata, dtime_s)
self.object:set_animation({x=162,y=167}, 1)
self.object:set_armor_groups({immortal = 1})
self.object:set_yaw(math.random(math.pi*-1, math.pi))
end,
--[[get_staticdata = function(self)
--return minetest.serialize({owner = self.owner, sleeping = self.sleeping, expiretime = self.time, mesh = self.mesh, textures = self.textures, yaw = self.yaw, inv = serializeContents(self.inv)})
end,--]]
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
if not puncher:is_player() then return end
local wielditem = puncher:get_wielded_item()
local wieldname = wielditem:get_name()
local hitloc = medical.gethitloc(self, puncher, tool_capabilities, dir)
if medical.attachedtools[wieldname] then
medical.usedtools[wieldname](self, puncher, wielditem, hitloc)
end
-- attach things
end,
on_rightclick = function(self, clicker)
if not clicker:is_player() then return end
local wielditem = clicker:get_wielded_item()
local wieldname = wielditem:get_name()
local hitloc = medical.gethitloc(self, clicker, nil, nil)
if medical.attachedtools[wieldname] then
medical.usedtools[wieldname](self, clicker, wielditem, hitloc)
end
-- use things
end
})
--open fracture test
minetest.register_entity("medical:fracturetest", {
hp_max = 1,
physical = true,
weight = 5,
collisionbox = {-0.1,-0.1,-0.1, 0.1,0.1,0.1},
visual = "mesh",
mesh = "bone.b3d",
visual_size = {x=1, y=1},--{x=.211, y=.211},
textures = {"default_clay.png","default_clay.png","default_clay.png","default_clay.png","default_clay.png","default_clay.png"}, -- number of required textures depends on visual
colors = {}, -- number of required colors depends on visual
spritediv = {x=1, y=1},
initial_sprite_basepos = {x=0, y=0},
is_visible = true,
makes_footstep_sound = false,
automatic_rotate = false,
on_activate = function(self, staticdata, dtime_s)
minetest.after(1, function()
local all_objects = minetest.get_objects_inside_radius(self.object:get_pos(), 10)
local _,obj
for _,obj in ipairs(all_objects) do
if obj:get_entity_name() == "medical:body" then
minetest.chat_send_all(obj:get_entity_name())
self.object:set_attach(obj, "Arm_Right", {x=0,y=4,z=0}, {x=1,y=0,z=math.random(-10, 10)})
break
end
end
end)
end
})

139
hitloc.lua Normal file
View File

@ -0,0 +1,139 @@
local limb_location = {}
--todo: make these change depending on what state the patient is in.
--[[ standing locations
limb_location.head = {x=0,y=1.6,z=0}
limb_location.torso = {x=0,y=1,z=0}
limb_location.rightarm = {x=.3,y=1,z=0}
limb_location.leftarm = {x=-.3,y=1,z=0}
limb_location.rightleg = {x=.1,y=.4,z=0}
limb_location.leftleg = {x=-.1,y=.4,z=0}
--]]
--[[ sitting locations
limb_location.head = {x=0,y=.9,z=0}
limb_location.torso = {x=0,y=.4,z=0}
limb_location.rightarm = {x=.3,y=.4,z=0}
limb_location.leftarm = {x=-.3,y=.4,z=0}
limb_location.rightleg = {x=.1,y=.1,z=.35}
limb_location.leftleg = {x=-.1,y=.1,z=.35}
--]]
-- laying locations
limb_location.head = {x=0,y=.1,z=-.65}
limb_location.torso = {x=0,y=.1,z=-.2}
limb_location.rightarm = {x=.4,y=.1,z=-.125}
limb_location.leftarm = {x=-.4,y=.1,z=-.125}
limb_location.rightleg = {x=.2,y=.1,z=.5}
limb_location.leftleg = {x=-.2,y=.1,z=.5}
local DEBUG_WAYPOINT = true
local DEBUG_CHAT = true
local function rotateVector(x, y, a)
local c = math.cos(a)
local s = math.sin(a)
return c*x - s*y, s*x + c*y
end
function medical.gethitloc(player, hitter, tool_capabilities, dir)
if not player or not hitter then return end
local playerpos = player:get_pos()
local hitpos
local hitterpos = hitter:get_pos()
local adj_hitterpos = hitterpos
local isPlayer = hitter:is_player()
if isPlayer then
adj_hitterpos.y = adj_hitterpos.y + 1.45 -- eye offset
local offset, _ = hitter:get_eye_offset()
local hitteryaw = hitter:get_look_horizontal()
local x, z = rotateVector(offset.x, offset.z, hitteryaw)
offset = vector.multiply({x=x, y=offset.y, z=z}, .1)
adj_hitterpos = vector.add(adj_hitterpos, offset)
else
local properties = hitter:get_properties()
local offset = properties.eye_height or math.abs(properties.collisionbox[2] - properties.collisionbox[4])
adj_hitterpos.y = adj_hitterpos.y + offset/2
end
if tool_capabilities and dir and tool_capabilities.groupcaps.medical_dir ~= nil then
hitpos = vector.add(adj_hitterpos, vector.multiply(dir, vector.distance(playerpos, hitterpos)))
else
local pointdir = hitter:get_look_dir() or {}
if not pointdir or pointdir == nil or not isPlayer then
local yaw = hitter:getyaw()
local pitch = 0
pointdir.x = -1*math.cos(yaw)*math.cos(pitch)
pointdir.z = -1*math.sin(yaw)*math.cos(pitch)
pointdir.y = math.sin(pitch)
end
hitpos = vector.add(adj_hitterpos, vector.multiply(pointdir, vector.distance(playerpos, hitterpos)))
end
if minetest.raycast then
local ray = minetest.raycast(adj_hitterpos, hitpos) -- it checks the players exact front before anything else because the default hit dir is weird, this may cause inaccuracies if a weapon with spread gives a look vector as a dir and the ray that goes stright ahead still hits the player
local pointed = ray:next()
if pointed and pointed.ref and pointed.ref == hitter then
pointed = ray:next()
end
if pointed and pointed.ref == player then
hitpos = pointed.intersection_point
end
end
if DEBUG_WAYPOINT then
local marker = hitter:hud_add({
hud_elem_type = "waypoint",
name = "hit",
number = 0xFF0000,
world_pos = hitpos
})
minetest.after(10, function() hitter:hud_remove(marker) end, hitter, marker)
end
return hitpos
end
function medical.getlimb(player, hitter, tool_capabilities, dir, hitloc)
local hitpos
if hitloc then
hitpos = hitloc
else
hitpos = medical.gethitloc(player, hitter, tool_capabilities, dir)
if not hitpos then return end
end
local hitlimb
local hitdistance
local playeryaw
local playerpos = player:get_pos()
if player:is_player() then
playeryaw = player:get_look_horizontal()
else
playeryaw = player:get_yaw()
end
for id, pos in pairs(limb_location) do
local x, z = rotateVector(pos.x, pos.z, playeryaw)
local rot_pos = {x=x,y=pos.y,z=z}
local adj_pos = vector.add(playerpos, rot_pos)
local dist = vector.distance(adj_pos, hitpos)
if hitdistance == nil or dist < hitdistance then
hitdistance = dist
hitlimb = id
end
if DEBUG_WAYPOINT then
local mrker = hitter:hud_add({
hud_elem_type = "waypoint",
name = id,
number = 0xFF0000,
world_pos = adj_pos
})
minetest.after(5, function() hitter:hud_remove(mrker) end, hitter, mrker)
end
end
if DEBUG_CHAT then
minetest.chat_send_all(dump(hitlimb))
end
return hitlimb
end
minetest.register_on_player_hpchange(function(player, hp_change, reason)
if reason.type then minetest.chat_send_all(reason.type) end
return hp_change
end, true)
minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
medical.getlimb(player, hitter, tool_capabilities, dir)
end)

15
init.lua Normal file
View File

@ -0,0 +1,15 @@
medical = {}
medical.mod_storage = minetest.get_mod_storage()
medical.usedtools = {}
medical.attachedtools = {}
medical.data = medical.mod_storage:to_table() or {}
if not medical.data.vitals then medical.data.vitals = {} end
if not medical.data.injuries then medical.data.injuries = {} end
--mod_storage:from_table(medical)
local modpath = minetest.get_modpath(minetest.get_current_modname())
dofile(modpath.."/vitals.lua")
dofile(modpath.."/hitloc.lua")
dofile(modpath.."/body.lua")

BIN
models/bone.b3d Normal file

Binary file not shown.

56
vitals.lua Normal file
View File

@ -0,0 +1,56 @@
local timer = 0
local default_vitals = {}
default_vitals.temp = 98 --farhenhiet
default_vitals.oxygen = 94 --percent
default_vitals.respiratory = 12 --breaths per minute
default_vitals.pulse = 70 --beats per minute
default_vitals.volume = 5000 --milliliters
default_vitals.systolic = 110 --mmHg
default_vitals.diastolic = 70 --mmHg
minetest.register_globalstep(function(dtime)
timer = timer + dtime;
if timer >= 5 then
for _,player in ipairs(minetest.get_connected_players()) do
--player:set_bone_position("Head", {x=0,y=10,z=0}, {x=0,y=180,z=0})
--local bonepos = player:get_bone_position("Head")
--[[local text = ""
for id, data in pairs (bonepos) do
text = text.." "..tostring(id)..":"..dump(data)
end
minetest.chat_send_all(text)--]]
local name = player:get_player_name()
if not medical.data.vitals[name] then medical.data.vitals[name] = default_vitals end
if medical.data.injuries[name] then
--handle loss of vital signs due to injuries
end
if hunger then
--handle hunger things
end
if thirst then
--handle thirst things
end
mv = medical.data.vitals[name]
local perfusion = ((mv.oxygen-60)/34) * ((mv.pulse-30)/40) * ((mv.volume-2000)/3000) * ((mv.temp-70)/28)
if perfusion < .9 then --compensate by raising pulse and respiratory rate
elseif perfusion < .7 then --subject gets cold and dizzy
elseif perfusion < .5 then --subject is confused
elseif perfusion < .3 then --subject is unconscious
elseif perfusion < .1 then --subject stops breathing and pumping blood
else --subject is ded
end
end
timer = 0
end
end)