mods/sponge/init.lua
WilLiam12 e482755330 k
2021-03-26 20:52:52 -03:00

260 lines
6.6 KiB
Lua

local tex = function(n) return "sponge_"..n..".png" end
local node_wet = "sponge:wet"
local node_dry = "sponge:dry"
local item_wet = "sponge:wet_item"
local wet_meta = "ds2.minetest.sponge.wetness"
-- configuration setup
local drain_radius
local msg = "bad configuration: "
local s = minetest.settings:get("ds2.minetest.sponge.drain_radius")
if s == nil then
-- default value
drain_radius = 2
else
local v = tonumber(s)
assert(v ~= nil, msg.."drain_radius was not a valid numerical value: "..s)
-- allow it to be zero to disable the node
assert(v >= 0, msg.."drain_radius must be positive: "..v)
assert((v % 1.0) == 0, msg.."drain_radius must be an integer: "..v)
drain_radius = v
end
local r = drain_radius
local rw = function(v) return (v * 2) + 1 end
local cube = function(v) return v*v*v end
-- the node can never include itself
local max_absorbed = cube(rw(r)) - 1
-- sanity checking to ensure water value can fit inside 8-bit param2.
-- we store it as (water - 1) as we have a separate block for dry.
assert(max_absorbed <= 256, "selected radius total volume doesn't fit into param2")
-- ways to get water out of a wet sponge.
local wetsponge_on_rightclick
-- check if buckets is enabled by looking at their item defs
local empty = "bucket:bucket_empty"
local full = "bucket:bucket_water"
local defs = minetest.registered_items
local buckets_enabled = defs[empty] and defs[full]
-- take a bucket from a player and give them back the wet one.
-- returns the left-over itemstack, if any.
local player_give_bucket = function(player, original)
local list = player:get_wield_list()
local inv = player:get_inventory()
local count = original:get_count()
local bucket = ItemStack(full)
if inv:room_for_item(list, bucket) then
count = count - 1
original:set_count(count)
inv:add_item(list, bucket)
end
return original
end
local wet_replace = { name = node_wet }
local dry_replace = { name = node_dry }
local dry_replace_notrigger = { name = node_dry, param2 = 1 }
if buckets_enabled then
wetsponge_on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if clicker:is_player() and itemstack:get_name() == empty then
-- do the necessary fiddling with the item stack
itemstack = player_give_bucket(clicker, itemstack)
-- decrement the count and revert to dry if necessary.
local count = node.param2
count = count - 1
local node
if count < 0 then
node = dry_replace_notrigger
else
wet_replace.param2 = count
node = wet_replace
end
minetest.set_node(pos, node)
end
return itemstack
end
else
wetsponge_on_rightclick = function() end
end
-- when someone breaks this block, create a wet sponge item.
local air = { name = "air" }
local l = {}
local item_label_prefix = "Wet sponge "
local handle_drop_single = function(pos, itemstack, digger)
l[1] = itemstack:to_string()
return minetest.handle_node_drops(pos, l, digger)
end
local wet_sponge_on_dig = function(pos, node, digger)
local itemstack = ItemStack(item_wet)
local count = node.param2 + 1
local meta = itemstack:get_meta()
meta:set_int(wet_meta, count)
meta:set_string("description", item_label_prefix.."(absorbed nodes: "..count..")")
handle_drop_single(pos, itemstack, digger)
minetest.set_node(pos, air)
end
-- when a wet sponge item is placed: read back the level from it's metadata.
-- if it's absent, assume it's the maximum as determined by radius.
-- then, set itemstack to zero and place wet node,
-- but only if placed in air for now.
local n = {}
local setnodeptnn = function(pos, name, param2)
n.name = name
n.param2 = param2
return minetest.set_node(pos, n)
end
local wet_sponge_on_place = function(itemstack, placer, pointed)
if pointed.type ~= "node" then return end
local target = pointed.above
local old = minetest.get_node(target)
if old.name ~= "air" then return end
local meta = itemstack:get_meta()
local level = meta:get_int(wet_meta)
if level == 0 then level = max_absorbed end
-- if for some daft reason the values are out of range, clamp them
if level < 0 then level = 1 end
if level > max_absorbed then level = max_absorbed end
local param2 = level - 1
setnodeptnn(target, node_wet, param2)
itemstack:set_count(0)
return itemstack
end
-- placement logic for drainage
local p = {}
local try_drain = function(x, y, z)
p.x = x
p.y = y
p.z = z
local node = minetest.get_node(p)
local is_water = (node.name == "default:water_source")
if is_water then
minetest.set_node(p, air)
end
return is_water
end
local on_construct = function(pos)
-- we have to check our param2 to know whether it was placed by a player.
local node = minetest.get_node(pos)
if node.param2 > 0 then return end
local xc, yc, zc = pos.x, pos.y, pos.z
local count = 0
-- rip indentation
for z = zc - r, zc + r, 1 do
for y = yc - r, yc + r, 1 do
for x = xc - r, xc + r, 1 do
-- oh look, a convienient table
if try_drain(x, y, z) then
count = count + 1
end
end
end
end
-- shouldn't be possible here, but guard anyway
assert(count < 256)
if count > 0 then
wet_replace.param2 = count - 1
minetest.set_node(pos, wet_replace)
end
end
-- registration of nodes
-- I don't really know what groups would be appropriate for a spongy block
-- (that would be compatible with existing tools).
local groups = {
oddly_breakable_by_hand = 3,
}
-- explicitly disable water absorption behaviour if drain_radius is zero.
local enable = (drain_radius ~= 0)
local ifdrain = function(v)
return enable and v or nil
end
minetest.register_node(node_dry, {
description = "Dry sponge",
tiles = { tex("dry") },
groups = groups,
on_construct = ifdrain(on_construct),
})
minetest.register_node(node_wet, {
description = "Wet sponge block (HACKERRRRR)",
tiles = { tex("wet") },
groups = {
oddly_breakable_by_hand = 3,
not_in_creative_inventory = 1,
},
on_rightclick = wetsponge_on_rightclick,
on_dig = wet_sponge_on_dig,
})
-- the wet item: used to keep track of capacity
minetest.register_craftitem(item_wet, {
description = item_label_prefix .. "(pre-filled)",
stack_max = 1,
inventory_image = tex("wet_item"),
on_place = wet_sponge_on_place,
})
-- dry out sponges via furnace.
-- in future this may need balancing - sponges can hold a fair amount of water,
-- and water is relatively hard to boil.
minetest.register_craft({
type = "cooking",
output = node_dry,
recipe = item_wet,
cooktime = 10,
})
-- mapgen: generate under water (TODO: biomes? like ocean)
minetest.register_decoration({
deco_type = "simple",
decoration = node_wet,
place_on = "default:sand",
sidelen = 16,
fill_ratio = 0.00005,
y_max = -16,
y_min = -31000,
spawn_by = "default:water_source",
num_spawn_by = 4,
param2 = 255,
flags = "force_placement",
height = 5,
})