1 --this is where mobs are defined
6 local path = minetest.get_modpath(minetest.get_current_modname())
8 dofile(path.."/spawning.lua")
9 dofile(path.."/items.lua")
12 --these are helpers to create entities
14 mob.initial_properties = {
17 collide_with_objects = false,
18 collisionbox = {-0.37, -0.37, -0.37, 0.37, 0.865, 0.37},
20 visual_size = {x = 3, y = 3},
23 "body.png","leg.png","leg.png","leg.png","leg.png"
27 automatic_face_movement_dir = 0.0,
28 automatic_face_movement_max_rotation_per_sec = 600,
36 mob.get_staticdata = function(self)
37 return minetest.serialize({
43 mob.on_activate = function(self, staticdata, dtime_s)
44 self.object:set_armor_groups({immortal = 1})
45 --self.object:set_velocity({x = math.random(-5,5), y = 5, z = math.random(-5,5)})
46 self.object:set_acceleration({x = 0, y = -9.81, z = 0})
47 if string.sub(staticdata, 1, string.len("return")) == "return" then
48 local data = minetest.deserialize(staticdata)
49 if data and type(data) == "table" then
50 --self.range = data.range
54 self.object:set_animation({x=5,y=15}, 1, 0, true)
55 self.object:set_hp(self.hp)
56 self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
58 local head = minetest.add_entity(self.object:get_pos(), "mob:head")
61 self.child:get_luaentity().parent = self.object
62 self.child:set_attach(self.object, "", vector.new(2.4,1.2,0), vector.new(180,0,0))
65 --self.object:set_yaw(math.pi*math.random(-1,1)*math.random())
67 mob.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
68 local hurt = tool_capabilities.damage_groups.fleshy
72 local hp = self.object:get_hp()
73 self.object:set_hp(hp-hurt)
75 minetest.sound_play("hurt", {object=self.object, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
79 mob.on_death = function(self, killer)
80 local pos = self.object:getpos()
82 minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
83 minetest.add_particlespawner({
88 minvel = vector.new(-5,-5,-5),
89 maxvel = vector.new(5,5,5),
90 minacc = {x=0, y=0, z=0},
91 maxacc = {x=0, y=0, z=0},
96 collisiondetection = false,
98 texture = "smoke.png",
100 local obj = minetest.add_item(pos,"mob:raw_porkchop")
101 self.child:get_luaentity().parent = nil
104 mob.push = function(self)
105 local pos = self.object:getpos()
107 for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius)) do
108 if object:is_player() or object:get_luaentity().mob == true then
109 local player_pos = object:getpos()
113 local currentvel = self.object:getvelocity()
114 local vel = vector.subtract(pos, player_pos)
115 vel = vector.normalize(vel)
116 local distance = vector.distance(pos,player_pos)
117 distance = (radius-distance)*10
118 vel = vector.multiply(vel,distance)
119 local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
122 self.object:add_velocity(acceleration)
124 acceleration = vector.multiply(acceleration, 5)
125 object:add_player_velocity(acceleration)
129 --This makes the mob walk at a certain speed and jump
130 mob.move = function(self,dtime)
131 self.timer = self.timer - dtime
132 if self.timer <= 0 then
133 self.timer = math.random(5,10)
134 self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
135 --local yaw = self.object:get_yaw() + dtime
137 --self.object:set_yaw(yaw)
140 local pos1 = self.object:getpos()
141 pos1.y = pos1.y + 0.37
142 local currentvel = self.object:getvelocity()
143 local goal = vector.multiply(self.direction,5)
144 local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
145 acceleration = vector.multiply(acceleration, 0.05)
146 self.object:add_velocity(acceleration)
149 if currentvel.y <= 0 then
150 local in_front = minetest.raycast(pos1, vector.add(pos1,vector.multiply(self.direction,3)), false, false):next()
151 local below = minetest.raycast(pos1, vector.add(pos1, vector.new(0,-0.02,0)), false, false):next()
153 in_front = minetest.registered_nodes[minetest.get_node(in_front.under).name].walkable
156 below = minetest.registered_nodes[minetest.get_node(below.under).name].walkable
159 if in_front and below then
160 self.object:add_velocity(vector.new(0,5,0))
165 mob.swim = function(self)
166 local pos = self.object:getpos()
168 local node = minetest.get_node(pos).name
169 local vel = self.object:getvelocity()
171 local acceleration = vector.new(0,goal-vel.y,0)
172 self.swimming = false
174 if node == "main:water" or node =="main:waterflow" then
176 self.object:add_velocity(acceleration)
179 --sets the mob animation and speed
180 mob.set_animation = function(self)
181 local distance = vector.distance(vector.new(0,0,0), self.object:getvelocity())
182 self.object:set_animation_frame_speed(distance*5)
185 --converts yaw to degrees
186 local degrees = function(yaw)
188 return(yaw*180.0/math.pi)
191 local degree_round = function(degree)
192 return(degree + 0.5 - (degree + 0.5) % 1)
195 local radians_to_degrees = function(radians)
196 return(radians*180.0/math.pi)
199 --a movement test to move the head
200 mob.move_head = function(self,pos2)
202 --if passed a direction to look
204 local pos = self.object:get_pos()
205 local body_yaw = self.object:get_yaw() - (math.pi/2)
206 local dir = vector.multiply(minetest.yaw_to_dir(body_yaw),0.72)
207 local real_dir = minetest.yaw_to_dir(body_yaw)
208 local body_yaw = degree_round(degrees(minetest.dir_to_yaw(dir)))
210 --pos is where the head actually is
211 pos = vector.add(pos,dir)
215 local head_yaw = degree_round(degrees(minetest.dir_to_yaw(vector.direction(pos,pos2))))
217 local new_yaw = (body_yaw-head_yaw)
221 if math.abs(new_yaw) <= 90 or math.abs(new_yaw) >= 270 then
222 --do other calculations on pitch and roll
224 local triangle = vector.new(vector.distance(pos,pos2),0,pos2.y-pos.y)
226 local tri_yaw = minetest.dir_to_yaw(triangle)+(math.pi/2)
228 pitch = radians_to_degrees(tri_yaw)
236 self.child:set_attach(self.object, "", vector.new(2.4,1.2,0), vector.new(180, 180+(-new_yaw), 180))
237 self.child:set_animation({x=pitch,y=pitch}, 15, 0, true)
238 self.head_rotation = vector.new(180, 180+(-new_yaw), 180)
239 --if nothing to look at
241 --print("not looking")
242 self.child:set_attach(self.object, "", vector.new(2.4,1.2,0), vector.new(180, 180, 180))
243 self.child:set_animation({x=90,y=90}, 15, 0, true)
248 mob.look_around = function(self)
249 local pos = self.object:get_pos()
251 local player_found = false
252 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 6)) do
253 if object:is_player() and player_found == false then
256 --look at player's camera
257 local pos2 = object:get_pos()
258 pos2.y = pos2.y + 1.625
259 self.move_head(self,pos2)
262 --stare straight if not found
263 if player_found == false then
264 self.move_head(self,nil)
268 mob.on_step = function(self, dtime)
269 self.move(self,dtime)
270 self.set_animation(self)
271 self.look_around(self)
274 minetest.register_entity("mob:pig", mob)
278 head.initial_properties = {
281 collide_with_objects = false,
282 collisionbox = {0, 0, 0, 0, 0, 0},
284 visual_size = {x = 1.1, y = 1.1},
287 "head.png","nose.png"
291 --automatic_face_movement_dir = 0.0,
292 --automatic_face_movement_max_rotation_per_sec = 600,
295 --remove the head if no body
296 head.on_step = function(self, dtime)
297 if self.parent == nil then
301 minetest.register_entity("mob:head", head)