]> git.lizzy.rs Git - Crafter.git/blob - mods/mob/init.lua
Fix mob head roll issue
[Crafter.git] / mods / mob / init.lua
1 --this is where mobs are defined
2
3 global_mob_table = {}
4
5
6 local path = minetest.get_modpath(minetest.get_current_modname())
7
8 dofile(path.."/spawning.lua")
9 dofile(path.."/items.lua")
10
11
12 --these are helpers to create entities
13 local mob = {}
14 mob.initial_properties = {
15         hp_max = 1,
16         physical = true,
17         collide_with_objects = false,
18         collisionbox = {-0.37, -0.37, -0.37, 0.37, 0.865, 0.37},
19         visual = "mesh",
20         visual_size = {x = 3, y = 3},
21         mesh = "pig.x",
22         textures = {
23                 "body.png","leg.png","leg.png","leg.png","leg.png"
24         },
25         is_visible = true,
26         pointable = true,
27         automatic_face_movement_dir = 0.0,
28         automatic_face_movement_max_rotation_per_sec = 600,
29 }
30 mob.hp = 5
31 mob.mob = true
32 mob.hostile = false
33 mob.timer = 0
34
35
36 mob.get_staticdata = function(self)
37         return minetest.serialize({
38                 --range = self.range,
39                 hp = self.hp,           
40         })
41 end
42
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
51                         self.hp = data.hp
52                 end
53         end
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))
57         
58         local head = minetest.add_entity(self.object:get_pos(), "mob:head")
59         if head then
60                 self.child = 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))
63         end
64         
65         --self.object:set_yaw(math.pi*math.random(-1,1)*math.random())
66 end
67 mob.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)            
68         local hurt = tool_capabilities.damage_groups.fleshy
69         if not hurt then
70                 hurt = 1
71         end
72         local hp = self.object:get_hp()
73         self.object:set_hp(hp-hurt)
74         if hp > 1 then
75                 minetest.sound_play("hurt", {object=self.object, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
76         end
77         self.hp = hp-hurt
78 end
79 mob.on_death = function(self, killer)
80         local pos = self.object:getpos()
81         pos.y = pos.y + 0.4
82         minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
83         minetest.add_particlespawner({
84                 amount = 40,
85                 time = 0.001,
86                 minpos = pos,
87                 maxpos = pos,
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},
92                 minexptime = 1.1,
93                 maxexptime = 1.5,
94                 minsize = 1,
95                 maxsize = 2,
96                 collisiondetection = false,
97                 vertical = false,
98                 texture = "smoke.png",
99         })
100         local obj = minetest.add_item(pos,"mob:raw_porkchop")
101         self.child:get_luaentity().parent = nil
102 end
103 --repel from players
104 mob.push = function(self)
105         local pos = self.object:getpos()
106         local radius = 1
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()
110                         pos.y = 0
111                         player_pos.y = 0
112                         
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)
120                         
121                         
122                         self.object:add_velocity(acceleration)
123                         
124                         acceleration = vector.multiply(acceleration, 5)
125                         object:add_player_velocity(acceleration)
126                 end
127         end
128 end
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
136                 
137                 --self.object:set_yaw(yaw)
138         end
139         
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)
147
148         --try to jump
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()
152                 if in_front then
153                         in_front = minetest.registered_nodes[minetest.get_node(in_front.under).name].walkable
154                 end
155                 if below then
156                         below = minetest.registered_nodes[minetest.get_node(below.under).name].walkable
157                 end
158                 
159                 if in_front and below then
160                         self.object:add_velocity(vector.new(0,5,0))
161                 end
162         end
163 end
164 --makes the mob swim
165 mob.swim = function(self)
166         local pos = self.object:getpos()
167         pos.y = pos.y + 0.7
168         local node = minetest.get_node(pos).name
169         local vel = self.object:getvelocity()
170         local goal = 3
171         local acceleration = vector.new(0,goal-vel.y,0)
172         self.swimming = false
173         
174         if node == "main:water" or node =="main:waterflow" then
175                 self.swimming = true
176                 self.object:add_velocity(acceleration)
177         end
178 end
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)
183 end
184
185 --converts yaw to degrees
186 local degrees = function(yaw)
187         yaw = yaw + math.pi
188         return(yaw*180.0/math.pi)
189 end
190
191 local degree_round = function(degree)
192         return(degree + 0.5 - (degree + 0.5) % 1)
193 end
194
195 local radians_to_degrees = function(radians)
196         return(radians*180.0/math.pi)
197 end
198
199 --a movement test to move the head
200 mob.move_head = function(self,pos2)
201         if self.child then
202                 --if passed a direction to look
203                 if pos2 then
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)))
209                         
210                         --pos is where the head actually is
211                         pos = vector.add(pos,dir)
212                         pos.y = pos.y + 0.36
213                                         
214                         
215                         local head_yaw  = degree_round(degrees(minetest.dir_to_yaw(vector.direction(pos,pos2))))                        
216                         
217                         local new_yaw = (body_yaw-head_yaw)
218
219                         local pitch = 0 
220                         local roll = 0  
221                         if math.abs(new_yaw) <= 90 or math.abs(new_yaw) >= 270 then
222                                 --do other calculations on pitch and roll
223                                 
224                                 local triangle = vector.new(vector.distance(pos,pos2),0,pos2.y-pos.y)
225                                 
226                                 local tri_yaw = minetest.dir_to_yaw(triangle)+(math.pi/2)
227                                 
228                                 pitch = radians_to_degrees(tri_yaw)
229                                 
230                                 pitch = pitch+90
231                         else
232                                 new_yaw = 0
233                                 pitch = 90
234                         end
235                         --                                                                      roll        newyaw      pitch
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
240                 else
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)
244                 end
245         end
246 end
247
248 mob.look_around = function(self)
249         local pos = self.object:get_pos()
250         --STARE O_O
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
254                         --print("test")
255                         player_found = true
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)
260                 end
261         end
262         --stare straight if not found
263         if player_found == false then
264                 self.move_head(self,nil)
265         end
266 end
267
268 mob.on_step = function(self, dtime)
269         self.move(self,dtime)
270         self.set_animation(self)
271         self.look_around(self)
272 end
273
274 minetest.register_entity("mob:pig", mob)
275
276
277 local head = {}
278 head.initial_properties = {
279         hp_max = 1,
280         physical = false,
281         collide_with_objects = false,
282         collisionbox = {0, 0, 0, 0, 0, 0},
283         visual = "mesh",
284         visual_size = {x = 1.1, y = 1.1},
285         mesh = "pig_head.x",
286         textures = {
287                 "head.png","nose.png"
288         },
289         is_visible = true,
290         pointable = false,
291         --automatic_face_movement_dir = 0.0,
292         --automatic_face_movement_max_rotation_per_sec = 600,
293 }
294
295 --remove the head if no body
296 head.on_step = function(self, dtime)
297         if self.parent == nil then
298                 self.object:remove()
299         end
300 end
301 minetest.register_entity("mob:head", head)