2 mobs.create_movement_functions = function(def,mob_register)
4 mob_register.swim = function(self,dtime)
5 local pos = self.object:get_pos()
7 local node = minetest.get_node(pos).name
9 if node == "main:water" or node =="main:waterflow" then
10 local vel = self.object:get_velocity()
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))
18 self.object:add_velocity(acceleration)
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")
32 self.object:punch(self.object, 2,
34 full_punch_interval=1.5,
35 damage_groups = {damage=hurty},
38 local firey = get_group(noder, "fire")
40 start_fire(self.object)
42 self.hurt_inside_timer = 0.25
44 self.hurt_inside_timer = self.hurt_inside_timer - dtime
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
55 self.jump(self,moveresult)
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)
71 self.hurt_inside(self,dtime)
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)
79 self.whip_turn = self.whip_turn - dtime
80 if self.whip_turn <= 0 then
84 acceleration = vector.multiply(acceleration, 0.05)
86 self.object:add_velocity(acceleration)
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()
93 if self.path_data and table.getn(self.path_data) > 0 then
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))
107 --assume collisionbox is even x and z
108 local modifier = self.object:get_properties().collisionbox[4]*3
111 local pos2 = vector.add(vector.multiply(self.direction,modifier),pos)
113 local ray = minetest.raycast(pos, pos2, false, false)
118 pointed_thing = ray:next()
121 if pointed_thing then
122 if minetest.get_nodedef(minetest.get_node(pointed_thing.under).name, "walkable") then
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))
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))
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))
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
150 self.jump(self,moveresult)
153 self.swim(self,dtime)
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)
166 self.hurt_inside(self,dtime)
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)
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})
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
188 self.jump_timer = 1+math.random()
191 self.object:set_velocity(vector.new(0,0,0))
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
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)
207 --delete path if height too far
208 if self.path_data and height_diff > self.view_distance/2 then
210 self.old_path_pos = nil
211 self.old_acute_following_pos = nil
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))
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
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
227 local path = minetest.find_path(self.object:get_pos(),self.following_pos,self.view_distance,1,5,"A*_noprefetch")
229 --if the path fails then raycast down to scare player or accidentally find new path
230 --disabled for extreme cpu usage
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")
243 self.path_data = path
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]
250 self.path_data[table.getn(self.path_data)] = nil
252 --cut corners (go diagonal)
253 if self.path_data and table.getn(self.path_data) >= 3 then
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]
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)
264 local can_cut,_ = minetest.line_of_sight(pos1, pos2)
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]
273 self.path_data[table.getn(self.path_data)] = nil
281 if number > table.getn(self.path_data) then
288 --if self.path_data and table.getn(self.path_data) <= 2 then
289 -- self.path_data = nil
294 self.old_path_pos = acute_pos
295 self.old_acute_following_pos = acute_following_pos
298 elseif (not self.following and self.path_data) or (self.path_data and height_diff > self.view_distance/2) then
300 self.old_path_pos = nil
301 self.old_acute_following_pos = nil
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({
309 velocity = {x=0, y=0, z=0},
310 acceleration = {x=0, y=0, z=0},
311 expirationtime = 0.01,
313 texture = "dirt.png",
318 --this is the real time path deletion as it goes along it
319 if self.swimming == true then
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]
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