3 --made for MC like Survival game
4 --License for code WTFPL and otherwise stated in readmes
7 local MP
= minetest
.get_modpath(minetest
.get_current_modname())
8 local S
, NS
= dofile(MP
.."/intllib.lua")
10 --dofile(minetest.get_modpath("mobs").."/api.lua")
14 --################### ENDERMAN
17 local pr
= PseudoRandom(os
.time()*(-334))
19 -- How freqeuntly to take and place blocks, in seconds
20 local take_frequency_min
= 25
21 local take_frequency_max
= 90
22 local place_frequency_min
= 10
23 local place_frequency_max
= 30
25 -- Create the textures table for the enderman, depending on which kind of block
26 -- the enderman holds (if any).
27 local create_enderman_textures
= function(block_type
, itemstring
)
28 local base
= "mobs_mc_enderman.png^mobs_mc_enderman_eyes.png"
30 --[[ Order of the textures in the texture table:
39 Enderman texture (base)
42 if block_type
== "cube" then
43 local tiles
= minetest
.registered_nodes
[itemstring
].tiles
46 if mobs_mc
.enderman_block_texture_overrides
[itemstring
] then
47 -- Texture override available? Use these instead!
48 textures
= mobs_mc
.enderman_block_texture_overrides
[itemstring
]
50 -- Extract the texture names
52 if type(tiles
[i
]) == "string" then
54 elseif type(tiles
[i
]) == "table" then
59 table.insert(textures
, last
)
71 base
, -- Enderman texture
73 -- Node of plantlike drawtype, 45° (recommended)
74 elseif block_type
== "plantlike45" then
75 local textures
= minetest
.registered_nodes
[itemstring
].tiles
87 -- Node of plantlike drawtype, 90°
88 elseif block_type
== "plantlike90" then
89 local textures
= minetest
.registered_nodes
[itemstring
].tiles
101 elseif block_type
== "unknown" then
111 base
, -- Enderman texture
113 -- No block held (for initial texture)
114 elseif block_type
== "nothing" or block_type
== nil then
124 base
, -- Enderman texture
129 -- Select a new animation definition.
130 local select_enderman_animation
= function(animation_type
)
131 -- Enderman holds a block
132 if animation_type
== "block" then
146 -- Enderman doesn't hold a block
147 elseif animation_type
== "normal" or animation_type
== nil then
164 local mobs_griefing
= minetest
.settings
:get_bool("mobs_griefing") ~= false
166 mobs
:register_mob("mobs_mc:enderman", {
167 -- TODO: Make endermen attack when looked at
174 collisionbox
= {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3},
176 mesh
= "mobs_mc_enderman.b3d",
177 textures
= create_enderman_textures(),
178 visual_size
= {x
=3, y
=3},
179 makes_footstep_sound
= true,
181 war_cry
= "mobs_sandmonster",
182 death
= "green_slime_death",
183 damage
= "Creeperdeath",
191 {name
= mobs_mc
.items
.ender_pearl
,
196 animation
= select_enderman_animation("normal"),
198 do_custom
= function(self
, dtime
)
199 if not mobs_griefing
then
202 -- Take and put nodes
203 if not self
._take_place_timer
or not self
._next_take_place_time
then
204 self
._take_place_timer
= 0
205 self
._next_take_place_time
= math
.random(take_frequency_min
, take_frequency_max
)
208 self
._take_place_timer
= self
._take_place_timer
+ dtime
209 if (self
._taken_node
== nil or self
._taken_node
== "") and self
._take_place_timer
>= self
._next_take_place_time
then
211 self
._take_place_timer
= 0
212 self
._next_take_place_time
= math
.random(place_frequency_min
, place_frequency_max
)
213 local pos
= self
.object
:getpos()
214 local takable_nodes
= minetest
.find_nodes_in_area({x
=pos
.x
-2, y
=pos
.y
-1, z
=pos
.z
-2}, {x
=pos
.x
+2, y
=pos
.y
+1, z
=pos
.z
+2}, mobs_mc
.enderman_takable
)
215 if #takable_nodes
>= 1 then
216 local r
= pr
:next(1, #takable_nodes
)
217 local take_pos
= takable_nodes
[r
]
218 local node
= minetest
.get_node(take_pos
)
219 local dug
= minetest
.dig_node(take_pos
)
221 if mobs_mc
.enderman_replace_on_take
[node
.name
] then
222 self
._taken_node
= mobs_mc
.enderman_replace_on_take
[node
.name
]
224 self
._taken_node
= node
.name
226 local def
= minetest
.registered_nodes
[self
._taken_node
]
227 -- Update animation and texture accordingly (adds visibly carried block)
230 if def
.drawtype
== "normal" or
231 def
.drawtype
== "nodebox" or
232 def
.drawtype
== "liquid" or
233 def
.drawtype
== "flowingliquid" or
234 def
.drawtype
== "glasslike" or
235 def
.drawtype
== "glasslike_framed" or
236 def
.drawtype
== "glasslike_framed_optional" or
237 def
.drawtype
== "allfaces" or
238 def
.drawtype
== "allfaces_optional" or
239 def
.drawtype
== nil then
241 elseif def
.drawtype
== "plantlike" then
243 block_type
= "plantlike45"
244 elseif def
.drawtype
== "airlike" then
248 -- Fallback for complex drawtypes
249 block_type
= "unknown"
251 self
.base_texture
= create_enderman_textures(block_type
, self
._taken_node
)
252 self
.object
:set_properties({ textures
= self
.base_texture
})
253 self
.animation
= select_enderman_animation("block")
254 mobs
:set_animation(self
, self
.animation
.current
)
255 if def
.sounds
and def
.sounds
.dug
then
256 minetest
.sound_play(def
.sounds
.dug
, {pos
= take_pos
, max_hear_distance
= 16})
260 elseif self
._taken_node
~= nil and self
._taken_node
~= "" and self
._take_place_timer
>= self
._next_take_place_time
then
262 self
._take_place_timer
= 0
263 self
._next_take_place_time
= math
.random(take_frequency_min
, take_frequency_max
)
264 local pos
= self
.object
:getpos()
265 local yaw
= self
.object
:get_yaw()
266 -- Place node at looking direction
267 local place_pos
= vector
.subtract(pos
, minetest
.facedir_to_dir(minetest
.dir_to_facedir(minetest
.yaw_to_dir(yaw
))))
268 if minetest
.get_node(place_pos
).name
== "air" then
269 -- ... but only if there's a free space
270 local success
= minetest
.place_node(place_pos
, {name
= self
._taken_node
})
272 local def
= minetest
.registered_nodes
[self
._taken_node
]
273 -- Update animation accordingly (removes visible block)
274 self
.animation
= select_enderman_animation("normal")
275 mobs
:set_animation(self
, self
.animation
.current
)
276 if def
.sounds
and def
.sounds
.place
then
277 minetest
.sound_play(def
.sounds
.place
, {pos
= place_pos
, max_hear_distance
= 16})
279 self
._taken_node
= ""
284 -- TODO: Teleport enderman on damage, etc.
285 _do_teleport
= function(self
)
286 -- Attempt to randomly teleport enderman
287 local pos
= self
.object
:getpos()
288 -- Find all solid nodes below air in a 65×65×65 cuboid centered on the enderman
289 local nodes
= minetest
.find_nodes_in_area_under_air(vector
.subtract(pos
, 32), vector
.add(pos
, 32), {"group:solid", "group:cracky", "group:crumbly"})
292 -- Up to 64 attempts to teleport
293 for n
=1, math
.min(64, #nodes
) do
294 local r
= pr
:next(1, #nodes
)
295 local nodepos
= nodes
[r
]
297 -- Selected node needs to have 3 nodes of free space above
299 local node
= minetest
.get_node({x
=nodepos
.x
, y
=nodepos
.y
+u
, z
=nodepos
.z
})
300 if minetest
.registered_nodes
[node
.name
].walkable
then
306 telepos
= {x
=nodepos
.x
, y
=nodepos
.y
+1, z
=nodepos
.z
}
310 self
.object
:setpos(telepos
)
314 on_die
= function(self
, pos
)
315 -- Drop carried node on death
316 if self
._taken_node
~= nil and self
._taken_node
~= "" then
317 minetest
.add_item(pos
, self
._taken_node
)
325 attack_type
= "dogfight",
331 mobs
:spawn_specific("mobs_mc:enderman", mobs_mc
.spawn
.solid
, {"air"}, 0, minetest
.LIGHT_MAX
+1, 30, 3000, 12, mobs_mc
.spawn_height
.end_min
, mobs_mc
.spawn_height
.end_max
)
333 mobs
:spawn_specific("mobs_mc:enderman", mobs_mc
.spawn
.solid
, {"air"}, 0, 7, 30, 19000, 2, mobs_mc
.spawn_height
.overworld_min
, mobs_mc
.spawn_height
.overworld_max
)
334 -- Nether spawn (rare)
335 mobs
:spawn_specific("mobs_mc:enderman", mobs_mc
.spawn
.solid
, {"air"}, 0, 7, 30, 27500, 4, mobs_mc
.spawn_height
.nether_min
, mobs_mc
.spawn_height
.nether_max
)
338 mobs
:register_egg("mobs_mc:enderman", S("Enderman"), "mobs_mc_spawn_icon_enderman.png", 0)
340 if minetest
.settings
:get_bool("log_mods") then
342 minetest
.log("action", "MC Enderman loaded")