]> git.lizzy.rs Git - Crafter.git/blob - mods/mob/init.lua
212445d6016c3a5ff7b31e6c69978105345c3915
[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 mob.on_activate = function(self, staticdata, dtime_s)
43         self.object:set_armor_groups({immortal = 1})
44         --self.object:set_velocity({x = math.random(-5,5), y = 5, z = math.random(-5,5)})
45         self.object:set_acceleration({x = 0, y = -9.81, z = 0})
46         if string.sub(staticdata, 1, string.len("return")) == "return" then
47                 local data = minetest.deserialize(staticdata)
48                 if data and type(data) == "table" then
49                         --self.range = data.range
50                         self.hp = data.hp
51                 end
52         end
53         self.object:set_animation({x=5,y=15}, 1, 0, true)
54         self.object:set_hp(self.hp)
55         self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
56         
57         local head = minetest.add_entity(self.object:get_pos(), "mob:head")
58         if head then
59                 head:set_attach(self.object, "", vector.new(2.4,1.2,0),vector.new(180,0,180))
60                 self.child = head
61         end
62         
63         --self.object:set_yaw(math.pi*math.random(-1,1)*math.random())
64 end
65 mob.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)            
66         local hurt = tool_capabilities.damage_groups.fleshy
67         if not hurt then
68                 hurt = 1
69         end
70         local hp = self.object:get_hp()
71         self.object:set_hp(hp-hurt)
72         if hp > 1 then
73                 minetest.sound_play("hurt", {object=self.object, gain = 1.0, max_hear_distance = 60,pitch = math.random(80,100)/100})
74         end
75         self.hp = hp-hurt
76 end
77 mob.on_death = function(self, killer)
78         local pos = self.object:getpos()
79         pos.y = pos.y + 0.4
80         minetest.sound_play("mob_die", {pos = pos, gain = 1.0})
81         minetest.add_particlespawner({
82                 amount = 40,
83                 time = 0.001,
84                 minpos = pos,
85                 maxpos = pos,
86                 minvel = vector.new(-5,-5,-5),
87                 maxvel = vector.new(5,5,5),
88                 minacc = {x=0, y=0, z=0},
89                 maxacc = {x=0, y=0, z=0},
90                 minexptime = 1.1,
91                 maxexptime = 1.5,
92                 minsize = 1,
93                 maxsize = 2,
94                 collisiondetection = false,
95                 vertical = false,
96                 texture = "smoke.png",
97         })
98         local obj = minetest.add_item(pos,"mob:raw_porkchop")
99 end
100 --repel from players
101 mob.push = function(self)
102         local pos = self.object:getpos()
103         local radius = 1
104         for _,object in ipairs(minetest.get_objects_inside_radius(pos, radius)) do
105                 if object:is_player() or object:get_luaentity().mob == true then
106                         local player_pos = object:getpos()
107                         pos.y = 0
108                         player_pos.y = 0
109                         
110                         local currentvel = self.object:getvelocity()
111                         local vel = vector.subtract(pos, player_pos)
112                         vel = vector.normalize(vel)
113                         local distance = vector.distance(pos,player_pos)
114                         distance = (radius-distance)*10
115                         vel = vector.multiply(vel,distance)
116                         local acceleration = vector.new(vel.x-currentvel.x,0,vel.z-currentvel.z)
117                         
118                         
119                         self.object:add_velocity(acceleration)
120                         
121                         acceleration = vector.multiply(acceleration, -0.5)
122                         object:add_player_velocity(acceleration)
123                 end
124         end
125 end
126 --This makes the mob walk at a certain speed and jump
127 mob.move = function(self,dtime)
128         self.timer = self.timer - dtime
129         if self.timer <= 0 then
130                 self.timer = math.random(1,3)
131                 self.direction = vector.new(math.random()*math.random(-1,1),0,math.random()*math.random(-1,1))
132                 --local yaw = self.object:get_yaw() + dtime
133                 
134                 --self.object:set_yaw(yaw)
135         end
136         
137         local pos1 = self.object:getpos()
138         pos1.y = pos1.y + 0.37
139         local currentvel = self.object:getvelocity()
140         local goal = vector.multiply(self.direction,5)
141         local acceleration = vector.new(goal.x-currentvel.x,0,goal.z-currentvel.z)
142         acceleration = vector.multiply(acceleration, 0.05)
143         self.object:add_velocity(acceleration)
144
145         --try to jump
146         if currentvel.y <= 0 then
147                 local in_front = minetest.raycast(pos1, vector.add(pos1,vector.multiply(self.direction,3)), false, false):next()
148                 local below = minetest.raycast(pos1, vector.add(pos1, vector.new(0,-0.02,0)), false, false):next()
149                 if in_front then
150                         in_front = minetest.registered_nodes[minetest.get_node(in_front.under).name].walkable
151                 end
152                 if below then
153                         below = minetest.registered_nodes[minetest.get_node(below.under).name].walkable
154                 end
155                 
156                 if in_front and below then
157                         self.object:add_velocity(vector.new(0,5,0))
158                 end
159         end
160 end
161 --makes the mob swim
162 mob.swim = function(self)
163         local pos = self.object:getpos()
164         pos.y = pos.y + 0.7
165         local node = minetest.get_node(pos).name
166         local vel = self.object:getvelocity()
167         local goal = 3
168         local acceleration = vector.new(0,goal-vel.y,0)
169         self.swimming = false
170         
171         if node == "main:water" or node =="main:waterflow" then
172                 self.swimming = true
173                 self.object:add_velocity(acceleration)
174         end
175 end
176 --sets the mob animation and speed
177 mob.set_animation = function(self)
178         local distance = vector.distance(vector.new(0,0,0), self.object:getvelocity())
179         self.object:set_animation_frame_speed(distance*5)
180 end
181
182 --converts yaw to degrees
183 local degrees = function(yaw)
184         yaw = yaw + math.pi
185         return(yaw*180.0/math.pi)
186 end
187
188 local degree_round = function(degree)
189         return(degree + 0.5 - (degree + 0.5) % 1)
190 end
191
192 local radians_to_degrees = function(radians)
193         return(radians*180.0/math.pi)
194 end
195
196 --a movement test to move the head
197 mob.move_head = function(self)
198         if self.child then
199                 local pos = self.object:get_pos()
200                 local body_yaw = self.object:get_yaw() - (math.pi/2)
201                 local dir = vector.multiply(minetest.yaw_to_dir(body_yaw),0.72)
202                 local real_dir = minetest.yaw_to_dir(body_yaw)
203                 local body_yaw = degree_round(degrees(minetest.dir_to_yaw(dir)))
204                 
205                 pos = vector.add(pos,dir)
206                 pos.y = pos.y + 0.36
207                 
208                 --pos is where the head actually is
209                 --STARE O_O
210                 for _,object in ipairs(minetest.get_objects_inside_radius(pos, 6)) do
211                         if object:is_player() then
212                                 local pos2 = object:get_pos()
213                                 pos2.y = pos2.y + 1.625
214                                 
215                                 local head_yaw  = degree_round(degrees(minetest.dir_to_yaw(vector.direction(pos,pos2))))                        
216                                 
217                                 local new_yaw = (head_yaw-body_yaw)
218
219                                 local pitch = 0                         
220                                 if math.abs(new_yaw) <= 90 or math.abs(new_yaw) >= 270 then
221                                         --do other calculations on pitch and roll
222                                         
223                                         local triangle = vector.new(vector.distance(pos,pos2),0,pos2.y-pos.y)
224                                         
225                                         local tri_yaw = minetest.dir_to_yaw(triangle)+(math.pi/2)
226                                         
227                                         pitch = radians_to_degrees(tri_yaw)
228                                                                         
229                                         modifier = 0    
230                                         if new_yaw > 0 then
231                                                 modifier = 1
232                                         else
233                                                 modifier = -1
234                                         end
235                                 else
236                                         new_yaw = 0
237                                 end
238                                 --                                                                      roll        newyaw      pitch
239                                 self.child:set_attach(self.object, "", vector.new(2.4,1.2,0), vector.new(180,     new_yaw,    180+pitch))                               
240                                 --self.head_rotation = vector.new(180,new_yaw,180)
241                         end
242                 end
243         end
244 end
245
246 mob.on_step = function(self, dtime)
247         self.move(self,dtime)
248         self.set_animation(self)
249         self.move_head(self)
250 end
251
252 minetest.register_entity("mob:pig", mob)
253
254
255 local head = {}
256 head.initial_properties = {
257         hp_max = 1,
258         physical = false,
259         collide_with_objects = false,
260         collisionbox = {0, 0, 0, 0, 0, 0},
261         visual = "mesh",
262         visual_size = {x = 1.1, y = 1.1},
263         mesh = "pig_head.x",
264         textures = {
265                 "head.png","nose.png"
266         },
267         is_visible = true,
268         pointable = false,
269         --automatic_face_movement_dir = 0.0,
270         --automatic_face_movement_max_rotation_per_sec = 600,
271 }
272
273 --remove the head if no body
274 head.on_step = function(self, dtime)
275         if not self.object:get_attach() then
276                 self.object:remove()
277         end
278 end
279 minetest.register_entity("mob:head", head)