1 local S
= minetest
.get_translator("tsm_pyramids")
3 -- Pyramid width (must be an odd number)
5 -- Pyramid width minus 1
6 local PYRA_Wm
= PYRA_W
- 1
7 -- Half of (Pyramid width minus 1)
8 local PYRA_Wh
= PYRA_Wm
/ 2
9 -- Minimum spawn height
14 dofile(minetest
.get_modpath("tsm_pyramids").."/mummy.lua")
15 dofile(minetest
.get_modpath("tsm_pyramids").."/nodes.lua")
16 dofile(minetest
.get_modpath("tsm_pyramids").."/room.lua")
18 local mg_name
= minetest
.get_mapgen_setting("mg_name")
21 {name
="default:apple", max = 3},
22 {name
="default:steel_ingot", max = 3},
23 {name
="default:copper_ingot", max = 3},
24 {name
="default:gold_ingot", max = 2},
25 {name
="default:diamond", max = 1},
26 {name
="default:pick_steel", max = 1},
27 {name
="default:pick_diamond", max = 1},
28 {name
="default:papyrus", max = 9},
31 if minetest
.get_modpath("farming") then
32 table.insert(chest_stuff
, {name
="farming:bread", max = 3})
33 table.insert(chest_stuff
, {name
="farming:cotton", max = 8})
35 table.insert(chest_stuff
, {name
="farming:apple", max = 8})
36 table.insert(chest_stuff
, {name
="farming:apple", max = 3})
38 if minetest
.get_modpath("tnt") then
39 table.insert(chest_stuff
, {name
="tnt:gunpowder", max = 6})
41 table.insert(chest_stuff
, {name
="farming:apple", max = 3})
44 function tsm_pyramids
.fill_chest(pos
, stype
, flood_sand
)
45 local sand
= "default:sand"
46 if stype
== "desert_sandstone" or stype
== "desert_stone" then
47 sand
= "default:desert_sand"
49 local n
= minetest
.get_node(pos
)
50 if n
and n
.name
and n
.name
== "default:chest" then
51 local meta
= minetest
.get_meta(pos
)
52 local inv
= meta
:get_inventory()
53 inv
:set_size("main", 8*4)
55 -- Fill with sand in sand-flooded pyramids
57 table.insert(stacks
, {name
=sand
, count
= math
.random(1,32)})
60 if math
.random(1,10) >= 7 then
61 if minetest
.get_modpath("treasurer") ~= nil then
62 stacks
= treasurer
.select_random_treasures(3,7,9,{"minetool", "food", "crafting_component"})
65 local stuff
= chest_stuff
[math
.random(1,#chest_stuff
)]
66 table.insert(stacks
, {name
=stuff
.name
, count
= math
.random(1,stuff
.max)})
71 if not inv
:contains_item("main", stacks
[s
]) then
72 inv
:set_stack("main", math
.random(1,32), stacks
[s
])
78 local function add_spawner(pos
, mummy_offset
)
79 minetest
.set_node(pos
, {name
="tsm_pyramids:spawner_mummy"})
80 if not minetest
.settings
:get_bool("only_peaceful_mobs") then tsm_pyramids
.spawn_mummy(vector
.add(pos
, mummy_offset
),2) end
83 local function can_replace(pos
)
84 local n
= minetest
.get_node_or_nil(pos
)
85 if n
and n
.name
and minetest
.registered_nodes
[n
.name
] and not minetest
.registered_nodes
[n
.name
].walkable
then
94 local function make_foundation_part(pos
, set_to_stone
)
98 while can_replace(p2
)==true do
103 table.insert(set_to_stone
, table.copy(p2
))
108 local function make_entrance(pos
, rot
, brick
, sand
, flood_sand
)
109 local roffset_arr
= {
110 { x
=0, y
=0, z
=1 }, -- front
111 { x
=-1, y
=0, z
=0 }, -- left
112 { x
=0, y
=0, z
=-1 }, -- back
113 { x
=1, y
=0, z
=0 }, -- right
115 local roffset
= roffset_arr
[rot
+ 1]
118 way
= vector
.add(pos
, {x
=PYRA_Wh
, y
=0, z
=0})
120 way
= vector
.add(pos
, {x
=PYRA_Wm
, y
=0, z
=PYRA_Wh
})
122 way
= vector
.add(pos
, {x
=PYRA_Wh
, y
=0, z
=PYRA_Wm
})
124 way
= vector
.add(pos
, {x
=0, y
=0, z
=PYRA_Wh
})
126 local max_sand_height
= math
.random(1,3)
128 local sand_height
= math
.random(1,max_sand_height
)
131 local way_dir
= vector
.add(vector
.add(way
, {x
=0,y
=iy
,z
=0}), vector
.multiply(roffset
, ie
))
132 if flood_sand
and sand
~= "ignore" and iy
<= sand_height
and ie
>= 3 then
133 minetest
.set_node(way_dir
, {name
=sand
})
135 minetest
.remove_node(way_dir
)
137 -- build decoration above entrance
138 if ie
>=3 and iy
== 3 then
139 local deco
= {x
=way_dir
.x
, y
=way_dir
.y
+1,z
=way_dir
.z
}
140 minetest
.set_node(deco
, {name
=brick
})
141 if rot
== 0 or rot
== 2 then
142 minetest
.set_node(vector
.add(deco
, {x
=-1, y
=0, z
=0}), {name
=brick
})
143 minetest
.set_node(vector
.add(deco
, {x
=1, y
=0, z
=0}), {name
=brick
})
145 minetest
.set_node(vector
.add(deco
, {x
=0, y
=0, z
=-1}), {name
=brick
})
146 minetest
.set_node(vector
.add(deco
, {x
=0, y
=0, z
=1}), {name
=brick
})
153 local function make_pyramid(pos
, brick
, sandstone
, stone
, sand
)
154 local set_to_brick
= {}
155 local set_to_sand
= {}
156 local set_to_stone
= {}
158 for iy
=0,math
.random(10,PYRA_Wh
),1 do
159 for ix
=iy
,PYRA_W
-1-iy
,1 do
160 for iz
=iy
,PYRA_W
-1-iy
,1 do
162 make_foundation_part({x
=pos
.x
+ix
,y
=pos
.y
,z
=pos
.z
+iz
}, set_to_stone
)
164 table.insert(set_to_brick
, {x
=pos
.x
+ix
,y
=pos
.y
+iy
,z
=pos
.z
+iz
})
165 if sand
~= "ignore" then
167 local n
= minetest
.get_node({x
=pos
.x
+ix
,y
=pos
.y
+iy
+yy
,z
=pos
.z
+iz
})
168 if n
and n
.name
and n
.name
== stone
then
169 table.insert(set_to_sand
, {x
=pos
.x
+ix
,y
=pos
.y
+iy
+yy
,z
=pos
.z
+iz
})
176 minetest
.bulk_set_node(set_to_stone
, {name
=stone
})
177 minetest
.bulk_set_node(set_to_brick
, {name
=brick
})
178 if sand
~= "ignore" then
179 minetest
.bulk_set_node(set_to_sand
, {name
=sand
})
183 local function make(pos
, brick
, sandstone
, stone
, sand
, ptype
, room_id
)
184 local bpos
= table.copy(pos
)
186 make_pyramid(bpos
, brick
, sandstone
, stone
, sand
)
188 local rot
= math
.random(0, 3)
190 local ok
, msg
, flood_sand
= tsm_pyramids
.make_room(bpos
, ptype
, room_id
, rot
)
191 -- Place mummy spawner
192 local r
= math
.random(1,3)
193 -- 4 possible spawner positions
194 local spawner_posses
= {
196 {{x
=bpos
.x
+PYRA_Wh
,y
=bpos
.y
+2, z
=bpos
.z
+5}, {x
=0, y
=0, z
=2}},
198 {{x
=bpos
.x
+PYRA_Wm
-5,y
=bpos
.y
+2, z
=bpos
.z
+PYRA_Wh
}, {x
=-2, y
=0, z
=0}},
200 {{x
=bpos
.x
+PYRA_Wh
,y
=bpos
.y
+2, z
=bpos
.z
+PYRA_W
-5}, {x
=0, y
=0, z
=-2}},
202 {{x
=bpos
.x
+5,y
=bpos
.y
+2, z
=bpos
.z
+PYRA_Wh
}, {x
=2, y
=0, z
=0}},
204 -- Delete the spawner position in which the entrance will be placed
205 table.remove(spawner_posses
, (rot
% 4) + 1)
206 add_spawner(spawner_posses
[r
][1], spawner_posses
[r
][2])
208 make_entrance(bpos
, rot
, brick
, sand
, flood_sand
)
210 minetest
.log("action", "[tsm_pyramids] Created pyramid at "..minetest
.pos_to_string(bpos
)..".")
214 local perl1
= {SEED1
= 9130, OCTA1
= 3, PERS1
= 0.5, SCAL1
= 250} -- Values should match minetest mapgen V6 desert noise.
215 local perlin1
-- perlin noise buffer
217 local function hlp_fnct(pos
, name
)
218 local n
= minetest
.get_node_or_nil(pos
)
219 if n
and n
.name
and n
.name
== name
then
225 local function ground(pos
, old
)
226 local p2
= table.copy(pos
)
227 while hlp_fnct(p2
, "air") do
231 return {x
=old
.x
, y
=p2
.y
, z
=old
.z
}
237 -- Attempt to generate a pyramid in the generated area.
238 -- Up to one pyramid per mapchunk.
239 minetest
.register_on_generated(function(minp
, maxp
, seed
)
240 if maxp
.y
< PYRA_MIN_Y
then return end
242 -- TODO: Use Minetests pseudo-random tools
243 math
.randomseed(seed
)
246 perlin1
= minetest
.get_perlin(perl1
.SEED1
, perl1
.OCTA1
, perl1
.PERS1
, perl1
.SCAL1
)
248 --[[ Make sure the pyramid doesn't bleed outside of maxp,
249 so it doesn't get placed incompletely by the mapgen.
250 This creates a bias somewhat, as this means there are some coordinates in
251 which pyramids cannot spawn. But it's still better to have broken pyramids.
253 local limit
= function(pos
, maxp
)
254 pos
.x
= math
.min(pos
.x
, maxp
.x
- PYRA_W
+1)
255 pos
.y
= math
.min(pos
.y
, maxp
.y
- PYRA_Wh
)
256 pos
.z
= math
.min(pos
.z
, maxp
.z
- PYRA_W
+1)
259 local noise1
= perlin1
:get_2d({x
=minp
.x
,y
=minp
.y
})
261 if noise1
> 0.25 or noise1
< -0.26 then
262 -- Need a bit of luck to place a pyramid
263 if math
.random(0,10) > 7 then
264 minetest
.log("verbose", "[tsm_pyramids] Pyramid not placed, bad dice roll. minp="..minetest
.pos_to_string(minp
))
268 local mpos
= {x
=math
.random(minp
.x
,maxp
.x
), y
=math
.random(minp
.y
,maxp
.y
), z
=math
.random(minp
.z
,maxp
.z
)}
270 local sands
= {"default:sand", "default:desert_sand", "default:desert_stone"}
275 local sand_cnt_max
= 0
276 local sand_cnt_max_id
277 -- Look for sand or desert stone to place the pyramid on
282 psand
[s
] = minetest
.find_node_near(mpos
, 25, sand
)
285 mpos
= {x
=math
.random(minp
.x
,maxp
.x
), y
=math
.random(minp
.y
,maxp
.y
), z
=math
.random(minp
.z
,maxp
.z
)}
286 local spos
= minetest
.find_node_near(mpos
, 25, sand
)
288 sand_cnt
= sand_cnt
+ 1
289 if psand
[s
] == nil then
293 if sand_cnt
> sand_cnt_max
then
294 sand_cnt_max
= sand_cnt
301 minetest
.log("verbose", "[tsm_pyramids] Pyramid not placed, no suitable surface. minp="..minetest
.pos_to_string(minp
))
304 -- Select the material type by the most prominent node type
305 -- E.g. if desert sand is most prominent, we place a desert sandstone pyramid
306 if sand_cnt_max_id
then
307 sand
= sands
[sand_cnt_max_id
]
309 if p2
.y
< PYRA_MIN_Y
then
310 minetest
.log("info", "[tsm_pyramids] Pyramid not placed, too deep. p2="..minetest
.pos_to_string(p2
))
313 -- Now sink the pyramid until each corner of it is no longer floating in mid-air
316 {x
=p2
.x
,y
=p2
.y
-1,z
=p2
.z
},
317 {x
=p2
.x
+PYRA_Wm
,y
=p2
.y
-1,z
=p2
.z
+PYRA_Wm
},
318 {x
=p2
.x
+PYRA_Wm
,y
=p2
.y
-1,z
=p2
.z
},
319 {x
=p2
.x
,y
=p2
.y
-1,z
=p2
.z
+PYRA_Wm
},
322 local opos
= oposses
[o
]
323 local n
= minetest
.get_node_or_nil(opos
)
324 if n
and n
.name
and n
.name
== "air" then
325 local old
= table.copy(p2
)
326 p2
= ground(opos
, p2
)
329 -- Random bonus sinking
330 p2
.y
= math
.max(p2
.y
- math
.random(0,3), PYRA_MIN_Y
)
332 -- Bad luck, we have hit the chunk border!
333 if p2
.y
< minp
.y
then
334 minetest
.log("info", "[tsm_pyramids] Pyramid not placed, sunken too much. p2="..minetest
.pos_to_string(p2
))
338 -- Make sure the pyramid is not near a "killer" node, like water
339 local middle
= vector
.add(p2
, {x
=PYRA_Wh
, y
=0, z
=PYRA_Wh
})
340 if minetest
.find_node_near(p2
, 5, {"default:water_source"}) ~= nil or
341 minetest
.find_node_near(vector
.add(p2
, {x
=PYRA_W
, y
=0, z
=0}), 5, {"default:water_source"}) ~= nil or
342 minetest
.find_node_near(vector
.add(p2
, {x
=0, y
=0, z
=PYRA_W
}), 5, {"default:water_source"}) ~= nil or
343 minetest
.find_node_near(vector
.add(p2
, {x
=PYRA_W
, y
=0, z
=PYRA_W
}), 5, {"default:water_source"}) ~= nil or
345 minetest
.find_node_near(middle
, PYRA_W
, {"default:dirt_with_grass"}) ~= nil or
346 minetest
.find_node_near(middle
, 52, {"default:sandstonebrick", "default:desert_sandstone_brick", "default:desert_stonebrick"}) ~= nil then
347 minetest
.log("info", "[tsm_pyramids] Pyramid not placed, inappropriate node nearby. p2="..minetest
.pos_to_string(p2
))
351 -- Bonus chance to spawn a sandstone pyramid in v6 desert because otherwise they would be too rare in v6
352 if (mg_name
== "v6" and sand
== "default:desert_sand" and math
.random(1, 2) == 1) then
353 sand
= "default:sand"
356 -- Desert stone pyramids only generate in areas with almost no sand
357 if sand
== "default:desert_stone" then
358 local nodes
= minetest
.find_nodes_in_area(vector
.add(p2
, {x
=-1, y
=-2, z
=-1}), vector
.add(p2
, {x
=PYRA_W
+1, y
=PYRA_Wh
, z
=PYRA_W
+1}), {"group:sand"})
360 sand
= "default:desert_sand"
364 -- Generate the pyramid!
365 if sand
== "default:desert_sand" then
366 -- Desert sandstone pyramid
367 make(p2
, "default:desert_sandstone_brick", "default:desert_sandstone", "default:desert_stone", "default:desert_sand", "desert_sandstone")
368 elseif sand
== "default:sand" then
370 make(p2
, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone")
372 -- Desert stone pyramid
373 make(p2
, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "ignore", "desert_stone")
378 -- Add backwards-compability for nodes from the original pyramids mod
379 if minetest
.get_modpath("pyramids") == nil then
381 minetest
.register_alias("pyramids:trap", "tsm_pyramids:trap")
382 minetest
.register_alias("pyramids:trap_2", "tsm_pyramids:trap_2")
383 minetest
.register_alias("pyramids:deco_stone1", "tsm_pyramids:deco_stone1")
384 minetest
.register_alias("pyramids:deco_stone2", "tsm_pyramids:deco_stone2")
385 minetest
.register_alias("pyramids:deco_stone3", "tsm_pyramids:deco_stone3")
386 minetest
.register_alias("pyramids:spawner_mummy", "tsm_pyramids:spawner_mummy")
389 minetest
.register_chatcommand("spawnpyramid", {
390 description
= S("Generate a pyramid"),
391 params
= S("[<room_type>]"),
392 privs
= { server
= true },
393 func
= function(name
, param
)
394 local player
= minetest
.get_player_by_name(name
)
396 return false, S("No player.")
398 local pos
= player
:get_pos()
399 pos
= vector
.round(pos
)
400 local s
= math
.random(1,3)
401 local r
= tonumber(param
)
407 pos
= vector
.add(pos
, {x
=-PYRA_Wh
, y
=-1, z
=0})
410 ok
, msg
= make(pos
, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone", room_id
)
413 ok
, msg
= make(pos
, "default:desert_sandstone_brick", "default:desert_sandstone", "default:desert_stone", "default:desert_sand", "desert_sandstone", room_id
)
416 ok
, msg
= make(pos
, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "ignore", "desert_stone", room_id
)
419 return true, S("Pyramid generated at @1.", minetest
.pos_to_string(pos
))