1 --this is where mobs are defined
3 --this is going to be used to set an active mob limit
7 local path = minetest.get_modpath(minetest.get_current_modname())
9 dofile(path.."/spawning.lua")
10 dofile(path.."/items.lua")
13 --these are helpers to create entities
16 dofile(path.."/head_code.lua")
17 dofile(path.."/movement_code.lua")
18 dofile(path.."/data_handling_code.lua")
19 dofile(path.."/interaction_code.lua")
21 mob.initial_properties = {
24 collide_with_objects = false,
25 collisionbox = {-0.37, -0.4, -0.37, 0.37, 0.5, 0.37},
27 visual_size = {x = 3, y = 3},
30 "body.png","leg.png","leg.png","leg.png","leg.png"
34 automatic_face_movement_dir = 0.0,
35 automatic_face_movement_max_rotation_per_sec = 300,
45 mob.view_distance = 20
49 ----------------------------------
53 mob.on_death = function(self, killer)
54 local pos = self.object:getpos()
56 minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
57 minetest.add_particlespawner({
62 minvel = vector.new(-5,-5,-5),
63 maxvel = vector.new(5,5,5),
64 minacc = {x=0, y=0, z=0},
65 maxacc = {x=0, y=0, z=0},
70 collisiondetection = false,
72 texture = "smoke.png",
74 local obj = minetest.add_item(pos,"mob:raw_porkchop")
75 self.child:get_luaentity().parent = nil
79 mob.push = function(self)
80 local pos = self.object:getpos()
82 for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius)) do
83 if object:is_player() or object:get_luaentity().mob == true then
84 local player_pos = object:getpos()
88 local currentvel = self.object:getvelocity()
89 local vel = vector.subtract(pos, player_pos)
90 vel = vector.normalize(vel)
91 local distance = vector.distance(pos,player_pos)
92 distance = (radius-distance)*10
93 vel = vector.multiply(vel,distance)
94 local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
97 self.object:add_velocity(acceleration)
99 acceleration = vector.multiply(acceleration, 5)
100 object:add_player_velocity(acceleration)
107 mob.swim = function(self)
108 local pos = self.object:getpos()
110 local node = minetest.get_node(pos).name
111 local vel = self.object:getvelocity()
113 local acceleration = vector.new(0,goal-vel.y,0)
114 self.swimming = false
116 if node == "main:water" or node =="main:waterflow" then
118 self.object:add_velocity(acceleration)
122 --sets the mob animation and speed
123 mob.set_animation = function(self)
124 local distance = vector.distance(vector.new(0,0,0), self.object:getvelocity())
125 self.object:set_animation_frame_speed(distance*5)
132 mob.look_around = function(self)
133 local pos = self.object:get_pos()
135 --this is where the mob is actually looking
136 local eye_ray = self.raycast_look(self,dtime)
137 --this is below where the mob is pointed, checks if ledge
138 --[[ --work on this later
139 local ledge_ray = self.look_below(self)
141 local is_a_drop = true
142 --check if there's a drop
144 for pointed_thing in ledge_ray do
145 if pointed_thing then
146 local pos2 = pointed_thing.under
147 local distance = math.floor(vector.subtract(pos2,pos).y-self.object:get_properties().collisionbox[2]+0.5+0.5)
148 if distance >= -3 then
155 if is_a_drop == true then
156 self.direction = vector.multiply(self.direction, -1)
157 print("turning around")
161 --a mob will check if it needs to jump
163 for pointed_thing in eye_ray do
164 local pos = self.object:get_pos()
165 local pos2 = pointed_thing.under
166 local walkable = minetest.registered_nodes[minetest.get_node(pos2).name].walkable
168 if vector.distance(pos,pos2) < 1 then
179 self.following = false
180 local player_found = false
181 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 6)) do
182 if object:is_player() and player_found == false then
185 --look at player's camera
186 local pos2 = object:get_pos()
187 pos2.y = pos2.y + 1.625
189 local found_player = self.move_head(self,pos2)
191 if found_player == true then
192 self.direction = vector.direction(pos,pos2)
193 local distance = vector.distance(pos,pos2)-2
199 if distance < 0.5 and self.punch_timer <= 0 and object:get_hp() > 0 then
201 object:punch(self.object, 2,
203 full_punch_interval=1.5,
204 damage_groups = {fleshy=2},
205 },vector.direction(pos,pos2))
206 elseif distance < 0.5 and object:get_hp() <= 0 then
207 --make the head spin "victory dance"
209 if not self.head_spin then
212 self.child:set_attach(self.object, "", vector.new(2.4,1.2,0), vector.new(self.head_spin,0,0))
213 self.child:set_animation({x=90,y=90}, 15, 0, true)
214 self.head_spin = self.head_spin + 5
215 if self.head_spin > 360 then
220 self.speed = distance * 2
221 self.following = true
229 --stare straight if not found
230 if player_found == false then
231 self.move_head(self,nil)
235 --this is the info on the mob
236 mob.debug_nametag = function(self,dtime)
237 --we're doing this to the child because the nametage breaks the
238 --animation on the mob's body
240 --we add in items we want to see in this list
241 local debug_items = {"hunger","timer","punch_timer"}
243 for _,item in pairs(debug_items) do
245 text = text..item..": "..self[item].."\n"
248 self.child:set_nametag_attributes({
255 --this depletes the mobs hunger
256 mob.do_hunger = function(self,dtime)
257 self.hunger = self.hunger - dtime
260 --this sets the state of the mob
261 mob.set_state = function(self,dtime)
262 self.do_hunger(self,dtime)
265 mob.on_step = function(self, dtime)
266 self.set_state(self,dtime)
267 self.move(self,dtime)
268 self.set_animation(self)
269 self.look_around(self)
270 self.manage_punch_timer(self,dtime)
271 mob.debug_nametag(self,dtime)
274 minetest.register_entity("mob:pig", mob)
280 ------------------------------------------------------------------------the head
283 head.initial_properties = {
286 collide_with_objects = false,
287 collisionbox = {0, 0, 0, 0, 0, 0},
289 visual_size = {x = 1.1, y = 1.1},
292 "head.png","nose.png"
296 --automatic_face_movement_dir = 0.0,
297 --automatic_face_movement_max_rotation_per_sec = 600,
300 --remove the head if no body
301 head.on_step = function(self, dtime)
302 if self.parent == nil then
306 minetest.register_entity("mob:head", head)