]> git.lizzy.rs Git - Crafter.git/blob - mods/player_mechanics/player_interaction.lua
Pushing a test for fall damage calculations
[Crafter.git] / mods / player_mechanics / player_interaction.lua
1 local minetest,armor_class,math,pairs,ipairs = minetest,armor_class,math,pairs,ipairs
2
3 local pos
4 local name
5 local damage_nodes
6 local real_nodes
7 local a_min
8 local a_max
9 local _
10 local cancel_fall_damage = function(player)
11         name = player:get_player_name()
12         if player:get_hp() <= 0 then
13                 return
14         end
15         -- used for finding a damage node from the center of the player
16         -- rudementary collision detection
17         pos = player:get_pos()
18         minetest.chat_send_player(name,dump(pos))
19         pos.y = pos.y + (player:get_properties().collisionbox[5]/2)
20         a_min = vector.new(
21                 pos.x-0.25,
22                 pos.y-0.85,
23                 pos.z-0.25
24         )
25         a_max = vector.new(
26                 pos.x+0.25,
27                 pos.y+0.85,
28                 pos.z+0.25
29         )
30         _,saving_nodes = minetest.find_nodes_in_area( a_min,  a_max, {"group:disable_fall_damage"})
31         real_nodes = {}
32         for node_data,_ in pairs(saving_nodes) do
33                 if saving_nodes[node_data] > 0 then
34                         table.insert(real_nodes,node_data)
35                 end
36         end
37         -- find the highest damage node
38         if table.getn(real_nodes) > 0 then
39                 return(true)
40         end
41         return(false)
42 end
43
44
45
46
47
48
49
50 --hurt sound and disable fall damage group handling
51 minetest.register_on_player_hpchange(function(player, hp_change, reason)
52         if reason.type == "fall" then
53                 if cancel_fall_damage(player) then
54                         return(0)
55                 else
56                         --boots absorb fall damage
57                         local fall_damage = math.floor(player:get_player_velocity().y+0.5)+13
58                         --print("fall damage:",fall_damage)
59                         local inv = player:get_inventory()
60                         local stack = inv:get_stack("armor_feet", 1)
61                         local name = stack:get_name()
62                         if name ~= "" then
63                                 local absorption = 0
64
65                                 absorption = minetest.get_item_group(name,"armor_level")*2
66                                 --print("absorbtion:",absorption)
67                                 local wear_level = ((9-minetest.get_item_group(name,"armor_level"))*8)*(5-minetest.get_item_group(name,"armor_type"))*math.abs(fall_damage)
68                                 
69                                 stack:add_wear(wear_level)
70                                 
71                                 inv:set_stack("armor_feet", 1, stack)
72                                 
73                                 local new_stack = inv:get_stack("armor_feet",1):get_name()
74
75                         if new_stack == "" then                                 
76                                         minetest.sound_play("armor_break",{to_player=player:get_player_name(),gain=1,pitch=math.random(80,100)/100})
77                                         armor_class.recalculate_armor(player)
78                                         armor_class.set_armor_gui(player)
79                                         --do particles too
80                                 elseif minetest.get_item_group(new_stack,"boots") > 0 then 
81                                         local pos = player:get_pos()
82                                         minetest.add_particlespawner({
83                                                 amount = 30,
84                                                 time = 0.00001,
85                                                 minpos = {x=pos.x-0.5, y=pos.y+0.1, z=pos.z-0.5},
86                                                 maxpos = {x=pos.x+0.5, y=pos.y+0.1, z=pos.z+0.5},
87                                                 minvel = vector.new(-0.5,1,-0.5),
88                                                 maxvel = vector.new(0.5 ,2 ,0.5),
89                                                 minacc = {x=0, y=-9.81, z=1},
90                                                 maxacc = {x=0, y=-9.81, z=1},
91                                                 minexptime = 0.5,
92                                                 maxexptime = 1.5,
93                                                 minsize = 0,
94                                                 maxsize = 0,
95                                                 --attached = player,
96                                                 collisiondetection = true,
97                                                 collision_removal = true,
98                                                 vertical = false,
99                                                 node = {name= name.."particletexture"},
100                                                 --texture = "eat_particles_1.png"
101                                         })
102                                         minetest.sound_play("armor_fall_damage", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})   
103                                 end
104
105                                 fall_damage = fall_damage + absorption
106
107                                 if fall_damage >= 0 then
108                                         fall_damage = 0
109                                 else
110                                         minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
111                                 end
112                         else
113                                 minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
114                         end
115                         --print("returned fall damage",fall_damage)
116                         return(fall_damage)
117                 end
118         elseif hp_change < 0 then
119                 minetest.sound_play("hurt", {object=player, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
120         end
121         return(hp_change)
122 end, true)
123
124 --throw all items on death
125 minetest.register_on_dieplayer(function(player, reason)
126         local pos = player:get_pos()
127         local inv = player:get_inventory()
128         
129         for i = 1,inv:get_size("main") do
130                 local stack = inv:get_stack("main", i)
131                 local name = stack:get_name()
132                 local count = stack:get_count()
133                 if name ~= "" then
134                         local obj = minetest.add_item(pos, stack)
135                         if obj then
136                                 obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
137                         end
138                         inv:set_stack("main", i, ItemStack(""))
139                 else
140                         inv:set_stack("main", i, ItemStack(""))
141                 end
142         end
143
144         local stack = inv:get_stack("armor_head", 1)
145         local name = stack:get_name()
146         if name ~= "" then
147                 local obj = minetest.add_item(pos, stack)
148                 if obj then
149                         obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
150                 end
151                 inv:set_stack("armor_head", 1, ItemStack(""))
152         end
153
154         stack = inv:get_stack("armor_torso", 1)
155         name = stack:get_name()
156         if name ~= "" then
157                 local obj = minetest.add_item(pos, stack)
158                 if obj then
159                         obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
160                 end
161                 inv:set_stack("armor_torso", 1, ItemStack(""))
162         end
163
164         stack = inv:get_stack("armor_legs", 1)
165         name = stack:get_name()
166         if name ~= "" then
167                 local obj = minetest.add_item(pos, stack)
168                 if obj then
169                         obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
170                 end
171                 inv:set_stack("armor_legs", 1, ItemStack(""))
172         end
173
174
175         stack = inv:get_stack("armor_feet", 1)
176         name = stack:get_name()
177         if name ~= "" then
178                 local obj = minetest.add_item(pos, stack)
179                 if obj then
180                         obj:set_velocity(vector.new(math.random(-3,3),math.random(4,8),math.random(-3,3)))
181                 end
182                 inv:set_stack("armor_feet", 1, ItemStack(""))
183         end
184
185
186         armor_class.recalculate_armor(player)
187 end)
188
189
190 --this dumps the players crafting table on closing the inventory
191 dump_craft = function(player)
192         local inv = player:get_inventory()
193         local pos = player:get_pos()
194         pos.y = pos.y + player:get_properties().eye_height
195         for i = 1,inv:get_size("craft") do
196                 local item = inv:get_stack("craft", i)
197                 local obj = minetest.add_item(pos, item)
198                 if obj then
199                         local x=math.random(-2,2)*math.random()
200                         local y=math.random(2,5)
201                         local z=math.random(-2,2)*math.random()
202                         obj:set_velocity({x=x, y=y, z=z})
203                 end
204                 inv:set_stack("craft", i, nil)
205         end
206 end
207
208
209 --play sound to keep up with player's placing vs inconsistent client placing sound 
210 minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
211         local node = minetest.registered_nodes[newnode.name]
212         local sound = node.sounds
213         local placing = ""
214         if sound then
215                 placing = sound.placing
216         end
217         --only play the sound when is defined
218         if type(placing) == "table" then
219                 minetest.sound_play(placing.name, {
220                           pos = pos,
221                           gain = placing.gain,
222                           --pitch = math.random(60,100)/100
223                 })
224         end
225 end)
226
227 --replace stack when empty (building)
228 minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
229         local old = itemstack:get_name()
230         --pass through to check
231         minetest.after(0,function(pos, newnode, placer, oldnode, itemstack, pointed_thing,old)
232                 if not placer then
233                         return
234                 end
235                 local new = placer:get_wielded_item():get_name()
236                 if old ~= new and new == "" then
237                         local inv = placer:get_inventory()
238                         --check if another stack
239                         if inv:contains_item("main", old) then
240                                 --print("moving stack")
241                                 --run through inventory
242                                 for i = 1,inv:get_size("main") do
243                                         --if found set wielded item and remove old stack
244                                         if inv:get_stack("main", i):get_name() == old then
245                                                 local count = inv:get_stack("main", i):get_count()
246                                                 placer:set_wielded_item(old.." "..count)
247                                                 inv:set_stack("main",i,ItemStack(""))   
248                                                 minetest.sound_play("pickup", {
249                                                           to_player = player,
250                                                           gain = 0.7,
251                                                           pitch = math.random(60,100)/100
252                                                 })
253                                                 return                          
254                                         end
255                                 end
256                         end
257                 end
258         end,pos, newnode, placer, oldnode, itemstack, pointed_thing,old)
259 end)
260
261 local do_critical_particles = function(pos)
262         minetest.add_particlespawner({
263                 amount = 40,
264                 time = 0.001,
265                 minpos = pos,
266                 maxpos = pos,
267                 minvel = vector.new(-2,-2,-2),
268                 maxvel = vector.new(2,8,2),
269                 minacc = {x=0, y=4, z=0},
270                 maxacc = {x=0, y=12, z=0},
271                 minexptime = 1.1,
272                 maxexptime = 1.5,
273                 minsize = 1,
274                 maxsize = 2,
275                 collisiondetection = false,
276                 vertical = false,
277                 texture = "critical.png",
278         })
279 end
280
281 --we need to do this to override the default damage mechanics
282 minetest.register_on_joinplayer(function(player)
283         local meta = player:get_meta()
284         meta:set_float("player_punch_timer",0)
285 end)
286
287 minetest.register_globalstep(function(dtime)
288         for _,player in ipairs(minetest.get_connected_players()) do
289                 local meta = player:get_meta()
290                 local punch_timer = meta:get_float("player_punch_timer")
291
292                 --limit this so the game engine isn't calculating huge floats
293                 if punch_timer > 0 then
294                         punch_timer = punch_timer - dtime
295                         if punch_timer < 0 then punch_timer = 0 end
296                         meta:set_float("player_punch_timer",punch_timer)
297                 end
298         end
299 end)
300
301 --this throws the player when they're punched and activates the custom damage mechanics
302 minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
303         local meta = player:get_meta()
304         local punch_timer = meta:get_float("player_punch_timer")
305         local hurt = tool_capabilities.damage_groups.damage
306         local hp = player:get_hp()
307         if punch_timer <= 0 and hp > 0 then
308                 meta:set_float("player_punch_timer",0.25)
309                 if hitter:is_player() and hitter ~= player then
310                         local puncher_vel = hitter:get_player_velocity().y
311                         if puncher_vel < 0 then
312                                 hurt = hurt * 1.5
313                                 critical = true
314                                 do_critical_particles(player:get_pos())
315                                 minetest.sound_play("critical", {pos=player:get_pos(), gain = 0.1, max_hear_distance = 16,pitch = math.random(80,100)/100})
316                         end
317                 end
318
319                 dir = vector.multiply(dir,10)
320                 local vel = player:get_player_velocity()
321                 dir.y = 0
322                 if vel.y <= 0 then
323                         dir.y = 7
324                 end
325
326                 local hp_modifier = math.ceil(armor_class.calculate_armor_absorbtion(player)/3)
327                 --print("hp_modifier:",hp_modifier)
328                 armor_class.damage_armor(player,math.abs(hurt))
329
330                 --print("hurt:",hurt,"|","hp_modifier:",hp_modifier)
331                 local modify_output = (hurt == 0)
332                 
333                 hurt = hurt - hp_modifier
334
335                 if modify_output == false and hurt <= 0 then
336                         hurt = 1
337                 elseif modify_output == true then
338                         hurt = 0
339                 end
340                 player:add_player_velocity(dir)
341                 player:set_hp(hp-hurt)
342         end
343 end)
344
345