Make villager stand still if there is near player
[MineClone/MineClone2.git] / mods / ENTITIES / mobs_mc / horse.lua
blob82d455201056f6119232478e50721149ab544680
1 --MCmobs v0.4
2 --maikerumine
3 --made for MC like Survival game
4 --License for code WTFPL and otherwise stated in readmes
6 -- intllib
7 local MP = minetest.get_modpath(minetest.get_current_modname())
8 local S, NS = dofile(MP.."/intllib.lua")
10 --###################
11 --################### HORSE
12 --###################
14 -- Return overlay texture for horse/donkey/mule, e.g. chest, saddle or horse armor
15 local horse_extra_texture = function(horse)
16 local base = horse._naked_texture
17 local saddle = horse._saddle
18 local chest = horse._chest
19 local armor = horse._horse_armor
20 local textures = {}
21 if armor and minetest.get_item_group(armor, "horse_armor") > 0 then
22 textures[2] = base .. "^" .. minetest.registered_items[armor]._horse_overlay_image
23 else
24 textures[2] = base
25 end
26 if saddle then
27 textures[3] = base
28 else
29 textures[3] = "blank.png"
30 end
31 if chest then
32 textures[1] = base
33 else
34 textures[1] = "blank.png"
35 end
36 return textures
37 end
39 -- Helper functions to determine equipment rules
40 local can_equip_horse_armor = function(entity_id)
41 return entity_id == "mobs_mc:horse" or entity_id == "mobs_mc:skeleton_horse" or entity_id == "mobs_mc:zombie_horse"
42 end
43 local can_equip_chest = function(entity_id)
44 return entity_id == "mobs_mc:mule" or entity_id == "mobs_mc:donkey"
45 end
46 local can_breed = function(entity_id)
47 return entity_id == "mobs_mc:horse" or "mobs_mc:mule" or entity_id == "mobs_mc:donkey"
48 end
50 --[[ Generate all possible horse textures.
51 Horse textures are a combination of a base texture and an optional marking overlay. ]]
52 -- The base horse textures (fur) (fur)
53 local horse_base = {
54 "mobs_mc_horse_brown.png",
55 "mobs_mc_horse_darkbrown.png",
56 "mobs_mc_horse_white.png",
57 "mobs_mc_horse_gray.png",
58 "mobs_mc_horse_black.png",
59 "mobs_mc_horse_chestnut.png",
61 -- Horse marking texture overlay, to be appended to the base texture string
62 local horse_markings = {
63 "", -- no markings
64 "mobs_mc_horse_markings_whitedots.png", -- snowflake appaloosa
65 "mobs_mc_horse_markings_blackdots.png", -- sooty
66 "mobs_mc_horse_markings_whitefield.png", -- paint
67 "mobs_mc_horse_markings_white.png", -- stockings and blaze
70 local horse_textures = {}
71 for b=1, #horse_base do
72 for m=1, #horse_markings do
73 local fur = horse_base[b]
74 if horse_markings[m] ~= "" then
75 fur = fur .. "^" .. horse_markings[m]
76 end
77 table.insert(horse_textures, {
78 "blank.png", -- chest
79 fur, -- base texture + markings and optional armor
80 "blank.png", -- saddle
82 end
83 end
85 -- Horse
86 local horse = {
87 type = "animal",
88 visual = "mesh",
89 mesh = "mobs_mc_horse.b3d",
90 visual_size = {x=3.0, y=3.0},
91 collisionbox = {-0.69825, -0.01, -0.69825, 0.69825, 1.59, 0.69825},
92 animation = {
93 stand_speed = 25,
94 stand_start = 0,
95 stand_end = 0,
96 walk_speed = 25,
97 walk_start = 0,
98 walk_end = 40,
99 run_speed = 50,
100 run_start = 0,
101 run_end = 40,
103 textures = horse_textures,
104 fear_height = 4,
105 fly = false,
106 walk_chance = 60,
107 view_range = 16,
108 follow = mobs_mc.follow.horse,
109 passive = true,
110 hp_min = 15,
111 hp_max = 30,
112 floats = 1,
113 lava_damage = 4,
114 water_damage = 1,
115 makes_footstep_sound = true,
116 jump = true,
117 jump_height = 5.75, -- can clear 2.5 blocks
118 drops = {
119 {name = mobs_mc.items.leather,
120 chance = 1,
121 min = 0,
122 max = 2,},
125 do_custom = function(self, dtime)
127 -- set needed values if not already present
128 if not self._regentimer then
129 self._regentimer = 0
131 if not self.v2 then
132 self.v2 = 0
133 self.max_speed_forward = 7
134 self.max_speed_reverse = 2
135 self.accel = 6
136 self.terrain_type = 3
137 self.driver_attach_at = {x = 0, y = 7.5, z = -1.75}
138 self.driver_eye_offset = {x = 0, y = 3, z = 0}
139 self.driver_scale = {x = 1/self.visual_size.x, y = 1/self.visual_size.y}
142 -- Slowly regenerate health
143 self._regentimer = self._regentimer + dtime
144 if self._regentimer >= 4 then
145 if self.health < self.hp_max then
146 self.health = self.health + 1
148 self._regentimer = 0
151 -- if driver present allow control of horse
152 if self.driver then
154 mobs.drive(self, "walk", "stand", false, dtime)
156 return false -- skip rest of mob functions
159 return true
160 end,
162 on_die = function(self, pos)
164 -- drop saddle when horse is killed while riding
165 if self._saddle then
166 minetest.add_item(pos, mobs_mc.items.saddle)
168 -- also detach from horse properly
169 if self.driver then
170 mobs.detach(self.driver, {x = 1, y = 0, z = 1})
173 end,
175 on_rightclick = function(self, clicker)
177 -- make sure player is clicking
178 if not clicker or not clicker:is_player() then
179 return
182 local item = clicker:get_wielded_item()
183 if can_breed(self.name) and (item:get_name() == mobs_mc.items.golden_apple or item:get_name() == mobs_mc.items.golden_carrot) then
184 -- Breed horse with golden apple or golden carrot
185 if mobs:feed_tame(self, clicker, 1, true, false) then return end
187 -- Feed/tame with anything else
188 -- TODO: Different health bonus for feeding
189 if mobs:feed_tame(self, clicker, 1, false, true) then return end
190 if mobs:protect(self, clicker) then return end
192 -- Make sure tamed horse is mature and being clicked by owner only
193 if self.tamed and not self.child and self.owner == clicker:get_player_name() then
195 local inv = clicker:get_inventory()
197 -- detatch player already riding horse
198 if self.driver and clicker == self.driver then
200 mobs.detach(clicker, {x = 1, y = 0, z = 1})
202 -- Put on saddle if tamed
203 elseif not self.driver and not self._saddle
204 and clicker:get_wielded_item():get_name() == mobs_mc.items.saddle then
206 -- Put on saddle and take saddle from player's inventory
207 local w = clicker:get_wielded_item()
208 self._saddle = true
209 if not minetest.settings:get_bool("creative_mode") then
210 w:take_item()
211 clicker:set_wielded_item(w)
214 -- Update texture
215 if not self._naked_texture then
216 -- Base horse texture without chest or saddle
217 self._naked_texture = self.base_texture[2]
219 local tex = horse_extra_texture(self)
220 self.base_texture = tex
221 self.object:set_properties({textures = self.base_texture})
223 -- Put on horse armor if tamed
224 elseif can_equip_horse_armor(self.name) and not self.driver and not self._horse_armor
225 and minetest.get_item_group(clicker:get_wielded_item():get_name(), "horse_armor") > 0 then
228 -- Put on armor and take armor from player's inventory
229 local w = clicker:get_wielded_item()
230 local armor = minetest.get_item_group(w:get_name(), "horse_armor")
231 self._horse_armor = w:get_name()
232 if not minetest.settings:get_bool("creative_mode") then
233 w:take_item()
234 clicker:set_wielded_item(w)
237 -- Set horse armor strength
238 self.armor = armor
239 local agroups = self.object:get_armor_groups()
240 agroups.fleshy = self.armor
241 self.object:set_armor_groups(agroups)
243 -- Update texture
244 if not self._naked_texture then
245 -- Base horse texture without chest or saddle
246 self._naked_texture = self.base_texture[2]
248 local tex = horse_extra_texture(self)
249 self.base_texture = tex
250 self.object:set_properties({textures = self.base_texture})
253 -- Mount horse
254 elseif not self.driver and self._saddle then
256 self.object:set_properties({stepheight = 1.1})
257 mobs.attach(self, clicker)
259 -- Used to capture horse
260 elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then
261 mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
264 end,
266 on_breed = function(parent1, parent2)
267 local pos = parent1.object:get_pos()
268 local child = mobs:spawn_child(pos, parent1.name)
269 if child then
270 local ent_c = child:get_luaentity()
271 local p = math.random(1, 2)
272 local child_texture
273 -- Randomly pick one of the parents for the child texture
274 if p == 1 then
275 if parent1._naked_texture then
276 child_texture = parent1._naked_texture
277 else
278 child_texture = parent1.base_texture[2]
280 else
281 if parent2._naked_texture then
282 child_texture = parent2._naked_texture
283 else
284 child_texture = parent2.base_texture[2]
287 local splt = string.split(child_texture, "^")
288 if #splt >= 2 then
289 -- Randomly mutate base texture (fur) and markings
290 -- with chance of 1/9 each
291 local base = splt[1]
292 local markings = splt[2]
293 local mutate_base = math.random(1, 9)
294 local mutate_markings = math.random(1, 9)
295 if mutate_base == 1 then
296 local b = math.random(1, #horse_base)
297 base = horse_base[b]
299 if mutate_markings == 1 then
300 local m = math.random(1, #horse_markings)
301 markings = horse_markings[m]
303 child_texture = base
304 if markings ~= "" then
305 child_texture = child_texture .. "^" .. markings
308 ent_c.base_texture = { "blank.png", child_texture, "blank.png" }
309 ent_c._naked_texture = child_texture
311 child:set_properties({textures = ent_c.base_texture})
312 return false
314 end,
317 mobs:register_mob("mobs_mc:horse", horse)
319 -- Skeleton horse
320 local skeleton_horse = table.copy(horse)
321 skeleton_horse.textures = {{"blank.png", "mobs_mc_horse_skeleton.png", "blank.png"}}
322 skeleton_horse.drops = {
323 {name = mobs_mc.items.bone,
324 chance = 1,
325 min = 0,
326 max = 2,},
328 skeleton_horse.sounds = {
329 random = "skeleton1",
330 death = "skeletondeath",
331 damage = "skeletonhurt1",
332 distance = 16,
334 skeleton_horse.blood_amount = 0
335 mobs:register_mob("mobs_mc:skeleton_horse", skeleton_horse)
337 -- Zombie horse
338 local zombie_horse = table.copy(horse)
339 zombie_horse.textures = {{"blank.png", "mobs_mc_horse_zombie.png", "blank.png"}}
340 zombie_horse.drops = {
341 {name = mobs_mc.items.rotten_flesh,
342 chance = 1,
343 min = 0,
344 max = 2,},
346 zombie_horse.sounds = {
347 random = "mobs_mc_zombie_idle",
348 war_cry = "mobs_mc_zombie_idle",
349 death = "mobs_mc_zombie_death",
350 damage = "mobs_mc_zombie_hurt",
351 distance = 16,
353 mobs:register_mob("mobs_mc:zombie_horse", zombie_horse)
355 -- Donkey
356 local d = 0.86 -- donkey scale
357 local donkey = table.copy(horse)
358 donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
359 donkey.animation = {
360 speed_normal = 25,
361 stand_start = 0, stand_end = 0,
362 walk_start = 0, walk_end = 40,
364 donkey.visual_size = { x=horse.visual_size.x*d, y=horse.visual_size.y*d }
365 donkey.collisionbox = {
366 horse.collisionbox[1] * d,
367 horse.collisionbox[2] * d,
368 horse.collisionbox[3] * d,
369 horse.collisionbox[4] * d,
370 horse.collisionbox[5] * d,
371 horse.collisionbox[6] * d,
373 donkey.jump = true
374 donkey.jump_height = 3.75 -- can clear 1 block height
376 mobs:register_mob("mobs_mc:donkey", donkey)
378 -- Mule
379 local m = 0.94
380 local mule = table.copy(donkey)
381 mule.textures = {{"blank.png", "mobs_mc_mule.png", "blank.png"}}
382 mule.visual_size = { x=horse.visual_size.x*m, y=horse.visual_size.y*m }
383 mule.collisionbox = {
384 horse.collisionbox[1] * m,
385 horse.collisionbox[2] * m,
386 horse.collisionbox[3] * m,
387 horse.collisionbox[4] * m,
388 horse.collisionbox[5] * m,
389 horse.collisionbox[6] * m,
391 mobs:register_mob("mobs_mc:mule", mule)
393 --===========================
394 --Spawn Function
395 mobs:spawn_specific("mobs_mc:horse", mobs_mc.spawn.grassland_savanna, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 12, mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.overworld_max)
396 mobs:spawn_specific("mobs_mc:donkey", mobs_mc.spawn.grassland_savanna, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 15000, 12, mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.overworld_max)
398 -- compatibility
399 mobs:alias_mob("mobs:horse", "mobs_mc:horse")
401 -- spawn eggs
402 mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
403 mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
404 mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
405 mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
406 mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)
409 if minetest.settings:get_bool("log_mods") then
410 minetest.log("action", "MC Horse loaded")