3 --made for MC like Survival game
4 --License for code WTFPL and otherwise stated in readmes
7 -- In this game, endermen attack the player on sight, like other monsters do.
8 -- However, they have a reduced viewing range to make them less dangerous.
9 -- This differs from MC, in which endermen only become hostile when provoked,
10 -- and they are provoked by looking directly at them.
11 -- TODO: Implement MC behaviour.
14 local MP
= minetest
.get_modpath(minetest
.get_current_modname())
15 local S
, NS
= dofile(MP
.."/intllib.lua")
17 --dofile(minetest.get_modpath("mobs").."/api.lua")
21 --################### ENDERMAN
24 local pr
= PseudoRandom(os
.time()*(-334))
26 -- How freqeuntly to take and place blocks, in seconds
27 local take_frequency_min
= 25
28 local take_frequency_max
= 90
29 local place_frequency_min
= 10
30 local place_frequency_max
= 30
32 -- Create the textures table for the enderman, depending on which kind of block
33 -- the enderman holds (if any).
34 local create_enderman_textures
= function(block_type
, itemstring
)
35 local base
= "mobs_mc_enderman.png^mobs_mc_enderman_eyes.png"
37 --[[ Order of the textures in the texture table:
46 Enderman texture (base)
49 if block_type
== "cube" then
50 local tiles
= minetest
.registered_nodes
[itemstring
].tiles
53 if mobs_mc
.enderman_block_texture_overrides
[itemstring
] then
54 -- Texture override available? Use these instead!
55 textures
= mobs_mc
.enderman_block_texture_overrides
[itemstring
]
57 -- Extract the texture names
59 if type(tiles
[i
]) == "string" then
61 elseif type(tiles
[i
]) == "table" then
66 table.insert(textures
, last
)
78 base
, -- Enderman texture
80 -- Node of plantlike drawtype, 45° (recommended)
81 elseif block_type
== "plantlike45" then
82 local textures
= minetest
.registered_nodes
[itemstring
].tiles
94 -- Node of plantlike drawtype, 90°
95 elseif block_type
== "plantlike90" then
96 local textures
= minetest
.registered_nodes
[itemstring
].tiles
108 elseif block_type
== "unknown" then
118 base
, -- Enderman texture
120 -- No block held (for initial texture)
121 elseif block_type
== "nothing" or block_type
== nil then
131 base
, -- Enderman texture
136 -- Select a new animation definition.
137 local select_enderman_animation
= function(animation_type
)
138 -- Enderman holds a block
139 if animation_type
== "block" then
153 -- Enderman doesn't hold a block
154 elseif animation_type
== "normal" or animation_type
== nil then
171 local mobs_griefing
= minetest
.settings
:get_bool("mobs_griefing") ~= false
173 mobs
:register_mob("mobs_mc:enderman", {
174 -- TODO: Endermen should be classified as passive
181 collisionbox
= {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3},
183 mesh
= "mobs_mc_enderman.b3d",
184 textures
= create_enderman_textures(),
185 visual_size
= {x
=3, y
=3},
186 makes_footstep_sound
= true,
188 war_cry
= "mobs_sandmonster",
189 death
= "green_slime_death",
190 -- TODO: damage, random
198 {name
= mobs_mc
.items
.ender_pearl
,
203 animation
= select_enderman_animation("normal"),
205 do_custom
= function(self
, dtime
)
206 if not mobs_griefing
then
209 -- Take and put nodes
210 if not self
._take_place_timer
or not self
._next_take_place_time
then
211 self
._take_place_timer
= 0
212 self
._next_take_place_time
= math
.random(take_frequency_min
, take_frequency_max
)
215 self
._take_place_timer
= self
._take_place_timer
+ dtime
216 if (self
._taken_node
== nil or self
._taken_node
== "") and self
._take_place_timer
>= self
._next_take_place_time
then
218 self
._take_place_timer
= 0
219 self
._next_take_place_time
= math
.random(place_frequency_min
, place_frequency_max
)
220 local pos
= self
.object
:get_pos()
221 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
)
222 if #takable_nodes
>= 1 then
223 local r
= pr
:next(1, #takable_nodes
)
224 local take_pos
= takable_nodes
[r
]
225 local node
= minetest
.get_node(take_pos
)
226 local dug
= minetest
.dig_node(take_pos
)
228 if mobs_mc
.enderman_replace_on_take
[node
.name
] then
229 self
._taken_node
= mobs_mc
.enderman_replace_on_take
[node
.name
]
231 self
._taken_node
= node
.name
233 local def
= minetest
.registered_nodes
[self
._taken_node
]
234 -- Update animation and texture accordingly (adds visibly carried block)
237 if def
.drawtype
== "normal" or
238 def
.drawtype
== "nodebox" or
239 def
.drawtype
== "liquid" or
240 def
.drawtype
== "flowingliquid" or
241 def
.drawtype
== "glasslike" or
242 def
.drawtype
== "glasslike_framed" or
243 def
.drawtype
== "glasslike_framed_optional" or
244 def
.drawtype
== "allfaces" or
245 def
.drawtype
== "allfaces_optional" or
246 def
.drawtype
== nil then
248 elseif def
.drawtype
== "plantlike" then
250 block_type
= "plantlike45"
251 elseif def
.drawtype
== "airlike" then
255 -- Fallback for complex drawtypes
256 block_type
= "unknown"
258 self
.base_texture
= create_enderman_textures(block_type
, self
._taken_node
)
259 self
.object
:set_properties({ textures
= self
.base_texture
})
260 self
.animation
= select_enderman_animation("block")
261 mobs
:set_animation(self
, self
.animation
.current
)
262 if def
.sounds
and def
.sounds
.dug
then
263 minetest
.sound_play(def
.sounds
.dug
, {pos
= take_pos
, max_hear_distance
= 16})
267 elseif self
._taken_node
~= nil and self
._taken_node
~= "" and self
._take_place_timer
>= self
._next_take_place_time
then
269 self
._take_place_timer
= 0
270 self
._next_take_place_time
= math
.random(take_frequency_min
, take_frequency_max
)
271 local pos
= self
.object
:get_pos()
272 local yaw
= self
.object
:get_yaw()
273 -- Place node at looking direction
274 local place_pos
= vector
.subtract(pos
, minetest
.facedir_to_dir(minetest
.dir_to_facedir(minetest
.yaw_to_dir(yaw
))))
275 if minetest
.get_node(place_pos
).name
== "air" then
276 -- ... but only if there's a free space
277 local success
= minetest
.place_node(place_pos
, {name
= self
._taken_node
})
279 local def
= minetest
.registered_nodes
[self
._taken_node
]
280 -- Update animation accordingly (removes visible block)
281 self
.animation
= select_enderman_animation("normal")
282 mobs
:set_animation(self
, self
.animation
.current
)
283 if def
.sounds
and def
.sounds
.place
then
284 minetest
.sound_play(def
.sounds
.place
, {pos
= place_pos
, max_hear_distance
= 16})
286 self
._taken_node
= ""
291 -- TODO: Teleport enderman on damage, etc.
292 _do_teleport
= function(self
)
293 -- Attempt to randomly teleport enderman
294 local pos
= self
.object
:get_pos()
295 -- Find all solid nodes below air in a 65×65×65 cuboid centered on the enderman
296 local nodes
= minetest
.find_nodes_in_area_under_air(vector
.subtract(pos
, 32), vector
.add(pos
, 32), {"group:solid", "group:cracky", "group:crumbly"})
299 -- Up to 64 attempts to teleport
300 for n
=1, math
.min(64, #nodes
) do
301 local r
= pr
:next(1, #nodes
)
302 local nodepos
= nodes
[r
]
304 -- Selected node needs to have 3 nodes of free space above
306 local node
= minetest
.get_node({x
=nodepos
.x
, y
=nodepos
.y
+u
, z
=nodepos
.z
})
307 if minetest
.registered_nodes
[node
.name
].walkable
then
313 telepos
= {x
=nodepos
.x
, y
=nodepos
.y
+1, z
=nodepos
.z
}
317 self
.object
:setpos(telepos
)
321 on_die
= function(self
, pos
)
322 -- Drop carried node on death
323 if self
._taken_node
~= nil and self
._taken_node
~= "" then
324 minetest
.add_item(pos
, self
._taken_node
)
330 -- TODO: Increase view range when it detects being seen
331 -- Low view range to emulate that behaviour somehow
334 attack_type
= "dogfight",
340 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
)
342 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
)
343 -- Nether spawn (rare)
344 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
)
347 mobs
:register_egg("mobs_mc:enderman", S("Enderman"), "mobs_mc_spawn_icon_enderman.png", 0)
349 if minetest
.settings
:get_bool("log_mods") then
351 minetest
.log("action", "MC Enderman loaded")