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