Fix breeding giving weird childs
[MineClone/MineClone2.git] / mods / ENTITIES / mobs_mc / horse.lua
blob32f010c95f0732ddf9f507e09a6e248713dc5684
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 table.insert(horse_textures, {
74 "blank.png", -- chest
75 horse_base[b] .. horse_markings[m], -- base texture + markings and optional armor
76 "blank.png", -- saddle
78 end
79 end
81 -- Horse
82 local horse = {
83 type = "animal",
84 visual = "mesh",
85 mesh = "mobs_mc_horse.b3d",
86 visual_size = {x=3.0, y=3.0},
87 collisionbox = {-0.69825, -0.01, -0.69825, 0.69825, 1.59, 0.69825},
88 animation = {
89 stand_speed = 25,
90 stand_start = 0,
91 stand_end = 0,
92 walk_speed = 25,
93 walk_start = 0,
94 walk_end = 40,
95 run_speed = 50,
96 run_start = 0,
97 run_end = 40,
99 textures = horse_textures,
100 fear_height = 4,
101 fly = false,
102 walk_chance = 60,
103 view_range = 16,
104 follow = mobs_mc.follow.horse,
105 passive = true,
106 hp_min = 15,
107 hp_max = 30,
108 floats = 1,
109 lava_damage = 4,
110 water_damage = 1,
111 makes_footstep_sound = true,
112 jump = true,
113 jump_height = 5.75, -- can clear 2.5 blocks
114 drops = {
115 {name = mobs_mc.items.leather,
116 chance = 1,
117 min = 0,
118 max = 2,},
121 do_custom = function(self, dtime)
123 -- set needed values if not already present
124 if not self._regentimer then
125 self._regentimer = 0
127 if not self.v2 then
128 self.v2 = 0
129 self.max_speed_forward = 7
130 self.max_speed_reverse = 2
131 self.accel = 6
132 self.terrain_type = 3
133 self.driver_attach_at = {x = 0, y = 7.5, z = -1.75}
134 self.driver_eye_offset = {x = 0, y = 3, z = 0}
135 self.driver_scale = {x = 1/self.visual_size.x, y = 1/self.visual_size.y}
138 -- Slowly regenerate health
139 self._regentimer = self._regentimer + dtime
140 if self._regentimer >= 4 then
141 if self.health < self.hp_max then
142 self.health = self.health + 1
144 self._regentimer = 0
147 -- if driver present allow control of horse
148 if self.driver then
150 mobs.drive(self, "walk", "stand", false, dtime)
152 return false -- skip rest of mob functions
155 return true
156 end,
158 on_die = function(self, pos)
160 -- drop saddle when horse is killed while riding
161 if self._saddle then
162 minetest.add_item(pos, mobs_mc.items.saddle)
164 -- also detach from horse properly
165 if self.driver then
166 mobs.detach(self.driver, {x = 1, y = 0, z = 1})
169 end,
171 on_rightclick = function(self, clicker)
173 -- make sure player is clicking
174 if not clicker or not clicker:is_player() then
175 return
178 local item = clicker:get_wielded_item()
179 if can_breed(self.name) and (item:get_name() == mobs_mc.items.golden_apple or item:get_name() == mobs_mc.items.golden_carrot) then
180 -- Breed horse with golden apple or golden carrot
181 if mobs:feed_tame(self, clicker, 1, true, false) then return end
183 -- Feed/tame with anything else
184 -- TODO: Different health bonus for feeding
185 if mobs:feed_tame(self, clicker, 1, false, true) then return end
186 if mobs:protect(self, clicker) then return end
188 -- Make sure tamed horse is mature and being clicked by owner only
189 if self.tamed and not self.child and self.owner == clicker:get_player_name() then
191 local inv = clicker:get_inventory()
193 -- detatch player already riding horse
194 if self.driver and clicker == self.driver then
196 mobs.detach(clicker, {x = 1, y = 0, z = 1})
198 -- Put on saddle if tamed
199 elseif not self.driver and not self._saddle
200 and clicker:get_wielded_item():get_name() == mobs_mc.items.saddle then
202 -- Put on saddle and take saddle from player's inventory
203 local w = clicker:get_wielded_item()
204 self._saddle = true
205 if not minetest.settings:get_bool("creative_mode") then
206 w:take_item()
207 clicker:set_wielded_item(w)
210 -- Update texture
211 if not self._naked_texture then
212 -- Base horse texture without chest or saddle
213 self._naked_texture = self.base_texture[2]
215 local tex = horse_extra_texture(self)
216 self.base_texture = tex
217 self.object:set_properties({textures = self.base_texture})
219 -- Put on horse armor if tamed
220 elseif can_equip_horse_armor(self.name) and not self.driver and not self._horse_armor
221 and minetest.get_item_group(clicker:get_wielded_item():get_name(), "horse_armor") > 0 then
224 -- Put on armor and take armor from player's inventory
225 local w = clicker:get_wielded_item()
226 local armor = minetest.get_item_group(w:get_name(), "horse_armor")
227 self._horse_armor = w:get_name()
228 if not minetest.settings:get_bool("creative_mode") then
229 w:take_item()
230 clicker:set_wielded_item(w)
233 -- Set horse armor strength
234 self.armor = armor
235 local agroups = self.object:get_armor_groups()
236 agroups.fleshy = self.armor
237 self.object:set_armor_groups(agroups)
239 -- Update texture
240 if not self._naked_texture then
241 -- Base horse texture without chest or saddle
242 self._naked_texture = self.base_texture[2]
244 local tex = horse_extra_texture(self)
245 self.base_texture = tex
246 self.object:set_properties({textures = self.base_texture})
249 -- Mount horse
250 elseif not self.driver and self._saddle then
252 self.object:set_properties({stepheight = 1.1})
253 mobs.attach(self, clicker)
255 -- Used to capture horse
256 elseif not self.driver and clicker:get_wielded_item():get_name() ~= "" then
257 mobs:capture_mob(self, clicker, 0, 5, 60, false, nil)
260 end,
262 on_breed = function(parent1, parent2)
263 local pos = parent1.object:get_pos()
264 local child = mobs:spawn_child(pos, parent1.name)
265 if child then
266 local ent_c = child:get_luaentity()
267 local p = math.random(1, 2)
268 if p == 1 then
269 ent_c.base_texture = parent1.base_texture
270 else
271 ent_c.base_texture = parent2.base_texture
273 child:set_properties({textures = ent_c.base_texture})
274 return false
276 end,
279 mobs:register_mob("mobs_mc:horse", horse)
281 -- Skeleton horse
282 local skeleton_horse = table.copy(horse)
283 skeleton_horse.textures = {{"blank.png", "mobs_mc_horse_skeleton.png", "blank.png"}}
284 skeleton_horse.drops = {
285 {name = mobs_mc.items.bone,
286 chance = 1,
287 min = 0,
288 max = 2,},
290 skeleton_horse.sounds = {
291 random = "skeleton1",
292 death = "skeletondeath",
293 damage = "skeletonhurt1",
294 distance = 16,
296 skeleton_horse.blood_amount = 0
297 mobs:register_mob("mobs_mc:skeleton_horse", skeleton_horse)
299 -- Zombie horse
300 local zombie_horse = table.copy(horse)
301 zombie_horse.textures = {{"blank.png", "mobs_mc_horse_zombie.png", "blank.png"}}
302 zombie_horse.drops = {
303 {name = mobs_mc.items.rotten_flesh,
304 chance = 1,
305 min = 0,
306 max = 2,},
308 zombie_horse.sounds = {
309 random = "mobs_mc_zombie_idle",
310 war_cry = "mobs_mc_zombie_idle",
311 death = "mobs_mc_zombie_death",
312 damage = "mobs_mc_zombie_hurt",
313 distance = 16,
315 mobs:register_mob("mobs_mc:zombie_horse", zombie_horse)
317 -- Donkey
318 local d = 0.86 -- donkey scale
319 local donkey = table.copy(horse)
320 donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
321 donkey.animation = {
322 speed_normal = 25,
323 stand_start = 0, stand_end = 0,
324 walk_start = 0, walk_end = 40,
326 donkey.visual_size = { x=horse.visual_size.x*d, y=horse.visual_size.y*d }
327 donkey.collisionbox = {
328 horse.collisionbox[1] * d,
329 horse.collisionbox[2] * d,
330 horse.collisionbox[3] * d,
331 horse.collisionbox[4] * d,
332 horse.collisionbox[5] * d,
333 horse.collisionbox[6] * d,
335 donkey.jump = true
336 donkey.jump_height = 3.75 -- can clear 1 block height
338 mobs:register_mob("mobs_mc:donkey", donkey)
340 -- Mule
341 local m = 0.94
342 local mule = table.copy(donkey)
343 mule.textures = {{"blank.png", "mobs_mc_mule.png", "blank.png"}}
344 mule.visual_size = { x=horse.visual_size.x*m, y=horse.visual_size.y*m }
345 mule.collisionbox = {
346 horse.collisionbox[1] * m,
347 horse.collisionbox[2] * m,
348 horse.collisionbox[3] * m,
349 horse.collisionbox[4] * m,
350 horse.collisionbox[5] * m,
351 horse.collisionbox[6] * m,
353 mobs:register_mob("mobs_mc:mule", mule)
355 --===========================
356 --Spawn Function
357 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)
358 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)
360 -- compatibility
361 mobs:alias_mob("mobs:horse", "mobs_mc:horse")
363 -- spawn eggs
364 mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
365 mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
366 mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
367 mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
368 mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)
371 if minetest.settings:get_bool("log_mods") then
372 minetest.log("action", "MC Horse loaded")