73 Commits

Author SHA1 Message Date
84bea1052e Version 1.0.4 2022-10-16 17:06:50 +02:00
303d3cf45c Respawn spawner entity on punch/load 2022-10-16 17:06:03 +02:00
ac9a442a07 Add min_minetest_version 2022-10-16 16:26:55 +02:00
a17725133e Rename one of the engraving stones (Man→Human) 2022-10-16 16:24:16 +02:00
041a4c5dcc Add .mailmap for Wuzzy 2022-10-16 16:20:37 +02:00
36fc4d2639 Remove giant useless .gitignore 2022-10-16 16:18:45 +02:00
111639b778 Remove useless .gitattributes 2022-10-16 16:18:23 +02:00
3fc59c9010 Fix crash if mummy dies in fire 2022-10-16 16:17:14 +02:00
61ebaab55e Version 1.0.3 2022-02-19 23:27:55 +01:00
8a449ea8a8 Fix crash if on_punch was called w/ nil damage 2022-02-19 23:27:23 +01:00
0abcd7960a Version 1.0.2 2020-04-06 14:59:36 +02:00
f5fef5118d Fix broken mummy hit texture 2020-04-06 14:59:11 +02:00
0974de93e4 Fix occassional crash when mummy dies 2020-04-06 14:41:48 +02:00
0629d3b6ed Version 1.0.1 2020-04-06 00:47:39 +02:00
5e9cd77fdc Use TRUE ephemeral sounds 2020-04-06 00:47:00 +02:00
1b3f948daa Use ephemeral sounds 2020-04-06 00:19:56 +02:00
63572c5c23 Fix crash 2019-10-01 13:06:20 +02:00
2538680eea Fix undeclared global warnings 2019-09-26 14:31:24 +02:00
85da5073b9 Version 1.0.0 2019-09-02 20:45:11 +02:00
d995fd381a Spawn egg: Make node on_rightclick take precedence 2019-08-25 18:47:10 +02:00
355aa1d40d Add mummy description field (CMI) 2019-08-25 18:21:12 +02:00
44482f6268 Add basic CMI support (experimental) 2019-08-25 18:04:16 +02:00
ae4fc9135c Add _cmi_is_mob 2019-08-25 17:35:56 +02:00
22b0823de4 Version 0.8 2019-08-25 17:30:10 +02:00
e0f929d8dd Refactor pyramid type selection 2019-08-25 16:41:22 +02:00
5abc9c1e47 Fix some bugs with traps generating 2019-08-25 16:33:14 +02:00
47b32ecae1 Simplify trap stone definition 2019-08-25 16:02:25 +02:00
c2167e305a Add new trap type: Deep drop 2019-08-25 15:17:04 +02:00
f71ca591c9 More treasure variety 2019-08-25 14:00:03 +02:00
9d5dace4fb Guarantee 1 chest with treasures 2019-08-25 12:37:36 +02:00
0efa3dd75e Remove unneccessary set_hp 2019-08-25 12:30:32 +02:00
34750f407a Call on_death when mummy dies in node 2019-08-25 12:29:39 +02:00
049e575da1 Don't spawn mummies above liquids 2019-08-25 12:09:13 +02:00
5104b2a117 Fix bad hp_max of mummy 2019-08-25 05:22:04 +02:00
d9c4b78998 Remove papyrus from treasures 2019-08-25 05:18:35 +02:00
fe4ff2025c Mummies drop papyrus again 2019-08-25 05:18:08 +02:00
19c81a9b4f Improve initial mummy spawn 2019-08-25 01:52:12 +02:00
4fde7b9091 Improve mummy spawner behaviour 2019-08-25 01:37:59 +02:00
56277166d3 More reliable method to delete dummy 2019-08-25 01:02:49 +02:00
e6a76549f6 Enable traps for more rooms 2019-08-25 00:50:22 +02:00
b278da5bcf Remove useless node sets in make_entrance 2019-08-25 00:19:45 +02:00
4bce10ff7d Implement custom room walls 2019-08-25 00:19:35 +02:00
a7b45cbba7 Implement stype restriction 2019-08-24 23:19:41 +02:00
7f5e97357e Remove useless call 2019-08-24 22:53:11 +02:00
694d279ff0 Add reverse sandstone room style 2019-08-24 22:30:38 +02:00
a6e3a50266 Keep pyramids away from cactus and trees 2019-08-24 22:00:08 +02:00
269987771d Remove sand spam 2019-08-24 21:45:41 +02:00
4aa41e096f Fix some logging errors 2019-08-24 21:28:35 +02:00
4d25bdadf2 Reduce spawning of floating pyramids 2019-08-24 21:19:25 +02:00
1d9fee5ab1 Improve node restriction handling 2019-08-24 20:12:03 +02:00
4ec1b6b5bc Present desert stone pyramids in sandy areas 2019-08-24 20:05:51 +02:00
4300f641dc Keep pyramids away from the beach 2019-08-24 19:37:11 +02:00
01acc67011 Desert stone pyramids: Disable sand 2019-08-24 19:26:37 +02:00
9af486611c Reacivate desert stone pyramids ... for now 2019-08-24 19:25:40 +02:00
76bd636df2 Drop a minetest.after 2019-08-24 18:58:20 +02:00
e3a6dac028 Distiction between column and sandstone 2019-08-24 17:43:18 +02:00
71393b0368 Improve hieroglpyhs room 2019-08-24 17:14:08 +02:00
479d625484 Fix crash when spawning traps 2019-08-24 16:24:23 +02:00
6f24883fa3 Add 4 new rooms 2019-08-24 16:08:11 +02:00
39e5289b74 Reduce the water distance restriction 2019-08-23 21:01:35 +02:00
212636b66d Never spawn pyramids beyond maxp 2019-08-23 18:53:35 +02:00
10cf7524b5 Add pyramid size variable 2019-08-23 17:26:01 +02:00
fe41da8bd0 More tiles to place traps on 2019-08-23 14:37:38 +02:00
1e6f18253e Prevent traps generating below pillars 2019-08-23 14:34:42 +02:00
1fdb855347 Build walls around trap section 2019-08-23 13:53:43 +02:00
f1a7d039e7 Generate 2 solid layers at bottom of pit
To prevent lava escaping
2019-08-23 13:30:33 +02:00
20f0c8a845 Update mummy doll properties for MT 5.0.0 2019-08-23 13:04:45 +02:00
2f82b3665c Remove outdated TODOs/FIXMEs 2019-08-23 13:02:18 +02:00
92d36f9e79 Disable desert stone pyramids for now 2019-08-23 13:00:35 +02:00
e40a41e473 Merge branch 'desert_stone' 2019-08-23 12:58:27 +02:00
bd3f84ed4c Make falling of trap stones more unpredictable 2019-08-22 16:18:08 +02:00
e824fa467e Randomly rotate pyramids 2019-08-22 14:50:26 +02:00
c87a2afafa Make sounds mono 2019-08-20 21:01:42 +02:00
15 changed files with 1173 additions and 685 deletions

22
.gitattributes vendored
View File

@ -1,22 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

215
.gitignore vendored
View File

@ -1,215 +0,0 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
x64/
build/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
*.pubxml
# NuGet Packages Directory
## TODO: If you have NuGet Package Restore enabled, uncomment the next line
#packages/
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#############
## Windows detritus
#############
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac crap
.DS_Store
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist/
build/
eggs/
parts/
var/
sdist/
develop-eggs/
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg

2
.mailmap Normal file
View File

@ -0,0 +1,2 @@
Wuzzy <Wuzzy@disroot.org> <Wuzzy2@mail.ru>
Wuzzy <Wuzzy@disroot.org> <almikes@aol.com>

View File

@ -1,6 +1,6 @@
# Pyramids (with Treasurer support) [`tsm_pyramids`] # Pyramids (with Treasurer support) [`tsm_pyramids`]
* Version: 0.7 * Version: 1.0.4
## Description ## Description
This is a mod for Minetest Game which adds randomly spawned pyramids in deserts and This is a mod for Minetest Game which adds randomly spawned pyramids in deserts and

17
TODO Normal file
View File

@ -0,0 +1,17 @@
Minibugs:
- Mummy doesn't avoid lava
Features:
- More random rooms!
- Man statue
- Falling traps from above
- More variety in pyramid exterior styles
- Different entrances
- Stairs leading to entrance
- Open roof? For sun room
- Multiple entries (temple-like pyramids)
- Different pyramid sizes
- Damaged pyramids
- Missing blocks
- Trap stones
- No mummies, traps or treasures

341
init.lua
View File

@ -1,5 +1,14 @@
local S = minetest.get_translator("tsm_pyramids") local S = minetest.get_translator("tsm_pyramids")
-- Pyramid width (must be an odd number)
local PYRA_W = 23
-- Pyramid width minus 1
local PYRA_Wm = PYRA_W - 1
-- Half of (Pyramid width minus 1)
local PYRA_Wh = PYRA_Wm / 2
-- Minimum spawn height
local PYRA_MIN_Y = 3
tsm_pyramids = {} tsm_pyramids = {}
dofile(minetest.get_modpath("tsm_pyramids").."/mummy.lua") dofile(minetest.get_modpath("tsm_pyramids").."/mummy.lua")
@ -9,36 +18,63 @@ dofile(minetest.get_modpath("tsm_pyramids").."/room.lua")
local mg_name = minetest.get_mapgen_setting("mg_name") local mg_name = minetest.get_mapgen_setting("mg_name")
local chest_stuff = { local chest_stuff = {
{name="default:apple", max = 3}, normal = {
{name="default:steel_ingot", max = 3}, {name="default:steel_ingot", max = 3},
{name="default:copper_ingot", max = 3}, {name="default:copper_ingot", max = 3},
{name="default:gold_ingot", max = 2}, {name="default:gold_ingot", max = 2},
{name="default:diamond", max = 1}, {name="default:diamond", max = 1},
{name="default:pick_steel", max = 1}, {name="default:pick_steel", max = 1},
},
desert_stone = {
{name="default:mese_crystal", max = 4},
{name="default:gold_ingot", max = 10},
{name="default:pick_diamond", max = 1}, {name="default:pick_diamond", max = 1},
{name="default:papyrus", max = 9}, },
desert_sandstone = {
{name="default:apple", max = 1},
{name="default:stick", max = 64},
{name="default:acacia_bush_sapling", max = 1},
{name="default:paper", max = 9},
{name="default:shovel_bronze", max = 1},
{name="default:pick_mese", max = 1},
},
sandstone = {
{name="default:obsidian_shard", max = 5},
{name="default:apple", max = 3},
{name="default:blueberries", max = 9},
{name="default:glass", max = 64},
{name="default:bush_sapling", max = 1},
{name="default:pick_bronze", max = 1},
},
} }
if minetest.get_modpath("farming") then if minetest.get_modpath("farming") then
table.insert(chest_stuff, {name="farming:bread", max = 3}) table.insert(chest_stuff.desert_sandstone, {name="farming:bread", max = 3})
table.insert(chest_stuff, {name="farming:cotton", max = 8}) table.insert(chest_stuff.sandstone, {name="farming:bread", max = 4})
table.insert(chest_stuff.normal, {name="farming:cotton", max = 32})
table.insert(chest_stuff.desert_sandstone, {name="farming:seed_cotton", max = 3})
table.insert(chest_stuff.desert_sandstone, {name="farming:hoe_stone", max = 1})
else else
table.insert(chest_stuff, {name="farming:apple", max = 8}) table.insert(chest_stuff.normal, {name="farming:apple", max = 8})
table.insert(chest_stuff, {name="farming:apple", max = 3}) table.insert(chest_stuff.normal, {name="farming:apple", max = 3})
end end
if minetest.get_modpath("tnt") then if minetest.get_modpath("tnt") then
table.insert(chest_stuff, {name="tnt:gunpowder", max = 6}) table.insert(chest_stuff.normal, {name="tnt:gunpowder", max = 6})
table.insert(chest_stuff.desert_stone, {name="tnt:gunpowder", max = 6})
else else
table.insert(chest_stuff, {name="farming:apple", max = 3}) table.insert(chest_stuff.normal, {name="farming:apple", max = 3})
end end
function tsm_pyramids.fill_chest(pos, stype, flood_sand) function tsm_pyramids.fill_chest(pos, stype, flood_sand, treasure_chance)
minetest.after(2, function()
local sand = "default:sand" local sand = "default:sand"
if not treasure_chance then
treasure_chance = 100
end
if stype == "desert_sandstone" or stype == "desert_stone" then if stype == "desert_sandstone" or stype == "desert_stone" then
sand = "default:desert_sand" sand = "default:desert_sand"
end end
local n = minetest.get_node(pos) local n = minetest.get_node(pos)
local treasure_added = false
if n and n.name and n.name == "default:chest" then if n and n.name and n.name == "default:chest" then
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
local inv = meta:get_inventory() local inv = meta:get_inventory()
@ -49,14 +85,19 @@ function tsm_pyramids.fill_chest(pos, stype, flood_sand)
table.insert(stacks, {name=sand, count = math.random(1,32)}) table.insert(stacks, {name=sand, count = math.random(1,32)})
end end
-- Add treasures -- Add treasures
if math.random(1,10) >= 7 then if math.random(1,100) <= treasure_chance then
if minetest.get_modpath("treasurer") ~= nil then if minetest.get_modpath("treasurer") ~= nil then
stacks = treasurer.select_random_treasures(3,7,9,{"minetool", "food", "crafting_component"}) stacks = treasurer.select_random_treasures(3,7,9,{"minetool", "food", "crafting_component"})
else else
for i=0,2,1 do for i=0,2,1 do
local stuff = chest_stuff[math.random(1,#chest_stuff)] local stuff = chest_stuff.normal[math.random(1,#chest_stuff.normal)]
table.insert(stacks, {name=stuff.name, count = math.random(1,stuff.max)}) table.insert(stacks, {name=stuff.name, count = math.random(1,stuff.max)})
end end
if math.random(1,100) <= 75 then
local stuff = chest_stuff[stype][math.random(1,#chest_stuff[stype])]
table.insert(stacks, {name=stuff.name, count = math.random(1,stuff.max)})
end
treasure_added = true
end end
end end
for s=1,#stacks do for s=1,#stacks do
@ -64,14 +105,17 @@ function tsm_pyramids.fill_chest(pos, stype, flood_sand)
inv:set_stack("main", math.random(1,32), stacks[s]) inv:set_stack("main", math.random(1,32), stacks[s])
end end
end end
end end
end) return treasure_added
end end
local function add_spawner(pos, mummy_offset) local function add_spawner(pos, mummy_offset)
minetest.set_node(pos, {name="tsm_pyramids:spawner_mummy"}) minetest.set_node(pos, {name="tsm_pyramids:spawner_mummy"})
if not minetest.settings:get_bool("only_peaceful_mobs") then tsm_pyramids.spawn_mummy(vector.add(pos, mummy_offset),2) end if not minetest.settings:get_bool("only_peaceful_mobs") then
for i=1,2 do
tsm_pyramids.attempt_mummy_spawn(pos, false)
end
end
end end
local function can_replace(pos) local function can_replace(pos)
@ -99,21 +143,46 @@ local function make_foundation_part(pos, set_to_stone)
end end
end end
local function make_entrance(pos, brick, sand, flood_sand) local function make_entrance(pos, rot, brick, sand, flood_sand)
local gang = {x=pos.x+10,y=pos.y, z=pos.z} local roffset_arr = {
{ x=0, y=0, z=1 }, -- front
{ x=-1, y=0, z=0 }, -- left
{ x=0, y=0, z=-1 }, -- back
{ x=1, y=0, z=0 }, -- right
}
local roffset = roffset_arr[rot + 1]
local way
if rot == 0 then
way = vector.add(pos, {x=PYRA_Wh, y=0, z=0})
elseif rot == 1 then
way = vector.add(pos, {x=PYRA_Wm, y=0, z=PYRA_Wh})
elseif rot == 2 then
way = vector.add(pos, {x=PYRA_Wh, y=0, z=PYRA_Wm})
else
way = vector.add(pos, {x=0, y=0, z=PYRA_Wh})
end
local max_sand_height = math.random(1,3) local max_sand_height = math.random(1,3)
for iz=0,6,1 do for ie=0,6,1 do
local sand_height = math.random(1,max_sand_height) local sand_height = math.random(1,max_sand_height)
for iy=2,3,1 do for iy=2,3,1 do
if flood_sand and sand ~= "ignore" and iy <= sand_height and iz >= 3 then -- dig hallway
minetest.set_node({x=gang.x+1,y=gang.y+iy,z=gang.z+iz}, {name=sand}) local way_dir = vector.add(vector.add(way, {x=0,y=iy,z=0}), vector.multiply(roffset, ie))
if flood_sand and sand ~= "ignore" and iy <= sand_height and ie >= 3 then
minetest.set_node(way_dir, {name=sand})
else else
minetest.remove_node({x=gang.x+1,y=gang.y+iy,z=gang.z+iz}) minetest.remove_node(way_dir)
end
-- build decoration above entrance
if ie == 3 and iy == 3 then
local deco = {x=way_dir.x, y=way_dir.y+1,z=way_dir.z}
minetest.set_node(deco, {name=brick})
if rot == 0 or rot == 2 then
minetest.set_node(vector.add(deco, {x=-1, y=0, z=0}), {name=brick})
minetest.set_node(vector.add(deco, {x=1, y=0, z=0}), {name=brick})
else
minetest.set_node(vector.add(deco, {x=0, y=0, z=-1}), {name=brick})
minetest.set_node(vector.add(deco, {x=0, y=0, z=1}), {name=brick})
end end
if iz >=3 and iy == 3 then
minetest.set_node({x=gang.x,y=gang.y+iy+1,z=gang.z+iz}, {name=brick})
minetest.set_node({x=gang.x+1,y=gang.y+iy+1,z=gang.z+iz}, {name=brick})
minetest.set_node({x=gang.x+2,y=gang.y+iy+1,z=gang.z+iz}, {name=brick})
end end
end end
end end
@ -121,60 +190,55 @@ end
local function make_pyramid(pos, brick, sandstone, stone, sand) local function make_pyramid(pos, brick, sandstone, stone, sand)
local set_to_brick = {} local set_to_brick = {}
local set_to_sand = {}
local set_to_stone = {} local set_to_stone = {}
-- Build pyramid -- Build pyramid
for iy=0,math.random(10,11),1 do for iy=0,math.random(10,PYRA_Wh),1 do
for ix=iy,22-iy,1 do for ix=iy,PYRA_W-1-iy,1 do
for iz=iy,22-iy,1 do for iz=iy,PYRA_W-1-iy,1 do
if iy < 1 then if iy < 1 then
make_foundation_part({x=pos.x+ix,y=pos.y,z=pos.z+iz}, set_to_stone) make_foundation_part({x=pos.x+ix,y=pos.y,z=pos.z+iz}, set_to_stone)
end end
table.insert(set_to_brick, {x=pos.x+ix,y=pos.y+iy,z=pos.z+iz}) table.insert(set_to_brick, {x=pos.x+ix,y=pos.y+iy,z=pos.z+iz})
if sand ~= "ignore" then
for yy=1,10-iy,1 do
local n = minetest.get_node({x=pos.x+ix,y=pos.y+iy+yy,z=pos.z+iz})
if n and n.name and n.name == stone then
table.insert(set_to_sand, {x=pos.x+ix,y=pos.y+iy+yy,z=pos.z+iz})
end
end
end
end end
end end
end end
minetest.bulk_set_node(set_to_stone , {name=stone}) minetest.bulk_set_node(set_to_stone , {name=stone})
minetest.bulk_set_node(set_to_brick, {name=brick}) minetest.bulk_set_node(set_to_brick, {name=brick})
if sand ~= "ignore" then
minetest.bulk_set_node(set_to_sand, {name=sand})
end
end end
local function make(pos, brick, sandstone, stone, sand, ptype, room_id) local function make(pos, brick, sandstone, stone, sand, ptype, room_id)
local bpos = table.copy(pos)
-- Build pyramid -- Build pyramid
make_pyramid(pos, brick, sandstone, stone, sand) make_pyramid(bpos, brick, sandstone, stone, sand)
local rot = math.random(0, 3)
-- Build room -- Build room
local ok, msg, flood_sand = tsm_pyramids.make_room(pos, ptype, room_id) local ok, msg, flood_sand = tsm_pyramids.make_room(bpos, ptype, room_id, rot)
-- Place mummy spawner -- Place mummy spawner
local r = math.random(1,3) local r = math.random(1,3)
if r == 1 then -- 4 possible spawner positions
local spawner_posses = {
-- front -- front
add_spawner({x=pos.x+11,y=pos.y+2, z=pos.z+17}, {x=0, y=0, z=-2}) {{x=bpos.x+PYRA_Wh,y=bpos.y+2, z=bpos.z+5}, {x=0, y=0, z=2}},
elseif r == 2 then
-- right
add_spawner({x=pos.x+17,y=pos.y+2, z=pos.z+11}, {x=-2, y=0, z=0})
else
-- left -- left
add_spawner({x=pos.x+5,y=pos.y+2, z=pos.z+11}, {x=2, y=0, z=0}) {{x=bpos.x+PYRA_Wm-5,y=bpos.y+2, z=bpos.z+PYRA_Wh}, {x=-2, y=0, z=0}},
end -- back
{{x=bpos.x+PYRA_Wh,y=bpos.y+2, z=bpos.z+PYRA_W-5}, {x=0, y=0, z=-2}},
-- right
{{x=bpos.x+5,y=bpos.y+2, z=bpos.z+PYRA_Wh}, {x=2, y=0, z=0}},
}
-- Delete the spawner position in which the entrance will be placed
table.remove(spawner_posses, (rot % 4) + 1)
add_spawner(spawner_posses[r][1], spawner_posses[r][2])
-- Build entrance -- Build entrance
make_entrance({x=pos.x,y=pos.y, z=pos.z}, brick, sand, flood_sand) make_entrance(bpos, rot, brick, sand, flood_sand)
-- Done -- Done
minetest.log("action", "Created pyramid at ("..pos.x..","..pos.y..","..pos.z..")") minetest.log("action", "[tsm_pyramids] Created pyramid at "..minetest.pos_to_string(bpos)..".")
return ok, msg return ok, msg
end end
local perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} -- Values should match minetest mapgen V6 desert noise. local perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} -- Values should match minetest mapgen V6 desert noise.
local perlin1 local perlin1 -- perlin noise buffer
local function hlp_fnct(pos, name) local function hlp_fnct(pos, name)
local n = minetest.get_node_or_nil(pos) local n = minetest.get_node_or_nil(pos)
@ -185,94 +249,168 @@ local function hlp_fnct(pos, name)
end end
end end
local function ground(pos, old) local function ground(pos, old)
local p2 = pos local p2 = table.copy(pos)
while hlp_fnct(p2, "air") do while hlp_fnct(p2, "air") do
p2.y = p2.y -1 p2.y = p2.y -1
end end
if p2.y < old.y then if p2.y < old.y then
return p2 return {x=old.x, y=p2.y, z=old.z}
else else
return old return old
end end
end end
-- Select the recommended type of pyramid to use, based on the environment.
minetest.register_on_generated(function(minp, maxp, seed) -- One of sandstone, desert sandstone, desert stone.
if maxp.y < 0 then return end local select_pyramid_type = function(minp, maxp)
math.randomseed(seed)
if not perlin1 then
perlin1 = minetest.get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
end
local noise1 = perlin1:get_2d({x=minp.x,y=minp.y})--,z=minp.z})
if noise1 > 0.25 or noise1 < -0.26 then
local mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)} local mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
local sand
local sands = {"default:sand", "default:desert_sand", "default:desert_stone"} local sands = {"default:sand", "default:desert_sand", "default:desert_stone"}
local p2 local p2
local psand = {} local psand = {}
local sand local sand
local cnt = 0 local cnt = 0
local cnt_min = 100 local sand_cnt_max = 0
local sand_cnt_max_id
-- Look for sand or desert stone to place the pyramid on
for s=1, #sands do for s=1, #sands do
cnt = 0 cnt = 0
local sand_cnt = 0
sand = sands[s] sand = sands[s]
psand[s] = minetest.find_node_near(mpos, 25, sand) psand[s] = minetest.find_node_near(mpos, 25, sand)
while psand == nil and cnt < 5 do while cnt < 5 do
cnt = cnt+1 cnt = cnt+1
mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)} mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
psand[s] = minetest.find_node_near(mpos, 25, sand) local spos = minetest.find_node_near(mpos, 25, sand)
if spos ~= nil then
sand_cnt = sand_cnt + 1
if psand[s] == nil then
psand[s] = spos
end end
if psand[s] ~= nil then end
if cnt < cnt_min then if sand_cnt > sand_cnt_max then
cnt_min = cnt sand_cnt_max = sand_cnt
sand_cnt_max_id = s
p2 = psand[s] p2 = psand[s]
end end
end end
end end
if p2 == nil then return end
if p2.y < 0 then return end
local off = 0 -- Select the material type by the most prominent node type
local opos1 = {x=p2.x+22,y=p2.y-1,z=p2.z+22} -- E.g. if desert sand is most prominent, we place a desert sandstone pyramid
local opos2 = {x=p2.x+22,y=p2.y-1,z=p2.z} if sand_cnt_max_id then
local opos3 = {x=p2.x,y=p2.y-1,z=p2.z+22} sand = sands[sand_cnt_max_id]
local opos1_n = minetest.get_node_or_nil(opos1) else
local opos2_n = minetest.get_node_or_nil(opos2) sand = nil
local opos3_n = minetest.get_node_or_nil(opos3) p2 = nil
if opos1_n and opos1_n.name and opos1_n.name == "air" then
p2 = ground(opos1, p2)
end
if opos2_n and opos2_n.name and opos2_n.name == "air" then
p2 = ground(opos2, p2)
end
if opos3_n and opos3_n.name and opos3_n.name == "air" then
p2 = ground(opos3, p2)
end
p2.y = p2.y - 3
if p2.y < 0 then p2.y = 0 end
if minetest.find_node_near(p2, 25, {"default:water_source"}) ~= nil or
minetest.find_node_near(p2, 22, {"default:dirt_with_grass"}) ~= nil or
minetest.find_node_near(p2, 52, {"default:sandstonebrick"}) ~= nil or
minetest.find_node_near(p2, 52, {"default:desert_sandstone_brick"}) ~= nil then
return
end end
return sand, p2
end
-- Attempt to generate a pyramid in the generated area.
-- Up to one pyramid per mapchunk.
minetest.register_on_generated(function(minp, maxp, seed)
if maxp.y < PYRA_MIN_Y then return end
-- TODO: Use Minetests pseudo-random tools
math.randomseed(seed)
if not perlin1 then
perlin1 = minetest.get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
end
--[[ Make sure the pyramid doesn't bleed outside of maxp,
so it doesn't get placed incompletely by the mapgen.
This creates a bias somewhat, as this means there are some coordinates in
which pyramids cannot spawn. But it's still better to have broken pyramids.
]]
local limit = function(pos, maxp)
pos.x = math.min(pos.x, maxp.x - PYRA_W+1)
pos.y = math.min(pos.y, maxp.y - PYRA_Wh)
pos.z = math.min(pos.z, maxp.z - PYRA_W+1)
return pos
end
local noise1 = perlin1:get_2d({x=minp.x,y=minp.y})
if noise1 > 0.25 or noise1 < -0.26 then
-- Need a bit of luck to place a pyramid
if math.random(0,10) > 7 then if math.random(0,10) > 7 then
minetest.log("verbose", "[tsm_pyramids] Pyramid not placed, bad dice roll. minp="..minetest.pos_to_string(minp))
return return
end end
local sand, p2
sand, p2 = select_pyramid_type(minp, maxp)
if p2 == nil then
minetest.log("verbose", "[tsm_pyramids] Pyramid not placed, no suitable surface. minp="..minetest.pos_to_string(minp))
return
end
if p2.y < PYRA_MIN_Y then
minetest.log("info", "[tsm_pyramids] Pyramid not placed, too deep. p2="..minetest.pos_to_string(p2))
return
end
-- Now sink the pyramid until each corner of it is no longer floating in mid-air
p2 = limit(p2, maxp)
local oposses = {
{x=p2.x,y=p2.y-1,z=p2.z},
{x=p2.x+PYRA_Wm,y=p2.y-1,z=p2.z+PYRA_Wm},
{x=p2.x+PYRA_Wm,y=p2.y-1,z=p2.z},
{x=p2.x,y=p2.y-1,z=p2.z+PYRA_Wm},
}
for o=1, #oposses do
local opos = oposses[o]
local n = minetest.get_node_or_nil(opos)
if n and n.name and n.name == "air" then
local old = table.copy(p2)
p2 = ground(opos, p2)
end
end
-- Random bonus sinking
p2.y = math.max(p2.y - math.random(0,3), PYRA_MIN_Y)
-- Bad luck, we have hit the chunk border!
if p2.y < minp.y then
minetest.log("info", "[tsm_pyramids] Pyramid not placed, sunken too much. p2="..minetest.pos_to_string(p2))
return
end
-- Make sure the pyramid is not near a "killer" node, like water
local middle = vector.add(p2, {x=PYRA_Wh, y=0, z=PYRA_Wh})
if minetest.find_node_near(p2, 5, {"default:water_source"}) ~= nil or
minetest.find_node_near(vector.add(p2, {x=PYRA_W, y=0, z=0}), 5, {"default:water_source"}) ~= nil or
minetest.find_node_near(vector.add(p2, {x=0, y=0, z=PYRA_W}), 5, {"default:water_source"}) ~= nil or
minetest.find_node_near(vector.add(p2, {x=PYRA_W, y=0, z=PYRA_W}), 5, {"default:water_source"}) ~= nil or
minetest.find_node_near(middle, PYRA_W, {"default:dirt_with_grass"}) ~= nil or
minetest.find_node_near(middle, 52, {"default:sandstonebrick", "default:desert_sandstone_brick", "default:desert_stonebrick"}) ~= nil or
minetest.find_node_near(middle, PYRA_Wh + 3, {"default:cactus", "group:leaves", "group:tree"}) ~= nil then
minetest.log("info", "[tsm_pyramids] Pyramid not placed, inappropriate node nearby. p2="..minetest.pos_to_string(p2))
return
end
-- Bonus chance to spawn a sandstone pyramid in v6 desert because otherwise they would be too rare in v6
if (mg_name == "v6" and sand == "default:desert_sand" and math.random(1, 2) == 1) then if (mg_name == "v6" and sand == "default:desert_sand" and math.random(1, 2) == 1) then
sand = "default:sand" sand = "default:sand"
end end
-- Desert stone pyramids only generate in areas with almost no sand
if sand == "default:desert_stone" then
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"})
if #nodes > 5 then
sand = "default:desert_sand"
end
end
-- Generate the pyramid!
if sand == "default:desert_sand" then if sand == "default:desert_sand" then
-- Desert sandstone pyramid -- Desert sandstone pyramid
minetest.after(0.8, make, p2, "default:desert_sandstone_brick", "default:desert_sandstone", "default:desert_stone", "default:desert_sand", "desert_sandstone") make(p2, "default:desert_sandstone_brick", "default:desert_sandstone", "default:desert_stone", "default:desert_sand", "desert_sandstone")
elseif sand == "default:sand" then elseif sand == "default:sand" then
-- Sandstone pyramid -- Sandstone pyramid
minetest.after(0.8, make, p2, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone") make(p2, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone")
else else
-- Desert stone pyramid -- Desert stone pyramid
minetest.after(0.8, make, p2, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "default:desert_sand", "desert_stone") make(p2, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "ignore", "desert_stone")
end end
end end
end) end)
@ -286,9 +424,6 @@ if minetest.get_modpath("pyramids") == nil then
minetest.register_alias("pyramids:deco_stone2", "tsm_pyramids:deco_stone2") minetest.register_alias("pyramids:deco_stone2", "tsm_pyramids:deco_stone2")
minetest.register_alias("pyramids:deco_stone3", "tsm_pyramids:deco_stone3") minetest.register_alias("pyramids:deco_stone3", "tsm_pyramids:deco_stone3")
minetest.register_alias("pyramids:spawner_mummy", "tsm_pyramids:spawner_mummy") minetest.register_alias("pyramids:spawner_mummy", "tsm_pyramids:spawner_mummy")
-- FIXME: Entities are currently NOT backwards-compatible
-- TODO: Update README when full backwards-compability is achieved
end end
minetest.register_chatcommand("spawnpyramid", { minetest.register_chatcommand("spawnpyramid", {
@ -309,7 +444,7 @@ minetest.register_chatcommand("spawnpyramid", {
room_id = r room_id = r
end end
local ok, msg local ok, msg
pos = vector.add(pos, {x=-11, y=-1, z=0}) pos = vector.add(pos, {x=-PYRA_Wh, y=-1, z=0})
if s == 1 then if s == 1 then
-- Sandstone -- Sandstone
ok, msg = make(pos, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone", room_id) ok, msg = make(pos, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone", room_id)

View File

@ -6,10 +6,11 @@ Desert Sandstone with Cactus Engraving=
Desert Sandstone with Scarab Engraving= Desert Sandstone with Scarab Engraving=
Falling Cracked Sandstone Brick= Falling Cracked Sandstone Brick=
Falling Cracked Desert Sandstone Brick= Falling Cracked Desert Sandstone Brick=
Mummy=
Mummy Spawn Egg= Mummy Spawn Egg=
Mummy Spawner= Mummy Spawner=
Sandstone with Eye Engraving= Sandstone with Eye Engraving=
Sandstone with Man Engraving= Sandstone with Human Engraving=
Sandstone with Sun Engraving= Sandstone with Sun Engraving=
A mummy spawner causes hostile mummies to appear in its vicinity as long it exists.= A mummy spawner causes hostile mummies to appear in its vicinity as long it exists.=
Can be used to create a hostile mummy.= Can be used to create a hostile mummy.=

View File

@ -6,10 +6,11 @@ Desert Sandstone with Cactus Engraving=Wüstensandstein mit Kaktusgravur
Desert Sandstone with Scarab Engraving=Wüstensandstein mit Skarabäusgravur Desert Sandstone with Scarab Engraving=Wüstensandstein mit Skarabäusgravur
Falling Cracked Sandstone Brick=Fallender rissiger Sandsteinziegel Falling Cracked Sandstone Brick=Fallender rissiger Sandsteinziegel
Falling Cracked Desert Sandstone Brick=Fallender rissiger Wüstensandsteinziegel Falling Cracked Desert Sandstone Brick=Fallender rissiger Wüstensandsteinziegel
Mummy=Mumie
Mummy Spawn Egg=Mumien-Spawn-Ei Mummy Spawn Egg=Mumien-Spawn-Ei
Mummy Spawner=Mumien-Spawner Mummy Spawner=Mumien-Spawner
Sandstone with Eye Engraving=Sandstein mit Augengravur Sandstone with Eye Engraving=Sandstein mit Augengravur
Sandstone with Man Engraving=Sandstein mit Manngravur Sandstone with Human Engraving=Sandstein mit Menschengravur
Sandstone with Sun Engraving=Sandstein mit Sonnengravur Sandstone with Sun Engraving=Sandstein mit Sonnengravur
A mummy spawner causes hostile mummies to appear in its vicinity as long it exists.=Ein Mumien-Spawner lässt feindliche Mumien in seiner näheren Umgebung auftauchen, solange er existiert. A mummy spawner causes hostile mummies to appear in its vicinity as long it exists.=Ein Mumien-Spawner lässt feindliche Mumien in seiner näheren Umgebung auftauchen, solange er existiert.
Can be used to create a hostile mummy.=Kann benutzt werden, um eine feindliche Mumie zu erzeugen (auch »spawnen« genannt). Can be used to create a hostile mummy.=Kann benutzt werden, um eine feindliche Mumie zu erzeugen (auch »spawnen« genannt).

View File

@ -1,4 +1,5 @@
name = tsm_pyramids name = tsm_pyramids
description = Pyramids with treasures! You can find them in deserts and sandstone deserts. description = Pyramids with treasures! You can find them in deserts and sandstone deserts.
depends = default depends = default
optional_depends = farming, tnt, treasurer, doc_items, awards optional_depends = farming, tnt, treasurer, doc_items, awards, cmi
min_minetest_version = 5.0

283
mummy.lua
View File

@ -1,5 +1,7 @@
local S = minetest.get_translator("tsm_pyramids") local S = minetest.get_translator("tsm_pyramids")
local mod_cmi = minetest.get_modpath("cmi") ~= nil
local mummy_walk_limit = 1 local mummy_walk_limit = 1
local mummy_chillaxin_speed = 1 local mummy_chillaxin_speed = 1
local mummy_animation_speed = 10 local mummy_animation_speed = 10
@ -12,11 +14,13 @@ local mummy_texture = {"tsm_pyramids_mummy.png"}
local mummy_hp = 20 local mummy_hp = 20
local mummy_drop = "default:papyrus" local mummy_drop = "default:papyrus"
local spawner_entity_offset = -0.28
local sound_normal = "mummy" local sound_normal = "mummy"
local sound_hit = "mummy_hurt" local sound_hit = "mummy_hurt"
local sound_dead = "mummy_death" local sound_dead = "mummy_death"
local spawner_range = 17 local spawner_check_range = 17
local spawner_max_mobs = 6 local spawner_max_mobs = 6
local function get_animations() local function get_animations()
@ -47,15 +51,11 @@ local ANIM_WALK_MINE = 5
local ANIM_MINE = 6 local ANIM_MINE = 6
local function hit(self) local function hit(self)
local prop = { self.object:set_texture_mod("^tsm_pyramids_hit.png")
mesh = mummy_mesh,
textures = {"tsm_pyramids_mummy.png^tsm_pyramids_hit.png"},
}
self.object:set_properties(prop)
minetest.after(0.4, function(self) minetest.after(0.4, function(self)
local prop = {textures = mummy_texture,} local prop = {textures = mummy_texture,}
if self.object ~= nil then if self ~= nil and self.object ~= nil then
self.object:set_properties(prop) self.object:set_texture_mod("")
end end
end, self) end, self)
end end
@ -63,13 +63,13 @@ end
local function mummy_update_visuals_def(self) local function mummy_update_visuals_def(self)
npc_anim = 0 -- Animation will be set further below immediately npc_anim = 0 -- Animation will be set further below immediately
local prop = { local prop = {
mesh = mummy_mesh,
textures = mummy_texture, textures = mummy_texture,
} }
self.object:set_properties(prop) self.object:set_properties(prop)
end end
local MUMMY_DEF = { local MUMMY_DEF = {
hp_max = mummy_hp,
physical = true, physical = true,
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.9, 0.4}, collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.9, 0.4},
visual = "mesh", visual = "mesh",
@ -90,13 +90,36 @@ local MUMMY_DEF = {
envdmg_timer = 0, envdmg_timer = 0,
attacker = "", attacker = "",
attacking_timer = 0, attacking_timer = 0,
mob_name = "mummy"
-- CMI stuff
-- Track last cause of damage for cmi.notify_die
last_damage_cause = { type = "unknown" },
_cmi_is_mob = true,
description = S("Mummy"),
} }
-- Returns true if a mummy spawner entity was found at pos.
-- If self is provided, this object does not count.
local function check_if_mummy_spawner_entity_exists(pos, self)
local ents = minetest.get_objects_inside_radius(pos, 0.5)
for e=1, #ents do
if (not self) or (ents[e] ~= ents[e]) then
local lua = ents[e]:get_luaentity()
if lua then
if lua.name == "tsm_pyramids:mummy_spawner" then
-- entity found
return true
end
end
end
end
return false
end
local spawner_DEF = { local spawner_DEF = {
hp_max = 1, hp_max = 1,
physical = true, physical = false,
collisionbox = {0,0,0,0,0,0}, pointable = false,
visual = "mesh", visual = "mesh",
visual_size = {x=3.3,y=3.3}, visual_size = {x=3.3,y=3.3},
mesh = mummy_mesh, mesh = mummy_mesh,
@ -104,10 +127,16 @@ local spawner_DEF = {
makes_footstep_sound = false, makes_footstep_sound = false,
timer = 0, timer = 0,
automatic_rotate = math.pi * 2.9, automatic_rotate = math.pi * 2.9,
m_name = "dummy"
} }
spawner_DEF.on_activate = function(self) spawner_DEF.on_activate = function(self)
local pos = self.object:get_pos()
local spos = vector.new(pos.x, pos.y + spawner_entity_offset, pos.z)
if check_if_mummy_spawner_entity_exists(spos, self) then
-- Remove possible duplicate entity
self.object:remove()
return
end
mummy_update_visuals_def(self) mummy_update_visuals_def(self)
self.object:set_velocity({x=0, y=0, z=0}) self.object:set_velocity({x=0, y=0, z=0})
self.object:set_acceleration({x=0, y=0, z=0}) self.object:set_acceleration({x=0, y=0, z=0})
@ -115,13 +144,18 @@ spawner_DEF.on_activate = function(self)
end end
-- Regularily check if entity is still inside spawner
spawner_DEF.on_step = function(self, dtime) spawner_DEF.on_step = function(self, dtime)
self.timer = self.timer + 0.01 self.timer = self.timer + dtime
local n = minetest.get_node_or_nil(self.object:get_pos()) local pos = self.object:get_pos()
if self.timer > 1 then pos.y = pos.y - spawner_entity_offset
local n = minetest.get_node_or_nil(pos)
if self.timer > 50 then
if n and n.name and n.name ~= "tsm_pyramids:spawner_mummy" then if n and n.name and n.name ~= "tsm_pyramids:spawner_mummy" then
self.object:remove() self.object:remove()
return
end end
self.timer = 0
end end
end end
@ -129,25 +163,33 @@ spawner_DEF.on_punch = function(self, hitter)
end end
MUMMY_DEF.on_activate = function(self) MUMMY_DEF.on_activate = function(self, staticdata, dtime_s)
if mod_cmi then
cmi.notify_activate(self, dtime_s)
end
mummy_update_visuals_def(self) mummy_update_visuals_def(self)
self.anim = get_animations() self.anim = get_animations()
self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, mummy_animation_speed, mummy_animation_blend) self.object:set_animation({x=self.anim.stand_START,y=self.anim.stand_END}, mummy_animation_speed, mummy_animation_blend)
self.npc_anim = ANIM_STAND self.npc_anim = ANIM_STAND
self.object:set_acceleration({x=0,y=-20,z=0})--20 self.object:set_acceleration({x=0,y=-20,z=0})--20
self.state = 1 self.state = 1
self.object:set_hp(mummy_hp)
self.object:set_armor_groups({fleshy=130}) self.object:set_armor_groups({fleshy=130})
end end
MUMMY_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir) MUMMY_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
if mod_cmi then
cmi.notify_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
end
self.attacker = puncher self.attacker = puncher
if damage and damage > 0 then
self.last_damage = {
type = "punch",
puncher = puncher,
}
end
if puncher ~= nil then if puncher ~= nil then
local sound = sound_hit minetest.sound_play(sound_hit, {pos = self.object:get_pos(), loop = false, max_hear_distance = 10, gain = 0.4}, true)
if self.object:get_hp() == 0 then sound = sound_dead end
minetest.sound_play(sound, {to_player = puncher:get_player_name(), loop = false, gain = 0.3})
if time_from_last_punch >= 0.45 then if time_from_last_punch >= 0.45 then
hit(self) hit(self)
self.direction = {x=self.object:get_velocity().x, y=self.object:get_velocity().y, z=self.object:get_velocity().z} self.direction = {x=self.object:get_velocity().x, y=self.object:get_velocity().y, z=self.object:get_velocity().z}
@ -160,16 +202,26 @@ MUMMY_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabili
end end
end end
end end
end
if self.object:get_hp() == 0 then MUMMY_DEF.on_death = function(self, killer)
local obj = minetest.add_item(self.object:get_pos(), mummy_drop.." "..math.random(0,3)) minetest.sound_play(sound_dead, {pos = self.object:get_pos(), max_hear_distance = 10 , gain = 0.3}, true)
-- Drop item on death
local count = math.random(0,3)
if count > 0 then
local pos = self.object:get_pos()
pos.y = pos.y + 1.0
minetest.add_item(pos, mummy_drop .. " " .. count)
end
if mod_cmi then
cmi.notify_die(self, self.last_damage)
end end
end end
local cnt1 = 0
local cnt2 = 0
MUMMY_DEF.on_step = function(self, dtime) MUMMY_DEF.on_step = function(self, dtime)
if mod_cmi then
cmi.notify_step(self, dtime)
end
self.timer = self.timer + 0.01 self.timer = self.timer + 0.01
self.turn_timer = self.turn_timer + 0.01 self.turn_timer = self.turn_timer + 0.01
self.jump_timer = self.jump_timer + 0.01 self.jump_timer = self.jump_timer + 0.01
@ -183,13 +235,11 @@ MUMMY_DEF.on_step = function(self, dtime)
self.time_passed = 0 self.time_passed = 0
end end
if self.object:get_hp() == 0 then -- Environment damage
minetest.sound_play(sound_dead, {pos = current_pos, max_hear_distance = 10 , gain = 0.3})
self.object:remove()
end
local def = minetest.registered_nodes[current_node.name] local def = minetest.registered_nodes[current_node.name]
local dps = def.damage_per_second local dps = def.damage_per_second
local dmg = 0 local dmg = 0
local dmg_node, dmg_pos
if dps ~= nil and dps > 0 then if dps ~= nil and dps > 0 then
dmg = dps dmg = dps
end end
@ -209,11 +259,25 @@ MUMMY_DEF.on_step = function(self, dtime)
self.envdmg_timer = self.envdmg_timer + dtime self.envdmg_timer = self.envdmg_timer + dtime
if dmg > 0 then if dmg > 0 then
if self.envdmg_timer >= 1 then if self.envdmg_timer >= 1 then
local new_hp = self.object:get_hp() - dmg
if new_hp <= 0 then
if self.on_death then
self.on_death(self)
end
self.object:remove()
return
else
self.envdmg_timer = 0 self.envdmg_timer = 0
self.object:set_hp(self.object:get_hp()-dmg) self.object:set_hp(new_hp)
self.last_damage = {
type = "environment",
pos = current_pos,
node = current_node,
}
hit(self) hit(self)
self.sound_timer = 0 self.sound_timer = 0
minetest.sound_play(sound_hit, {pos = current_pos, max_hear_distance = 10, gain = 0.3}) minetest.sound_play(sound_hit, {pos = current_pos, max_hear_distance = 10, gain = 0.4}, true)
end
end end
else else
self.time_passed = 0 self.time_passed = 0
@ -231,7 +295,7 @@ MUMMY_DEF.on_step = function(self, dtime)
--play sound --play sound
if self.sound_timer > math.random(5,35) then if self.sound_timer > math.random(5,35) then
minetest.sound_play(sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.2}) minetest.sound_play(sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.2}, true)
self.sound_timer = 0 self.sound_timer = 0
end end
@ -335,16 +399,29 @@ minetest.register_craftitem("tsm_pyramids:spawn_egg", {
liquids_pointable = false, liquids_pointable = false,
stack_max = 99, stack_max = 99,
on_place = function(itemstack, placer, pointed_thing) on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type == "node" then if pointed_thing.type ~= "node" then
minetest.add_entity(pointed_thing.above,"tsm_pyramids:mummy")
if not minetest.settings:get_bool("creative_mode") then itemstack:take_item() end
return itemstack return itemstack
end end
-- am I clicking on something with existing on_rightclick function?
local node = minetest.get_node(pointed_thing.under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
minetest.add_entity(pointed_thing.above,"tsm_pyramids:mummy")
if not minetest.settings:get_bool("creative_mode") then
itemstack:take_item()
end
return itemstack
end, end,
}) })
function tsm_pyramids.spawn_mummy (pos, number) -- Spawn a mummy at position
function tsm_pyramids.spawn_mummy_at(pos, number)
local node = minetest.get_node(pos) local node = minetest.get_node(pos)
if node.name ~= "air" then if node.name ~= "air" then
return return
@ -361,6 +438,20 @@ else
spawnersounds = default.node_sound_stone_defaults() spawnersounds = default.node_sound_stone_defaults()
end end
local spawn_mummy_spawner_entity = function(pos)
local spos = vector.new(pos.x, pos.y+spawner_entity_offset, pos.z)
minetest.add_entity(spos, "tsm_pyramids:mummy_spawner")
end
-- Respawn mummy spawner entity at pos if none exists
local respawn_mummy_spawner_entity = function(pos)
local spos = vector.new(pos.x, pos.y + spawner_entity_offset, pos.z)
if check_if_mummy_spawner_entity_exists(spos) then
return
end
spawn_mummy_spawner_entity(pos)
end
minetest.register_node("tsm_pyramids:spawner_mummy", { minetest.register_node("tsm_pyramids:spawner_mummy", {
description = S("Mummy Spawner"), description = S("Mummy Spawner"),
_doc_items_longdesc = S("A mummy spawner causes hostile mummies to appear in its vicinity as long it exists."), _doc_items_longdesc = S("A mummy spawner causes hostile mummies to appear in its vicinity as long it exists."),
@ -371,13 +462,15 @@ minetest.register_node("tsm_pyramids:spawner_mummy", {
groups = {cracky=1,level=1}, groups = {cracky=1,level=1},
drop = "", drop = "",
on_construct = function(pos) on_construct = function(pos)
pos.y = pos.y - 0.28 spawn_mummy_spawner_entity(pos)
minetest.add_entity(pos,"tsm_pyramids:mummy_spawner") end,
on_punch = function(pos)
respawn_mummy_spawner_entity(pos)
end, end,
on_destruct = function(pos) on_destruct = function(pos)
for _,obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do for _,obj in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
if not obj:is_player() then if obj ~= nil and not obj:is_player() then
if obj ~= nil and obj:get_luaentity().m_name == "dummy" then if obj:get_luaentity().name == "tsm_pyramids:mummy_spawner" then
obj:remove() obj:remove()
end end
end end
@ -385,35 +478,91 @@ minetest.register_node("tsm_pyramids:spawner_mummy", {
end, end,
sounds = spawnersounds, sounds = spawnersounds,
}) })
-- Neccessary in case the spawner entity got lost due to /clearobjects
minetest.register_lbm({
label = "Respawn mummy spawner entity",
name = "tsm_pyramids:respawn_mummy_spawner_entity",
nodenames = { "tsm_pyramids:spawner_mummy" },
run_at_every_load = true,
action = function(pos, node)
respawn_mummy_spawner_entity(pos)
end,
})
-- Attempt to spawn a mummy at a random appropriate position around pos.
-- Criteria:
-- * Must be close to pos
-- * Not in sunlight
-- * Must be air on top of a non-air block
-- * No more than 6 mummies in area
-- * Player must be near is player_near_required is true
function tsm_pyramids.attempt_mummy_spawn(pos, player_near_required)
local player_near = false
local mobs = 0
for _,obj in ipairs(minetest.get_objects_inside_radius(pos, spawner_check_range)) do
if obj:is_player() then
player_near = true
else
if obj:get_luaentity() and obj:get_luaentity().name == "tsm_pyramids:mummy" then
mobs = mobs + 1
end
end
end
if player_near or (not player_near_required) then
if mobs < spawner_max_mobs then
local offset = {x=5,y=2,z=5}
local nposses = minetest.find_nodes_in_area(vector.subtract(pos, offset), vector.add(pos,offset), "air")
local tries = math.min(6, #nposses)
for i=1, tries do
local r = math.random(1, #nposses)
local npos = nposses[r]
-- Check if mummy has 2 nodes of free space
local two_space = false
-- Check if mummy has something to walk on
local footing = false
-- Find the lowest node
for y=-1, -5, -1 do
npos.y = npos.y - 1
local below = minetest.get_node(npos)
if minetest.registered_items[below.name].liquidtype ~= "none" then
break
end
if below.name ~= "air" then
if y < -1 then
two_space = true
end
npos.y = npos.y + 1
footing = true
break
end
end
local light = minetest.get_node_light(npos, 0.5)
if not two_space then
local above = minetest.get_node({x=npos.x, y=npos.y+1, z=npos.z})
if above.name == "air" then
two_space = true
end
end
if footing and two_space and light < 15 then
tsm_pyramids.spawn_mummy_at(npos, 1)
break
else
table.remove(nposses, r)
end
end
end
end
end
if not minetest.settings:get_bool("only_peaceful_mobs") then if not minetest.settings:get_bool("only_peaceful_mobs") then
minetest.register_abm({ minetest.register_abm({
nodenames = {"tsm_pyramids:spawner_mummy"}, nodenames = {"tsm_pyramids:spawner_mummy"},
interval = 2.0, interval = 2.0,
chance = 20, chance = 20,
action = function(pos, node, active_object_count, active_object_count_wider) action = function(pos, node, active_object_count, active_object_count_wider)
local player_near = false tsm_pyramids.attempt_mummy_spawn(pos, true)
local mobs = 0 end,
for _,obj in ipairs(minetest.get_objects_inside_radius(pos, spawner_range)) do
if obj:is_player() then
player_near = true
else
if obj:get_luaentity() and obj:get_luaentity().mob_name == "mummy" then
mobs = mobs + 1
end
end
end
if player_near then
if mobs < spawner_max_mobs then
pos.x = pos.x+1
local p = minetest.find_node_near(pos, 5, {"air"})
local p2 = {x=pos.x, y=pos.y+1, z=pos.z}
local n2 = minetest.get_node(p2)
if n2.name == "air" then
tsm_pyramids.spawn_mummy(p, 1)
end
end
end
end
}) })
end end

View File

@ -5,7 +5,7 @@ local img = {
"ankh", "scarab", "cactus" "ankh", "scarab", "cactus"
} }
local desc = { local desc = {
S("Sandstone with Eye Engraving"), S("Sandstone with Man Engraving"), S("Sandstone with Sun Engraving"), S("Sandstone with Eye Engraving"), S("Sandstone with Human Engraving"), S("Sandstone with Sun Engraving"),
S("Desert Sandstone with Ankh Engraving"), S("Desert Sandstone with Scarab Engraving"), S("Desert Sandstone with Cactus Engraving") S("Desert Sandstone with Ankh Engraving"), S("Desert Sandstone with Scarab Engraving"), S("Desert Sandstone with Cactus Engraving")
} }
@ -34,12 +34,19 @@ for i=1, #img do
end end
local trap_on_timer = function(pos, elapsed) local trap_on_timer = function(pos, elapsed)
local objs = minetest.get_objects_inside_radius(pos, 2)
local n = minetest.get_node(pos) local n = minetest.get_node(pos)
if not (n and n.name) then
return true
end
-- Drop trap stone when player is nearby
local objs = minetest.get_objects_inside_radius(pos, 2)
for i, obj in pairs(objs) do for i, obj in pairs(objs) do
if obj:is_player() then if obj:is_player() then
if n and n.name then
if minetest.registered_nodes[n.name]._tsm_pyramids_crack and minetest.registered_nodes[n.name]._tsm_pyramids_crack < 2 then if minetest.registered_nodes[n.name]._tsm_pyramids_crack and minetest.registered_nodes[n.name]._tsm_pyramids_crack < 2 then
-- 70% chance to ignore player to make the time of falling less predictable
if math.random(1, 10) >= 3 then
return true
end
if n.name == "tsm_pyramids:trap" then if n.name == "tsm_pyramids:trap" then
minetest.set_node(pos, {name="tsm_pyramids:trap_2"}) minetest.set_node(pos, {name="tsm_pyramids:trap_2"})
minetest.check_for_falling(pos) minetest.check_for_falling(pos)
@ -51,14 +58,14 @@ local trap_on_timer = function(pos, elapsed)
end end
end end
end end
end
return true return true
end end
minetest.register_node("tsm_pyramids:trap", { local register_trap_stone = function(basename, desc_normal, desc_falling, base_tile, drop)
description = S("Cracked Sandstone Brick"), minetest.register_node("tsm_pyramids:"..basename, {
description = desc_normal,
_doc_items_longdesc = S("This brick is old, porous and unstable and is barely able to hold itself. One should be careful not to disturb it."), _doc_items_longdesc = S("This brick is old, porous and unstable and is barely able to hold itself. One should be careful not to disturb it."),
tiles = {"default_sandstone_brick.png^tsm_pyramids_crack.png"}, tiles = { base_tile .. "^tsm_pyramids_crack.png" },
is_ground_content = false, is_ground_content = false,
groups = {crumbly=3,cracky=3}, groups = {crumbly=3,cracky=3},
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
@ -67,60 +74,26 @@ minetest.register_node("tsm_pyramids:trap", {
end, end,
_tsm_pyramids_crack = 1, _tsm_pyramids_crack = 1,
on_timer = trap_on_timer, on_timer = trap_on_timer,
drop = { drop = drop,
items = { })
{ items = { "default:sand" }, rarity = 1 },
{ items = { "default:sand" }, rarity = 2 },
},
}
})
minetest.register_node("tsm_pyramids:trap_2", { minetest.register_node("tsm_pyramids:"..basename.."_2", {
description = S("Falling Cracked Sandstone Brick"), description = desc_falling,
_doc_items_longdesc = S("This old porous brick falls under its own weight."), _doc_items_longdesc = S("This old porous brick falls under its own weight."),
tiles = {"default_sandstone_brick.png^tsm_pyramids_crack2.png"}, tiles = { base_tile .. "^tsm_pyramids_crack2.png" },
is_ground_content = false, is_ground_content = false,
groups = {crumbly=3,cracky=3,falling_node=1,not_in_creative_inventory=1}, groups = {crumbly=3,cracky=3,falling_node=1,not_in_creative_inventory=1},
sounds = default.node_sound_stone_defaults(), sounds = default.node_sound_stone_defaults(),
drop = { drop = drop,
items = { })
{ items = { "default:sand" }, rarity = 1 }, end
{ items = { "default:sand" }, rarity = 2 },
},
}
})
minetest.register_node("tsm_pyramids:desert_trap", { register_trap_stone("trap",
description = S("Cracked Desert Sandstone Brick"), S("Cracked Sandstone Brick"), S("Falling Cracked Sandstone Brick"),
_doc_items_longdesc = S("This brick is old, porous and unstable and is barely able to hold itself. One should be careful not to disturb it."), "default_sandstone_brick.png",
tiles = {"default_desert_sandstone_brick.png^tsm_pyramids_crack.png"}, { items = { { items = { "default:sand" }, rarity = 1 }, { items = { "default:sand" }, rarity = 2 }, } })
is_ground_content = false, register_trap_stone("desert_trap",
groups = {crumbly=3,cracky=3}, S("Cracked Desert Sandstone Brick"), S("Falling Cracked Desert Sandstone Brick"),
sounds = default.node_sound_stone_defaults(), "default_desert_sandstone_brick.png",
on_construct = function(pos) { items = { { items = { "default:desert_sand" }, rarity = 1 }, { items = { "default:desert_sand" }, rarity = 2 }, } })
minetest.get_node_timer(pos):start(0.1)
end,
_tsm_pyramids_crack = 1,
on_timer = trap_on_timer,
drop = {
items = {
{ items = { "default:desert_sand" }, rarity = 1 },
{ items = { "default:desert_sand" }, rarity = 2 },
},
}
})
minetest.register_node("tsm_pyramids:desert_trap_2", {
description = S("Falling Cracked Desert Sandstone Brick"),
_doc_items_longdesc = S("This old porous brick falls under its own weight."),
tiles = {"default_desert_sandstone_brick.png^tsm_pyramids_crack2.png"},
is_ground_content = false,
groups = {crumbly=3,cracky=3,falling_node=1,not_in_creative_inventory=1},
sounds = default.node_sound_stone_defaults(),
drop = {
items = {
{ items = { "default:desert_sand" }, rarity = 1 },
{ items = { "default:desert_sand" }, rarity = 2 },
},
}
})

748
room.lua

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.