]> git.lizzy.rs Git - Crafter.git/blob - mods/mob/api/movement.lua
Overhaul fire
[Crafter.git] / mods / mob / api / movement.lua
1 --
2 mobs.create_movement_functions = function(def,mob_register)
3         --makes the mob swim
4         mob_register.swim = function(self,dtime)
5                 local pos = self.object:get_pos()
6                 pos.y = pos.y + 0.3
7                 local node = minetest.get_node(pos).name
8                 self.swimming = false
9                 if node == "main:water" or node =="main:waterflow" then
10                         local vel = self.object:get_velocity()
11                         local goal = 3
12                         local acceleration = vector.new(0,goal-vel.y,0)
13                         --jump out of the water
14                         if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
15                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
16                         --else swim
17                         else
18                                 self.object:add_velocity(acceleration)
19                         end
20                         self.swimming = true
21                 end
22         end
23
24         local get_group = minetest.get_item_group
25         local get_node = minetest.get_node
26         mob_register.hurt_inside = function(self,dtime)
27                 if self.hp > 0 and self.hurt_inside_timer <= 0 then
28                         local pos = self.object:get_pos()
29                         local noder = get_node(pos).name
30                         local hurty = get_group(noder, "hurt_inside")
31                         if hurty > 0 then
32                                 self.object:punch(self.object, 2, 
33                                         {
34                                         full_punch_interval=1.5,
35                                         damage_groups = {damage=hurty},
36                                 })
37                         end
38                         local firey = get_group(noder, "fire")
39                         if not self.on_fire and firey > 0 then
40                                 start_fire(self.object)
41                         end
42                         self.hurt_inside_timer = 0.25
43                 else
44                         self.hurt_inside_timer = self.hurt_inside_timer - dtime
45                 end
46         end
47
48         --This makes the mob walk at a certain speed and jump
49         if def.movement_type == "walk" then
50                 mob_register.move = function(self,dtime,moveresult)
51                         self.manage_jump_timer(self,dtime)
52                         self.timer = self.timer - dtime
53
54                         --jump
55                         self.jump(self,moveresult)
56                         
57                         --swim
58                         self.swim(self,dtime)
59                         
60                         --print(self.timer)
61                         --direction state change
62                         if self.timer <= 0 and not self.following == true then
63                                 --print("changing direction")
64                                 self.timer = math.random(2,7)
65                                 self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
66                                 --local yaw = self.object:get_yaw() + dtime
67                                 self.speed = math.random(0,self.max_speed)
68                                 --self.object:set_yaw(yaw)
69                         end
70
71                         self.hurt_inside(self,dtime)
72
73                         local currentvel = self.object:get_velocity()
74                         local goal = vector.multiply(self.direction,self.speed)
75                         local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
76                         if self.whip_turn then
77                                 acceleration = vector.multiply(acceleration, 0.5)
78
79                                 self.whip_turn = self.whip_turn - dtime
80                                 if self.whip_turn <= 0 then
81                                         self.whip_turn = nil
82                                 end
83                         else
84                                 acceleration = vector.multiply(acceleration, 0.05)
85                         end
86                         self.object:add_velocity(acceleration)
87                 end
88                 mob_register.jump = function(self,moveresult)
89                         if moveresult and moveresult.touching_ground and self.direction then
90                                 local pos = self.object:get_pos()
91                                 pos.y = pos.y+0.1
92
93                                 if self.path_data and table.getn(self.path_data) > 0 then
94                                         --smart jump
95                                         local y = math.floor(pos.y+0.5)
96                                         local vel = self.object:get_velocity()
97                                         if y < self.path_data[1].y then
98                                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
99                                         elseif self.path_data[2] and y < self.path_data[2].y then
100                                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
101                                         elseif self.path_data[3] and y < self.path_data[3].y then
102                                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
103                                         elseif ((vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0)) then
104                                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
105                                         end
106                                 else
107                                         --assume collisionbox is even x and z
108                                         local modifier = self.object:get_properties().collisionbox[4]*3
109                                         
110
111                                         local pos2 = vector.add(vector.multiply(self.direction,modifier),pos)
112
113                                         local ray = minetest.raycast(pos, pos2, false, false)
114                                         
115                                         local pointed_thing
116
117                                         if ray then
118                                                 pointed_thing = ray:next()
119                                         end
120                                                 
121                                         if pointed_thing then
122                                                 if minetest.get_nodedef(minetest.get_node(pointed_thing.under).name, "walkable") then
123                                                         --print("jump")
124                                                         local vel = self.object:get_velocity()
125                                                         --self.jump_timer = 1+math.random()
126                                                         self.object:set_velocity(vector.new(vel.x,5,vel.z))
127                                                 else
128                                                         --print("velocity check")
129                                                         local vel = self.object:get_velocity()
130                                                         if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
131                                                                 self.object:set_velocity(vector.new(vel.x,5,vel.z))
132                                                         end
133                                                 end
134                                         else
135                                                 --print("velcheck 2")
136                                                 local vel = self.object:get_velocity()
137                                                 if (vel.x == 0 and self.direction.x ~= 0) or (vel.z == 0 and self.direction.z ~= 0) then
138                                                         self.object:set_velocity(vector.new(vel.x,5,vel.z))
139                                                 end
140                                         end
141                                 end
142                         end
143                 end
144         elseif def.movement_type == "jump" then
145                 mob_register.move = function(self,dtime,moveresult)
146                         self.manage_jump_timer(self,dtime)
147                         self.timer = self.timer - dtime
148                         
149                         --jump
150                         self.jump(self,moveresult)
151                         
152                         --swim
153                         self.swim(self,dtime)
154                         
155                         --print(self.timer)
156                         --direction state change
157                         if self.timer <= 0 and not self.following == true then
158                                 --print("changing direction")
159                                 self.timer = math.random(2,7)
160                                 self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
161                                 --local yaw = self.object:get_yaw() + dtime
162                                 self.speed = math.random(0,self.max_speed)
163                                 --self.object:set_yaw(yaw)
164                         end
165
166                         self.hurt_inside(self,dtime)    
167                         
168                         local currentvel = self.object:get_velocity()
169                         if currentvel.y ~= 0 then
170                                 local goal = vector.multiply(self.direction,self.speed)
171                                 local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
172                                 acceleration = vector.multiply(acceleration, 0.05)
173                                 self.object:add_velocity(acceleration)
174                         end
175                 end
176                 
177                 mob_register.jump = function(self,moveresult)
178                         if moveresult and moveresult.touching_ground and self.direction then
179                                 if self.jump_timer <= 0 then
180                                         if self.make_jump_noise then
181                                                 minetest.sound_play("slime_splat", {object=self.object, gain = 1.0, max_hear_distance = 10,pitch = math.random(80,100)/100})
182                                         end
183                                         local vel = self.object:get_velocity()
184                                         self.object:set_velocity(vector.new(vel.x,5,vel.z))
185                                         if self.following == true then
186                                                 self.jump_timer = 0.5
187                                         else
188                                                 self.jump_timer = 1+math.random()
189                                         end
190                                 else
191                                         self.object:set_velocity(vector.new(0,0,0))
192                                 end
193                         end
194                 end
195         end
196         
197         if def.pathfinds then
198                 mob_register.pathfinding = function(self,dtime)
199                         if self.following and self.following_pos then
200                                 self.pathfinding_timer = self.pathfinding_timer + dtime
201                                 local height_diff
202                                 if self.object:get_pos().y > self.following_pos.y then
203                                         height_diff = math.abs(self.object:get_pos().y-self.following_pos.y)
204                                 elseif self.object:get_pos().y <= self.following_pos.y then
205                                         height_diff = math.abs(self.following_pos.y-self.object:get_pos().y)
206                                 end
207                                 --delete path if height too far
208                                 if self.path_data and height_diff > self.view_distance/2 then
209                                         self.path_data = nil
210                                         self.old_path_pos = nil
211                                         self.old_acute_following_pos = nil
212                                         return
213                                 end
214
215                                 if self.pathfinding_timer >= 0.5 and height_diff <= self.view_distance/2 then
216                                         local acute_pos = vector.floor(vector.add(self.object:get_pos(),0.5))
217                                         local acute_following_pos = vector.floor(vector.add(self.following_pos,0.5))
218
219                                         if (not self.old_path_pos or (self.old_path_pos and not vector.equals(acute_pos,self.old_path_pos))) and
220                                                         (not self.old_acute_following_pos or (self.old_acute_following_pos and vector.distance(self.old_acute_following_pos,acute_following_pos) > 2)) then
221                                                 
222                                                 --if a player tries to hide in a node
223                                                 if minetest.get_nodedef(minetest.get_node(acute_following_pos).name, "walkable") then
224                                                         acute_following_pos.y = acute_following_pos.y + 1
225                                                 end
226                                                 
227                                                 local path = minetest.find_path(self.object:get_pos(),self.following_pos,self.view_distance,1,5,"A*_noprefetch")
228
229                                                 --if the path fails then raycast down to scare player or accidentally find new path
230                                                 --disabled for extreme cpu usage
231                                                 --[[
232                                                 if not path then
233                                                         local ray = minetest.raycast(acute_following_pos, vector.new(acute_following_pos.x,acute_following_pos.y-self.view_distance,acute_following_pos.z), false, false)
234                                                         for pointed_thing in ray do
235                                                                 if pointed_thing.above then
236                                                                         path = minetest.find_path(self.object:get_pos(),pointed_thing.above,self.view_distance,1,5,"A*_noprefetch")
237                                                                         break
238                                                                 end
239                                                         end
240                                                 end
241                                                 ]]--
242                                                 if path then
243                                                         self.path_data = path
244
245                                                         --remove the first element of the list
246                                                         --shift whole list down
247                                                         for i = 2,table.getn(self.path_data) do
248                                                                 self.path_data[i-1] = self.path_data[i]
249                                                         end
250                                                         self.path_data[table.getn(self.path_data)] = nil
251                                                         
252                                                         --cut corners (go diagonal)
253                                                         if self.path_data and table.getn(self.path_data) >= 3 then
254                                                                 local number = 3
255                                                                 for i = 3,table.getn(self.path_data) do
256                                                                         local pos1 = self.path_data[number-2]
257                                                                         local pos2 = self.path_data[number]
258
259                                                                         --print(number)
260                                                                         --check if diagonal and has direct line of sight
261                                                                         if pos1 and pos2 and pos1.x ~= pos2.x and pos1.z ~= pos2.z and pos1.y == pos2.y then
262                                                                                 local pos3 = vector.divide(vector.add(pos1,pos2),2)
263                                                                                 pos3.y = pos3.y - 1
264                                                                                 local can_cut,_ = minetest.line_of_sight(pos1, pos2)
265                                                                                 if can_cut then
266
267                                                                                         if minetest.get_nodedef(minetest.get_node(pos3).name, "walkable") == true then
268                                                                                                 --shift whole list down
269                                                                                                 --print("removing"..number-1)
270                                                                                                 for z = number-1,table.getn(self.path_data) do
271                                                                                                         self.path_data[z-1] = self.path_data[z]
272                                                                                                 end
273                                                                                                 self.path_data[table.getn(self.path_data)] = nil
274                                                                                                 number = number + 2
275                                                                                         else
276                                                                                                 number = number + 1
277                                                                                         end
278                                                                                 else
279                                                                                         number = number + 1
280                                                                                 end
281                                                                                 if number > table.getn(self.path_data) then
282                                                                                         break
283                                                                                 end
284                                                                         else
285                                                                                 number = number + 1
286                                                                         end
287                                                                 end
288                                                                 --if self.path_data and table.getn(self.path_data) <= 2 then
289                                                                 --      self.path_data = nil
290                                                                 --end
291                                                         end
292                                                 end
293                                                                                                 
294                                                 self.old_path_pos = acute_pos
295                                                 self.old_acute_following_pos = acute_following_pos      
296                                         end
297                                 end
298                         elseif (not self.following and self.path_data) or (self.path_data and height_diff > self.view_distance/2) then
299                                 self.path_data = nil
300                                 self.old_path_pos = nil
301                                 self.old_acute_following_pos = nil
302                         end
303                         --[[
304                         if self.path_data then
305                                 for index,pos_data in pairs(self.path_data) do
306                                         --print(dump(pos_data))
307                                         minetest.add_particle({
308                                                 pos = pos_data,
309                                                 velocity = {x=0, y=0, z=0},
310                                                 acceleration = {x=0, y=0, z=0},
311                                                 expirationtime = 0.01,
312                                                 size = 1,
313                                                 texture = "dirt.png",
314                                         })
315                                 end
316                         end
317                         ]]--
318                         --this is the real time path deletion as it goes along it
319                         if self.swimming == true then
320                                 self.path_data = nil
321                         end
322
323                         if self.path_data and table.getn(self.path_data) > 0 then
324                                 if vector.distance(self.object:get_pos(),self.path_data[1]) <= 1 then
325                                         --shift whole list down
326                                         for i = 2,table.getn(self.path_data) do
327                                                 self.path_data[i-1] = self.path_data[i]
328                                         end
329                                         self.path_data[table.getn(self.path_data)] = nil
330                                         self.whip_turn = 0.05
331                                         --if table.getn(self.path_data) == 0 then
332                                         --      self.path_data = nil
333                                         --end
334                                 end
335                         end
336                         --charge at the player
337                         if self.path_data and table.getn(self.path_data) < 2 then
338                                 self.path_data = nil
339                         end
340
341                 end
342         end
343         
344         return(mob_register)
345 end
346