123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- -- Localize for performance.
- local math_floor = math.floor
- local math_random = math.random
- armor.elements = armor.elements or {"head", "torso", "legs", "feet"}
- armor.physics = armor.physics or {"jump", "speed", "gravity"}
- armor.default_skin = "character"
- armor.version = "MustTest"
- armor.formspec =
- "size[8,8.5]" ..
- default.gui_bg ..
- default.gui_bg_img ..
- default.gui_slots ..
- "button[0,0.5;2,0.5;main;Back]" ..
- "image[4,0.25;2,4;armor_preview]" ..
- "label[6,0.1;Health: hp_max]" ..
- "label[6,0.4;Block: armor_heal]" ..
- "list[current_player;main;0,4.25;8,1;]" ..
- "list[current_player;main;0,5.5;8,3;8]" ..
- default.get_hotbar_bg(0, 4.25)
- -- Transient player data storage.
- armor.def = armor.def or {}
- armor.textures = armor.textures or {}
- --------------------------------------------------------------------------------
- -- Use this function (just before) you call player:punch(), to notify the armor
- -- mod what the reason info for the punch is. Because as of this writing, you
- -- can't pass the PlayerHPChangeReason table directly to the :punch() method.
- -- Silly Minetest!
- function armor.notify_punch_reason(reason)
- armor.hp_change_reason = reason
- armor.hp_change_reason.type = "punch"
- end
- -- Same as above, but use if you're calling :set_hp() on the player, and need to
- -- notify the armor code what the HP change is for. Note that this is especially
- -- important if you're changing the players 'hp_max' as well. In such cases, the
- -- reason object often DOES NOT propogate through the engine, and thus this has
- -- to be done manually and entirely in Lua. Silly Minetest!
- function armor.notify_set_hp_reason(reason)
- armor.hp_change_reason = reason
- armor.hp_change_reason.type = "set_hp"
- end
- --------------------------------------------------------------------------------
- -- To be called by armor code only.
- function armor.notify_death_reason(reason)
- armor.death_reason = reason
- end
- -- May return nil. Note: this function also clears the reason data, to ensure it
- -- is only used once!
- function armor.get_hp_change_reason(engine_reason)
- if armor.hp_change_reason then
- local reason = armor.hp_change_reason
- armor.hp_change_reason = nil
- -- Copy everything from the engine's reason, but don't clobber our special
- -- 'reason' key.
- for k, v in pairs(engine_reason) do
- if k ~= "reason" then
- reason[k] = v
- end
- end
- return reason
- end
- return nil
- end
- -- To be called in one place only (the bones code) as it clears the reason
- -- at the same time.
- function armor.get_death_reason(engine_reason)
- if armor.death_reason then
- local reason = armor.death_reason
- armor.death_reason = nil
- -- Copy everything from the engine's reason, but don't clobber our special
- -- 'reason' key.
- for k, v in pairs(engine_reason) do
- if k ~= "reason" then
- reason[k] = v
- end
- end
- return reason
- end
- return nil
- end
- function armor.update_player_visuals(self, player)
- if not player then
- return
- end
- local name = player:get_player_name()
- if self.textures[name] then
- default.player_set_textures(player, {
- self.textures[name].skin,
- self.textures[name].armor,
- self.textures[name].wielditem,
- })
- end
- end
- function armor.set_player_armor(self, player)
- local name, player_inv = armor:get_valid_player(player, "[set_player_armor]")
- if not name then
- return
- end
- local armor_texture = "3d_armor_trans.png"
- -- Armor groups.
- local loc_arm_grps = {}
- local armor_heal = 0
- local state = 0
- local items = 0
- local elements = {}
- local textures = {}
- local physics_o = {speed=1,gravity=1,jump=1}
- local material = {type=nil, count=1}
- local preview_string = armor:get_preview(name) or "character_preview.png"
- -- List of textures to be applied to the character preview.
- local preview_table = {}
- for _,v in ipairs(self.elements) do
- elements[v] = false
- end
- for i = 1, 6 do
- local stack = player_inv:get_stack("armor", i)
- local item = stack:get_name()
- if stack:get_count() == 1 then
- local def = stack:get_definition()
- for k, v in pairs(elements) do
- if v == false then
- local level = def.groups["armor_" .. k]
- if level and level > 0 then
- --minetest.log('armor piece: ' .. k)
- local tex = def.texture or item:gsub("%:", "_")
- textures[#textures+1] = (tex .. ".png")
- preview_table[#preview_table+1] = (tex .. "_preview.png")
- state = state + stack:get_wear()
- items = items + 1
- armor_heal = armor_heal + (def.groups["armor_heal"] or 0)
- -- Local armor groups.
- local lag = def._armor_resist_groups or {}
- for k, v in pairs(lag) do
- --minetest.log('group: ' .. k)
- loc_arm_grps[k] = (loc_arm_grps[k] or 0) + lag[k]
- end
- for kk,vv in ipairs(self.physics) do
- local o_value = def.groups["physics_"..vv]
- if o_value then
- physics_o[vv] = physics_o[vv] + o_value
- end
- end
- local mat = string.match(item, "%:.+_(.+)$")
- if material.type then
- if material.type == mat then
- material.count = material.count + 1
- end
- else
- material.type = mat
- end
- -- Mark this type/peice of armor as handled.
- -- This avoids letting players use duplicate armor peices.
- elements[k] = true
- end
- end
- end
- end
- end
- -- I guess this gives an armor bonus if all armors are the same material?
- -- MustTest.
- if material.type and material.count == #self.elements then
- loc_arm_grps.fleshy = (loc_arm_grps.fleshy or 0) * 1.1
- end
- armor_heal = armor_heal * ARMOR_HEAL_MULTIPLIER
- if #textures > 0 then
- armor_texture = table.concat(textures, "^")
- end
- local armor_groups = {}
- for k, v in pairs(loc_arm_grps) do
- armor_groups[k] = 100 - (loc_arm_grps[k] * ARMOR_LEVEL_MULTIPLIER)
- --minetest.log('armor: ' .. k .. '=' .. armor_groups[k])
- -- Damage mitigation cannot go above 90%.
- if armor_groups[k] < 10 then
- armor_groups[k] = 10
- end
- end
- -- Sort preview texture list so that the shield is always on top.
- -- This looks better.
- table.sort(preview_table, function(a, b)
- if not a:find("shield") and b:find("shield") then
- return true
- end
- return false
- end)
- -- Generate character preview (a list of textures applied on top of each other).
- for k, v in ipairs(preview_table) do
- preview_string = preview_string .. "^" .. v
- end
- player:set_armor_groups(utility.builtin_armor_groups(armor_groups))
- pova.set_modifier(player, "physics", physics_o, "3d_armor")
- self.textures[name].armor = armor_texture
- self.textures[name].preview = preview_string
- self.def[name].state = state
- self.def[name].count = items
- self.def[name].heal = armor_heal
- self.def[name].jump = physics_o.jump
- self.def[name].speed = physics_o.speed
- self.def[name].gravity = physics_o.gravity
- self.def[name].resistances = loc_arm_grps
- self:update_player_visuals(player)
- end
- function armor.update_armor(self, player)
- -- Legacy support: Called when armor levels are changed
- -- Other mods can hook on to this function, see hud mod for example
- end
- function armor.get_player_skin(self, name)
- local skin = skins.skins[name]
- return skin or armor.default_skin
- end
- function armor.get_preview(self, name)
- end
- local function get_player_max_hp(name)
- local pref = minetest.get_player_by_name(name)
- if pref then
- local scale = 500
- local hp_max = pova.get_active_modifier(pref, "properties").hp_max
- return math_floor(hp_max / scale)
- end
- return 20
- end
- -- Pair internal armor group keys to human-readable names.
- local formspec_keysubs = {
- fleshy = "slash",
- boom = "explosive",
- cracky = "bash",
- crumbly = "wither",
- snappy = "pierce",
- choppy = "cleave",
- arrow = "ranged",
- lava = "molten",
- heat = "fire",
- electrocute = "arcane",
- }
- function armor.get_armor_formspec(self, name)
- if not armor.textures[name] then
- minetest.log("error", "3d_armor: Player texture["..name.."] is nil [get_armor_formspec]")
- return ""
- end
- if not armor.def[name] then
- minetest.log("error", "3d_armor: Armor def["..name.."] is nil [get_armor_formspec]")
- return ""
- end
- local formspec = armor.formspec .. "list[detached:"..name.."_armor;armor;0,1.5;3,2;]"
- formspec = formspec:gsub("armor_preview", armor.textures[name].preview)
- formspec = formspec:gsub("armor_heal", math_floor(armor.def[name].heal))
- formspec = formspec:gsub("hp_max", tostring(get_player_max_hp(name)))
- --minetest.log('testing: ' .. type(armor.def[name].resistances))
- -- Print out armor stats, whatever they are.
- local y = 0.7
- for k, v in pairs(armor.def[name].resistances) do
- --minetest.log('k=' .. k .. ', v=' .. v)
- if formspec_keysubs[k] then
- k = formspec_keysubs[k]
- end
- local s = k:sub(1, 1):upper() .. k:sub(2)
- formspec = formspec .. "label[6," .. y .. ";" .. s .. ": " .. math_floor(v) .. "]"
- y = y + 0.3
- end
- return formspec
- end
- function armor.update_inventory(self, player)
- local name = armor:get_valid_player(player, "[set_player_armor]")
- if not name then
- return
- end
- local formspec = armor:get_armor_formspec(name)
- formspec = formspec.."listring[current_player;main]"
- .."listring[detached:"..name.."_armor;armor]"
- local page = player:get_inventory_formspec()
- if page:find("detached:"..name.."_armor") then
- inventory_plus.set_inventory_formspec(player, formspec)
- end
- end
- function armor.get_valid_player(self, player, msg)
- msg = msg or ""
- if not player then
- minetest.log("error", "3d_armor: Player reference is nil "..msg)
- return
- end
- local pname = player:get_player_name()
- if not pname then
- minetest.log("error", "3d_armor: Player name is nil "..msg)
- return
- end
- local pos = player:get_pos()
- local player_inv = player:get_inventory()
- local armor_inv = minetest.get_inventory({type="detached", name=pname.."_armor"})
- if not pos then
- minetest.log("error", "3d_armor: Player position is nil "..msg)
- return
- elseif not player_inv then
- minetest.log("error", "3d_armor: Player inventory is nil "..msg)
- return
- elseif not armor_inv then
- -- This happens because player:set_hp() is used in 'on_joinplayer()' from
- -- another mod (XP) before the armor inv is set up. This is normal.
- -- Can't figure out why this happens even when the XP change happens *after*
- -- the joinplayer callbacks inside minetest.after()!?
- minetest.log("warning", "3d_armor: Detached armor inventory is nil "..msg)
- return
- end
- return pname, player_inv, armor_inv, pos
- end
- function armor.on_player_receive_fields(player, formname, fields)
- local name = armor:get_valid_player(player, "[on_player_receive_fields]")
- if not name then
- return
- end
- if fields.armor then
- local formspec = armor:get_armor_formspec(name)
- inventory_plus.set_inventory_formspec(player, formspec)
- return
- end
- for field, _ in pairs(fields) do
- if string.find(field, "skins_set") then
- minetest.after(0, function(player)
- local skin = armor:get_player_skin(name)
- armor.textures[name].skin = skin..".png"
- armor:set_player_armor(player)
- end, player)
- end
- end
- end
- function armor.on_joinplayer(player)
- default.player_set_model(player, "3d_armor_character.b3d")
- local name = player:get_player_name()
- local player_inv = player:get_inventory()
- local armor_inv = minetest.create_detached_inventory(name.."_armor", {
- on_put = function(inv, listname, index, stack, player)
- player:get_inventory():set_stack(listname, index, stack)
- armor:set_player_armor(player)
- armor:update_inventory(player)
- end,
- on_take = function(inv, listname, index, stack, player)
- player:get_inventory():set_stack(listname, index, nil)
- armor:set_player_armor(player)
- armor:update_inventory(player)
- end,
- on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- local plaver_inv = player:get_inventory()
- local stack = inv:get_stack(to_list, to_index)
- player_inv:set_stack(to_list, to_index, stack)
- player_inv:set_stack(from_list, from_index, nil)
- armor:set_player_armor(player)
- armor:update_inventory(player)
- end,
- allow_put = function(inv, listname, index, stack, player)
- return 1
- end,
- allow_take = function(inv, listname, index, stack, player)
- return stack:get_count()
- end,
- allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- return count
- end,
- }, name)
- armor_inv:set_size("armor", 6)
- player_inv:set_size("armor", 6)
- for i=1, 6 do
- local stack = player_inv:get_stack("armor", i)
- armor_inv:set_stack("armor", i, stack)
- end
- armor.def[name] = {
- state = 0,
- count = 0,
- heal = 0,
- jump = 1,
- speed = 1,
- gravity = 1,
- }
- armor.textures[name] = {
- skin = armor.default_skin..".png",
- armor = "3d_armor_trans.png",
- wielditem = "3d_armor_trans.png",
- preview = armor.default_skin.."_preview.png",
- }
- local skin = skins.skins[name]
- if skin then
- armor.textures[name].skin = skin .. ".png"
- end
- if minetest.get_modpath("player_textures") then
- local filename = minetest.get_modpath("player_textures").."/textures/player_"..name
- local f = io.open(filename..".png")
- if f then
- f:close()
- armor.textures[name].skin = "player_"..name..".png"
- end
- end
- for i=1, ARMOR_INIT_TIMES do
- minetest.after(ARMOR_INIT_DELAY * i, function(player)
- armor:set_player_armor(player)
- end, player)
- end
- end
- function armor.drop_armor(pos, stack)
- local obj = minetest.add_item(pos, stack)
- if obj then
- obj:set_velocity({x=math_random(-1, 1), y=5, z=math_random(-1, 1)})
- end
- end
- function armor.on_dieplayer(player, bp)
- local name, player_inv, armor_inv = armor:get_valid_player(player, "[on_dieplayer]")
- local pos = vector.new(bp)
- if not name then
- return
- end
- local drop = {}
- for i=1, player_inv:get_size("armor") do
- local stack = armor_inv:get_stack("armor", i)
- if stack:get_count() > 0 then
- table.insert(drop, stack)
- armor_inv:set_stack("armor", i, nil)
- player_inv:set_stack("armor", i, nil)
- end
- end
- armor:set_player_armor(player)
- local formspec = inventory_plus.get_formspec(player,"main")
- inventory_plus.set_inventory_formspec(player, formspec)
- local location = minetest.pos_to_string(pos)
- local node = minetest.get_node(pos)
- if node.name == "bones:bones" then
- local meta = minetest.get_meta(pos)
- local inv = meta:get_inventory()
- for _,stack in ipairs(drop) do
- if stack:get_count() > 0 and inv:room_for_item("main", stack) then
- inv:add_item("main", stack)
- minetest.log("action", "Put " .. stack:to_string() .. " in bones @ " .. location .. ".")
- else
- armor.drop_armor(pos, stack)
- end
- end
- else
- minetest.log("warning", "Failed to add armor to bones node at " ..
- minetest.pos_to_string(pos) .. "!")
- for _,stack in ipairs(drop) do
- armor.drop_armor(pos, stack)
- end
- end
- end
- function armor.get_damage_type_from_reason(reason)
- local rs = reason.type or ""
- if rs == "set_hp" or rs == "punch" then
- -- Use custom reason only if available, otherwise use engine-defined reason,
- -- which will just be 'set_hp' or 'punch'.
- if reason.reason and reason.reason ~= "" then
- if reason.reason == "node_damage" then
- -- If the notification reason is 'node_damage', then 'damage_group'
- -- should store the actual damage type.
- rs = reason.damage_group
- else
- -- Otherwise the reason itself is usually the damage type.
- rs = reason.reason
- end
- end
- end
- return rs
- end
- function armor.damage_type_disables_cloak(rstr)
- if rstr == "fleshy" or rstr == "arrow" or rstr == "boom" or rstr == "fireball"
- or rstr == "cracky" or rstr == "crumbly" or rstr == "snappy" or rstr == "choppy"
- or rstr == "crush" then
- return true
- end
- return false
- end
- function armor.armor_wear_ignores_damage(rstr)
- if rstr == "" or rstr == "xp_update" or rstr == "hp_boost_end"
- or rstr == "hunger" or rstr == "drown" or rstr == "poison"
- or rstr == "pressure" then
- return true
- end
- return false
- end
- -- Calc wear multiplier based on reason and armor piece.
- -- Notes: 'type' will be "set_hp" if from player:set_hp().
- -- Must use 'reason' field in that case.
- --
- -- Reason types are:
- -- fall (fall damage, duh)
- -- punch (punched by something)
- -- drown (drowning, duh)
- -- heat (caused by quite a few sources of heat, including lava)
- -- pressure (water pressure, usually)
- -- ground (ground/floor hazard, spikes, etc)
- -- sharp (like cactus)
- -- crush (by falling node/object)
- -- portal (arcane damage by teleporting)
- -- poison (mushrooms, rotten meat)
- -- hunger (starvation)
- -- kill (kill command)
- -- radiation (reactors, etc)
- -- electrocute (solar panels)
- -- fireball (DM artillery, etc)
- -- arrow (player weapon or mob)
- -- boom (explosions)
- --
- -- Note: the above are also the names of damage groups and armor groups.
- function armor.wear_from_reason(item, def, reason)
- local rs = armor.get_damage_type_from_reason(reason)
- --minetest.log('Reason: ' .. rs)
- -- If reason not known, just return default wear multiplier.
- if rs == "" then
- return 1
- end
- if def._armor_wear_groups then
- local mult = def._armor_wear_groups[rs] or 1
- --minetest.log('wear multiplier: ' .. mult)
- return mult
- end
- -- Default, if wear modifier not found.
- return 1
- end
- function armor.on_player_hp_change(player, hp_change, reason)
- -- If a notified reason is available, use that instead.
- if reason.type == "punch" or reason.type == "set_hp" then
- local huh = armor.get_hp_change_reason(reason)
- if huh then
- reason = huh
- --minetest.chat_send_all('replace dump: ' .. dump(reason))
- end
- end
- local pname, player_inv, armor_inv = armor:get_valid_player(player, "[on_hpchange]")
- if not (pname and hp_change < 0) then
- return hp_change
- end
- -- Admin does not take damage.
- local singleplayer = minetest.is_singleplayer()
- if not singleplayer then
- if gdac.player_is_admin(player) then
- return 0
- end
- end
- --minetest.log('reason: ' .. (reason.type or reason.reason or "N/A"))
- --minetest.log('dump: ' .. dump(reason))
- --minetest.chat_send_all('dump: ' .. dump(reason))
- --minetest.log('on_player_hp_change: ' .. hp_change)
- -- used for insta kill tools/commands like /kill (doesnt damage armor)
- if hp_change <= -60000 then
- return hp_change
- end
- local heal_max = 0
- local state = 0
- local items = 0
- -- Need to scale fall damage since players' HP is very high.
- -- AFAIK, the only other way to adjust this would be to change every node's
- -- 'fall_damage_add_percent', but that would NOT be a good idea.
- if reason.type == "fall" then
- --minetest.log('fall: ' .. hp_change)
- -- Kids, don't get bit like I did. I just spend 1 hr trying to debug this
- -- code, and it turned out the problem was passing a negative value to this
- -- function for the amount of damage. Facepalm. Why do they let me code!?
- if armor.stomp_at(player, player:get_pos(), math.abs(hp_change * 1000)) then
- hp_change = hp_change * 100
- else
- hp_change = hp_change * 500
- end
- elseif reason.type == "drown" then
- -- In the case of drowning damage, we HAVE to do it this way, because
- -- Minetest does NOT, apparently, correctly apply drowning damage itself
- -- when the value is very high!
- hp_change = hp_change * 500
- end
- -- Why do I have to do this ugly hack? Because Minetest!!!!11111!!!11
- -- Note: purpose of this hack is to ensure that the node's 'damage_per_second'
- -- can be mitigated by player's current armor stats. As of this writing, by
- -- default in Minetest, 'damage_per_second' behaves like :set_hp(), bypassing
- -- armor groups.
- if reason.type == "node_damage" and reason.node and reason.node ~= "" then
- local ndef = minetest.registered_nodes[reason.node]
- if ndef and ndef._damage_per_second_type then
- local dtp = ndef._damage_per_second_type
- local dps = ndef.damage_per_second or 0
- -- Do NOT execute the following code within this function's call-stack.
- -- That's just asking for trouble because of possible recursion.
- minetest.after(0, function()
- local pref = minetest.get_player_by_name(pname)
- if pref then
- -- PlayerHPChangeReason.type will be 'punch'.
- utility.damage_player(pref, dtp, dps,
- {reason="node_damage", damage_group=dtp, source_node=reason.node, node_pos=reason.node_pos})
- end
- end)
- -- Do not apply damage from this point. Damage will be applied via 'punch'
- -- on the next server step.
- return 0
- end
- end
- local damage_type = armor.get_damage_type_from_reason(reason)
- local ignore_wear = armor.armor_wear_ignores_damage(damage_type)
- -- Test code to check that I know what I'm doing.
- --minetest.log('hpchange type: ' .. reason.type .. ', reason: ' .. damage_type)
- --minetest.log('scaled hp change: ' .. hp_change)
- -- Do not scale damage if the engine type is 'set_hp'.
- if reason.type == "punch" then
- -- If HP change would kill player, do NOT scale it!
- -- That results in misbehavior. This does have the result that damage
- -- scaling behaves weird on the final hit before a player dies, as in that
- -- case damage isn't scaled.
- if math.abs(hp_change) < player:get_hp() then
- hp_change = hp_change * hunger.get_damage_resistance(pname)
- end
- end
- for i = 1, 6 do
- local stack = player_inv:get_stack("armor", i)
- if stack:get_count() > 0 then
- local idef = stack:get_definition()
- local use = idef.groups["armor_use"] or 0
- local heal = idef.groups["armor_heal"] or 0
- local item = stack:get_name()
- if not ignore_wear then
- stack:add_wear(use * armor.wear_from_reason(item, idef, reason))
- end
- armor_inv:set_stack("armor", i, stack)
- player_inv:set_stack("armor", i, stack)
- state = state + stack:get_wear()
- items = items + 1
- if stack:get_count() == 0 then
- local desc = minetest.registered_items[item].description
- if desc then
- minetest.chat_send_player(pname, "# Server: Your " .. desc .. " got destroyed!")
- ambiance.sound_play("default_tool_breaks", player:get_pos(), 1.0, 20)
- end
- armor:set_player_armor(player)
- armor:update_inventory(player)
- end
- heal_max = heal_max + heal
- end
- end
- armor.def[pname].state = state
- armor.def[pname].count = items
- heal_max = heal_max * ARMOR_HEAL_MULTIPLIER
- heal_max = math.min(heal_max, 90)
- if math_random(100) < heal_max then
- hp_change = 0
- end
- armor:update_armor(player)
- -- Critical: the hp change must be an integer; floating-point comparisons are
- -- deadly.
- hp_change = math_floor(hp_change)
- -- Check for combat-related reasons.
- -- (Ignore this if damage was blocked by the heal chance.)
- if math.abs(hp_change) > 0 and armor.damage_type_disables_cloak(damage_type) then
- cloaking.disable_if_enabled(pname, true)
- end
- -- If this change would kill the player, set the death reason.
- -- Note: this RELIES on the bones code getting called after this returns, on
- -- the SAME server step, such that no other death reason could intervene for
- -- any other player that is currently logged in.
- if math.abs(hp_change) >= player:get_hp() then
- --minetest.chat_send_all('armor notify: ' .. dump(reason))
- armor.notify_death_reason(reason)
- end
- -- Simulate a 'stun' effect for heavy hits.
- if hp_change <= -(3*500) then
- pova.update_modifier(player, "physics", {sneak=false}, "damage.stun.1", {time=2})
- end
- if hp_change <= -(6*500) then
- pova.update_modifier(player, "physics", {speed=0.8}, "damage.stun.3", {time=3})
- elseif hp_change <= -(2*500) then
- pova.update_modifier(player, "physics", {speed=0.95}, "damage.stun.2", {time=3})
- end
- return hp_change
- end
|