Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
Diablosxm | a6d1f55f0a | |
Jacob Lifshay | d16b530685 | |
Treer | ea677c5a1b | |
Treer | 21c7e2801d | |
JoeEnderman | 3470b1e22e | |
Treer | 3e809a811b | |
Treer | 6c6a182366 | |
JoeEnderman | 9c1fa2c843 | |
Treer | 957fdc887b | |
Treer | 7dc32f6bb8 | |
fluxionary | a8a6bb00c5 | |
fluxionary | 12ca98c25a | |
Treer | a03375c5a4 | |
Treer | d3f79e961b | |
Treer | d8e6a6aca3 |
|
@ -27,8 +27,12 @@ read_globals = {
|
|||
"stairsplus",
|
||||
"string.split",
|
||||
table = { fields = { "copy", "getn" } },
|
||||
"technic",
|
||||
"toolranks",
|
||||
"vector",
|
||||
"VoxelArea",
|
||||
"VoxelManip",
|
||||
"walls",
|
||||
xpanes = { fields = { "register_pane" } },
|
||||
}
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -16,6 +16,8 @@ right-click/used on the frame to activate it.
|
|||
|
||||
See portal_api.txt for how to create custom portals to your own realms.
|
||||
|
||||
Nether Portals can allow surface fast-travel.
|
||||
|
||||
This mod provides Nether basalts (natural, hewn, and chiseled) as nodes which
|
||||
require a player to journey to the magma ocean to obtain, so these can be used
|
||||
for gating progression through a game. For example, a portal to another realm
|
||||
|
@ -24,8 +26,7 @@ the nether first, or basalt might be a crafting ingredient required to reach
|
|||
a particular branch of the tech-tree.
|
||||
|
||||
Netherbrick tools are provided (pick, shovel, axe, & sword), see tools.lua
|
||||
|
||||
Nether Portals can allow surface fast-travel.
|
||||
The Nether pickaxe has a 10x bonus against wear when mining netherrack.
|
||||
|
||||
|
||||
## License of source code:
|
||||
|
@ -50,9 +51,11 @@ SOFTWARE.
|
|||
### [Public Domain Dedication (CC0 1.0)](https://creativecommons.org/publicdomain/zero/1.0/)
|
||||
|
||||
* `nether_portal_teleport.ogg` is a timing adjusted version of "teleport" by [outroelison](https://freesound.org/people/outroelison), used under CC0 1.0
|
||||
* `nether_rack_destroy.ogg` is from "Rock destroy" by [Bertsz](https://freesound.org/people/Bertsz/), used under CC0 1.0
|
||||
|
||||
### [Attribution 3.0 Unported (CC BY 3.0)](https://creativecommons.org/licenses/by/3.0/)
|
||||
|
||||
* `nether_lightstaff.ogg` is "Fire Burst" by [SilverIllusionist](https://freesound.org/people/SilverIllusionist/), 2019
|
||||
* `nether_portal_ambient.ogg` & `nether_portal_ambient.0.ogg` are extractions from "Deep Cinematic Rumble Stereo" by [Patrick Lieberkind](http://www.lieberkindvisuals.dk), used under CC BY 3.0
|
||||
* `nether_portal_extinguish.ogg` is an extraction from "Tight Laser Weapon Hit Scifi" by [damjancd](https://freesound.org/people/damjancd), used under CC BY 3.0
|
||||
* `nether_portal_ignite.ogg` is a derivative of "Flame Ignition" by [hykenfreak](https://freesound.org/people/hykenfreak), used under CC BY 3.0. "Nether Portal ignite" is licensed under CC BY 3.0 by Treer.
|
||||
|
@ -62,8 +65,11 @@ SOFTWARE.
|
|||
* `nether_book_`* (files starting with "nether_book"): Treer, 2019-2020
|
||||
* `nether_brick_deep.png`: Treer, 2021
|
||||
* `nether_fumarole.ogg`: Treer, 2020
|
||||
* `nether_geode.png`: Treer, 2021
|
||||
* `nether_geode_glass.png`: Treer, 2021
|
||||
* `nether_lava_bubble`* (files starting with "nether_lava_bubble"): Treer, 2020
|
||||
* `nether_lava_crust_animated.png`: Treer, 2019-2020
|
||||
* `nether_lightstaff.png`: Treer, 2021
|
||||
* `nether_particle_anim`* (files starting with "nether_particle_anim"): Treer, 2019
|
||||
* `nether_portal_ignition_failure.ogg`: Treer, 2019
|
||||
* `nether_smoke_puff.png`: Treer, 2020
|
||||
|
|
|
@ -7,3 +7,4 @@ loot?
|
|||
mesecons?
|
||||
moreblocks?
|
||||
climate_api?
|
||||
xpanes?
|
8
init.lua
8
init.lua
|
@ -144,7 +144,9 @@ if nether.NETHER_REALM_ENABLED then
|
|||
end
|
||||
end
|
||||
dofile(nether.path .. "/portal_examples.lua")
|
||||
|
||||
if minetest.get_modpath("technic") then
|
||||
dofile(nether.path .. "/nether-compressor-recipe.lua")
|
||||
end
|
||||
|
||||
-- Portals are ignited by right-clicking with a mese crystal fragment
|
||||
nether.register_portal_ignition_item(
|
||||
|
@ -312,7 +314,7 @@ The expedition parties have found no diamonds or gold, and after an experienced
|
|||
geodeSky.sky_data.base_color = nether.fogColor.geodes
|
||||
|
||||
climate_api.register_weather(
|
||||
"nether:nether",
|
||||
"nether:caverns",
|
||||
{ nether_biome = "nether" },
|
||||
{ ["climate_api:skybox"] = netherSky }
|
||||
)
|
||||
|
@ -345,4 +347,4 @@ minetest.register_on_dieplayer(
|
|||
)
|
||||
end
|
||||
end
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# textdomain: nether
|
||||
|
||||
# Translation FR by Louis Royer
|
||||
# Translation FR by Louis Royer and JoeEnderman
|
||||
|
||||
|
||||
### init.lua ###
|
||||
|
@ -15,57 +15,76 @@ Nether Portal=Portail du Nether
|
|||
|
||||
### mapgen_mantle.lua ###
|
||||
|
||||
, @1m above lava-sea level=
|
||||
, @1m below lava-sea level=
|
||||
, approaching y boundary of Nether=
|
||||
, @1m above lava-sea level=, @1m au-dessus du niveau de la mer de lave
|
||||
, @1m below lava-sea level=, @1m en-dessous du niveau de la mer de lave
|
||||
, approaching y boundary of Nether=, approchant de la limite y du Nether
|
||||
@1@2@3@4=
|
||||
Center/Mantle, but outside the caverns=
|
||||
Center/Mantle, inside cavern=
|
||||
Describes which region of the nether the player is in=
|
||||
Negative nether=
|
||||
Positive nether=
|
||||
Shell between negative nether and center region=
|
||||
Shell between positive nether and center region=
|
||||
The Overworld=
|
||||
Unknown player position=
|
||||
Center/Mantle, but outside the caverns=Centre/Manteau, mais à l'extérieur des cavernes
|
||||
Center/Mantle, inside cavern=Centre/Manteau, à l'intérieur d'une caverne
|
||||
Describes which region of the nether the player is in=Indique dans quelle région du Nether se trouve le joueur
|
||||
Negative nether=Nether négatif
|
||||
Positive nether=Nether positif
|
||||
Shell between negative nether and center region=Coquille entre le Nether négatif et la région centrale
|
||||
Shell between positive nether and center region=Coquille entre le Nether positif et la région centrale
|
||||
The Overworld=L'Overworld
|
||||
Unknown player position=Position du joueur inconnue
|
||||
[Perlin @1] =
|
||||
|
||||
### nodes.lua ###
|
||||
|
||||
A finely finished block of solid Nether Basalt.=
|
||||
A rough cut solid block of Nether Basalt.=
|
||||
A thin crust of cooled lava with liquid lava beneath=
|
||||
A vent in the earth emitting steam and gas=
|
||||
Can be repurposed to provide puffs of smoke in a chimney=
|
||||
Chiselled Basalt=
|
||||
A Deep Netherrack Wall=Un mur profond en Netherrack
|
||||
A Netherrack Wall=Un mur en Netherrack
|
||||
A finely finished block of solid Nether Basalt.=Un bloc fini de basalte du Nether solide.
|
||||
A rough cut solid block of Nether Basalt.=Un bloc solide de basalte du Nether taillé à la hache.
|
||||
A thin crust of cooled lava with liquid lava beneath=Une croûte fine de lave refroidie avec de la lave liquide en dessous
|
||||
A vent in the earth emitting steam and gas=Une fissure dans la terre émettant de la vapeur et du gaz
|
||||
Can be repurposed to provide puffs of smoke in a chimney=Peut être réutilisé pour produire des bouffées de fumée dans une cheminée
|
||||
Chiselled Basalt=Basalte sculpté
|
||||
|
||||
Columns of dark basalt found only in magma oceans deep within the Nether.=
|
||||
Columns of dark basalt found only in magma oceans deep within the Nether.=Colonnes de basalte noir que l'on trouve uniquement dans les océans de magma profonds du Nether.
|
||||
|
||||
Compressed Netherbrick=
|
||||
Cracked Nether Brick=
|
||||
Deep Glowstone=
|
||||
Deep Netherrack=
|
||||
Fumarolic Chimney=
|
||||
Fumarolic Chimney Corner=
|
||||
Fumarolic Chimney Slab=
|
||||
Compressed Netherbrick=Briques du Nether compressées
|
||||
Cracked Nether Brick=Briques du Nether craquelées
|
||||
Deep Glowstone=Pierre lumineuse profonde
|
||||
Deep Nether Brick=Briques du Nether profondes
|
||||
Deep Nether Slab=Dalle du Nether profonde
|
||||
Deep Nether Stair=Escalier du Nether profond
|
||||
Deep Netherrack=Netherrack profond
|
||||
Deep Netherrack Slab=Dalle de Netherrack profonde
|
||||
Deep Netherrack Stair=Escalier de Netherrack profond
|
||||
Fumarolic Chimney=Cheminée fumarolique
|
||||
Fumarolic Chimney Corner=Coin de cheminée fumarolique
|
||||
Fumarolic Chimney Slab=Dalle de cheminée fumarolique
|
||||
Glowstone=Pierre lumineuse
|
||||
Hewn Basalt=
|
||||
Hewn Basalt=Basalte taillé
|
||||
Inner Deep Nether Stair=Escalier intérieur du Nether profond
|
||||
Inner Nether Stair=Escalier intérieur du Nether
|
||||
Lava Crust=
|
||||
Lava Crust=Croûte de lave
|
||||
|
||||
Lava crust is strong enough to walk on, but still hot enough to inflict burns.=
|
||||
Lava crust is strong enough to walk on, but still hot enough to inflict burns.=La croûte de lave est assez solide pour marcher dessus, mais encore assez chaude pour causer des brûlures
|
||||
|
||||
Nether Basalt=
|
||||
Nether Basalt=Basalte du Nether
|
||||
Nether Beryl=Béryl du Nether
|
||||
Nether Berylite=Bérylite du Nether
|
||||
Nether Brick=Brique du Nether
|
||||
Nether Brick Fence=Barrière en briques du Nether
|
||||
Nether Brick Fence Rail=Rail de barrière en briques du Nether
|
||||
Nether Crystal Pane=Panneau de cristal du Nether
|
||||
Nether Slab=Dalle du Nether
|
||||
Nether Stair=Escalier du Nether
|
||||
|
||||
Nether geode crystal, found lining the interior walls of Nether geodes=Cristal de géode du Nether, trouvé le long des parois intérieures des géodes du Nether
|
||||
|
||||
Nether geode crystal. A crystalline structure with faint glow found inside large Nether geodes=Cristal de géode du Nether. Une structure cristalline avec une faible lueur trouvée à l'intérieur des grandes géodes du Nether.
|
||||
|
||||
Netherrack=Roche du Nether
|
||||
Netherrack from deep in the mantle=
|
||||
Netherrack stair=
|
||||
Netherrack from deep in the mantle=Roche du Nether provenant des profondeurs du manteau
|
||||
Netherrack Slab=Dalle du Nether
|
||||
Netherrack Stair=Escalier du Nether
|
||||
Nethersand=Sable du Nether
|
||||
Outer Deep Nether Stair=Escalier extérieur profond du Nether
|
||||
Outer Nether Stair=Escalier extérieur du Nether
|
||||
Portal=
|
||||
Portal=Portail
|
||||
|
||||
### portal_api.lua ###
|
||||
|
||||
|
@ -82,7 +101,7 @@ In all my travels, and time spent in the Great Libraries, I have encountered no
|
|||
|
||||
In all my travels, and time spent in the Great Libraries, I have encountered no shortage of legends surrounding preternatural doorways said to open into other worlds, yet only one can I confirm as being more than merely a story.=Après tous mes voyages, et le temps passé dans les Grandes Bibliothèques, je ne manque pas de légendes sur les portes surnaturelles qui, dit-on s’ouvrent vers d’autres mondes, mais seul une personne peut confirmer que ce sont plus que de simples histoires.
|
||||
|
||||
Mysterious forces prevented you from opening that portal. Please try another location=
|
||||
Mysterious forces prevented you from opening that portal. Please try another location=Des forces mystérieuses vous empêchent d'ouvrir ce portail. Veuillez essayer un autre emplacement.
|
||||
|
||||
Portal wormhole=Vortex du portail
|
||||
|
||||
|
@ -107,9 +126,16 @@ There is a floating land of hills and forests up there, over the edges of which
|
|||
|
||||
### tools.lua ###
|
||||
|
||||
Nether Axe=
|
||||
Nether Ingot=
|
||||
Nether Lump=
|
||||
Nether Pickaxe=
|
||||
Nether Shovel=
|
||||
Nether Sword=
|
||||
Nether Axe=Hache du Nether
|
||||
Nether Ingot=Lingot du Nether
|
||||
Nether Lump=Morceau du Nether
|
||||
Nether Pickaxe@nWell suited for mining netherrack=Pioche du Nether@nBien adaptée pour miner la roche du Nether
|
||||
Nether Shovel=Pelle du Nether
|
||||
Nether Sword=Épée du Nether
|
||||
|
||||
Nether staff of Eternal Light@nCreates glowstone from netherrack=Bâton du Nether de lumière éternelle@nCrée des blocs de pierre lumineuse à partir de roche du Nether
|
||||
|
||||
Nether staff of Light@nTemporarily transforms the netherrack into glowstone=Bâton du Nether de lumière@nTransforme temporairement la roche du Nether en blocs de pierre lumineuse
|
||||
|
||||
Uniquely suited for mining netherrack, with minimal wear when doing so. Blunts quickly on other materials.=Convient parfaitement pour miner la roche du Nether avec une usure minimale. S'émousse rapidement sur les autres matériaux.
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ Unknown player position=
|
|||
|
||||
### nodes.lua ###
|
||||
|
||||
A Deep Netherrack Wall=
|
||||
A Netherrack Wall=
|
||||
A finely finished block of solid Nether Basalt.=
|
||||
A rough cut solid block of Nether Basalt.=
|
||||
A thin crust of cooled lava with liquid lava beneath=
|
||||
|
@ -43,26 +45,43 @@ Columns of dark basalt found only in magma oceans deep within the Nether.=
|
|||
Compressed Netherbrick=
|
||||
Cracked Nether Brick=
|
||||
Deep Glowstone=
|
||||
Deep Nether Brick=
|
||||
Deep Nether Slab=
|
||||
Deep Nether Stair=
|
||||
Deep Netherrack=
|
||||
Deep Netherrack Slab=
|
||||
Deep Netherrack Stair=
|
||||
Fumarolic Chimney=
|
||||
Fumarolic Chimney Corner=
|
||||
Fumarolic Chimney Slab=
|
||||
Glowstone=
|
||||
Hewn Basalt=
|
||||
Inner Deep Nether Stair=
|
||||
Inner Nether Stair=
|
||||
Lava Crust=
|
||||
|
||||
Lava crust is strong enough to walk on, but still hot enough to inflict burns.=
|
||||
|
||||
Nether Basalt=
|
||||
Nether Beryl=
|
||||
Nether Berylite=
|
||||
Nether Brick=
|
||||
Nether Brick Fence=
|
||||
Nether Brick Fence Rail=
|
||||
Nether Crystal Pane=
|
||||
Nether Slab=
|
||||
Nether Stair=
|
||||
|
||||
Nether geode crystal, found lining the interior walls of Nether geodes=
|
||||
|
||||
Nether geode crystal. A crystalline structure with faint glow found inside large Nether geodes=
|
||||
|
||||
Netherrack=
|
||||
Netherrack from deep in the mantle=
|
||||
Netherrack stair=
|
||||
Netherrack Slab=
|
||||
Netherrack Stair=
|
||||
Nethersand=
|
||||
Outer Deep Nether Stair=
|
||||
Outer Nether Stair=
|
||||
Portal=
|
||||
|
||||
|
@ -109,6 +128,13 @@ There is a floating land of hills and forests up there, over the edges of which
|
|||
Nether Axe=
|
||||
Nether Ingot=
|
||||
Nether Lump=
|
||||
Nether Pickaxe=
|
||||
Nether Pickaxe@nWell suited for mining netherrack=
|
||||
Nether Shovel=
|
||||
Nether Sword=
|
||||
|
||||
Nether staff of Eternal Light@nCreates glowstone from netherrack=
|
||||
|
||||
Nether staff of Light@nTemporarily transforms the netherrack into glowstone=
|
||||
|
||||
Uniquely suited for mining netherrack, with minimal wear when doing so. Blunts quickly on other materials.=
|
||||
|
||||
|
|
22
mapgen.lua
22
mapgen.lua
|
@ -71,6 +71,7 @@ end
|
|||
-- Load specialty helper functions
|
||||
dofile(nether.path .. "/mapgen_dungeons.lua")
|
||||
dofile(nether.path .. "/mapgen_mantle.lua")
|
||||
dofile(nether.path .. "/mapgen_geodes.lua")
|
||||
|
||||
|
||||
-- Misc math functions
|
||||
|
@ -170,7 +171,11 @@ mapgen.shift_existing_biomes(NETHER_FLOOR, NETHER_CEILING)
|
|||
-- Ores and decorations can be registered against "nether:rack" instead, and the lua
|
||||
-- on_generate() callback will carve the Nether with nether:rack before invoking
|
||||
-- generate_decorations and generate_ores.
|
||||
minetest.register_node("nether:native_mapgen", {})
|
||||
-- It is disguised as stone to hide any bug where it leaks out of the nether, such as
|
||||
-- https://github.com/minetest/minetest/issues/13440 or if on_generated() somehow was aborted.
|
||||
local stone_copy_def = table.copy(minetest.registered_nodes["default:stone"] or {})
|
||||
stone_copy_def.drop = stone_copy_def.drop or "default:stone" -- probably already defined as cobblestone
|
||||
minetest.register_node("nether:native_mapgen", stone_copy_def)
|
||||
|
||||
minetest.register_biome({
|
||||
name = "nether_caverns",
|
||||
|
@ -283,6 +288,7 @@ local dbuf = {}
|
|||
local c_air = minetest.get_content_id("air")
|
||||
local c_netherrack = minetest.get_content_id("nether:rack")
|
||||
local c_netherrack_deep = minetest.get_content_id("nether:rack_deep")
|
||||
local c_crystaldark = minetest.get_content_id("nether:geode")
|
||||
local c_lavasea_source = minetest.get_content_id("nether:lava_source") -- same as lava but with staggered animation to look better as an ocean
|
||||
local c_lava_crust = minetest.get_content_id("nether:lava_crust")
|
||||
local c_native_mapgen = minetest.get_content_id("nether:native_mapgen")
|
||||
|
@ -382,7 +388,8 @@ local function on_generated(minp, maxp, seed)
|
|||
if cave_noise > tcave then
|
||||
-- Prime region
|
||||
-- This was the only region in initial versions of the Nether mod.
|
||||
-- It is the only region which portals from the surface will open into.
|
||||
-- It is the only region which portals from the surface will open into,
|
||||
-- getting to any other regions in the Nether will require Shanks' Pony.
|
||||
data[vi] = c_air
|
||||
contains_nether = true
|
||||
|
||||
|
@ -392,12 +399,11 @@ local function on_generated(minp, maxp, seed)
|
|||
-- Reaching here would require the player to first find and journey through the central region,
|
||||
-- as it's always separated from the Prime region by the central region.
|
||||
|
||||
data[vi] = c_netherrack -- For now I've just left this region as solid netherrack instead of air.
|
||||
data[vi] = mapgen.getGeodeInteriorNodeId(x, y, z)-- function from mapgen_geodes.lua
|
||||
|
||||
-- Only set contains_nether to true here if you want tunnels created between the secondary region
|
||||
-- and the central region.
|
||||
--contains_nether = true
|
||||
--data[vi] = c_air
|
||||
contains_nether = true
|
||||
else
|
||||
-- netherrack walls and/or center region/mantle
|
||||
abs_cave_noise = math_abs(cave_noise)
|
||||
|
@ -414,7 +420,11 @@ local function on_generated(minp, maxp, seed)
|
|||
data[vi] = c_netherrack_deep
|
||||
else
|
||||
-- the shell seperating the mantle from the rest of the nether...
|
||||
data[vi] = c_netherrack -- excavate_dungeons() will mostly reverse this inside dungeons
|
||||
if cave_noise > 0 then
|
||||
data[vi] = c_netherrack -- excavate_dungeons() will mostly reverse this inside dungeons
|
||||
else
|
||||
data[vi] = c_crystaldark
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ minetest.set_gen_notify({dungeon = true})
|
|||
local c_air = minetest.get_content_id("air")
|
||||
local c_netherrack = minetest.get_content_id("nether:rack")
|
||||
local c_netherrack_deep = minetest.get_content_id("nether:rack_deep")
|
||||
local c_crystaldark = minetest.get_content_id("nether:geode")
|
||||
local c_dungeonbrick = minetest.get_content_id("nether:brick")
|
||||
local c_dungeonbrick_alt = minetest.get_content_id("nether:brick_cracked")
|
||||
local c_netherbrick_slab = minetest.get_content_id("stairs:slab_nether_brick")
|
||||
|
@ -164,7 +165,7 @@ nether.mapgen.excavate_dungeons = function(data, area, rooms)
|
|||
vi = area:index(room_min.x, y, z)
|
||||
for x = room_min.x, room_max.x do
|
||||
node_id = data[vi]
|
||||
if node_id == c_netherrack or node_id == c_netherrack_deep then data[vi] = c_air end
|
||||
if node_id == c_netherrack or node_id == c_netherrack_deep or node_id == c_crystaldark then data[vi] = c_air end
|
||||
vi = vi + 1
|
||||
end
|
||||
end
|
||||
|
@ -181,7 +182,7 @@ nether.mapgen.excavate_dungeons = function(data, area, rooms)
|
|||
vi = vi + area.ystride
|
||||
node_id = data[vi]
|
||||
-- searching forward of the stairs could also be done
|
||||
if node_id == c_netherrack or node_id == c_netherrack_deep then data[vi] = c_air end
|
||||
if node_id == c_netherrack or node_id == c_netherrack_deep or node_id == c_crystaldark then data[vi] = c_air end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -231,11 +232,11 @@ nether.mapgen.decorate_dungeons = function(data, area, rooms)
|
|||
and room_min.z > minEdge.z and room_max.z < maxEdge.z then
|
||||
--data[area:indexp(roomInfo)] = minetest.get_content_id("default:mese_post_light") -- debug
|
||||
|
||||
-- Can't use glass panes because they need the param data set.
|
||||
-- Until whisper glass is added, every window will be made of netherbrick fence (rather
|
||||
-- than material depending on room_seed)
|
||||
-- Glass panes can't go in the windows because we aren't setting param data.
|
||||
-- Until a Nether glass is added, every window will be made of netherbrick fence rather
|
||||
-- than material depending on room_seed.
|
||||
local window_node = c_netherfence
|
||||
--if c_netherglass ~= nil and room_seed % 20 >= 12 then window_node = c_crystallight end
|
||||
--if c_netherglass ~= nil and room_seed % 20 >= 12 then window_node = c_netherglass end
|
||||
|
||||
local function placeWindow(vi, viOutsideOffset, windowNo)
|
||||
if is_dungeon_brick(data[vi]) and is_dungeon_brick(data[vi + yStride]) then
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
--[[
|
||||
|
||||
Nether mod for minetest
|
||||
|
||||
This file contains helper functions for generating geode interiors,
|
||||
a proof-of-concept to demonstrate how the secondary/spare region
|
||||
in the nether might be put to use by someone.
|
||||
|
||||
|
||||
Copyright (C) 2021 Treer
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for
|
||||
any purpose with or without fee is hereby granted, provided that the
|
||||
above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
|
||||
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
|
||||
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
||||
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
SOFTWARE.
|
||||
|
||||
]]--
|
||||
|
||||
|
||||
local debugf = nether.debug
|
||||
local mapgen = nether.mapgen
|
||||
|
||||
|
||||
-- Content ids
|
||||
|
||||
local c_air = minetest.get_content_id("air")
|
||||
local c_crystal = minetest.get_content_id("nether:geodelite") -- geodelite has a faint glow
|
||||
local c_netherrack = minetest.get_content_id("nether:rack")
|
||||
local c_glowstone = minetest.get_content_id("nether:glowstone")
|
||||
|
||||
-- Math funcs
|
||||
local math_max, math_min, math_abs, math_floor, math_pi = math.max, math.min, math.abs, math.floor, math.pi -- avoid needing table lookups each time a common math function is invoked
|
||||
|
||||
|
||||
-- Create a tiling space of close-packed spheres, using Hexagonal close packing
|
||||
-- of spheres with radius 0.5.
|
||||
-- With a layer of spheres on a flat surface, if the pack-z distance is 1 due to 0.5
|
||||
-- radius then the pack-x distance will be the height of an equilateral triangle: sqrt(3) / 2,
|
||||
-- and the pack-y distance between each layer will be sqrt(6) / 3,
|
||||
-- The tessellating space will be a rectangular box of 2*pack-x by 1*pack-z by 3*pack-y
|
||||
|
||||
local xPack = math.sqrt(3)/2 -- 0.866, height of an equalateral triangle
|
||||
local xPack2 = xPack * 2 -- 1.732
|
||||
local yPack = math.sqrt(6) / 3 -- 0.816, y height of each layer
|
||||
local yPack2 = yPack * 2
|
||||
local yPack3 = yPack * 3
|
||||
local layer2offsetx = xPack / 3 -- 0.289, height to center of equalateral triangle
|
||||
local layer3offsetx = xPack2 / 3 -- 0.577
|
||||
local structureSize = 50 -- magic numbers may need retuning if this changes too much
|
||||
|
||||
local layer1 = {
|
||||
{0, 0, 0},
|
||||
{0, 0, 1},
|
||||
{xPack, 0, -0.5},
|
||||
{xPack, 0, 0.5},
|
||||
{xPack, 0, 1.5},
|
||||
{xPack2, 0, 0},
|
||||
{xPack2, 0, 1},
|
||||
}
|
||||
local layer2 = {
|
||||
{layer2offsetx - xPack, yPack, 0},
|
||||
{layer2offsetx - xPack, yPack, 1},
|
||||
{layer2offsetx, yPack, -0.5},
|
||||
{layer2offsetx, yPack, 0.5},
|
||||
{layer2offsetx, yPack, 1.5},
|
||||
{layer2offsetx + xPack, yPack, 0},
|
||||
{layer2offsetx + xPack, yPack, 1},
|
||||
{layer2offsetx + xPack2, yPack, -0.5},
|
||||
{layer2offsetx + xPack2, yPack, 0.5},
|
||||
{layer2offsetx + xPack2, yPack, 1.5},
|
||||
}
|
||||
local layer3 = {
|
||||
{layer3offsetx - xPack, yPack2, -0.5},
|
||||
{layer3offsetx - xPack, yPack2, 0.5},
|
||||
{layer3offsetx - xPack, yPack2, 1.5},
|
||||
{layer3offsetx, yPack2, 0},
|
||||
{layer3offsetx, yPack2, 1},
|
||||
{layer3offsetx + xPack, yPack2, -0.5},
|
||||
{layer3offsetx + xPack, yPack2, 0.5},
|
||||
{layer3offsetx + xPack, yPack2, 1.5},
|
||||
{layer3offsetx + xPack2, yPack2, 0},
|
||||
{layer3offsetx + xPack2, yPack2, 1},
|
||||
}
|
||||
local layer4 = {
|
||||
{0, yPack3, 0},
|
||||
{0, yPack3, 1},
|
||||
{xPack, yPack3, -0.5},
|
||||
{xPack, yPack3, 0.5},
|
||||
{xPack, yPack3, 1.5},
|
||||
{xPack2, yPack3, 0},
|
||||
{xPack2, yPack3, 1},
|
||||
}
|
||||
local layers = {
|
||||
{y = layer1[1][2], points = layer1}, -- layer1[1][2] is the y value of the first point in layer1, and all spheres in a layer have the same y
|
||||
{y = layer2[1][2], points = layer2},
|
||||
{y = layer3[1][2], points = layer3},
|
||||
{y = layer4[1][2], points = layer4},
|
||||
}
|
||||
|
||||
|
||||
-- Geode mapgen functions (AKA proof of secondary/spare region concept)
|
||||
|
||||
|
||||
-- fast for small lists
|
||||
function insertionSort(array)
|
||||
local i
|
||||
for i = 2, #array do
|
||||
local key = array[i]
|
||||
local j = i - 1
|
||||
while j > 0 and array[j] > key do
|
||||
array[j + 1] = array[j]
|
||||
j = j - 1
|
||||
end
|
||||
array[j + 1] = key
|
||||
end
|
||||
return array
|
||||
end
|
||||
|
||||
|
||||
local distSquaredList = {}
|
||||
local adj_x = 0
|
||||
local adj_y = 0
|
||||
local adj_z = 0
|
||||
local lasty, lastz
|
||||
local warpx, warpz
|
||||
|
||||
|
||||
-- It's quite a lot to calculate for each air node, but its not terribly slow and
|
||||
-- it'll be pretty darn rare for chunks in the secondary region to ever get emerged.
|
||||
mapgen.getGeodeInteriorNodeId = function(x, y, z)
|
||||
|
||||
if z ~= lastz then
|
||||
lastz = z
|
||||
-- Calculate structure warping
|
||||
-- To avoid calculating this for each node there's no warping as you look along the x axis :(
|
||||
adj_y = math.sin(math_pi / 222 * y) * 30
|
||||
|
||||
if y ~= lasty then
|
||||
lasty = y
|
||||
warpx = math.sin(math_pi / 100 * y) * 10
|
||||
warpz = math.sin(math_pi / 43 * y) * 15
|
||||
end
|
||||
local twistRadians = math_pi / 73 * y
|
||||
local sinTwist, cosTwist = math.sin(twistRadians), math.cos(twistRadians)
|
||||
adj_x = cosTwist * warpx - sinTwist * warpz
|
||||
adj_z = sinTwist * warpx + cosTwist * warpz
|
||||
end
|
||||
|
||||
-- convert x, y, z into a position in the tessellating space
|
||||
local cell_x = (((x + adj_x) / xPack2 + 0.5) % structureSize) / structureSize * xPack2
|
||||
local cell_y = (((y + adj_y) / yPack3 + 0.5) % structureSize) / structureSize * yPack3
|
||||
local cell_z = (((z + adj_z) + 0.5) % structureSize) / structureSize -- zPack = 1, so can be omitted
|
||||
|
||||
local iOut = 1
|
||||
local i, j
|
||||
local canSkip = false
|
||||
|
||||
for i = 1, #layers do
|
||||
|
||||
local layer = layers[i]
|
||||
local dy = cell_y - layer.y
|
||||
|
||||
if dy > -0.71 and dy < 0.71 then -- optimization - don't include points to far away to make a difference. (0.71 comes from sin(45°))
|
||||
local points = layer.points
|
||||
|
||||
for j = 1, #points do
|
||||
|
||||
local point = points[j]
|
||||
local dx = cell_x - point[1]
|
||||
local dz = cell_z - point[3]
|
||||
local distSquared = dx*dx + dy*dy + dz*dz
|
||||
|
||||
if distSquared < 0.25 then
|
||||
-- optimization - point is inside a sphere, so cannot be a wall edge. (0.25 comes from radius of 0.5 squared)
|
||||
return c_air
|
||||
end
|
||||
|
||||
distSquaredList[iOut] = distSquared
|
||||
iOut = iOut + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- clear the rest of the array instead of creating a new one to hopefully reduce luajit mem leaks.
|
||||
while distSquaredList[iOut] ~= nil do
|
||||
rawset(distSquaredList, iOut, nil)
|
||||
iOut = iOut + 1
|
||||
end
|
||||
|
||||
insertionSort(distSquaredList)
|
||||
|
||||
local d3_1 = distSquaredList[3] - distSquaredList[1]
|
||||
local d3_2 = distSquaredList[3] - distSquaredList[2]
|
||||
--local d4_1 = distSquaredList[4] - distSquaredList[1]
|
||||
--local d4_3 = distSquaredList[4] - distSquaredList[3]
|
||||
|
||||
-- Some shape formulas (tuned for a structureSize of 50)
|
||||
-- (d3_1 < 0.05) gives connective lines
|
||||
-- (d3_1 < 0.05 or d3_2 < .02) give fancy elven bridges - prob doesn't need the d3_1 part
|
||||
-- ((d3_1 < 0.05 or d3_2 < .02) and distSquaredList[1] > .3) tapers the fancy connections in the middle
|
||||
-- (d4_3 < 0.03 and d3_2 < 0.03) produces caltrops at intersections
|
||||
-- (d4_1 < 0.1) produces spherish balls at intersections
|
||||
-- The idea is voronoi based - edges in a voronoi diagram are where each nearby point is at equal distance.
|
||||
-- In this case we use squared distances to avoid calculating square roots.
|
||||
|
||||
if (d3_1 < 0.05 or d3_2 < .02) and distSquaredList[1] > .3 then
|
||||
return c_crystal
|
||||
elseif (distSquaredList[4] - distSquaredList[1]) < 0.08 then
|
||||
return c_glowstone
|
||||
else
|
||||
return c_air
|
||||
end
|
||||
end
|
2
mod.conf
2
mod.conf
|
@ -1,4 +1,4 @@
|
|||
name = nether
|
||||
description = Adds a deep underground realm with different mapgen that you can reach with obsidian portals.
|
||||
depends = stairs, default
|
||||
optional_depends = moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire, climate_api, ethereal
|
||||
optional_depends = toolranks, technic, moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire, climate_api, ethereal, xpanes, walls
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
local S = minetest.get_translator("nether")
|
||||
|
||||
technic.register_recipe_type("compressing", { description = S("Compressing") })
|
||||
|
||||
function register_compressor_recipe(data)
|
||||
data.time = data.time or 4
|
||||
technic.register_recipe("compressing", data)
|
||||
end
|
||||
|
||||
local recipes = {
|
||||
{"nether:rack", "nether:brick",},
|
||||
{"nether:rack_deep", "nether:brick_deep"},
|
||||
{"nether:brick 9", "nether:brick_compressed", 12},
|
||||
{"nether:brick_compressed 9", "nether:nether_lump", 12}
|
||||
|
||||
}
|
||||
-- clear craft recipe
|
||||
-- But allow brick blocks to be crafted like the other bricks from Minetest Game
|
||||
|
||||
minetest.clear_craft({
|
||||
recipe = {
|
||||
{"nether:brick","nether:brick","nether:brick"},
|
||||
{"nether:brick","nether:brick","nether:brick"},
|
||||
{"nether:brick","nether:brick","nether:brick"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.clear_craft({
|
||||
recipe = {
|
||||
{"nether:brick_compressed","nether:brick_compressed","nether:brick_compressed"},
|
||||
{"nether:brick_compressed","nether:brick_compressed","nether:brick_compressed"},
|
||||
{"nether:brick_compressed","nether:brick_compressed","nether:brick_compressed"},
|
||||
}
|
||||
})
|
||||
|
||||
for _, data in pairs(recipes) do
|
||||
register_compressor_recipe({input = {data[1]}, output = data[2], time = data[3]})
|
||||
end
|
||||
|
||||
|
300
nodes.lua
300
nodes.lua
|
@ -65,23 +65,186 @@ nether.register_wormhole_node("nether:portal_alt", {
|
|||
})
|
||||
|
||||
|
||||
--== Transmogrification functions ==--
|
||||
-- Functions enabling selected nodes to be temporarily transformed into other nodes.
|
||||
-- (so the light staff can temporarily turn netherrack into glowstone)
|
||||
|
||||
-- Swaps the node at `nodePos` with `newNode`, unless `newNode` is nil in which
|
||||
-- case the node is swapped back to its original type.
|
||||
-- `monoSimpleSoundSpec` is optional.
|
||||
-- returns true if a node was transmogrified
|
||||
nether.magicallyTransmogrify_node = function(nodePos, playerName, newNode, monoSimpleSoundSpec, isPermanent)
|
||||
|
||||
local meta = minetest.get_meta(nodePos)
|
||||
local playerEyePos = nodePos -- fallback value in case the player no longer exists
|
||||
local player = minetest.get_player_by_name(playerName)
|
||||
if player ~= nil then
|
||||
local playerPos = player:get_pos()
|
||||
playerEyePos = vector.add(playerPos, {x = 0, y = 1.5, z = 0}) -- not always the cameraPos, e.g. 3rd person mode.
|
||||
end
|
||||
|
||||
local oldNode = minetest.get_node(nodePos)
|
||||
if oldNode.name == "air" then
|
||||
-- the node has been mined or otherwise destroyed, abort the operation
|
||||
return false
|
||||
end
|
||||
local oldNodeDef = minetest.registered_nodes[oldNode.name] or minetest.registered_nodes["air"]
|
||||
|
||||
local specialFXSize = 1 -- a specialFXSize of 1 is for full SFX, 0.5 is half-sized
|
||||
local returningToNormal = newNode == nil
|
||||
if returningToNormal then
|
||||
-- This is the transmogrified node returning back to normal - a more subdued animation
|
||||
specialFXSize = 0.5
|
||||
-- read what the node used to be from the metadata
|
||||
newNode = {
|
||||
name = meta:get_string("transmogrified_name"),
|
||||
param1 = meta:get_string("transmogrified_param1"),
|
||||
param2 = meta:get_string("transmogrified_param2")
|
||||
}
|
||||
if newNode.name == "" then
|
||||
minetest.log("warning", "nether.magicallyTransmogrify_node() invoked to restore node which wasn't transmogrified")
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local soundSpec = monoSimpleSoundSpec
|
||||
if soundSpec == nil and oldNodeDef.sounds ~= nil then
|
||||
soundSpec = oldNodeDef.sounds.dug or oldNodeDef.sounds.dig
|
||||
if soundSpec == "__group" then soundSpec = "default_dig_cracky" end
|
||||
end
|
||||
if soundSpec ~= nil then
|
||||
minetest.sound_play(soundSpec, {pos = nodePos, max_hear_distance = 50})
|
||||
end
|
||||
|
||||
-- Start the particlespawner nearer the player's side of the node to create
|
||||
-- more initial occlusion for an illusion of the old node breaking apart / falling away.
|
||||
local dirToPlayer = vector.normalize(vector.subtract(playerEyePos, nodePos))
|
||||
local impactPos = vector.add(nodePos, vector.multiply(dirToPlayer, 0.5))
|
||||
local velocity = 1 + specialFXSize
|
||||
minetest.add_particlespawner({
|
||||
amount = 50 * specialFXSize,
|
||||
time = 0.1,
|
||||
minpos = vector.add(impactPos, -0.3),
|
||||
maxpos = vector.add(impactPos, 0.3),
|
||||
minvel = {x = -velocity, y = -velocity, z = -velocity},
|
||||
maxvel = {x = velocity, y = 3 * velocity, z = velocity}, -- biased upward to counter gravity in the initial stages
|
||||
minacc = {x=0, y=-10, z=0},
|
||||
maxacc = {x=0, y=-10, z=0},
|
||||
minexptime = 1.5 * specialFXSize,
|
||||
maxexptime = 3 * specialFXSize,
|
||||
minsize = 0.5,
|
||||
maxsize = 5,
|
||||
node = {name = oldNodeDef.name},
|
||||
glow = oldNodeDef.light_source
|
||||
})
|
||||
|
||||
if returningToNormal or isPermanent then
|
||||
-- clear the metadata that indicates the node is transformed
|
||||
meta:set_string("transmogrified_name", "")
|
||||
meta:set_int("transmogrified_param1", 0)
|
||||
meta:set_int("transmogrified_param2", 0)
|
||||
else
|
||||
-- save the original node so it can be restored
|
||||
meta:set_string("transmogrified_name", oldNode.name)
|
||||
meta:set_int("transmogrified_param1", oldNode.param1)
|
||||
meta:set_int("transmogrified_param2", oldNode.param2)
|
||||
end
|
||||
|
||||
minetest.swap_node(nodePos, newNode)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local function transmogrified_can_dig (pos, player)
|
||||
if minetest.get_meta(pos):get_string("transmogrified_name") ~= "" then
|
||||
-- This node was temporarily transformed into its current form
|
||||
-- revert it back, rather than allow the player to mine transmogrified nodes.
|
||||
local playerName = ""
|
||||
if player ~= nil then playerName = player:get_player_name() end
|
||||
nether.magicallyTransmogrify_node(pos, playerName)
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Nether nodes
|
||||
|
||||
minetest.register_node("nether:rack", {
|
||||
description = S("Netherrack"),
|
||||
tiles = {"nether_rack.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky = 3, level = 2},
|
||||
-- setting workable_with_nether_tools reduces the wear on nether:pick_nether when mining this node
|
||||
groups = {cracky = 3, level = 2, workable_with_nether_tools = 3},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
-- Geode crystals can only be introduced by the biomes-based mapgen, since it requires the
|
||||
-- MT 5.0 world-align texture features.
|
||||
minetest.register_node("nether:geode", {
|
||||
description = S("Nether Beryl"),
|
||||
_doc_items_longdesc = S("Nether geode crystal, found lining the interior walls of Nether geodes"),
|
||||
tiles = {{
|
||||
name = "nether_geode.png",
|
||||
align_style = "world",
|
||||
scale = 4
|
||||
}},
|
||||
is_ground_content = true,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3, nether_crystal = 1},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
-- Nether Berylite is a Beryl that can seen in the dark, used to light up the internal structure
|
||||
-- of the geode, so to avoid player confusion we'll just have it drop plain Beryl, and have only
|
||||
-- plain Beryl in the creative inventory.
|
||||
minetest.register_node("nether:geodelite", {
|
||||
description = S("Nether Berylite"),
|
||||
_doc_items_longdesc = S("Nether geode crystal. A crystalline structure with faint glow found inside large Nether geodes"),
|
||||
tiles = {{
|
||||
name = "nether_geode.png",
|
||||
align_style = "world",
|
||||
scale = 4
|
||||
}},
|
||||
light_source = 2,
|
||||
drop = "nether:geode",
|
||||
is_ground_content = true,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3, nether_crystal = 1, not_in_creative_inventory = 1},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
})
|
||||
|
||||
if minetest.get_modpath("xpanes") and minetest.global_exists("xpanes") and xpanes.register_pane ~= nil then
|
||||
xpanes.register_pane("nether_crystal_pane", {
|
||||
description = S("Nether Crystal Pane"),
|
||||
textures = {
|
||||
{
|
||||
name = "nether_geode_glass.png",
|
||||
align_style = "world",
|
||||
scale = 2
|
||||
},
|
||||
"",
|
||||
"xpanes_edge_obsidian.png"
|
||||
},
|
||||
inventory_image = "([combine:32x32:-8,-8=nether_geode_glass.png:24,-8=nether_geode_glass.png:-8,24=nether_geode_glass.png:24,24=nether_geode_glass.png)^[resize:16x16^[multiply:#922^default_obsidian_glass.png",
|
||||
wield_image = "([combine:32x32:-8,-8=nether_geode_glass.png:24,-8=nether_geode_glass.png:-8,24=nether_geode_glass.png:24,24=nether_geode_glass.png)^[resize:16x16^[multiply:#922^default_obsidian_glass.png", use_texture_alpha = true,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
groups = {snappy=2, cracky=3, oddly_breakable_by_hand=3},
|
||||
recipe = {
|
||||
{"group:nether_crystal", "group:nether_crystal", "group:nether_crystal"},
|
||||
{"group:nether_crystal", "group:nether_crystal", "group:nether_crystal"}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
-- Deep Netherrack, found in the mantle / central magma layers
|
||||
minetest.register_node("nether:rack_deep", {
|
||||
description = S("Deep Netherrack"),
|
||||
_doc_items_longdesc = S("Netherrack from deep in the mantle"),
|
||||
tiles = {"nether_rack_deep.png"},
|
||||
is_ground_content = true,
|
||||
groups = {cracky = 3, level = 2},
|
||||
-- setting workable_with_nether_tools reduces the wear on nether:pick_nether when mining this node
|
||||
groups = {cracky = 3, level = 2, workable_with_nether_tools = 3},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
|
@ -103,6 +266,7 @@ minetest.register_node("nether:glowstone", {
|
|||
paramtype = "light",
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
can_dig = transmogrified_can_dig, -- to ensure glowstone temporarily created by the lightstaff can't be kept
|
||||
})
|
||||
|
||||
-- Deep glowstone, found in the mantle / central magma layers
|
||||
|
@ -114,6 +278,7 @@ minetest.register_node("nether:glowstone_deep", {
|
|||
paramtype = "light",
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
can_dig = transmogrified_can_dig, -- to ensure glowstone temporarily created by the lightstaff can't be kept
|
||||
})
|
||||
|
||||
minetest.register_node("nether:brick", {
|
||||
|
@ -141,26 +306,6 @@ minetest.register_node("nether:brick_cracked", {
|
|||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
local fence_texture =
|
||||
"default_fence_overlay.png^nether_brick.png^default_fence_overlay.png^[makealpha:255,126,126"
|
||||
|
||||
minetest.register_node("nether:fence_nether_brick", {
|
||||
description = S("Nether Brick Fence"),
|
||||
drawtype = "fencelike",
|
||||
tiles = {"nether_brick.png"},
|
||||
inventory_image = fence_texture,
|
||||
wield_image = fence_texture,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
is_ground_content = false,
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {-1/7, -1/2, -1/7, 1/7, 1/2, 1/7},
|
||||
},
|
||||
groups = {cracky = 2, level = 2},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
})
|
||||
|
||||
minetest.register_node("nether:brick_deep", {
|
||||
description = S("Deep Nether Brick"),
|
||||
tiles = {{
|
||||
|
@ -173,39 +318,119 @@ minetest.register_node("nether:brick_deep", {
|
|||
sounds = default.node_sound_stone_defaults()
|
||||
})
|
||||
|
||||
-- Register fence and rails
|
||||
|
||||
local fence_texture =
|
||||
"default_fence_overlay.png^nether_brick.png^default_fence_overlay.png^[makealpha:255,126,126"
|
||||
|
||||
local rail_texture =
|
||||
"default_fence_rail_overlay.png^nether_brick.png^default_fence_rail_overlay.png^[makealpha:255,126,126"
|
||||
|
||||
default.register_fence("nether:fence_nether_brick", {
|
||||
description = S("Nether Brick Fence"),
|
||||
texture = "nether_brick.png",
|
||||
inventory_image = fence_texture,
|
||||
wield_image = fence_texture,
|
||||
material = "nether:brick",
|
||||
groups = {cracky = 2, level = 2},
|
||||
sounds = default.node_sound_stone_defaults()
|
||||
})
|
||||
|
||||
default.register_fence_rail("nether:fence_rail_nether_brick", {
|
||||
description = S("Nether Brick Fence Rail"),
|
||||
texture = "nether_brick.png",
|
||||
inventory_image = rail_texture,
|
||||
wield_image = rail_texture,
|
||||
material = "nether:brick",
|
||||
groups = {cracky = 2, level = 2},
|
||||
sounds = default.node_sound_stone_defaults()
|
||||
})
|
||||
|
||||
-- Register stair and slab
|
||||
|
||||
stairs.register_stair_and_slab(
|
||||
"nether_brick",
|
||||
"nether:brick",
|
||||
{cracky = 2, level = 2},
|
||||
{"nether_brick.png"},
|
||||
S("Nether Stair"),
|
||||
S("Nether Slab"),
|
||||
default.node_sound_stone_defaults(),
|
||||
nil,
|
||||
S("Inner Nether Stair"),
|
||||
S("Outer Nether Stair")
|
||||
-- Nether bricks can be made into stairs, slabs, inner stairs, and outer stairs
|
||||
|
||||
stairs.register_stair_and_slab( -- this function also registers inner and outer stairs
|
||||
"nether_brick", -- subname
|
||||
"nether:brick", -- recipeitem
|
||||
{cracky = 2, level = 2}, -- groups
|
||||
{"nether_brick.png"}, -- images
|
||||
S("Nether Stair"), -- desc_stair
|
||||
S("Nether Slab"), -- desc_slab
|
||||
minetest.registered_nodes["nether:brick"].sounds, -- sounds
|
||||
false, -- worldaligntex
|
||||
S("Inner Nether Stair"), -- desc_stair_inner
|
||||
S("Outer Nether Stair") -- desc_stair_outer
|
||||
)
|
||||
|
||||
stairs.register_stair_and_slab( -- this function also registers inner and outer stairs
|
||||
"nether_brick_deep", -- subname
|
||||
"nether:brick_deep", -- recipeitem
|
||||
{cracky = 2, level = 2}, -- groups
|
||||
{"nether_brick_deep.png"}, -- images
|
||||
S("Deep Nether Stair"), -- desc_stair
|
||||
S("Deep Nether Slab"), -- desc_slab
|
||||
minetest.registered_nodes["nether:brick_deep"].sounds, -- sounds
|
||||
false, -- worldaligntex
|
||||
S("Inner Deep Nether Stair"), -- desc_stair_inner
|
||||
S("Outer Deep Nether Stair") -- desc_stair_outer
|
||||
)
|
||||
|
||||
-- Netherrack can be shaped into stairs, slabs and walls
|
||||
|
||||
stairs.register_stair(
|
||||
"netherrack",
|
||||
"nether:rack",
|
||||
{cracky = 2, level = 2},
|
||||
{"nether_rack.png"},
|
||||
S("Netherrack stair"),
|
||||
default.node_sound_stone_defaults()
|
||||
S("Netherrack Stair"),
|
||||
minetest.registered_nodes["nether:rack"].sounds
|
||||
)
|
||||
stairs.register_slab( -- register a slab without adding inner and outer stairs
|
||||
"netherrack",
|
||||
"nether:rack",
|
||||
{cracky = 2, level = 2},
|
||||
{"nether_rack.png"},
|
||||
S("Netherrack Slab"),
|
||||
minetest.registered_nodes["nether:rack"].sounds
|
||||
)
|
||||
|
||||
stairs.register_stair(
|
||||
"netherrack_deep",
|
||||
"nether:rack_deep",
|
||||
{cracky = 2, level = 2},
|
||||
{"nether_rack_deep.png"},
|
||||
S("Deep Netherrack Stair"),
|
||||
minetest.registered_nodes["nether:rack_deep"].sounds
|
||||
)
|
||||
stairs.register_slab( -- register a slab without adding inner and outer stairs
|
||||
"netherrack_deep",
|
||||
"nether:rack_deep",
|
||||
{cracky = 2, level = 2},
|
||||
{"nether_rack_deep.png"},
|
||||
S("Deep Netherrack Slab"),
|
||||
minetest.registered_nodes["nether:rack_deep"].sounds
|
||||
)
|
||||
|
||||
-- Connecting walls
|
||||
if minetest.get_modpath("walls") and minetest.global_exists("walls") and walls.register ~= nil then
|
||||
walls.register("nether:rack_wall", S("A Netherrack Wall"), "nether_rack.png", "nether:rack", minetest.registered_nodes["nether:rack"].sounds)
|
||||
walls.register("nether:rack_deep_wall", S("A Deep Netherrack Wall"), "nether_rack_deep.png", "nether:rack_deep", minetest.registered_nodes["nether:rack_deep"].sounds)
|
||||
end
|
||||
|
||||
-- StairsPlus
|
||||
|
||||
if minetest.get_modpath("moreblocks") then
|
||||
-- Registers about 49 different shapes of nether brick, replacing the stairs & slabs registered above.
|
||||
-- (This could also be done for deep nether brick, but I've left that out to avoid a precedent of 49 new
|
||||
-- nodes every time the nether gets a new material. Nether structures won't be able to use them because
|
||||
-- they can't depend on moreblocks)
|
||||
stairsplus:register_all(
|
||||
"nether", "brick", "nether:brick", {
|
||||
description = S("Nether Brick"),
|
||||
groups = {cracky = 2, level = 2},
|
||||
tiles = {"nether_brick.png"},
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sounds = minetest.registered_nodes["nether:brick"].sounds,
|
||||
})
|
||||
end
|
||||
|
||||
|
@ -553,6 +778,7 @@ minetest.register_node("nether:lava_crust", {
|
|||
--liquid_viscosity = 7,
|
||||
damage_per_second = 2,
|
||||
groups = {oddly_breakable_by_hand = 3, cracky = 3, explody = 1, igniter = 1},
|
||||
sounds = default.node_sound_gravel_defaults(),
|
||||
})
|
||||
|
||||
|
||||
|
@ -615,7 +841,7 @@ local function fumarole_onTimer(pos, elapsed)
|
|||
local smoke_time_adj = 1
|
||||
|
||||
local posAbove = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
local extinguish = minetest.get_node(posAbove).name ~= "air"
|
||||
local extinguish = inNether and minetest.get_node(posAbove).name ~= "air"
|
||||
|
||||
if extinguish or (canCatchFire and math.floor(elapsed) % 7 == 0) then
|
||||
|
||||
|
|
|
@ -2166,22 +2166,20 @@ function nether.unregister_portal(name)
|
|||
end
|
||||
|
||||
function nether.register_portal_ignition_item(item_name, ignition_failure_sound)
|
||||
|
||||
local old_on_place = minetest.registered_items[item_name].on_place or minetest.item_place
|
||||
minetest.override_item(item_name, {
|
||||
on_place = function(stack, placer, pt)
|
||||
local done = false
|
||||
on_place = function(stack, placer, pt, ...)
|
||||
if pt.under and nether.is_frame_node[minetest.get_node(pt.under).name] then
|
||||
done = ignite_portal(pt.under, placer:get_player_name())
|
||||
local done = ignite_portal(pt.under, placer:get_player_name())
|
||||
if done and not minetest.settings:get_bool("creative_mode") then
|
||||
stack:take_item()
|
||||
end
|
||||
if not done and ignition_failure_sound ~= nil then
|
||||
minetest.sound_play(ignition_failure_sound, {pos = pt.under, max_hear_distance = 10})
|
||||
end
|
||||
return stack
|
||||
end
|
||||
if not done and ignition_failure_sound ~= nil then
|
||||
minetest.sound_play(ignition_failure_sound, {pos = pt.under, max_hear_distance = 10})
|
||||
end
|
||||
|
||||
|
||||
return stack
|
||||
return old_on_place(stack, placer, pt, ...)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 568 B |
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
262
tools.lua
262
tools.lua
|
@ -20,18 +20,33 @@
|
|||
local S = nether.get_translator
|
||||
|
||||
minetest.register_tool("nether:pick_nether", {
|
||||
description = S("Nether Pickaxe"),
|
||||
description = S("Nether Pickaxe\nWell suited for mining netherrack"),
|
||||
_doc_items_longdesc = S("Uniquely suited for mining netherrack, with minimal wear when doing so. Blunts quickly on other materials."),
|
||||
inventory_image = "nether_tool_netherpick.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.8,
|
||||
max_drop_level=3,
|
||||
groupcaps={
|
||||
cracky = {times={[1]=1.90, [2]=0.9, [3]=0.4}, uses=35, maxlevel=3},
|
||||
cracky = {times={[1]=1.90, [2]=0.9, [3]=0.3}, uses=35, maxlevel=2},
|
||||
},
|
||||
damage_groups = {fleshy=4},
|
||||
},
|
||||
sound = {breaks = "default_tool_breaks"},
|
||||
groups = {pickaxe = 1}
|
||||
groups = {pickaxe = 1},
|
||||
|
||||
after_use = function(itemstack, user, node, digparams)
|
||||
local wearDivisor = 1
|
||||
local nodeDef = minetest.registered_nodes[node.name]
|
||||
if nodeDef ~= nil and nodeDef.groups ~= nil then
|
||||
-- The nether pick hardly wears out when mining netherrack
|
||||
local workable = nodeDef.groups.workable_with_nether_tools or 0
|
||||
wearDivisor = 1 + (3 * workable) -- 10 for netherrack, 1 otherwise. Making it able to mine 350 netherrack nodes, instead of 35.
|
||||
end
|
||||
|
||||
local wear = math.floor(digparams.wear / wearDivisor)
|
||||
itemstack:add_wear(wear) -- apply the adjusted wear as usual
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_tool("nether:shovel_nether", {
|
||||
|
@ -136,3 +151,244 @@ minetest.register_craft({
|
|||
{"group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
if minetest.get_modpath("toolranks") then
|
||||
|
||||
local function add_toolranks(name)
|
||||
local nethertool_after_use = ItemStack(name):get_definition().after_use
|
||||
toolranks.add_tool(name)
|
||||
local toolranks_after_use = ItemStack(name):get_definition().after_use
|
||||
|
||||
if nethertool_after_use == nil or nethertool_after_use == toolranks_after_use then
|
||||
return
|
||||
end
|
||||
|
||||
minetest.override_item(name, {
|
||||
after_use = function(itemstack, user, node, digparams)
|
||||
-- combine nethertool_after_use and toolranks_after_use by allowing
|
||||
-- nethertool_after_use() to calculate the wear...
|
||||
local initial_wear = itemstack:get_wear()
|
||||
itemstack = nethertool_after_use(itemstack, user, node, digparams)
|
||||
local wear = itemstack:get_wear() - initial_wear
|
||||
itemstack:set_wear(initial_wear) -- restore/undo the wear
|
||||
|
||||
-- ...and have toolranks_after_use() apply the wear.
|
||||
digparams.wear = wear
|
||||
return toolranks_after_use(itemstack, user, node, digparams)
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
add_toolranks("nether:pick_nether")
|
||||
add_toolranks("nether:shovel_nether")
|
||||
add_toolranks("nether:axe_nether")
|
||||
add_toolranks("nether:sword_nether")
|
||||
end
|
||||
|
||||
|
||||
--===========================--
|
||||
--== Nether Staff of Light ==--
|
||||
--===========================--
|
||||
|
||||
nether.lightstaff_recipes = {
|
||||
["nether:rack"] = "nether:glowstone",
|
||||
["nether:brick"] = "nether:glowstone",
|
||||
["nether:brick_cracked"] = "nether:glowstone",
|
||||
["nether:brick_compressed"] = "nether:glowstone",
|
||||
["stairs:slab_netherrack"] = "nether:glowstone",
|
||||
["nether:rack_deep"] = "nether:glowstone_deep",
|
||||
["nether:brick_deep"] = "nether:glowstone_deep",
|
||||
["stairs:slab_netherrack_deep"] = "nether:glowstone_deep"
|
||||
}
|
||||
nether.lightstaff_range = 100
|
||||
nether.lightstaff_velocity = 60
|
||||
nether.lightstaff_gravity = 0 -- using 0 instead of 10 because projectile arcs look less magical - magic isn't affected by gravity ;) (but set this to 10 if you're making a crossbow etc.)
|
||||
nether.lightstaff_uses = 60 -- number of times the Eternal Lightstaff can be used before wearing out
|
||||
nether.lightstaff_duration = 40 -- lifespan of glowstone created by the termporay Lightstaff
|
||||
|
||||
-- 'serverLag' is a rough amount to reduce the projected impact-time the server must wait before initiating the
|
||||
-- impact events (i.e. node changing to glowstone with explosion particle effect).
|
||||
-- In tests using https://github.com/jagt/clumsy to simulate network lag I've found this value to not noticeably
|
||||
-- matter. A large network lag is noticeable in the time between clicking fire and when the shooting-particleEffect
|
||||
-- begins, as well as the time between when the impact sound/particleEffect start and when the netherrack turns
|
||||
-- into glowstone. The synchronization that 'serverLag' adjusts seems to already tolerate network lag well enough (at
|
||||
-- least when lag is consistent, as I have not simulated random lag)
|
||||
local serverLag = 0.05 -- in seconds. Larger values makes impact events more premature/early.
|
||||
|
||||
-- returns a pointed_thing, or nil if no solid node intersected the ray
|
||||
local function raycastForSolidNode(rayStartPos, rayEndPos)
|
||||
|
||||
local raycast = minetest.raycast(
|
||||
rayStartPos,
|
||||
rayEndPos,
|
||||
false, -- objects - if false, only nodes will be returned. Default is `true`
|
||||
true -- liquids - if false, liquid nodes won't be returned. Default is `false`
|
||||
)
|
||||
local next_pointed = raycast:next()
|
||||
while next_pointed do
|
||||
local under_node = minetest.get_node(next_pointed.under)
|
||||
local under_def = minetest.registered_nodes[under_node.name]
|
||||
|
||||
if (under_def and not under_def.buildable_to) or not under_def then
|
||||
return next_pointed
|
||||
end
|
||||
|
||||
next_pointed = raycast:next(next_pointed)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Turns a node into a light source
|
||||
-- `lightDuration` 0 is considered permanent, lightDuration is in seconds
|
||||
-- returns true if a node is transmogrified into a glowstone
|
||||
local function light_node(pos, playerName, lightDuration)
|
||||
|
||||
local result = false
|
||||
if minetest.is_protected(pos, playerName) then
|
||||
minetest.record_protection_violation(pos, playerName)
|
||||
return false
|
||||
end
|
||||
|
||||
local oldNode = minetest.get_node(pos)
|
||||
local litNodeName = nether.lightstaff_recipes[oldNode.name]
|
||||
|
||||
if litNodeName ~= nil then
|
||||
result = nether.magicallyTransmogrify_node(
|
||||
pos,
|
||||
playerName,
|
||||
{name=litNodeName},
|
||||
{name = "nether_rack_destroy", gain = 0.8},
|
||||
lightDuration == 0 -- isPermanent
|
||||
)
|
||||
|
||||
if lightDuration > 0 then
|
||||
minetest.after(lightDuration,
|
||||
function()
|
||||
-- Restore the node to its original type.
|
||||
--
|
||||
-- If the server crashes or shuts down before this is invoked, the node
|
||||
-- will remain in its transmogrified state. These could be cleaned up
|
||||
-- with an LBM, but I don't think that's necessary: if this functionality
|
||||
-- is only being used for the Nether Lightstaff then I don't think it
|
||||
-- matters if there's occasionally an extra glowstone left in the
|
||||
-- netherrack.
|
||||
nether.magicallyTransmogrify_node(pos, playerName)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- a lightDuration of 0 is considered permanent, lightDuration is in seconds
|
||||
-- returns true if a node is transmogrified into a glowstone
|
||||
local function lightstaff_on_use(user, boltColorString, lightDuration)
|
||||
|
||||
if not user then return false end
|
||||
local playerName = user:get_player_name()
|
||||
local playerlookDir = user:get_look_dir()
|
||||
local playerPos = user:get_pos()
|
||||
local playerEyePos = vector.add(playerPos, {x = 0, y = 1.5, z = 0}) -- not always the cameraPos, e.g. 3rd person mode.
|
||||
local target = vector.add(playerEyePos, vector.multiply(playerlookDir, nether.lightstaff_range))
|
||||
|
||||
local targetHitPos = nil
|
||||
local targetNodePos = nil
|
||||
local target_pointed = raycastForSolidNode(playerEyePos, target)
|
||||
if target_pointed then
|
||||
targetNodePos = target_pointed.under
|
||||
targetHitPos = vector.divide(vector.add(target_pointed.under, target_pointed.above), 2)
|
||||
end
|
||||
|
||||
local wieldOffset = {x= 0.5, y = -0.2, z= 0.8}
|
||||
local lookRotation = ({x = -user:get_look_vertical(), y = user:get_look_horizontal(), z = 0})
|
||||
local wieldPos = vector.add(playerEyePos, vector.rotate(wieldOffset, lookRotation))
|
||||
local aimPos = targetHitPos or target
|
||||
local distance = math.abs(vector.length(vector.subtract(aimPos, wieldPos)))
|
||||
local flightTime = distance / nether.lightstaff_velocity
|
||||
local dropDistance = nether.lightstaff_gravity * 0.5 * (flightTime * flightTime)
|
||||
aimPos.y = aimPos.y + dropDistance
|
||||
local boltDir = vector.normalize(vector.subtract(aimPos, wieldPos))
|
||||
|
||||
minetest.sound_play("nether_lightstaff", {to_player = playerName, gain = 0.8}, true)
|
||||
|
||||
-- animate a "magic bolt" from wieldPos to aimPos
|
||||
local particleSpawnDef = {
|
||||
amount = 20,
|
||||
time = 0.4,
|
||||
minpos = vector.add(wieldPos, -0.13),
|
||||
maxpos = vector.add(wieldPos, 0.13),
|
||||
minvel = vector.multiply(boltDir, nether.lightstaff_velocity - 0.3),
|
||||
maxvel = vector.multiply(boltDir, nether.lightstaff_velocity + 0.3),
|
||||
minacc = {x=0, y=-nether.lightstaff_gravity, z=0},
|
||||
maxacc = {x=0, y=-nether.lightstaff_gravity, z=0},
|
||||
minexptime = 1,
|
||||
maxexptime = 2,
|
||||
minsize = 4,
|
||||
maxsize = 5,
|
||||
collisiondetection = true,
|
||||
collision_removal = true,
|
||||
texture = "nether_particle_anim3.png",
|
||||
animation = { type = "vertical_frames", aspect_w = 7, aspect_h = 7, length = 0.8 },
|
||||
glow = 15
|
||||
}
|
||||
minetest.add_particlespawner(particleSpawnDef)
|
||||
particleSpawnDef.texture = "nether_particle_anim3.png^[colorize:" .. boltColorString .. ":alpha"
|
||||
particleSpawnDef.amount = 12
|
||||
particleSpawnDef.time = 0.2
|
||||
particleSpawnDef.minsize = 6
|
||||
particleSpawnDef.maxsize = 7
|
||||
particleSpawnDef.minpos = vector.add(wieldPos, -0.35)
|
||||
particleSpawnDef.maxpos = vector.add(wieldPos, 0.35)
|
||||
minetest.add_particlespawner(particleSpawnDef)
|
||||
|
||||
local result = false
|
||||
if targetNodePos then
|
||||
-- delay the impact until roughly when the particle effects will have reached the target
|
||||
minetest.after(
|
||||
math.max(0, (distance / nether.lightstaff_velocity) - serverLag),
|
||||
function()
|
||||
light_node(targetNodePos, playerName, lightDuration)
|
||||
end
|
||||
)
|
||||
|
||||
if lightDuration ~= 0 then
|
||||
-- we don't need to care whether the transmogrify will be successful
|
||||
result = true
|
||||
else
|
||||
-- check whether the transmogrify will be successful
|
||||
local targetNode = minetest.get_node(targetNodePos)
|
||||
result = nether.lightstaff_recipes[targetNode.name] ~= nil
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Inspired by FaceDeer's torch crossbow and Xanthin's Staff of Light
|
||||
minetest.register_tool("nether:lightstaff", {
|
||||
description = S("Nether staff of Light\nTemporarily transforms the netherrack into glowstone"),
|
||||
inventory_image = "nether_lightstaff.png",
|
||||
wield_image = "nether_lightstaff.png",
|
||||
light_source = 11, -- used by wielded_light mod etc.
|
||||
stack_max = 1,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
lightstaff_on_use(user, "#F70", nether.lightstaff_duration)
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_tool("nether:lightstaff_eternal", {
|
||||
description = S("Nether staff of Eternal Light\nCreates glowstone from netherrack"),
|
||||
inventory_image = "nether_lightstaff.png^[colorize:#55F:90",
|
||||
wield_image = "nether_lightstaff.png^[colorize:#55F:90",
|
||||
light_source = 11, -- used by wielded_light mod etc.
|
||||
sound = {breaks = "default_tool_breaks"},
|
||||
stack_max = 1,
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
if lightstaff_on_use(user, "#23F", 0) then -- was "#8088FF" or "#13F"
|
||||
-- The staff of Eternal Light wears out, to limit how much
|
||||
-- a player can alter the nether with it.
|
||||
itemstack:add_wear(65535 / (nether.lightstaff_uses - 1))
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue