mirror of
https://github.com/minetest-mods/nether.git
synced 2024-11-15 23:10:37 +01:00
Treasure: Nether staff of light
Adds "Nether staff of Light" and "Nether staff of Eternal Light" One is limited to 60 uses, and the other has unlimited uses but the glowstone it creates will only last for 40 seconds. There are no crafting recipes as I hope these to eventually be treasure that can be found in the nether.
This commit is contained in:
parent
5895152c60
commit
565bbe0508
|
@ -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 again wear when mining netherrack.
|
||||
|
||||
|
||||
## License of source code:
|
||||
|
@ -50,6 +51,7 @@ 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/)
|
||||
|
||||
|
@ -64,6 +66,7 @@ SOFTWARE.
|
|||
* `nether_fumarole.ogg`: Treer, 2020
|
||||
* `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
|
||||
|
|
106
nodes.lua
106
nodes.lua
|
@ -65,6 +65,110 @@ 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", {
|
||||
|
@ -105,6 +209,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
|
||||
|
@ -116,6 +221,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", {
|
||||
|
|
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 |
200
tools.lua
200
tools.lua
|
@ -151,3 +151,203 @@ minetest.register_craft({
|
|||
{"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 the particle physics doesn't seem accurate enough for curved trajectories
|
||||
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
|
||||
local serverLag = 0.05 -- rough amount reduce particle effect synchronization with lightstaff node changes
|
||||
|
||||
-- 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)))
|
||||
aimPos.y = aimPos.y + (distance / nether.lightstaff_velocity) * nether.lightstaff_gravity
|
||||
local boltDir = vector.normalize(vector.subtract(aimPos, wieldPos))
|
||||
|
||||
-- needs a proper casting sound, instead of the portal ignition
|
||||
minetest.sound_play("nether_portal_ignite", {to_player = playerName, gain = .3, pitch = 1.7}, 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