1 local minetest,armor_class,math,pairs,ipairs = minetest,armor_class,math,pairs,ipairs
10 local cancel_fall_damage = function(player)
11 name = player:get_player_name()
12 if player:get_hp() <= 0 then
15 -- used for finding a damage node from the center of the player
16 -- rudementary collision detection
17 pos = player:get_pos()
29 _,saving_nodes = minetest.find_nodes_in_area( a_min, a_max, {"group:disable_fall_damage"})
31 for node_data,_ in pairs(saving_nodes) do
32 if saving_nodes[node_data] > 0 then
33 table.insert(real_nodes,node_data)
36 -- find the highest damage node
37 if table.getn(real_nodes) > 0 then
44 local function calc_fall_damage(player,hp_change,velocity)
45 if cancel_fall_damage(player) then
48 --boots absorb fall damage
49 local fall_damage = velocity+13
50 --print("fall damage:",fall_damage)
51 local inv = player:get_inventory()
52 local stack = inv:get_stack("armor_feet", 1)
53 local name = stack:get_name()
57 absorption = minetest.get_item_group(name,"armor_level")*2
58 --print("absorbtion:",absorption)
59 local wear_level = ((9-minetest.get_item_group(name,"armor_level"))*8)*(5-minetest.get_item_group(name,"armor_type"))*math.abs(fall_damage)
61 stack:add_wear(wear_level)
63 inv:set_stack("armor_feet", 1, stack)
65 local new_stack = inv:get_stack("armor_feet",1):get_name()
67 if new_stack == "" then
68 minetest.sound_play("armor_break",{to_player=player:get_player_name(),gain=1,pitch=math.random(80,100)/100})
69 armor_class.recalculate_armor(player)
70 armor_class.set_armor_gui(player)
72 elseif minetest.get_item_group(new_stack,"boots") > 0 then
73 local pos = player:get_pos()
74 minetest.add_particlespawner({
77 minpos = {x=pos.x-0.5, y=pos.y+0.1, z=pos.z-0.5},
78 maxpos = {x=pos.x+0.5, y=pos.y+0.1, z=pos.z+0.5},
79 minvel = vector.new(-0.5,1,-0.5),
80 maxvel = vector.new(0.5 ,2 ,0.5),
81 minacc = {x=0, y=-9.81, z=1},
82 maxacc = {x=0, y=-9.81, z=1},
88 collisiondetection = true,
89 collision_removal = true,
91 node = {name= name.."particletexture"},
92 --texture = "eat_particles_1.png"
94 minetest.sound_play("armor_fall_damage", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
97 fall_damage = fall_damage + absorption
99 if fall_damage >= 0 then
102 player:set_hp(player:get_hp()+fall_damage,{reason="correction"})
103 minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
106 player:set_hp(player:get_hp()-hp_change,{reason="correction"})
107 minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
113 --hurt sound and disable fall damage group handling
114 minetest.register_on_player_hpchange(function(player, hp_change, reason)
115 if reason.type == "fall" then
116 local fall = math.floor(player:get_player_velocity().y+0.5)
117 minetest.after(0.01,function()
118 calc_fall_damage(player,hp_change,fall)
121 elseif hp_change < 0 and reason.reason ~= "correction" then
123 minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
128 --throw all items on death
129 minetest.register_on_dieplayer(function(player, reason)
130 local pos = player:get_pos()
131 local inv = player:get_inventory()
133 for i = 1,inv:get_size("main") do
134 local stack = inv:get_stack("main", i)
135 local name = stack:get_name()
136 local count = stack:get_count()
138 local obj = minetest.add_item(pos, stack)
140 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
142 inv:set_stack("main", i, ItemStack(""))
144 inv:set_stack("main", i, ItemStack(""))
148 local stack = inv:get_stack("armor_head", 1)
149 local name = stack:get_name()
151 local obj = minetest.add_item(pos, stack)
153 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
155 inv:set_stack("armor_head", 1, ItemStack(""))
158 stack = inv:get_stack("armor_torso", 1)
159 name = stack:get_name()
161 local obj = minetest.add_item(pos, stack)
163 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
165 inv:set_stack("armor_torso", 1, ItemStack(""))
168 stack = inv:get_stack("armor_legs", 1)
169 name = stack:get_name()
171 local obj = minetest.add_item(pos, stack)
173 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
175 inv:set_stack("armor_legs", 1, ItemStack(""))
179 stack = inv:get_stack("armor_feet", 1)
180 name = stack:get_name()
182 local obj = minetest.add_item(pos, stack)
184 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
186 inv:set_stack("armor_feet", 1, ItemStack(""))
190 armor_class.recalculate_armor(player)
194 --this dumps the players crafting table on closing the inventory
195 dump_craft = function(player)
196 local inv = player:get_inventory()
197 local pos = player:get_pos()
198 pos.y = pos.y + player:get_properties().eye_height
199 for i = 1,inv:get_size("craft") do
200 local item = inv:get_stack("craft", i)
201 local obj = minetest.add_item(pos, item)
203 local x=math.random(-2,2)*math.random()
204 local y=math.random(2,5)
205 local z=math.random(-2,2)*math.random()
206 obj:set_velocity({x=x, y=y, z=z})
208 inv:set_stack("craft", i, nil)
213 --play sound to keep up with player's placing vs inconsistent client placing sound
214 minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
215 local node = minetest.registered_nodes[newnode.name]
216 local sound = node.sounds
219 placing = sound.placing
221 --only play the sound when is defined
222 if type(placing) == "table" then
223 minetest.sound_play(placing.name, {
226 --pitch = math.random(60,100)/100
231 --replace stack when empty (building)
232 minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
233 local old = itemstack:get_name()
234 --pass through to check
235 minetest.after(0,function(pos, newnode, placer, oldnode, itemstack, pointed_thing,old)
239 local new = placer:get_wielded_item():get_name()
240 if old ~= new and new == "" then
241 local inv = placer:get_inventory()
242 --check if another stack
243 if inv:contains_item("main", old) then
244 --print("moving stack")
245 --run through inventory
246 for i = 1,inv:get_size("main") do
247 --if found set wielded item and remove old stack
248 if inv:get_stack("main", i):get_name() == old then
249 local count = inv:get_stack("main", i):get_count()
250 placer:set_wielded_item(old.." "..count)
251 inv:set_stack("main",i,ItemStack(""))
252 minetest.sound_play("pickup", {
255 pitch = math.random(60,100)/100
262 end,pos, newnode, placer, oldnode, itemstack, pointed_thing,old)
265 local do_critical_particles = function(pos)
266 minetest.add_particlespawner({
271 minvel = vector.new(-2,-2,-2),
272 maxvel = vector.new(2,8,2),
273 minacc = {x=0, y=4, z=0},
274 maxacc = {x=0, y=12, z=0},
279 collisiondetection = false,
281 texture = "critical.png",
285 --we need to do this to override the default damage mechanics
286 minetest.register_on_joinplayer(function(player)
287 local meta = player:get_meta()
288 meta:set_float("player_punch_timer",0)
291 minetest.register_globalstep(function(dtime)
292 for _,player in ipairs(minetest.get_connected_players()) do
293 local meta = player:get_meta()
294 local punch_timer = meta:get_float("player_punch_timer")
296 --limit this so the game engine isn't calculating huge floats
297 if punch_timer > 0 then
298 punch_timer = punch_timer - dtime
299 if punch_timer < 0 then punch_timer = 0 end
300 meta:set_float("player_punch_timer",punch_timer)
305 --this throws the player when they're punched and activates the custom damage mechanics
306 minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
307 local meta = player:get_meta()
308 local punch_timer = meta:get_float("player_punch_timer")
309 local hurt = tool_capabilities.damage_groups.damage
310 local hp = player:get_hp()
311 if punch_timer <= 0 and hp > 0 then
312 meta:set_float("player_punch_timer",0.25)
313 if hitter:is_player() and hitter ~= player then
314 local puncher_vel = hitter:get_player_velocity().y
315 if puncher_vel < 0 then
318 do_critical_particles(player:get_pos())
319 minetest.sound_play("critical", {pos=player:get_pos(), gain = 0.1, max_hear_distance = 16,pitch = math.random(80,100)/100})
323 dir = vector.multiply(dir,10)
324 local vel = player:get_player_velocity()
330 local hp_modifier = math.ceil(armor_class.calculate_armor_absorbtion(player)/3)
331 --print("hp_modifier:",hp_modifier)
332 armor_class.damage_armor(player,math.abs(hurt))
334 --print("hurt:",hurt,"|","hp_modifier:",hp_modifier)
335 local modify_output = (hurt == 0)
337 hurt = hurt - hp_modifier
339 if modify_output == false and hurt <= 0 then
341 elseif modify_output == true then
344 player:add_player_velocity(dir)
345 player:set_hp(hp-hurt)