]> git.lizzy.rs Git - Crafter.git/blob - mods/mob/api/interaction.lua
d174e81a55c0ac6b80708a03a378a3060084c1f4
[Crafter.git] / mods / mob / api / interaction.lua
1 --
2 mobs.create_interaction_functions = function(def,mob_register)
3     --the sword wear mechanic
4     mob_register.add_sword_wear = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
5         if puncher:is_player() then
6             local itemstack = puncher:get_wielded_item()
7             local wear = itemstack:get_definition().mob_hit_wear
8             if wear then
9                 itemstack:add_wear(wear)
10                 if itemstack:get_name() == "" then
11                     minetest.sound_play("tool_break",{to_player = puncher:get_player_name(),gain=0.4})
12                 end
13                 puncher:set_wielded_item(itemstack)
14             end
15         end
16     end
17
18     --critical effect particles
19     mob_register.do_critical_particles = function(pos)
20         minetest.add_particlespawner({
21             amount = 40,
22             time = 0.001,
23             minpos = pos,
24             maxpos = pos,
25             minvel = vector.new(-2,-2,-2),
26             maxvel = vector.new(2,8,2),
27             minacc = {x=0, y=4, z=0},
28             maxacc = {x=0, y=12, z=0},
29             minexptime = 1.1,
30             maxexptime = 1.5,
31             minsize = 1,
32             maxsize = 2,
33             collisiondetection = false,
34             vertical = false,
35             texture = "critical.png",
36         })
37     end
38     
39     mob_register.collision_detection = function(self)
40         local pos = self.object:get_pos()
41         --do collision detection from the base of the mob
42         pos.y = pos.y - self.object:get_properties().collisionbox[2]
43         for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.collision_boundary)) do
44             if object:is_player() or object:get_luaentity().mob == true then
45                 local pos2 = object:get_pos()
46                 
47                 local dir = vector.direction(pos,pos2)
48                 dir.y = 0
49                 
50                 --eliminate mob being stuck in corners
51                 if dir.x == 0 and dir.z == 0 then
52                     dir = vector.new(math.random(-1,1)*math.random(),0,math.random(-1,1)*math.random())
53                 end
54                 
55                 local velocity = vector.multiply(dir,1.1)
56                 
57                 vel1 = vector.multiply(velocity, -1)
58                 vel2 = velocity
59                 self.object:add_velocity(vel1)
60                 
61                 if object:is_player() then
62                     object:add_player_velocity(vel2)
63                 else
64                     object:add_velocity(vel2)
65                 end
66             end
67         end
68     end
69     
70     mob_register.fall_damage = function(self)
71         local vel = self.object:get_velocity()
72         if vel and self.oldvel then
73            if self.oldvel.y < -7 and vel.y == 0 then
74               local damage = math.abs(self.oldvel.y + 7)
75               damage = math.floor(damage/1.5)
76               self.object:punch(self.object, 2, 
77                  {
78                   full_punch_interval=1.5,
79                   damage_groups = {damage=damage},
80                  })
81            end
82         end
83         self.oldvel = vel
84     end
85
86     --this controls what happens when the mob gets punched
87     mob_register.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
88         local hp = self.hp
89         local vel = self.object:get_velocity()
90         local hurt = tool_capabilities.damage_groups.damage
91         
92         if not hurt then
93             hurt = 1
94         end
95         
96         local critical = false
97         
98         --criticals
99         local pos = self.object:get_pos()
100         if puncher:is_player() then
101             local puncher_vel = puncher:get_player_velocity().y
102             if puncher_vel < 0 then
103                 hurt = hurt * 1.5
104                 critical = true
105             end
106         end
107         
108         local hp = hp-hurt
109         
110         if (self.punched_timer <= 0 and hp > 1) then
111             if puncher ~= self.object then
112                 self.hostile = true
113             end
114             self.hostile_timer = 20
115             self.punched_timer = 0.8
116             
117             --critical effect
118             if critical == true then
119                 self.do_critical_particles(pos)
120                 minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
121             end
122             minetest.sound_play(self.hurt_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(100,140)/100})
123             
124             self.hp = hp
125             
126             self.direction = vector.multiply(dir,-1)
127             dir = vector.multiply(dir,10)
128             if vel.y <= 0 then
129                 dir.y = 4
130             else
131                 dir.y = 0
132             end
133             
134             
135             self.object:add_velocity(dir)
136             self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
137         elseif (self.punched_timer <= 0 and self.death_animation_timer == 0) then
138             self.death_animation_timer = 1
139             self.dead = true
140             
141             --critical effect
142             if critical == true then
143                 self.do_critical_particles(pos)
144                 minetest.sound_play("critical", {object=self.object, gain = 0.1, max_hear_distance = 10,pitch = math.random(80,100)/100})
145             end
146             minetest.sound_play(self.die_sound, {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(80,100)/100})
147             
148             self.object:set_texture_mod("^[colorize:red:130")
149             if self.child then
150             self.child:set_texture_mod("^[colorize:red:130") 
151             end
152             self.add_sword_wear(self, puncher, time_from_last_punch, tool_capabilities, dir)
153         end
154     end
155
156     --this is what happens when a mob dies
157     mob_register.on_death = function(self, killer)
158         local pos = self.object:getpos()
159         --pos.y = pos.y + 0.4
160         minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
161         minetest.add_particlespawner({
162             amount = 40,
163             time = 0.001,
164             minpos = pos,
165             maxpos = pos,
166             minvel = vector.new(-5,-5,-5),
167             maxvel = vector.new(5,5,5),
168             minacc = {x=0, y=0, z=0},
169             maxacc = {x=0, y=0, z=0},
170             minexptime = 1.1,
171             maxexptime = 1.5,
172             minsize = 1,
173             maxsize = 2,
174             collisiondetection = false,
175             vertical = false,
176             texture = "smoke.png",
177         })
178         
179         --only throw items if registered
180         if self.item_drop then
181             --detect if multiple items are going to be added
182             if self.item_amount  and self.item_minumum then
183                 local data_item_amount = math.random(self.item_minimum, self.item_amount)
184                 for i = self.item_minimum,data_item_amount do
185                     minetest.throw_item(pos,self.item_drop)
186                 end
187             else
188                 minetest.throw_item(pos,self.item_drop)
189             end
190         end
191             
192         global_mob_amount = global_mob_amount - 1
193         print("Mobs Died. Current Mobs: "..global_mob_amount)
194         if self.child then
195             self.child:get_luaentity().parent = nil
196         end
197         
198         self.object:remove()
199     end
200     
201     --the pig will look for and at players
202     mob_register.look_around = function(self,dtime)
203         local pos = self.object:get_pos()
204         
205         if self.die_in_light and self.die_in_light_level and self.die_in_light == true then
206             local light_level = minetest.get_node_light(pos)
207             if light_level then
208                 if (self.die_in_light == true and light_level > self.die_in_light_level) then
209                     local damage = self.hp
210                     self.object:punch(self.object, 2, 
211                         {
212                         full_punch_interval=1.5,
213                         damage_groups = {damage=damage},
214                     })
215                 end
216             end
217         end
218         
219         --STARE O_O
220         --and follow!
221         self.following = false
222         local player_found = false
223         for _,object in ipairs(minetest.get_objects_inside_radius(pos, self.view_distance)) do
224             if object:is_player() and player_found == false and object:get_hp() > 0 then
225                 --look at player's camera
226                 local pos2 = object:get_pos()
227                 pos2.y = pos2.y + 1.625
228                 
229                 player_found = true
230                 
231                 if self.child then
232                     self.move_head(self,pos2,dtime)
233                 end
234                 
235                 if self.hostile == true then
236                     
237                     self.direction = vector.direction(pos,pos2)
238                     local distance = vector.distance(pos,pos2)-2
239                     if distance < 0 then
240                         distance = 0
241                     end
242                     
243                     --punch the player
244                     if self.attack_type == "punch" then
245                         if distance < 1 and self.punch_timer <= 0 and object:get_hp() > 0 then
246                             local line_of_sight = minetest.line_of_sight(pos, pos2)
247                             if line_of_sight == true then
248                                 self.punch_timer = 1
249                                 object:punch(self.object, 2, 
250                                     {
251                                     full_punch_interval=1.5,
252                                     damage_groups = {fleshy=2},
253                                 },vector.direction(pos,pos2))
254                             end
255                         end
256                     elseif self.attack_type == "explode" then
257                         if distance <  self.explosion_radius then
258                             
259                             if not self.tnt_timer then
260                                 minetest.sound_play("tnt_ignite", {object = self.object, gain = 1.0,})
261                                 self.tnt_timer = self.explosion_time
262                                 self.object:set_texture_mod("^[colorize:white:130")
263                                 if self.child then
264                                     self.child:set_texture_mod("^[colorize:white:130") 
265                                 end
266                             end
267                         end
268                     elseif self.attack_type == "projectile" then
269                         if not self.projectile_timer then
270                             self.projectile_timer = self.projectile_timer_cooldown
271                         end
272                         if self.projectile_timer <= 0 then
273                             self.projectile_timer = self.projectile_timer_cooldown
274                             
275                             local obj = minetest.add_entity(pos, self.projectile_type)
276                             if obj then
277                                 local dir = vector.multiply(vector.direction(pos,pos2), 50)
278                                 obj:set_velocity(dir)
279                                 obj:get_luaentity().timer = 2
280                             end
281                         end
282                     end
283                     self.speed = distance * 4
284                     if self.speed > self.max_speed then
285                         self.speed = self.max_speed
286                     end
287                     self.following = true
288                 end
289                 --only look at one player
290                 break
291             end
292         end
293         --stare straight if not found
294         if player_found == false then
295             if self.child then
296                 self.move_head(self,nil,dtime)
297             end
298             if self.manage_hostile_timer then
299                 self.manage_hostile_timer(self,dtime)
300             end
301         end
302     end
303     
304     return(mob_register)
305 end