forked from minetest-mods/nether
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
69e8253193
@ -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.
|
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
|
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
|
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
|
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.
|
a particular branch of the tech-tree.
|
||||||
|
|
||||||
Netherbrick tools are provided (pick, shovel, axe, & sword), see tools.lua
|
Netherbrick tools are provided (pick, shovel, axe, & sword), see tools.lua
|
||||||
|
The Nether pickaxe has a 10x bonus again wear when mining netherrack.
|
||||||
Nether Portals can allow surface fast-travel.
|
|
||||||
|
|
||||||
|
|
||||||
## License of source code:
|
## License of source code:
|
||||||
@ -50,9 +51,11 @@ SOFTWARE.
|
|||||||
### [Public Domain Dedication (CC0 1.0)](https://creativecommons.org/publicdomain/zero/1.0/)
|
### [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_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/)
|
### [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_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_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.
|
* `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.
|
||||||
@ -64,6 +67,7 @@ SOFTWARE.
|
|||||||
* `nether_fumarole.ogg`: Treer, 2020
|
* `nether_fumarole.ogg`: Treer, 2020
|
||||||
* `nether_lava_bubble`* (files starting with "nether_lava_bubble"): Treer, 2020
|
* `nether_lava_bubble`* (files starting with "nether_lava_bubble"): Treer, 2020
|
||||||
* `nether_lava_crust_animated.png`: Treer, 2019-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_particle_anim`* (files starting with "nether_particle_anim"): Treer, 2019
|
||||||
* `nether_portal_ignition_failure.ogg`: Treer, 2019
|
* `nether_portal_ignition_failure.ogg`: Treer, 2019
|
||||||
* `nether_smoke_puff.png`: Treer, 2020
|
* `nether_smoke_puff.png`: Treer, 2020
|
||||||
|
2
mod.conf
2
mod.conf
@ -1,4 +1,4 @@
|
|||||||
name = nether
|
name = nether
|
||||||
description = Adds a deep underground realm with different mapgen that you can reach with obsidian portals.
|
description = Adds a deep underground realm with different mapgen that you can reach with obsidian portals.
|
||||||
depends = stairs, default
|
depends = stairs, default
|
||||||
optional_depends = moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire, climate_api, ethereal
|
optional_depends = moreblocks, mesecons, loot, dungeon_loot, doc_basics, fire, climate_api, ethereal, walls
|
||||||
|
190
nodes.lua
190
nodes.lua
@ -65,13 +65,118 @@ 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
|
-- Nether nodes
|
||||||
|
|
||||||
minetest.register_node("nether:rack", {
|
minetest.register_node("nether:rack", {
|
||||||
description = S("Netherrack"),
|
description = S("Netherrack"),
|
||||||
tiles = {"nether_rack.png"},
|
tiles = {"nether_rack.png"},
|
||||||
is_ground_content = true,
|
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(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -81,7 +186,8 @@ minetest.register_node("nether:rack_deep", {
|
|||||||
_doc_items_longdesc = S("Netherrack from deep in the mantle"),
|
_doc_items_longdesc = S("Netherrack from deep in the mantle"),
|
||||||
tiles = {"nether_rack_deep.png"},
|
tiles = {"nether_rack_deep.png"},
|
||||||
is_ground_content = true,
|
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(),
|
sounds = default.node_sound_stone_defaults(),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -103,6 +209,7 @@ minetest.register_node("nether:glowstone", {
|
|||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||||
sounds = default.node_sound_glass_defaults(),
|
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
|
-- Deep glowstone, found in the mantle / central magma layers
|
||||||
@ -114,6 +221,7 @@ minetest.register_node("nether:glowstone_deep", {
|
|||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
groups = {cracky = 3, oddly_breakable_by_hand = 3},
|
||||||
sounds = default.node_sound_glass_defaults(),
|
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", {
|
minetest.register_node("nether:brick", {
|
||||||
@ -175,37 +283,89 @@ minetest.register_node("nether:brick_deep", {
|
|||||||
|
|
||||||
-- Register stair and slab
|
-- Register stair and slab
|
||||||
|
|
||||||
stairs.register_stair_and_slab(
|
-- Nether bricks can be made into stairs, slabs, inner stairs, and outer stairs
|
||||||
"nether_brick",
|
|
||||||
"nether:brick",
|
stairs.register_stair_and_slab( -- this function also registers inner and outer stairs
|
||||||
{cracky = 2, level = 2},
|
"nether_brick", -- subname
|
||||||
{"nether_brick.png"},
|
"nether:brick", -- recipeitem
|
||||||
S("Nether Stair"),
|
{cracky = 2, level = 2}, -- groups
|
||||||
S("Nether Slab"),
|
{"nether_brick.png"}, -- images
|
||||||
default.node_sound_stone_defaults(),
|
S("Nether Stair"), -- desc_stair
|
||||||
nil,
|
S("Nether Slab"), -- desc_slab
|
||||||
S("Inner Nether Stair"),
|
minetest.registered_nodes["nether:brick"].sounds, -- sounds
|
||||||
S("Outer Nether Stair")
|
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(
|
stairs.register_stair(
|
||||||
"netherrack",
|
"netherrack",
|
||||||
"nether:rack",
|
"nether:rack",
|
||||||
{cracky = 2, level = 2},
|
{cracky = 2, level = 2},
|
||||||
{"nether_rack.png"},
|
{"nether_rack.png"},
|
||||||
S("Netherrack stair"),
|
S("Netherrack stair"),
|
||||||
default.node_sound_stone_defaults()
|
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("Deep 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", "A Netherrack wall", "nether_rack.png", "nether:rack", minetest.registered_nodes["nether:rack"].sounds)
|
||||||
|
walls.register("nether:rack_deep_wall", "A Deep Netherrack wall", "nether_rack_deep.png", "nether:rack_deep", minetest.registered_nodes["nether:rack_deep"].sounds)
|
||||||
|
end
|
||||||
|
|
||||||
-- StairsPlus
|
-- StairsPlus
|
||||||
|
|
||||||
if minetest.get_modpath("moreblocks") then
|
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(
|
stairsplus:register_all(
|
||||||
"nether", "brick", "nether:brick", {
|
"nether", "brick", "nether:brick", {
|
||||||
description = S("Nether Brick"),
|
description = S("Nether Brick"),
|
||||||
groups = {cracky = 2, level = 2},
|
groups = {cracky = 2, level = 2},
|
||||||
tiles = {"nether_brick.png"},
|
tiles = {"nether_brick.png"},
|
||||||
sounds = default.node_sound_stone_defaults(),
|
sounds = minetest.registered_nodes["nether:brick"].sounds,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
BIN
sounds/nether_lightstaff.ogg
Normal file
BIN
sounds/nether_lightstaff.ogg
Normal file
Binary file not shown.
BIN
sounds/nether_rack_destroy.ogg
Normal file
BIN
sounds/nether_rack_destroy.ogg
Normal file
Binary file not shown.
BIN
textures/nether_lightstaff.png
Normal file
BIN
textures/nether_lightstaff.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
230
tools.lua
230
tools.lua
@ -20,18 +20,33 @@
|
|||||||
local S = nether.get_translator
|
local S = nether.get_translator
|
||||||
|
|
||||||
minetest.register_tool("nether:pick_nether", {
|
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",
|
inventory_image = "nether_tool_netherpick.png",
|
||||||
tool_capabilities = {
|
tool_capabilities = {
|
||||||
full_punch_interval = 0.8,
|
full_punch_interval = 0.8,
|
||||||
max_drop_level=3,
|
max_drop_level=3,
|
||||||
groupcaps={
|
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},
|
damage_groups = {fleshy=4},
|
||||||
},
|
},
|
||||||
sound = {breaks = "default_tool_breaks"},
|
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", {
|
minetest.register_tool("nether:shovel_nether", {
|
||||||
@ -136,3 +151,212 @@ minetest.register_craft({
|
|||||||
{"group:stick"}
|
{"group:stick"}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--===========================--
|
||||||
|
--== 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
Block a user