Make villager stand still if there is near player
[MineClone/MineClone2.git] / mods / ENTITIES / mobs_mc / enderman.lua
blob1b60dac602fe727f65bd5a1a7d2bd44be4dc626b
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 --dofile(minetest.get_modpath("mobs").."/api.lua")
13 --###################
14 --################### ENDERMAN
15 --###################
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:
31 Flower, 90 degrees
32 Flower, 45 degrees
33 Held block, backside
34 Held block, bottom
35 Held block, front
36 Held block, left
37 Held block, right
38 Held block, top
39 Enderman texture (base)
41 -- Regular cube
42 if block_type == "cube" then
43 local tiles = minetest.registered_nodes[itemstring].tiles
44 local textures = {}
45 local last
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]
49 else
50 -- Extract the texture names
51 for i = 1, 6 do
52 if type(tiles[i]) == "string" then
53 last = tiles[i]
54 elseif type(tiles[i]) == "table" then
55 if tiles[i].name then
56 last = tiles[i].name
57 end
58 end
59 table.insert(textures, last)
60 end
61 end
62 return {
63 "blank.png",
64 "blank.png",
65 textures[5],
66 textures[2],
67 textures[6],
68 textures[3],
69 textures[4],
70 textures[1],
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
76 return {
77 "blank.png",
78 textures[1],
79 "blank.png",
80 "blank.png",
81 "blank.png",
82 "blank.png",
83 "blank.png",
84 "blank.png",
85 base,
87 -- Node of plantlike drawtype, 90°
88 elseif block_type == "plantlike90" then
89 local textures = minetest.registered_nodes[itemstring].tiles
90 return {
91 textures[1],
92 "blank.png",
93 "blank.png",
94 "blank.png",
95 "blank.png",
96 "blank.png",
97 "blank.png",
98 "blank.png",
99 base,
101 elseif block_type == "unknown" then
102 return {
103 "blank.png",
104 "blank.png",
105 "unknown_node.png",
106 "unknown_node.png",
107 "unknown_node.png",
108 "unknown_node.png",
109 "unknown_node.png",
110 "unknown_node.png",
111 base, -- Enderman texture
113 -- No block held (for initial texture)
114 elseif block_type == "nothing" or block_type == nil then
115 return {
116 "blank.png",
117 "blank.png",
118 "blank.png",
119 "blank.png",
120 "blank.png",
121 "blank.png",
122 "blank.png",
123 "blank.png",
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
133 return {
134 walk_speed = 25,
135 run_speed = 50,
136 stand_speed = 25,
137 stand_start = 200,
138 stand_end = 200,
139 walk_start = 161,
140 walk_end = 200,
141 run_start = 161,
142 run_end = 200,
143 punch_start = 121,
144 punch_end = 160,
146 -- Enderman doesn't hold a block
147 elseif animation_type == "normal" or animation_type == nil then
148 return {
149 walk_speed = 25,
150 run_speed = 50,
151 stand_speed = 25,
152 stand_start = 40,
153 stand_end = 80,
154 walk_start = 0,
155 walk_end = 40,
156 run_start = 0,
157 run_end = 40,
158 punch_start = 81,
159 punch_end = 120,
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
168 type = "animal",
169 passive = false,
170 pathfinding = 1,
171 stepheight = 1.2,
172 hp_min = 40,
173 hp_max = 40,
174 collisionbox = {-0.3, -0.01, -0.3, 0.3, 2.89, 0.3},
175 visual = "mesh",
176 mesh = "mobs_mc_enderman.b3d",
177 textures = create_enderman_textures(),
178 visual_size = {x=3, y=3},
179 makes_footstep_sound = true,
180 sounds = {
181 war_cry = "mobs_sandmonster",
182 death = "green_slime_death",
183 damage = "Creeperdeath",
184 distance = 16,
186 walk_velocity = 0.2,
187 run_velocity = 3.4,
188 damage = 7,
189 reach = 2,
190 drops = {
191 {name = mobs_mc.items.ender_pearl,
192 chance = 1,
193 min = 0,
194 max = 1,},
196 animation = select_enderman_animation("normal"),
197 _taken_node = "",
198 do_custom = function(self, dtime)
199 if not mobs_griefing then
200 return
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)
206 return
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
210 -- Take random node
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)
220 if dug then
221 if mobs_mc.enderman_replace_on_take[node.name] then
222 self._taken_node = mobs_mc.enderman_replace_on_take[node.name]
223 else
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)
228 local block_type
229 -- Cube-shaped
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
240 block_type = "cube"
241 elseif def.drawtype == "plantlike" then
242 -- Flowers and stuff
243 block_type = "plantlike45"
244 elseif def.drawtype == "airlike" then
245 -- Just air
246 block_type = nil
247 else
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
261 -- Place taken node
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})
271 if success then
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 = ""
283 end,
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"})
290 local telepos
291 if #nodes > 0 then
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]
296 local node_ok = true
297 -- Selected node needs to have 3 nodes of free space above
298 for u=1, 3 do
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
301 node_ok = false
302 break
305 if node_ok then
306 telepos = {x=nodepos.x, y=nodepos.y+1, z=nodepos.z}
309 if telepos then
310 self.object:setpos(telepos)
313 end,
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)
319 end,
320 water_damage = 8,
321 lava_damage = 4,
322 light_damage = 0,
323 view_range = 16,
324 fear_height = 4,
325 attack_type = "dogfight",
326 blood_amount = 0,
330 -- End spawn
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)
332 -- Overworld spawn
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)
337 -- spawn eggs
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")