anchorstone/init.lua

370 lines
13 KiB
Lua

anchorstone = {}
local S = minetest.get_translator()
local stone_sound = default.node_sound_stone_defaults()
local stone_texture = "default_stone.png"
local cobble_texture = "default_stone_block.png"
local anchorstone_trigger_breaks_sound = "default_tool_breaks"
local preserved_source_key = "preserved_source"
local anchorstone_name = "anchorstone:anchorstone"
local anchorstone_displaced_name = "anchorstone:displaced"
local anchorstone_resettable = minetest.settings:get_bool("anchorstone_resettable", true)
local anchorstone_ore = minetest.settings:get_bool("anchorstone_ore", true)
local anchorstone_trigger_uses = tonumber(minetest.settings:get("anchorstone_trigger_uses")) or 0
local trigger_stack_size = 99
local trigger_wear_amount = 0
local trigger_tool_capabilities = nil
if anchorstone_trigger_uses ~= 0 then
trigger_stack_size = 1
trigger_wear_amount = math.ceil(65535 / anchorstone_trigger_uses)
trigger_tool_capabilities = {
full_punch_interval=1.5,
max_drop_level=1,
groupcaps={},
damage_groups = {},
}
end
local preserve_anchorstone_meta = function(pos, oldnode, oldmeta, drops)
local preserved_source = oldmeta[preserved_source_key]
if preserved_source == nil then
preserved_source = minetest.pos_to_string(pos)
end
for index, itemstack in pairs(drops) do
if itemstack:get_name() == anchorstone_displaced_name then
itemstack_meta = itemstack:get_meta()
itemstack_meta:set_string(preserved_source_key, preserved_source)
itemstack_meta:set_string("description", S("Anchorstone from @1", preserved_source))
end
end
end
minetest.register_node(anchorstone_name, {
description = S("Native Anchorstone"),
_doc_items_longdesc = S('A strange mineral that has become mystically bonded to the location in space that it has rested in for so long.'),
_doc_items_usagehelp = S('When dug out and relocated native anchorstone becomes "displaced" anchorstone. It retains an affinity for the location it was bonded to that can be exploited to teleport objects there, with the right tools.'),
drawtype = "normal",
tiles = {stone_texture.."^anchorstone_spark.png"},
is_ground_content = true,
node_box = {type="regular"},
sounds = stone_sound,
groups = {cracky = 3, stone = 1},
drop = anchorstone_displaced_name,
preserve_metadata = preserve_anchorstone_meta,
})
local particle_node_pos_spread = vector.new(0.5,0.5,0.5)
local particle_user_pos_spread = vector.new(0.5,1.5,0.5)
local particle_speed_spread = vector.new(0.1,0.1,0.1)
local min_spark_delay = 30
local max_spark_delay = 120
minetest.register_node(anchorstone_displaced_name, {
description = S("Displaced Anchorstone"),
_doc_items_longdesc = S("Anchorstone that bonded to one location but that has been relocated somewhere else."),
_doc_items_usagehelp = S("Displaced anchorstone would really rather be back in its original location. The bond isn't strong enough to drag it there spontaneously, but the residual spatial tension can be used to teleport other objects there with the right tools."),
drawtype = "normal",
tiles = {cobble_texture.."^anchorstone_spark_saturated.png"},
is_ground_content = true,
node_box = {type="regular"},
sounds = stone_sound,
groups = {cracky = 3, stone = 1, not_in_creative_inventory = 1},
stack_max = 1,
preserve_metadata = preserve_anchorstone_meta,
-- Called after constructing node when node was placed using
-- minetest.item_place_node / minetest.place_node.
-- If return true no item is taken from itemstack.
-- `placer` may be any valid ObjectRef or nil.
after_place_node = function(pos, placer, itemstack, pointed_thing)
local item_meta = itemstack:get_meta()
local preserved_source = item_meta:get(preserved_source_key)
if preserved_source and minetest.string_to_pos(preserved_source) then
local node_meta = minetest.get_meta(pos)
node_meta:set_string(preserved_source_key, preserved_source)
node_meta:mark_as_private(preserved_source_key)
local node_timer = minetest.get_node_timer(pos)
node_timer:start(math.random(min_spark_delay, max_spark_delay))
else
-- metadata was lost somehow, alas.
minetest.set_node(pos, {name = anchorstone_name})
end
end,
on_blast = function(pos, intensity)
local meta = minetest.get_meta(pos)
local preserved_source = meta:get(preserved_source_key)
if preserved_source then
local preserved_source_pos = minetest.string_to_pos(preserved_source)
if preserved_source_pos then
local item = ItemStack(anchorstone_displaced_name)
local item_meta = item:get_meta()
item_meta:set_string(preserved_source_key, preserved_source)
minetest.item_drop(item, nil, pos)
end
end
minetest.set_node(pos, {name = "air"})
end,
on_timer = function(pos, elapsed)
local meta = minetest.get_meta(pos)
local preserved_source = meta:get(preserved_source_key)
if preserved_source then
local preserved_source_pos = minetest.string_to_pos(preserved_source)
if preserved_source_pos then
local dir = vector.multiply(vector.direction(pos, preserved_source_pos), 3)
minetest.add_particlespawner({
amount = 10,
time = 0.5,
minpos = vector.subtract(pos, particle_node_pos_spread),
maxpos = vector.add(pos, particle_node_pos_spread),
minvel = vector.subtract(dir, particle_speed_spread),
maxvel = vector.add(dir, particle_speed_spread),
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 1,
maxexptime = 3,
minsize = 1,
maxsize = 1,
collisiondetection = false,
vertical = false,
texture = "anchorstone_spark.png",
})
local node_timer = minetest.get_node_timer(pos)
node_timer:start(math.random(min_spark_delay, max_spark_delay))
return
end
end
-- metadata was lost somehow, revert to anchorstone
minetest.set_node(pos, {name = anchorstone_name})
end,
})
local trigger_help_addendum = ""
if anchorstone_trigger_uses > 0 then
trigger_help_addendum = S(" This tool can be used @1 times before breaking.", anchorstone_trigger_uses)
end
local trigger_def = {
description = S("Anchorstone Trigger"),
_doc_items_longdesc = S("A triggering device that allows teleportation via displaced anchorstone."),
_doc_items_usagehelp = S("When applied to a piece of displaced anchorstone this tool becomes entangled in the connection it has to its original location and is magically dragged there (along with whatever's holding on to it).") .. trigger_help_addendum,
inventory_image = "anchorstone_spark.png^anchorstone_tool_base.png",
stack_max = trigger_stack_size,
tool_capabilites = trigger_tool_capabilities,
sound = {
breaks = anchorstone_trigger_breaks_sound,
},
on_use = function(itemstack, user, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
if not node then
return itemstack
end
if node.name ~= anchorstone_displaced_name then
return itemstack
end
local node_meta = minetest.get_meta(pos)
if not node_meta then
return itemstack
end
local preserved_source_string = node_meta:get(preserved_source_key)
if not preserved_source_string then
return itemstack
end
local preserved_pos = minetest.string_to_pos(preserved_source_string)
if not preserved_pos then
return itemstack
end
local old_pos = user:get_pos()
old_pos.y = old_pos.y + 0.5
local speed = vector.multiply(vector.direction(old_pos, preserved_pos), 5/0.5)
minetest.add_particlespawner({
amount = 100,
time = 0.1,
minpos = vector.subtract(old_pos, particle_node_pos_spread),
maxpos = vector.add(old_pos, particle_user_pos_spread),
minvel = vector.subtract(speed, particle_speed_spread),
maxvel = vector.add(speed, particle_speed_spread),
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 0.1,
maxexptime = 0.5,
minsize = 1,
maxsize = 1,
collisiondetection = false,
vertical = false,
texture = "anchorstone_spark.png",
})
minetest.sound_play({name="anchorstone_teleport_from"}, {pos = old_pos}, true)
user:set_pos({x=preserved_pos.x, y=preserved_pos.y-0.5, z=preserved_pos.z})
preserved_pos = vector.subtract(preserved_pos, speed)
minetest.add_particlespawner({
amount = 100,
time = 0.1,
minpos = vector.subtract(preserved_pos, particle_node_pos_spread),
maxpos = vector.add(preserved_pos, particle_user_pos_spread),
minvel = vector.subtract(speed, particle_speed_spread),
maxvel = vector.add(speed, particle_speed_spread),
minacc = {x=0, y=0, z=0},
maxacc = {x=0, y=0, z=0},
minexptime = 0.5,
maxexptime = 0.5,
minsize = 1,
maxsize = 1,
collisiondetection = false,
vertical = false,
texture = "anchorstone_spark.png",
})
minetest.sound_play({name="anchorstone_teleport_to"}, {pos = preserved_pos}, true)
if trigger_wear_amount > 0 then
itemstack:add_wear(trigger_wear_amount)
end
return itemstack
end
}
if trigger_tool_capabilities then
minetest.register_tool("anchorstone:trigger", trigger_def)
else
minetest.register_craftitem("anchorstone:trigger", trigger_def)
end
minetest.register_craftitem("anchorstone:reader", {
description = S("Anchorstone Reader"),
_doc_items_longdesc = S("A much weaker form of the anchorstone trigger, this tool is able to determine the strength and direction of a displaced anchorstone's bond."),
_doc_items_usagehelp = S("Simply apply this tool to a piece of displaced anchorstone and it will tell you the location it originated from."),
inventory_image = "anchorstone_spark.png^[colorize:#8888FF:128^anchorstone_tool_base.png",
on_use = function(itemstack, user, pointed_thing)
if user == nil then
return itemstack
end
if pointed_thing.type ~= "node" then
return itemstack
end
local pos = pointed_thing.under
local node = minetest.get_node(pos)
if not node then
return itemstack
end
if node.name ~= anchorstone_displaced_name then
return itemstack
end
local node_meta = minetest.get_meta(pos)
if not node_meta then
return itemstack
end
local preserved_source_string = node_meta:get(preserved_source_key)
if not preserved_source_string then
return itemstack
end
local preserved_pos = minetest.string_to_pos(preserved_source_string)
if not preserved_pos then
return itemstack
end
minetest.chat_send_player(user:get_player_name(), S("Anchorstone origin: @1, @2m away", preserved_source_string, math.floor(vector.distance(pos, preserved_pos))))
return itemstack
end
})
-- An external API to allow convenient creation of displaced anchorstone by other mods
anchorstone.place_displaced_anchorstone_node = function(pos, destination_pos)
minetest.set_node(pos, {name = anchorstone_displaced_name})
local node_meta = minetest.get_meta(pos)
node_meta:set_string(preserved_source_key, destination_pos)
node_meta:mark_as_private(preserved_source_key)
local node_timer = minetest.get_node_timer(pos)
node_timer:start(math.random(min_spark_delay, max_spark_delay))
end
anchorstone.create_displaced_anchorstone_item = function(destination_pos)
local item = ItemStack(anchorstone_displaced_name)
local preserved_source = minetest.pos_to_string(destination_pos)
itemstack_meta = item:get_meta()
itemstack_meta:set_string(preserved_source_key, preserved_source)
itemstack_meta:set_string("description", S("Anchorstone from @1", preserved_source))
return item
end
----------------------------------------------
-- More default mod dependencies:
minetest.register_craft({
output = "anchorstone:trigger",
recipe = {
{"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"},
{"default:mese_crystal_fragment", anchorstone_displaced_name, "default:mese_crystal_fragment"},
{"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"}
}
})
if anchorstone_resettable then
-- Allows players to do arbitrary anchorstone placement
minetest.register_craft({
output = anchorstone_name,
recipe = {
{"default:mese_crystal_fragment", "bucket:bucket_lava", "default:mese_crystal_fragment"},
{"bucket:bucket_lava", anchorstone_displaced_name, "bucket:bucket_lava"},
{"default:mese_crystal_fragment", "bucket:bucket_lava", "default:mese_crystal_fragment"}
},
replacements = {{"bucket:bucket_lava", "bucket:bucket_empty"}, {"bucket:bucket_lava", "bucket:bucket_empty"}, {"bucket:bucket_lava", "bucket:bucket_empty"}, {"bucket:bucket_lava", "bucket:bucket_empty"}},
})
end
minetest.register_craft({
output = "anchorstone:reader",
recipe = {
{"", "default:steel_ingot", ""},
{"default:steel_ingot", anchorstone_displaced_name, "default:steel_ingot"},
{"", "default:steel_ingot", ""}
}
})
if anchorstone_ore then
minetest.register_ore({
ore_type = "scatter",
ore = anchorstone_name,
wherein = "default:stone",
clust_scarcity = 32 * 32 * 32,
-- Ore has a 1 out of clust_scarcity chance of spawning in a node.
-- If the desired average distance between ores is 'd', set this to
-- d * d * d.
clust_num_ores = 3,
clust_size = 2,
y_min = -31000,
y_max = 31000,
})
end