1 local init
= os
.clock()
4 mcl_structures
.get_struct
= function(file
)
5 local localfile
= minetest
.get_modpath("mcl_structures").."/schematics/"..file
6 local file
, errorload
= io
.open(localfile
, "rb")
7 if errorload
~= nil then
8 minetest
.log("error", '[mcl_structures] Could not open this struct: ' .. localfile
)
12 local allnode
= file
:read("*a")
19 mcl_structures
.call_struct
= function(pos
, struct_style
, rotation
)
23 if struct_style
== "village" then
24 return mcl_structures
.generate_village(pos
, rotation
)
25 elseif struct_style
== "desert_temple" then
26 return mcl_structures
.generate_desert_temple(pos
, rotation
)
27 elseif struct_style
== "desert_well" then
28 return mcl_structures
.generate_desert_well(pos
, rotation
)
29 elseif struct_style
== "igloo" then
30 return mcl_structures
.generate_igloo_top(pos
, rotation
)
31 elseif struct_style
== "witch_hut" then
32 return mcl_structures
.generate_witch_hut(pos
, rotation
)
33 elseif struct_style
== "ice_spike_small" then
34 return mcl_structures
.generate_ice_spike_small(pos
, rotation
)
35 elseif struct_style
== "ice_spike_large" then
36 return mcl_structures
.generate_ice_spike_large(pos
, rotation
)
37 elseif struct_style
== "boulder" then
38 return mcl_structures
.generate_boulder(pos
, rotation
)
39 elseif struct_style
== "fossil" then
40 return mcl_structures
.generate_fossil(pos
, rotation
)
41 elseif struct_style
== "end_exit_portal" then
42 return mcl_structures
.generate_end_exit_portal(pos
, rotation
)
43 elseif struct_style
== "end_portal_shrine" then
44 return mcl_structures
.generate_end_portal_shrine(pos
, rotation
)
48 mcl_structures
.generate_village
= function(pos
)
49 -- No generating for the moment, only place it :D
50 -- TODO: Do complete overhaul of the algorithm
51 local newpos
= {x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
}
52 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_village.mts"
53 return minetest
.place_schematic(newpos
, path
, "random", nil, true)
56 mcl_structures
.generate_desert_well
= function(pos
)
57 local newpos
= {x
=pos
.x
,y
=pos
.y
-2,z
=pos
.z
}
58 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_well.mts"
59 return minetest
.place_schematic(newpos
, path
, "0", nil, true)
62 mcl_structures
.generate_igloo_top
= function(pos
)
63 -- FIXME: This spawns bookshelf instead of furnace. Fix this!
64 -- Furnace does ot work atm because apparently meta is not set. :-(
65 local newpos
= {x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
}
66 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_top.mts"
67 return minetest
.place_schematic(newpos
, path
, "random", nil, true)
70 mcl_structures
.generate_igloo_basement
= function(pos
, orientation
)
71 -- TODO: Add brewing stand
72 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_igloo_basement.mts"
73 return minetest
.place_schematic(pos
, path
, orientation
, nil, true)
76 mcl_structures
.generate_boulder
= function(pos
)
77 -- Choose between 2 boulder sizes (2×2×2 or 3×3×3)
78 local r
= math
.random(1, 10)
81 path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_boulder_small.mts"
83 path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_boulder.mts"
86 local newpos
= {x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
}
87 return minetest
.place_schematic(newpos
, path
)
90 mcl_structures
.generate_witch_hut
= function(pos
, rotation
)
91 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_witch_hut.mts"
92 return minetest
.place_schematic(pos
, path
, rotation
, nil, true)
95 mcl_structures
.generate_ice_spike_small
= function(pos
)
96 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_small.mts"
97 return minetest
.place_schematic(pos
, path
, "random", nil, false)
100 mcl_structures
.generate_ice_spike_large
= function(pos
)
101 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_ice_spike_large.mts"
102 return minetest
.place_schematic(pos
, path
, "random", nil, false)
105 mcl_structures
.generate_fossil
= function(pos
)
106 -- Generates one out of 8 possible fossil pieces
107 local newpos
= {x
=pos
.x
,y
=pos
.y
-1,z
=pos
.z
}
109 "mcl_structures_fossil_skull_1.mts", -- 4×5×5
110 "mcl_structures_fossil_skull_2.mts", -- 5×5×5
111 "mcl_structures_fossil_skull_3.mts", -- 5×5×7
112 "mcl_structures_fossil_skull_4.mts", -- 7×5×5
113 "mcl_structures_fossil_spine_1.mts", -- 3×3×13
114 "mcl_structures_fossil_spine_2.mts", -- 5×4×13
115 "mcl_structures_fossil_spine_3.mts", -- 7×4×13
116 "mcl_structures_fossil_spine_4.mts", -- 8×5×13
118 local r
= math
.random(1, #fossils
)
119 local path
= minetest
.get_modpath("mcl_structures").."/schematics/"..fossils
[r
]
120 return minetest
.place_schematic(newpos
, path
, "random", nil, true)
123 mcl_structures
.generate_end_exit_portal
= function(pos
)
124 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_end_exit_portal.mts"
125 return minetest
.place_schematic(pos
, path
, "0", nil, true)
128 mcl_structures
.generate_end_portal_shrine
= function(pos
)
129 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_end_portal_room_simple.mts"
130 local offset
= {x
=6, y
=8, z
=6}
131 local size
= {x
=13, y
=8, z
=13}
132 local newpos
= { x
= pos
.x
- offset
.x
, y
= pos
.y
, z
= pos
.z
- offset
.z
}
133 local ret
= minetest
.place_schematic(newpos
, path
, "0", nil, true)
138 local area_start
, area_end
= newpos
, vector
.add(newpos
, size
)
139 -- Find and setup spawner with silverfish
140 local spawners
= minetest
.find_nodes_in_area(area_start
, area_end
, "mcl_mobspawners:spawner")
141 for s
=1, #spawners
do
142 local meta
= minetest
.get_meta(spawners
[s
])
143 mcl_mobspawners
.setup_spawner(spawners
[s
], "mobs_mc:silverfish")
146 -- Shuffle stone brick types
147 local bricks
= minetest
.find_nodes_in_area(area_start
, area_end
, "mcl_core:stonebrick")
148 -- FIXME: Use better seeding
149 local pr
= PseudoRandom(math
.random(0, 4294967295))
151 local r_bricktype
= pr
:next(1, 100)
152 local r_infested
= pr
:next(1, 100)
154 if r_infested
<= 5 then
155 if r_bricktype
<= 30 then -- 30%
156 bricktype
= "mcl_monster_eggs:monster_egg_stonebrickmossy"
157 elseif r_bricktype
<= 50 then -- 20%
158 bricktype
= "mcl_monster_eggs:monster_egg_stonebrickcracked"
160 bricktype
= "mcl_monster_eggs:monster_egg_stonebrick"
163 if r_bricktype
<= 30 then -- 30%
164 bricktype
= "mcl_core:stonebrickmossy"
165 elseif r_bricktype
<= 50 then -- 20%
166 bricktype
= "mcl_core:stonebrickcracked"
168 -- 50% stonebrick (no change necessary)
170 if bricktype
~= nil then
171 minetest
.set_node(bricks
[b
], { name
= bricktype
})
175 -- Also replace stairs
176 local stairs
= minetest
.find_nodes_in_area(area_start
, area_end
, {"mcl_stairs:stair_stonebrick", "mcl_stairs:stair_stonebrick_outer", "mcl_stairs:stair_stonebrick_inner"})
178 local stair
= minetest
.get_node(stairs
[s
])
179 local r_type
= pr
:next(1, 100)
180 if r_type
<= 30 then -- 30% mossy
181 if stair
.name
== "mcl_stairs:stair_stonebrick" then
182 stair
.name
= "mcl_stairs:stair_stonebrickmossy"
183 elseif stair
.name
== "mcl_stairs:stair_stonebrick_outer" then
184 stair
.name
= "mcl_stairs:stair_stonebrickmossy_outer"
185 elseif stair
.name
== "mcl_stairs:stair_stonebrick_inner" then
186 stair
.name
= "mcl_stairs:stair_stonebrickmossy_inner"
188 minetest
.set_node(stairs
[s
], stair
)
189 elseif r_type
<= 50 then -- 20% cracky
190 if stair
.name
== "mcl_stairs:stair_stonebrick" then
191 stair
.name
= "mcl_stairs:stair_stonebrickcracked"
192 elseif stair
.name
== "mcl_stairs:stair_stonebrick_outer" then
193 stair
.name
= "mcl_stairs:stair_stonebrickcracked_outer"
194 elseif stair
.name
== "mcl_stairs:stair_stonebrick_inner" then
195 stair
.name
= "mcl_stairs:stair_stonebrickcracked_inner"
197 minetest
.set_node(stairs
[s
], stair
)
202 -- Randomly add ender eyes into end portal frames, but never fill the entire frame
203 local frames
= minetest
.find_nodes_in_area(area_start
, area_end
, "mcl_portals:end_portal_frame")
206 local r_eye
= pr
:next(1, 10)
209 if eyes
< #frames
then
210 local frame_node
= minetest
.get_node(frames
[f
])
211 frame_node
.name
= "mcl_portals:end_portal_frame_eye"
212 minetest
.set_node(frames
[f
], frame_node
)
220 mcl_structures
.generate_desert_temple
= function(pos
)
221 -- No Generating for the temple ... Why using it ? No Change
222 local path
= minetest
.get_modpath("mcl_structures").."/schematics/mcl_structures_desert_temple.mts"
223 local newpos
= {x
=pos
.x
,y
=pos
.y
-12,z
=pos
.z
}
224 local size
= {x
=22, y
=24, z
=22}
225 if newpos
== nil then
228 local ret
= minetest
.place_schematic(newpos
, path
, "random", nil, true)
234 -- FIXME: Searching this large area just for the chets is not efficient. Need a better way to find the chests;
235 -- probably let's just infer it from newpos because the schematic always the same.
236 local chests
= minetest
.find_nodes_in_area({x
=newpos
.x
-size
.x
, y
=newpos
.y
, z
=newpos
.z
-size
.z
}, vector
.add(newpos
, size
), "mcl_chests:chest")
238 -- Add desert temple loot into chests
240 -- FIXME: Use better seeding
241 local pr
= PseudoRandom(math
.random(0, 4294967295))
242 local lootitems
= mcl_loot
.get_multi_loot({
247 { itemstring
= "mcl_mobitems:bone", weight
= 25, amount_min
= 4, amount_max
=6 },
248 { itemstring
= "mcl_mobitems:rotten_flesh", weight
= 25, amount_min
= 3, amount_max
=7 },
249 { itemstring
= "mcl_mobitems:spider_eye", weight
= 25, amount_min
= 1, amount_max
=3 },
250 -- TODO: Enchanted Book
251 { itemstring
= "mcl_books:book", weight
= 20, },
252 { itemstring
= "mcl_mobitems:saddle", weight
= 20, },
253 { itemstring
= "mcl_core:apple_gold", weight
= 20, },
254 { itemstring
= "mcl_core:gold_ingot", weight
= 15, amount_min
= 2, amount_max
= 7 },
255 { itemstring
= "mcl_core:iron_ingot", weight
= 15, amount_min
= 1, amount_max
= 5 },
256 { itemstring
= "mcl_core:emerald", weight
= 15, amount_min
= 1, amount_max
= 3 },
257 { itemstring
= "", weight
= 15, },
258 { itemstring
= "mobs_mc:iron_horse_armor", weight
= 15, },
259 { itemstring
= "mobs_mc:gold_horse_armor", weight
= 10, },
260 { itemstring
= "mobs_mc:diamond_horse_armor", weight
= 5, },
261 { itemstring
= "mcl_core:diamond", weight
= 5, amount_min
= 1, amount_max
= 3 },
262 -- TODO: Enchanted Golden Apple
263 { itemstring
= "mcl_core:apple_gold", weight
= 2, },
270 { itemstring
= "mcl_mobitems:bone", weight
= 10, amount_min
= 1, amount_max
= 8 },
271 { itemstring
= "mcl_mobitems:rotten_flesh", weight
= 10, amount_min
= 1, amount_max
= 8 },
272 { itemstring
= "mcl_mobitems:gunpowder", weight
= 10, amount_min
= 1, amount_max
= 8 },
273 { itemstring
= "mcl_core:sand", weight
= 10, amount_min
= 1, amount_max
= 8 },
274 { itemstring
= "mcl_mobitems:string", weight
= 10, amount_min
= 1, amount_max
= 8 },
278 local meta
= minetest
.get_meta(chests
[c
])
279 local inv
= meta
:get_inventory()
280 inv
:set_size("main", 9*3)
281 for i
=1, #lootitems
do
282 inv
:add_item("main", lootitems
[i
])
286 -- Initialize pressure plates
287 local pplates
= minetest
.find_nodes_in_area({x
=newpos
.x
-size
.x
, y
=newpos
.y
, z
=newpos
.z
-size
.z
}, vector
.add(newpos
, size
), "mesecons_pressureplates:pressure_plate_stone_off")
289 minetest
.registered_nodes
["mesecons_pressureplates:pressure_plate_stone_off"].on_construct(pplates
[p
])
295 local registered_structures
= {}
297 --[[ Returns a table of structure of the specified type.
298 Currently the only valid parameter is "stronghold".
299 Format of return value:
301 { pos = <position>, generated=<true/false> }, -- first structure
302 { pos = <position>, generated=<true/false> }, -- second structure
306 TODO: Implement this function for all other structure types as well.
308 mcl_structures
.get_registered_structures
= function(structure_type
)
309 if registered_structures
[structure_type
] then
310 return table.copy(registered_structures
[structure_type
])
316 -- Register a structures table for the given type. The table format is the same as for
317 -- mcl_structures.get_registered_structures.
318 mcl_structures
.register_structures
= function(structure_type
, structures
)
319 registered_structures
[structure_type
] = structures
323 minetest
.register_chatcommand("spawnstruct", {
324 params
= "desert_temple | desert_well | igloo | village | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine",
325 description
= "Generate a pre-defined structure near your position.",
326 privs
= {debug
= true},
327 func
= function(name
, param
)
328 local pos
= minetest
.get_player_by_name(name
):getpos()
333 if param
== "village" then
334 mcl_structures
.generate_village(pos
)
335 minetest
.chat_send_player(name
, "Village built. WARNING: Villages are experimental and might have bugs.")
336 elseif param
== "desert_temple" then
337 mcl_structures
.generate_desert_temple(pos
)
338 minetest
.chat_send_player(name
, "Desert temple built.")
339 elseif param
== "desert_well" then
340 mcl_structures
.generate_desert_well(pos
)
341 minetest
.chat_send_player(name
, "Desert well built.")
342 elseif param
== "igloo" then
343 mcl_structures
.generate_igloo_top(pos
)
344 minetest
.chat_send_player(name
, "Igloo built.")
345 elseif param
== "witch_hut" then
346 mcl_structures
.generate_witch_hut(pos
)
347 minetest
.chat_send_player(name
, "Witch hut built.")
348 elseif param
== "boulder" then
349 mcl_structures
.generate_boulder(pos
)
350 minetest
.chat_send_player(name
, "Moss stone boulder placed.")
351 elseif param
== "fossil" then
352 mcl_structures
.generate_fossil(pos
)
353 minetest
.chat_send_player(name
, "Fossil placed.")
354 elseif param
== "ice_spike_small" then
355 mcl_structures
.generate_ice_spike_small(pos
)
356 minetest
.chat_send_player(name
, "Small ice spike placed.")
357 elseif param
== "ice_spike_large" then
358 mcl_structures
.generate_ice_spike_large(pos
)
359 minetest
.chat_send_player(name
, "Large ice spike placed.")
360 elseif param
== "end_exit_portal" then
361 mcl_structures
.generate_end_exit_portal(pos
)
362 minetest
.chat_send_player(name
, "End exit portal placed.")
363 elseif param
== "end_portal_shrine" then
364 mcl_structures
.generate_end_portal_shrine(pos
)
365 minetest
.chat_send_player(name
, "End portal shrine placed.")
366 elseif param
== "" then
367 minetest
.chat_send_player(name
, "Error: No structure type given. Please use “/spawnstruct <type>”.")
370 minetest
.chat_send_player(name
, "Error: Unknown structure type. Please use “/spawnstruct <type>”.")
374 minetest
.chat_send_player(name
, "Use /help spawnstruct to see a list of avaiable types.")
379 local time_to_load
= os
.clock() - init
380 minetest
.log("action", (string.format("[MOD] "..minetest
.get_current_modname().." loaded in %.4f s", time_to_load
)))