Compare commits

..

No commits in common. "main" and "desert_stone" have entirely different histories.

17 changed files with 755 additions and 1421 deletions

23
.gitattributes vendored
View File

@ -1,5 +1,22 @@
# Improve language detection of repo by ignoring x files.
*.x -linguist-detectable
# Auto detect text files and perform LF normalization # Auto detect text files and perform LF normalization
* text=auto * 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 Normal file
View File

@ -0,0 +1,215 @@
#################
## 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

View File

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

View File

@ -1,56 +1,41 @@
# minetest-mod-tsm_pyramids # Pyramids (with Treasurer support) [`tsm_pyramids`]
BUILDINGS of pyramids with treasures! * Version: 0.7
## Information
Constructions of pyramids with treasures! You can find them in deserts and sandstone deserts.
## 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
sandstone deserts. The pyramids are very rare and contain chests with stuff. sandstone deserts. The pyramids are very rare and contain chests with stuff.
Also there are mummies inside, which attack the player if found in their radius. Also there are mummies inside, which attack the player if found in their radius.
![screenshot.png](screenshot.png) ## Historic notes
This mod is a fork of the old `pyramids` mod by BlockMen and intended to be a direct
## Technical info
This mod must be named `tsm_pyramids` and is a forked improved version of wuzzy one,
that is a fork of the old `pyramids` mod by BlockMen and intended to be a direct
(but unofficial) successor of it. (but unofficial) successor of it.
We recommended to use the modernized `pyramids` mod at minenux or oldcoder continuation,
due to the low availability of the developer to solve problems and his inclination towards
the obsolescence of minetests and does not help to solve any problem. This mod fork
is fully compatible with any engine version from 0.4.16 to 5.9.0 version.
The mod will override the default chest and this fork specially will refill the chests
at every pyramid created. Each pyramid will have a special mob named mummy, and the blocks
used in the pyramids are only few used (those with pictures).
The mod will register alias if the older mod "pyramid" is detected.
The mod provides a command, `spawnpyramid` will created a new pyramid and it receives
an optional argumwent as room type, there are 3 rooms types. Such command requirest
the server privilegie to use it.
## Licensing ## Licensing
This program is free software. It comes without any warranty, to This program is free software. It comes without any warranty, to
the extent permitted by applicable law. the extent permitted by applicable law.
* Source code and textures ### Source code and textures
* [MIT License](https://mit-license.org/)
* (c) Copyright BlockMen (2013) * [MIT License](https://mit-license.org/)
* Mummy model * (c) Copyright BlockMen (2013)
* MIT License
* (c) Copyright Pavel\_S (2013) ### Mummy model
* Textures
* `tsm_pyramids_eye.png` by bas080, [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/) * MIT License
* `tsm_pyramids_men.png` by bas080, CC-BY-SA 3.0 * (c) Copyright Pavel\_S (2013)
* `tsm_pyramids_sun.png` by bas080, CC-BY-SA 3.0
* Sounds from ([freesound.org](https://freesound.org)): ### Textures
* `mummy.1.ogg` by Raventhornn, [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
* `mummy.2.ogg` by Raventhornn, CC0 * `tsm_pyramids_eye.png` by bas080, [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/)
* `mummy_hurt.1.ogg` by Under7dude, CC0 * `tsm_pyramids_men.png` by bas080, CC-BY-SA 3.0
* `mummy_death.1.ogg` by scorpion67890 (modified by Wuzzy), CC0 * `tsm_pyramids_sun.png` by bas080, CC-BY-SA 3.0
* All other: BlockMen (MIT License) * All other: BlockMen (MIT License)
### Sounds
The authors are ([freesound.org](https://freesound.org)):
* `mummy.1.ogg` by Raventhornn, [CC0](https://creativecommons.org/publicdomain/zero/1.0/)
* `mummy.2.ogg` by Raventhornn, CC0
* `mummy_hurt.1.ogg` by Under7dude, CC0
* `mummy_death.1.ogg` by scorpion67890 (modified by Wuzzy), CC0

17
TODO
View File

@ -1,17 +0,0 @@
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

View File

@ -1,7 +0,0 @@
default
tnt
farming
treasurer?
doc_items?
awards?
cmi?

View File

@ -1 +0,0 @@
BUILDINGS of pyramids with treasures! You can find them in deserts and sandstone deserts.

508
init.lua
View File

@ -1,160 +1,77 @@
local modpath = minetest.get_current_modname() or "tsm_pyramids" local S = minetest.get_translator("tsm_pyramids")
-- support for i18n
local S
-- Intllib or native translator
if minetest.get_translator ~= nil then
S = minetest.get_translator(modpath)
else
if minetest.get_modpath("intllib") then
dofile(minetest.get_modpath("intllib") .. "/init.lua")
if intllib.make_gettext_pair then
gettext, ngettext = intllib.make_gettext_pair() -- new gettext method
else
gettext = intllib.Getter() -- old text file method
end
S = gettext
else -- boilerplate function
S = function(str, ...)
local args = {...}
return str:gsub("@%d+", function(match) return args[tonumber(match:sub(2))] end)
end
end
end
-- 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 = 1
-- Maximun spawn height
local PYRA_MAX_Y = 1000
-- minetest 5.x check
local is_50 = minetest.has_feature("object_use_texture_alpha")
-- minetest 5.5 check
local is_54 = minetest.has_feature("use_texture_alpha_string_modes") or nil
-- get mapgen cos perlin noise must match mapgen choice and nodes
local mgname = minetest.get_mapgen_setting("mg_name") or "v7"
-- also perlin noise must be in sync for simplev7 mod
local mgsimp = minetest.get_modpath("simplev7") or nil
tsm_pyramids = {} tsm_pyramids = {}
tsm_pyramids.is_50 = is_50
tsm_pyramids.is_54 = is_54
tsm_pyramids.S = S
tsm_pyramids.perlin1 = nil -- perlin noise buffer, make it global cos we need to acess in 5.0 after load all the rest of mods
dofile(minetest.get_modpath(modpath).."/mummy.lua") dofile(minetest.get_modpath("tsm_pyramids").."/mummy.lua")
dofile(minetest.get_modpath(modpath).."/nodes.lua") dofile(minetest.get_modpath("tsm_pyramids").."/nodes.lua")
dofile(minetest.get_modpath(modpath).."/room.lua") 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 = {
normal = { {name="default:apple", max = 3},
{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},
}, {name="default:pick_diamond", max = 1},
desert_stone = { {name="default:papyrus", max = 9},
{name="default:mese_crystal", max = 4},
{name="default:gold_ingot", max = 10},
{name="default:pick_diamond", max = 1},
},
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.desert_sandstone, {name="farming:bread", max = 3}) table.insert(chest_stuff, {name="farming:bread", max = 3})
table.insert(chest_stuff.sandstone, {name="farming:bread", max = 4}) table.insert(chest_stuff, {name="farming:cotton", max = 8})
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.normal, {name="farming:apple", max = 8}) table.insert(chest_stuff, {name="farming:apple", max = 8})
table.insert(chest_stuff.normal, {name="farming:apple", max = 3}) table.insert(chest_stuff, {name="farming:apple", max = 3})
end end
if minetest.get_modpath("tnt") then if minetest.get_modpath("tnt") then
table.insert(chest_stuff.normal, {name="tnt:gunpowder", max = 6}) table.insert(chest_stuff, {name="tnt:gunpowder", max = 6})
table.insert(chest_stuff.desert_stone, {name="tnt:gunpowder", max = 6})
else else
table.insert(chest_stuff.normal, {name="farming:apple", max = 3}) table.insert(chest_stuff, {name="farming:apple", max = 3})
end end
function tsm_pyramids.fill_chest(pos, stype, flood_sand, treasure_chance) function tsm_pyramids.fill_chest(pos, stype, flood_sand)
local sand = "default:sand" minetest.after(2, function()
local n = minetest.get_node(pos) local sand = "default:sand"
local meta = minetest.get_meta(pos) if stype == "desert_sandstone" or stype == "desert_stone" then
if not treasure_chance then sand = "default:desert_sand"
treasure_chance = 100
end
if meta:get_string("tsm_pyramids:stype") == "desert_sandstone" or
meta:get_string("tsm_pyramids:stype") == "desert_stone" or
stype == "desert_sandstone" or stype == "desert_stone" then
sand = "default:desert_sand"
end
local treasure_added = false
if n and n.name and n.name == "default:chest" then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("main", 8*4)
local stacks = {}
-- Fill with sand in sand-flooded pyramids
if meta:get_int("tsm_pyramids:sanded") == 1 or flood_sand then
table.insert(stacks, {name=sand, count = math.random(1,32)})
end end
-- Add treasures local n = minetest.get_node(pos)
if math.random(1,100) <= treasure_chance then if n and n.name and n.name == "default:chest" then
if minetest.get_modpath("treasurer") ~= nil then local meta = minetest.get_meta(pos)
stacks = treasurer.select_random_treasures(3,1,5,{"minetool", "food", "crafting_component"}) local inv = meta:get_inventory()
else inv:set_size("main", 8*4)
for i=0,2,1 do local stacks = {}
local stuff = chest_stuff.normal[math.random(1,#chest_stuff.normal)] -- Fill with sand in sand-flooded pyramids
table.insert(stacks, {name=stuff.name, count = math.random(1,stuff.max)}) if flood_sand then
end table.insert(stacks, {name=sand, count = math.random(1,32)})
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 -- Add treasures
for s=1,#stacks do if math.random(1,10) >= 7 then
if not inv:contains_item("main", stacks[s]) then if minetest.get_modpath("treasurer") ~= nil then
inv:set_stack("main", math.random(1,32), stacks[s]) stacks = treasurer.select_random_treasures(3,7,9,{"minetool", "food", "crafting_component"})
else
for i=0,2,1 do
local stuff = chest_stuff[math.random(1,#chest_stuff)]
table.insert(stacks, {name=stuff.name, count = math.random(1,stuff.max)})
end
end
end end
for s=1,#stacks do
if not inv:contains_item("main", stacks[s]) then
inv:set_stack("main", math.random(1,32), stacks[s])
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 if not minetest.settings:get_bool("only_peaceful_mobs") then tsm_pyramids.spawn_mummy(vector.add(pos, mummy_offset),2) end
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)
@ -182,124 +99,82 @@ local function make_foundation_part(pos, set_to_stone)
end end
end end
local function make_entrance(pos, rot, brick, sand, flood_sand) local function make_entrance(pos, brick, sand, flood_sand)
local roffset_arr = { local gang = {x=pos.x+10,y=pos.y, z=pos.z}
{ 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 ie=0,6,1 do for iz=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
-- dig hallway if flood_sand and sand ~= "ignore" and iy <= sand_height and iz >= 3 then
local way_dir = vector.add(vector.add(way, {x=0,y=iy,z=0}), vector.multiply(roffset, ie)) minetest.set_node({x=gang.x+1,y=gang.y+iy,z=gang.z+iz}, {name=sand})
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(way_dir) minetest.remove_node({x=gang.x+1,y=gang.y+iy,z=gang.z+iz})
end end
-- build decoration above entrance if iz >=3 and iy == 3 then
if ie == 3 and iy == 3 then minetest.set_node({x=gang.x,y=gang.y+iy+1,z=gang.z+iz}, {name=brick})
local deco = {x=way_dir.x, y=way_dir.y+1,z=way_dir.z} minetest.set_node({x=gang.x+1,y=gang.y+iy+1,z=gang.z+iz}, {name=brick})
minetest.set_node(deco, {name=brick}) minetest.set_node({x=gang.x+2,y=gang.y+iy+1,z=gang.z+iz}, {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 end
end end
end end
end end
local wa_bulk_set_node
if not minetest.bulk_set_node then
wa_bulk_set_node = function(poslist, nodename)
for _, pos in ipairs(poslist) do
minetest.set_node(pos, nodename)
end
end
else
wa_bulk_set_node = minetest.bulk_set_node
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,PYRA_Wh),1 do for iy=0,math.random(10,11),1 do
for ix=iy,PYRA_W-1-iy,1 do for ix=iy,22-iy,1 do
for iz=iy,PYRA_W-1-iy,1 do for iz=iy,22-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
wa_bulk_set_node(set_to_stone, {name=stone}) minetest.bulk_set_node(set_to_stone , {name=stone})
wa_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(bpos, brick, sandstone, stone, sand) make_pyramid(pos, brick, sandstone, stone, sand)
local rot = math.random(0, 3)
-- Build room -- Build room
local ok, msg, flood_sand = tsm_pyramids.make_room(bpos, ptype, room_id, rot) local ok, msg, flood_sand = tsm_pyramids.make_room(pos, ptype, room_id)
-- Place mummy spawner -- Place mummy spawner
local r = math.random(1,3) local r = math.random(1,3)
-- 4 possible spawner positions if r == 1 then
local spawner_posses = {
-- front -- front
{{x=bpos.x+PYRA_Wh,y=bpos.y+2, z=bpos.z+5}, {x=0, y=0, z=2}}, add_spawner({x=pos.x+11,y=pos.y+2, z=pos.z+17}, {x=0, y=0, z=-2})
-- left elseif r == 2 then
{{x=bpos.x+PYRA_Wm-5,y=bpos.y+2, z=bpos.z+PYRA_Wh}, {x=-2, y=0, z=0}},
-- back
{{x=bpos.x+PYRA_Wh,y=bpos.y+2, z=bpos.z+PYRA_W-5}, {x=0, y=0, z=-2}},
-- right -- right
{{x=bpos.x+5,y=bpos.y+2, z=bpos.z+PYRA_Wh}, {x=2, y=0, z=0}}, add_spawner({x=pos.x+17,y=pos.y+2, z=pos.z+11}, {x=-2, y=0, z=0})
} else
-- Delete the spawner position in which the entrance will be placed -- left
table.remove(spawner_posses, (rot % 4) + 1) add_spawner({x=pos.x+5,y=pos.y+2, z=pos.z+11}, {x=2, y=0, z=0})
add_spawner(spawner_posses[r][1], spawner_posses[r][2]) end
-- Build entrance -- Build entrance
make_entrance(bpos, rot, brick, sand, flood_sand) make_entrance({x=pos.x,y=pos.y, z=pos.z}, brick, sand, flood_sand)
-- Done -- Done
minetest.log("action", "[tsm_pyramids] Created pyramid at "..minetest.pos_to_string(bpos)..".") minetest.log("action", "Created pyramid at ("..pos.x..","..pos.y..","..pos.z..")")
return ok, msg return ok, msg
end end
local perl1 -- perlin noise / it depends of the mapgen, upstream do not set property local perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} -- Values should match minetest mapgen V6 desert noise.
local perlin1
if mgname == "v6" then perl1 = {SEED1 = 9130, OCTA1 = 3, PERS1 = 0.5, SCAL1 = 250} end -- Values should match minetest mapgen V6 desert noise.
if mgname == "v7p" then perl1 = {SEED1 = 9130, OCTA1 = 1, PERS1 = 0.5, SCAL1 = 25} end -- The multicraft v7plus desert noise are not knowwed.
if mgname == "v7" then perl1 = {SEED1 = 9130, OCTA1 = 1, PERS1 = 0.5, SCAL1 = 25} end -- Values should match minetest mapgen V7 desert noise.
if mgsimp ~= nil then perl1 = {SEED1 = 5349, OCTA1 = 3, PERS1 = 0.7, SCAL1 = 500} end -- must match to find some desert sand
-- get_perlin can only call it after the environment is created so wrap code for older engines into minetest.after(0, ...) and only call it once
if tsm_pyramids.is_50 then
tsm_pyramids.perlin1 = minetest.get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
else
tsm_pyramids.perlin1 = PerlinNoise(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
end
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)
@ -309,181 +184,95 @@ local function hlp_fnct(pos, name)
return false return false
end end
end end
local function ground(pos, old) local function ground(pos, old)
local p2 = table.copy(pos) local p2 = 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 {x=old.x, y=p2.y, z=old.z} return p2
else else
return old return old
end end
end end
-- Select the recommended type of pyramid to use, based on the environment.
-- One of sandstone, desert sandstone, desert stone.
local select_pyramid_type = function(minp, maxp)
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 p2
local psand = {}
local sand
local cnt = 0
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
cnt = 0
local sand_cnt = 0
sand = sands[s]
psand[s] = minetest.find_node_near(mpos, 25, sand)
while cnt < 5 do
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)}
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 sand_cnt > sand_cnt_max then
sand_cnt_max = sand_cnt
sand_cnt_max_id = s
p2 = psand[s]
end
end
end
-- Select the material type by the most prominent node type
-- E.g. if desert sand is most prominent, we place a desert sandstone pyramid
if sand_cnt_max_id then
sand = sands[sand_cnt_max_id]
else
sand = nil
p2 = nil
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) minetest.register_on_generated(function(minp, maxp, seed)
if maxp.y < PYRA_MIN_Y or maxp.y > PYRA_MAX_Y then return end if maxp.y < 0 then return end
-- TODO: Use Minetests pseudo-random tools
math.randomseed(seed) math.randomseed(seed)
if not perlin1 then
--[[ Make sure the pyramid doesn't bleed outside of maxp, perlin1 = minetest.get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
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 than 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 = nil
if not tsm_pyramids.perlin1 or tsm_pyramids.perlin1 == nil then
if tsm_pyramids.is_50 then
tsm_pyramids.perlin1 = minetest.get_perlin(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
noise1 = tsm_pyramids.perlin1:get_2d({x=minp.x,y=minp.y})
else
tsm_pyramids.perlin1 = PerlinNoise(perl1.SEED1, perl1.OCTA1, perl1.PERS1, perl1.SCAL1)
noise1 = tsm_pyramids.perlin1:get2d({x=minp.x,y=minp.y})
end
end
if not tsm_pyramids.perlin1 or tsm_pyramids.perlin1 == nil or not noise1 or noise1 == nil then
return
end end
local noise1 = perlin1:get_2d({x=minp.x,y=minp.y})--,z=minp.z})
if noise1 > 0.25 or noise1 < -0.26 then if noise1 > 0.25 or noise1 < -0.26 then
-- Need a bit of luck to place a pyramid local mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
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
end
local sand, p2
sand, p2 = select_pyramid_type(minp, maxp)
if p2 == nil then local sands = {"default:sand", "default:desert_sand", "default:desert_stone"}
minetest.log("verbose", "[tsm_pyramids] Pyramid not placed, no suitable surface. minp="..minetest.pos_to_string(minp)) local p2
return local psand = {}
end local sand
if p2.y < PYRA_MIN_Y or p2.y > PYRA_MAX_Y then local cnt = 0
minetest.log("info", "[tsm_pyramids] Pyramid not placed, too deep or too high. p2="..minetest.pos_to_string(p2)) local cnt_min = 100
return for s=1, #sands do
end cnt = 0
-- Now sink the pyramid until each corner of it is no longer floating in mid-air sand = sands[s]
p2 = limit(p2, maxp) psand[s] = minetest.find_node_near(mpos, 25, sand)
local oposses = { while psand == nil and cnt < 5 do
{x=p2.x,y=p2.y-1,z=p2.z}, cnt = cnt+1
{x=p2.x+PYRA_Wm,y=p2.y-1,z=p2.z+PYRA_Wm}, mpos = {x=math.random(minp.x,maxp.x), y=math.random(minp.y,maxp.y), z=math.random(minp.z,maxp.z)}
{x=p2.x+PYRA_Wm,y=p2.y-1,z=p2.z}, psand[s] = minetest.find_node_near(mpos, 25, sand)
{x=p2.x,y=p2.y-1,z=p2.z+PYRA_Wm}, end
} if psand[s] ~= nil then
for o=1, #oposses do if cnt < cnt_min then
local opos = oposses[o] cnt_min = cnt
local n = minetest.get_node_or_nil(opos) p2 = psand[s]
if n and n.name and n.name == "air" then end
local old = table.copy(p2)
p2 = ground(opos, p2)
end end
end end
-- Random bonus sinking if p2 == nil then return end
p2.y = math.max(p2.y - math.random(0,3), PYRA_MIN_Y) if p2.y < 0 then return end
-- Bad luck, we have hit the chunk border! local off = 0
if p2.y < minp.y then local opos1 = {x=p2.x+22,y=p2.y-1,z=p2.z+22}
minetest.log("info", "[tsm_pyramids] Pyramid not placed, sunken too much. p2="..minetest.pos_to_string(p2)) local opos2 = {x=p2.x+22,y=p2.y-1,z=p2.z}
local opos3 = {x=p2.x,y=p2.y-1,z=p2.z+22}
local opos1_n = minetest.get_node_or_nil(opos1)
local opos2_n = minetest.get_node_or_nil(opos2)
local opos3_n = minetest.get_node_or_nil(opos3)
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 return
end end
-- Make sure the pyramid is not near a "killer" node, like water if math.random(0,10) > 7 then
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 return
end 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
make(p2, "default:desert_sandstone_brick", "default:desert_sandstone", "default:desert_stone", "default:desert_sand", "desert_sandstone") minetest.after(0.8, 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
make(p2, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone") minetest.after(0.8, make, p2, "default:sandstonebrick", "default:sandstone", "default:sandstone", "default:sand", "sandstone")
else else
-- Desert stone pyramid -- Desert stone pyramid
make(p2, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "ignore", "desert_stone") minetest.after(0.8, make, p2, "default:desert_stonebrick", "default:desert_stone_block", "default:desert_stone", "default:desert_sand", "desert_stone")
end end
end end
end) end)
@ -497,6 +286,9 @@ 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", {
@ -517,7 +309,7 @@ minetest.register_chatcommand("spawnpyramid", {
room_id = r room_id = r
end end
local ok, msg local ok, msg
pos = vector.add(pos, {x=-PYRA_Wh, y=-1, z=0}) pos = vector.add(pos, {x=-11, 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,11 +6,10 @@ 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 Human Engraving= Sandstone with Man 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.=
@ -20,6 +19,6 @@ This old porous brick falls under its own weight.=
No more mummies!= No more mummies!=
Destroy a mummy spawner by digging.= Destroy a mummy spawner by digging.=
Generate a pyramid= Generate a pyramid=
[<room_type>]= [<room_type>]
Pyramid generated at @1.= Pyramid generated at @1.
Incorrect room type ID: @1= Incorrect room type ID: @1

View File

@ -6,11 +6,10 @@ 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 Human Engraving=Sandstein mit Menschengravur Sandstone with Man Engraving=Sandstein mit Manngravur
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,5 +1,4 @@
name = tsm_pyramids name = tsm_pyramids
description = BUILDINGS of 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, cmi optional_depends = farming, tnt, treasurer, doc_items, awards
min_minetest_version = 0.4.16

385
mummy.lua
View File

@ -1,6 +1,4 @@
local S = tsm_pyramids.S 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
@ -14,13 +12,11 @@ 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_check_range = 17 local spawner_range = 17
local spawner_max_mobs = 6 local spawner_max_mobs = 6
local function get_animations() local function get_animations()
@ -51,11 +47,15 @@ local ANIM_WALK_MINE = 5
local ANIM_MINE = 6 local ANIM_MINE = 6
local function hit(self) local function hit(self)
self.object:set_texture_mod("^tsm_pyramids_hit.png") local prop = {
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 ~= nil and self.object ~= nil then if self.object ~= nil then
self.object:set_texture_mod("") self.object:set_properties(prop)
end end
end, self) end, self)
end end
@ -63,22 +63,20 @@ 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 = {
initial_properties = { physical = true,
hp_max = mummy_hp, collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.9, 0.4},
physical = true, visual = "mesh",
collisionbox = {-0.4, -0.01, -0.4, 0.4, 1.9, 0.4}, visual_size = {x=8,y=8},
visual = "mesh", mesh = mummy_mesh,
visual_size = {x=8,y=8}, textures = mummy_texture,
mesh = mummy_mesh, makes_footstep_sound = true,
textures = mummy_texture,
makes_footstep_sound = true,
},
npc_anim = 0, npc_anim = 0,
timer = 0, timer = 0,
turn_timer = 0, turn_timer = 0,
@ -92,74 +90,24 @@ 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, upstream pointed that is not count but must be checked if are the same
local function check_if_mummy_spawner_entity_exists(pos, self)
local ents = minetest.get_objects_inside_radius(pos, 0.5)
if not ents then return false end
for e=1, #ents do
local objent = ents[e]
local lua = objent:get_luaentity()
if self then
if objent ~= self.object then
local sobj = self.object:get_luaentity()
if sobj.name then
if sobj.name == "tsm_pyramids:mummy_spawner" then return true end
if sobj.name == "mummy_spawner" then return true end
else
return false -- BUG could be a mob spawner but cannot get the name?
end
else
return false -- same object, is duplicate cos "self" is provided!
end
else
if type(lua) ~= "userdata" then -- not a player could be a spawner or a node
if lua then
-- entity found
if lua.name then
if lua.name == "tsm_pyramids:mummy_spawner" then return true end
if lua.name == "mummy_spawner" then return true end
end
end
else
return false
end
end
end
return false
end
local spawner_DEF = { local spawner_DEF = {
initial_properties = { 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, textures = mummy_texture,
textures = mummy_texture, makes_footstep_sound = false,
makes_footstep_sound = false,
automatic_rotate = math.pi * 2.9,
},
timer = 0, timer = 0,
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})
@ -167,18 +115,13 @@ 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 + dtime self.timer = self.timer + 0.01
local pos = self.object:get_pos() local n = minetest.get_node_or_nil(self.object:get_pos())
pos.y = pos.y - spawner_entity_offset if self.timer > 1 then
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
@ -186,33 +129,25 @@ spawner_DEF.on_punch = function(self, hitter)
end end
MUMMY_DEF.on_activate = function(self, staticdata, dtime_s) MUMMY_DEF.on_activate = function(self)
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, damage) MUMMY_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
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
minetest.sound_play(sound_hit, {pos = self.object:get_pos(), loop = false, max_hear_distance = 10, gain = 0.4}, true) local sound = sound_hit
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}
@ -225,26 +160,16 @@ MUMMY_DEF.on_punch = function(self, puncher, time_from_last_punch, tool_capabili
end end
end end
end end
if self.object:get_hp() == 0 then
local obj = minetest.add_item(self.object:get_pos(), mummy_drop.." "..math.random(0,3))
end
end end
MUMMY_DEF.on_death = function(self, killer) local cnt1 = 0
minetest.sound_play(sound_dead, {pos = self.object:get_pos(), max_hear_distance = 10 , gain = 0.3}, true) local cnt2 = 0
-- 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
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
@ -258,11 +183,13 @@ MUMMY_DEF.on_step = function(self, dtime)
self.time_passed = 0 self.time_passed = 0
end end
-- Environment damage if self.object:get_hp() == 0 then
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
@ -282,25 +209,11 @@ 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 self.envdmg_timer = 0
if new_hp <= 0 then self.object:set_hp(self.object:get_hp()-dmg)
if self.on_death then hit(self)
self.on_death(self) self.sound_timer = 0
end minetest.sound_play(sound_hit, {pos = current_pos, max_hear_distance = 10, gain = 0.3})
self.object:remove()
return
else
self.envdmg_timer = 0
self.object:set_hp(new_hp)
self.last_damage = {
type = "environment",
pos = current_pos,
node = current_node,
}
hit(self)
self.sound_timer = 0
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
@ -318,7 +231,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}, true) minetest.sound_play(sound_normal, {pos = current_pos, max_hear_distance = 10, gain = 0.2})
self.sound_timer = 0 self.sound_timer = 0
end end
@ -339,23 +252,20 @@ MUMMY_DEF.on_step = function(self, dtime)
if self.state == 1 then if self.state == 1 then
self.yawwer = true self.yawwer = true
self.attacker = "" self.attacker = ""
local pos_obj = self.object:get_pos() for _,object in ipairs(minetest.get_objects_inside_radius(self.object:get_pos(), 4)) do
if pos_obj then if object:is_player() then
for _,object in ipairs(minetest.get_objects_inside_radius(pos_obj, 4)) do self.yawwer = false
if object:is_player() then local NPC = self.object:get_pos()
self.yawwer = false local PLAYER = object:get_pos()
local NPC = self.object:get_pos() self.vec = {x=PLAYER.x-NPC.x, y=PLAYER.y-NPC.y, z=PLAYER.z-NPC.z}
local PLAYER = object:get_pos() self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2
self.vec = {x=PLAYER.x-NPC.x, y=PLAYER.y-NPC.y, z=PLAYER.z-NPC.z} if PLAYER.x > NPC.x then
self.yaw = math.atan(self.vec.z/self.vec.x)+math.pi^2 self.yaw = self.yaw + math.pi
if PLAYER.x > NPC.x then end
self.yaw = self.yaw + math.pi self.yaw = self.yaw - 2
end self.object:set_yaw(self.yaw)
self.yaw = self.yaw - 2 self.attacker = object
self.object:set_yaw(self.yaw) end
self.attacker = object
end
end
end end
if self.attacker == "" and self.turn_timer > math.random(1,4) then if self.attacker == "" and self.turn_timer > math.random(1,4) then
@ -364,8 +274,7 @@ MUMMY_DEF.on_step = function(self, dtime)
self.turn_timer = 0 self.turn_timer = 0
self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)} self.direction = {x = math.sin(self.yaw)*-1, y = -20, z = math.cos(self.yaw)}
end end
local old_vel = self.object:get_velocity() self.object:set_velocity({x=0,y=self.object:get_velocity().y,z=0})
self.object:set_velocity({x=0,y=old_vel and old_vel.y or 0,z=0})
if self.npc_anim ~= ANIM_STAND then if self.npc_anim ~= ANIM_STAND then
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)
@ -380,12 +289,7 @@ MUMMY_DEF.on_step = function(self, dtime)
if self.state == 2 then if self.state == 2 then
if self.direction ~= nil then if self.direction ~= nil then
local old_vel = self.object:get_velocity() self.object:set_velocity({x=self.direction.x*mummy_chillaxin_speed,y=self.object:get_velocity().y,z=self.direction.z*mummy_chillaxin_speed})
self.object:set_velocity({
x=self.direction.x*mummy_chillaxin_speed,
y=old_vel and old_vel.y or 0,
z=self.direction.z*mummy_chillaxin_speed,
})
end end
if self.turn_timer > math.random(1,4) and not self.attacker then if self.turn_timer > math.random(1,4) and not self.attacker then
self.yaw = 360 * math.random() self.yaw = 360 * math.random()
@ -431,29 +335,16 @@ 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,
}) })
-- Spawn a mummy at position function tsm_pyramids.spawn_mummy (pos, number)
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
@ -470,20 +361,6 @@ 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."),
@ -494,15 +371,13 @@ 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)
spawn_mummy_spawner_entity(pos) pos.y = pos.y - 0.28
end, minetest.add_entity(pos,"tsm_pyramids:mummy_spawner")
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, 0.5)) do for _,obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
if obj ~= nil and not obj:is_player() then if not obj:is_player() then
if obj:get_luaentity().name == "tsm_pyramids:mummy_spawner" then if obj ~= nil and obj:get_luaentity().m_name == "dummy" then
obj:remove() obj:remove()
end end
end end
@ -510,91 +385,35 @@ 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)
tsm_pyramids.attempt_mummy_spawn(pos, true) local player_near = false
end, local mobs = 0
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

158
nodes.lua
View File

@ -1,11 +1,11 @@
local S = tsm_pyramids.S local S = minetest.get_translator("tsm_pyramids")
local img = { local img = {
"eye", "men", "sun", "eye", "men", "sun",
"ankh", "scarab", "cactus" "ankh", "scarab", "cactus"
} }
local desc = { local desc = {
S("Sandstone with Eye Engraving"), S("Sandstone with Human Engraving"), S("Sandstone with Sun Engraving"), S("Sandstone with Eye Engraving"), S("Sandstone with Man 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,93 +34,93 @@ for i=1, #img do
end end
local trap_on_timer = function(pos, elapsed) local trap_on_timer = function(pos, elapsed)
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) local objs = minetest.get_objects_inside_radius(pos, 2)
local n = minetest.get_node(pos)
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 minetest.registered_nodes[n.name]._tsm_pyramids_crack and minetest.registered_nodes[n.name]._tsm_pyramids_crack < 2 then if n and n.name then
-- 70% chance to ignore player to make the time of falling less predictable if minetest.registered_nodes[n.name]._tsm_pyramids_crack and minetest.registered_nodes[n.name]._tsm_pyramids_crack < 2 then
if math.random(1, 10) >= 3 then if n.name == "tsm_pyramids:trap" then
minetest.set_node(pos, {name="tsm_pyramids:trap_2"})
minetest.check_for_falling(pos)
elseif n.name == "tsm_pyramids:desert_trap" then
minetest.set_node(pos, {name="tsm_pyramids:desert_trap_2"})
minetest.check_for_falling(pos)
end
return true return true
end end
if n.name == "tsm_pyramids:trap" then
minetest.set_node(pos, {name="tsm_pyramids:trap_2"})
if minetest.check_for_falling ~= nil then minetest.check_for_falling(pos) else nodeupdate(pos) end
elseif n.name == "tsm_pyramids:desert_trap" then
minetest.set_node(pos, {name="tsm_pyramids:desert_trap_2"})
if minetest.check_for_falling ~= nil then minetest.check_for_falling(pos) else nodeupdate(pos) end
end
return true
end end
end end
end end
return true return true
end end
local register_trap_stone = function(basename, desc_normal, desc_falling, base_tile, drop) minetest.register_node("tsm_pyramids:trap", {
minetest.register_node("tsm_pyramids:"..basename, { description = S("Cracked Sandstone Brick"),
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(), on_construct = function(pos)
on_construct = function(pos) minetest.get_node_timer(pos):start(0.1)
minetest.get_node_timer(pos):start(0.1) 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:"..basename.."_2", { },
description = desc_falling, }
_doc_items_longdesc = S("This old porous brick falls under its own weight."),
tiles = { base_tile .. "^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 = drop,
})
end
register_trap_stone("trap",
S("Cracked Sandstone Brick"), S("Falling Cracked Sandstone Brick"),
"default_sandstone_brick.png",
{ items = { { items = { "default:sand" }, rarity = 1 }, { items = { "default:sand" }, rarity = 2 }, } })
register_trap_stone("desert_trap",
S("Cracked Desert Sandstone Brick"), S("Falling Cracked Desert Sandstone Brick"),
"default_desert_sandstone_brick.png",
{ items = { { items = { "default:desert_sand" }, rarity = 1 }, { items = { "default:desert_sand" }, rarity = 2 }, } })
local chest = minetest.registered_nodes["default:chest"]
local def_on_rightclick = chest.on_rightclick
local def_on_timer = chest.on_timer
minetest.override_item(
"default:chest",
{
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if minetest.get_meta(pos):get_string("tsm_pyramids:stype") ~= "" then
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
timer:start(1800) -- remplissages des coffres toutes les 30 minutes
end
end
return def_on_rightclick(pos, node, clicker, itemstack, pointed_thing)
end,
on_timer = function(pos, elapsed)
if minetest.get_meta(pos):get_string("tsm_pyramids:stype") ~= "" then
minetest.log("action", "[DEBUG] chest refilling")
tsm_pyramids.fill_chest(pos)
return false
else
if def_on_timer then return def_on_timer(pos, elapsed) else return false end
end
end,
}) })
minetest.register_alias("tsm_pyramids:chest", "default:chest") minetest.register_node("tsm_pyramids:trap_2", {
description = S("Falling Cracked Sandstone Brick"),
_doc_items_longdesc = S("This old porous brick falls under its own weight."),
tiles = {"default_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:sand" }, rarity = 1 },
{ items = { "default:sand" }, rarity = 2 },
},
}
})
minetest.register_node("tsm_pyramids:desert_trap", {
description = S("Cracked Desert 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."),
tiles = {"default_desert_sandstone_brick.png^tsm_pyramids_crack.png"},
is_ground_content = false,
groups = {crumbly=3,cracky=3},
sounds = default.node_sound_stone_defaults(),
on_construct = function(pos)
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 },
},
}
})

772
room.lua

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.