Compare commits

...

17 Commits

7 changed files with 704 additions and 208 deletions

View File

@ -95,7 +95,7 @@ S("• When water is directly below lava, the water turns into stone."),
liquid_range = 7, liquid_range = 7,
post_effect_color = {a=209, r=0x03, g=0x3C, b=0x5C}, post_effect_color = {a=209, r=0x03, g=0x3C, b=0x5C},
stack_max = 64, stack_max = 64,
groups = { water=3, liquid=3, puts_out_fire=1, freezes=1, not_in_creative_inventory=1, dig_by_piston=1}, groups = { water=3, legacity_water=1, liquid=3, puts_out_fire=1, freezes=1, not_in_creative_inventory=1, dig_by_piston=1},
_mcl_blast_resistance = 100, _mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode -- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1, _mcl_hardness = -1,

View File

@ -353,15 +353,17 @@ local function furnace_node_timer(pos, elapsed)
-- Unique recipe: Pour water into empty bucket after cooking wet sponge successfully -- Unique recipe: Pour water into empty bucket after cooking wet sponge successfully
if inv:get_stack("fuel", 1):get_name() == "mcl_buckets:bucket_empty" then if inv:get_stack("fuel", 1):get_name() == "mcl_buckets:bucket_empty" then
if srclist[1]:get_name() == "mcl_sponges:sponge_wet" then local sponge_name = srclist[1]:get_name()
if mcl_sponges.is_sponge(sponge_name) then
if mcl_sponges.has_sponge_liquid(sponge_name, "water") then
inv:set_stack("fuel", 1, "mcl_buckets:bucket_water") inv:set_stack("fuel", 1, "mcl_buckets:bucket_water")
fuellist = inv:get_list("fuel") fuellist = inv:get_list("fuel")
-- Also for river water elseif mcl_sponges.has_sponge_liquid(sponge_name, "river_water") then
elseif srclist[1]:get_name() == "mcl_sponges:sponge_wet_river_water" then
inv:set_stack("fuel", 1, "mcl_buckets:bucket_river_water") inv:set_stack("fuel", 1, "mcl_buckets:bucket_river_water")
fuellist = inv:get_list("fuel") fuellist = inv:get_list("fuel")
end end
end end
end
srclist = inv:get_list("src") srclist = inv:get_list("src")
src_time = 0 src_time = 0

View File

@ -0,0 +1,108 @@
`mcl_sponges`
API-oriented mod for Sponges.
Node definitions
----------------
Significant fields in node definition:
* `.groups.sponge` = 1, indicates is a sponge
* `.groups.sponge_wet` > 0, indicates sponge is wet (else sponge is dry)
### `mcl_sponges.registered_sponges`
Table of sponge nodes registered under this API, indexed by sponge name.
### `mcl_sponges.register_sponge(sponge_name, sponge_def)`
* `sponge_name`:string - name under which to register the sponge
* `sponge_def`:table - node definition for sponge
Sponge operations
-----------------
### `mcl_sponges.is_sponge(name)`
Test whether a node name is that of a sponge.
* `name`:string - name of node (node definition name)
### `mcl_sponges.is_sponge_node(node)`
Test node is that of a sponge.
* `node`:table - table {name,param1,param2} from `minetest.get_node()`
### `mcl_sponges.is_sponge_pos(pos)`
Test node at world position is a sponge.
* `pos`:table - position as accepted by `minetest.get_node()`
### `mcl_sponges.is_sponge_wet(name)`
Test node name is that of a wet sponge.
* `name`:string - name of node (node definition name)
### `mcl_sponges.is_sponge_wet_node(node)`
Test node name is that of a wet sponge.
* `node`:table - table {name,param1,param2} from `minetest.get_node()`
### `mcl_sponges.is_sponge_wet_pos(pos)`
Test node name is that of a wet sponge.
* `pos`:table - position as accepted by `minetest.get_node()`
### `mcl_sponges.is_sponge_dry(name)`
Test node name is that of a dry sponge.
* `name`:string - name of node (node definition name)
### `mcl_sponges.is_sponge_dry_node(node)`
Test node name is that of a dry sponge.
* `node`:table - table {name,param1,param2} from `minetest.get_node()`
### `mcl_sponges.is_sponge_dry_pos(pos)`
Test node name is that of a dry sponge.
* `pos`:table - position as accepted by `minetest.get_node()`
### `mcl_sponges.has_sponge_liquid(name, liquid_name)`
Test sponge liquid.
* `name`: - name of node (node definition name)
* `liquid_name`:string - name of liquid associated with sponge; nil for dry.
### `mcl_sponges.has_sponge_liquid_node(name, liquid_name)`
Test sponge liquid.
* `node`: - table {name,param1,param2} from `minetest.get_node()`
* `liquid_name`:string - name of liquid associated with sponge; nil for dry.
### `mcl_sponges.has_sponge_liquid_pos(pos, liquid_name)`
* `pos`:table - position as accepted by `minetest.get_node()`
* `liquid_name`:string - name of liquid associated with sponge; nil for dry.
### `mcl_sponges.absorb_sponge_pos(pos)`
Cause sponge to absorb water according to game rules.
Returns true if sponge successfully absorbed liquid (is now wet);
returns false if sponge had nothing to absorb (stayed dry).
* `pos`:table - position of sponge.
Standard Sponge
---------------
Specified behavior of the standard sponge node:
* Instantly absorbs water when placed next to water.
* Instantly absorbs water when water comes in contact.
* Upon absorption, immediately turns wet and does not absorb more liquid.
* Absorbs flowing and source blocks up to 7 blocks away (taxicab distance).
* Absorption volume is octahedron, vertices 7 units away each cardinal direction.
* Does not absorb more than 135 blocks of water.
* Water closest to sponge gets absorbed first.
* Absorption propagates between adjacent water blocks; does not "jump over" non-water-blocks (incl. air).
* Wet sponge placed in the Nether instantly turns into dry sponge.
* Wet sponge may be smelted in a furnace to turn into dry sponge.
* If smelted with an empty bucket in the fuel slot, bucket fills with water (recover the liquid).
Resolution of ambiguous specifications:
* "Adjacency" interpreted to mean face-to-face contact (and not edge-to-edge/diagonal contact, nor corner-to-corner).
* Should more than 135 blocks be in absorption range, priority is determined by distance, +y (higher altitude first), +x (northmost?), then +z (eastmost?).
* If sponge is resting on node that then disappears and allows water to flow under, absorption occurs even if graphically the water does not touch the sponge.
* Should both water and river water touch the sponge, sponge absorbs whichever liquid would result in more blocks being absorbed (and leaves the other liquid alone).

View File

@ -0,0 +1,152 @@
local S = minetest.get_translator(minetest.get_current_modname())
mcl_sponges.registered_sponges = {}
local function merge_tables(a, b)
local result = {}
for k, v in pairs(a) do result[k] = v end
for k, v in pairs(b) do
if type(v) == "table" then
result[k] = merge_tables(result[k], v)
else
result[k] = v
end
end
return result
end
-- every sponge should express these attributes.
local function validate_sponge(name, nodedef)
local acceptable = true
if nodedef.furnace_drying == nil then
if nodedef.groups.sponge_wet and nodedef.groups.sponge_wet > 0 then
print(("WARNING: sponge group 'furnace_drying' not specified: %s"):format(name))
end
end
if not nodedef.tiles then
print(("WARNING: sponge tile texture not specified, using wet sponge: %s"):foramt(name))
end
if not nodedef.description then
print(("WARNING: No sponge description provided: %s"):format(name))
end
return acceptable
end
-- naming convention:
-- * <OPERATION>_sponge... - function taking registered node [definition] name, typically returns node name (string) or nil (not recognized as sponge).
-- * <OPERATION>_sponge..._node - takes a node (from minetest.get_node()), typically returns node (table) or nil (do not change).
-- * <OPERATION>_sponge..._pos - world position (calls minetest.get_node()), typically returns position (table; world already updated in place) or nil (world not changed).
mcl_sponges._merge_tables = merge_tables
local merge_tables = mcl_sponges._merge_tables
-- find sponge definition by name.
function mcl_sponges.get_sponge_def(name)
for sponge_name, sponge_def in pairs(mcl_sponges.registered_sponges) do
if sponge_name == name then
return sponge_def
end
end
return nil
end
function mcl_sponges.is_sponge(name)
return (mcl_sponges.registered_sponges[name] ~= nil)
end
function mcl_sponges.is_sponge_node(node)
local nodename = node.name
return mcl_sponges.is_sponge(nodename)
end
function mcl_sponges.is_sponge_pos(pos)
local node = minetest.get_node(pos)
if node == nil then return false end
return mcl_sponges.is_sponge_node(node)
end
function mcl_sponges.is_sponge_wet(name)
local nodedef = mcl_sponges.registered_sponges[nodedef]
return (not nodedef.groups.sponge_dry) or (nodedef.groups.sponge_dry == 0)
end
function mcl_sponges.is_sponge_wet_node(node)
return mcl_sponges.is_sponge_wet(node.name)
end
function mcl_sponges.is_sponge_wet_pos(pos)
local node = minetest.get_node(pos)
return mcl_sponges.is_sponge_node_wet(node)
end
function mcl_sponges.is_sponge_dry(name)
local nodedef = mcl_sponges.registered_sponges[nodedef]
return (nodedef.groups.sponge_dry and nodedef.groups.sponge_dry > 0)
end
function mcl_sponges.is_sponge_dry_node(node)
return mcl_sponges.is_sponge_dry(node.name)
end
function mcl_sponges.is_sponge_dry_pos(pos)
local node = minetest.get_node(pos)
return mcl_sponges.is_sponge_node_dry(node)
end
function mcl_sponges.has_sponge_liquid(name, liquid_name)
local nodedef = mcl_sponges.registered_sponges[name]
if nodedef._sponge_liquid == liquid_name then
return true
end
return false
end
function mcl_sponges.has_sponge_liquid_node(node, liquid_name)
return mcl_sponges.has_sponge_liquid(node.name, liquid_name)
end
function mcl_sponges.has_sponge_liquid_pos(pos, liquid_name)
local node = minetest.get_node(pos)
return mcl_sponges.has_sponge_liquid(node, liquid_name)
end
-- force sponge to absorb liquid.
function mcl_sponges.absorb_sponge_pos(pos)
local node = minetest.get_node(pos)
if not mcl_sponges.is_sponge_node(node) then
return false
end
return mcl_sponges._absorb_sponge_pos(pos)
end
function mcl_sponges.register_sponge(name, def)
if not validate_sponge(name, def) then
print(string.format("WARNING: rejected as sponge: %s", name))
return
end
mcl_sponges.registered_sponges[name] = def
minetest.register_node(name, def)
-- TODO: validate drying the sponge after all mods are loaded; if def.furnace_drying, then there should exist a crafting recipe such that this sponge is the input and *some* sponge (i.e. exists in registered_sponges) is the output.
-- automatically register as crafting: drying the sponge (convert wet sponge to dry sponge).
if def.furnace_drying then
end
end

View File

@ -1,205 +1,9 @@
local S = minetest.get_translator(minetest.get_current_modname()) local S = minetest.get_translator(minetest.get_current_modname())
local modpath = minetest.get_modpath(minetest.get_current_modname())
local absorb = function(pos) mcl_sponges = {}
local change = false
-- Count number of absorbed river water vs other nodes
-- to determine the wet sponge type.
local river_water = 0
local non_river_water = 0
local p, n
for i=-3,3 do
for j=-3,3 do
for k=-3,3 do
p = {x=pos.x+i, y=pos.y+j, z=pos.z+k}
n = minetest.get_node(p)
if minetest.get_item_group(n.name, "water") ~= 0 then
minetest.add_node(p, {name="air"})
change = true
if n.name == "mclx_core:river_water_source" or n.name == "mclx_core:river_water_flowing" then
river_water = river_water + 1
else
non_river_water = non_river_water + 1
end
end
end
end
end
-- The dominant water type wins. In case of a tie, normal water wins.
-- This slight bias is intentional.
local sponge_type
if river_water > non_river_water then
sponge_type = "mcl_sponges:sponge_wet_river_water"
else
sponge_type = "mcl_sponges:sponge_wet"
end
return change, sponge_type
end
minetest.register_node("mcl_sponges:sponge", {
description = S("Sponge"),
_tt_help = S("Removes water on contact"),
_doc_items_longdesc = S("Sponges are blocks which remove water around them when they are placed or come in contact with water, turning it into a wet sponge."),
drawtype = "normal",
is_ground_content = false,
tiles = {"mcl_sponges_sponge.png"},
walkable = true,
pointable = true,
diggable = true,
buildable_to = false,
stack_max = 64,
sounds = mcl_sounds.node_sound_dirt_defaults(),
groups = {handy=1, hoey=1, building_block=1},
on_place = function(itemstack, placer, pointed_thing)
local pn = placer:get_player_name()
if pointed_thing.type ~= "node" then
return itemstack
end
-- Use pointed node's on_rightclick function first, if present dofile(modpath .. "/api.lua")
local node = minetest.get_node(pointed_thing.under) dofile(modpath .. "/register.lua")
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
if minetest.is_protected(pointed_thing.above, pn) then
return itemstack
end
local pos = pointed_thing.above
local on_water = false
if minetest.get_item_group(minetest.get_node(pos).name, "water") ~= 0 then
on_water = true
end
local water_found = minetest.find_node_near(pos, 1, "group:water")
if water_found then
on_water = true
end
if on_water then
-- Absorb water
-- FIXME: pos is not always the right placement position because of pointed_thing
local absorbed, wet_sponge = absorb(pos)
if absorbed then
minetest.item_place_node(ItemStack(wet_sponge), placer, pointed_thing)
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end
end
return minetest.item_place_node(itemstack, placer, pointed_thing)
end,
_mcl_blast_resistance = 0.6,
_mcl_hardness = 0.6,
})
function place_wet_sponge(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
local name = placer:get_player_name()
if minetest.is_protected(pointed_thing.above, name) then
return itemstack
end
if mcl_worlds.pos_to_dimension(pointed_thing.above) == "nether" then
minetest.item_place_node(ItemStack("mcl_sponges:sponge"), placer, pointed_thing)
local pos = pointed_thing.above
for n = 0, 25 do
minetest.add_particle({
pos = {x = pos.x + math.random(-1, 1)*math.random()/2, y = pos.y + 0.6, z = pos.z + math.random(-1, 1)*math.random()/2},
velocity = {x = 0, y = math.random(), z = 0},
acceleration = {x=0, y=0, z=0},
expirationtime = math.random(),
collisiondetection = false,
vertical = false,
size = math.random(2, 5),
texture = "mcl_particles_sponge"..math.random(1, 5)..".png",
})
end
if not minetest.is_creative_enabled(name) then
itemstack:take_item()
end
return itemstack
end
return minetest.item_place_node(itemstack, placer, pointed_thing)
end
minetest.register_node("mcl_sponges:sponge_wet", {
description = S("Waterlogged Sponge"),
_tt_help = S("Can be dried in furnace"),
_doc_items_longdesc = S("A waterlogged sponge can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of a furnace, the water will pour into the bucket."),
drawtype = "normal",
is_ground_content = false,
tiles = {"mcl_sponges_sponge_wet.png"},
walkable = true,
pointable = true,
diggable = true,
buildable_to = false,
stack_max = 64,
sounds = mcl_sounds.node_sound_dirt_defaults(),
groups = {handy=1, hoey=1, building_block=1},
on_place = place_wet_sponge,
_mcl_blast_resistance = 0.6,
_mcl_hardness = 0.6,
})
if minetest.get_modpath("mclx_core") then
minetest.register_node("mcl_sponges:sponge_wet_river_water", {
description = S("Riverwaterlogged Sponge"),
_tt_help = S("Can be dried in furnace"),
_doc_items_longdesc = S("This is a sponge soaking wet with river water. It can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of the furnace, the river water will pour into the bucket.") .. "\n" .. S("A sponge becomes riverwaterlogged (instead of waterlogged) if it sucks up more river water than (normal) water."),
drawtype = "normal",
is_ground_content = false,
tiles = {"mcl_sponges_sponge_wet_river_water.png"},
walkable = true,
pointable = true,
diggable = true,
buildable_to = false,
stack_max = 64,
sounds = mcl_sounds.node_sound_dirt_defaults(),
groups = {handy=1, building_block=1},
on_place = place_wet_sponge,
_mcl_blast_resistance = 0.6,
_mcl_hardness = 0.6,
})
minetest.register_craft({
type = "cooking",
output = "mcl_sponges:sponge",
recipe = "mcl_sponges:sponge_wet_river_water",
cooktime = 10,
})
end
minetest.register_craft({
type = "cooking",
output = "mcl_sponges:sponge",
recipe = "mcl_sponges:sponge_wet",
cooktime = 10,
})
minetest.register_abm({
label = "Sponge water absorbtion",
nodenames = { "mcl_sponges:sponge" },
neighbors = { "group:water" },
interval = 1,
chance = 1,
action = function(pos)
local absorbed, wet_sponge = absorb(pos)
if absorbed then
minetest.add_node(pos, {name = wet_sponge})
end
end,
})

View File

@ -0,0 +1,426 @@
local S = minetest.get_translator(minetest.get_current_modname())
local merge_tables = mcl_sponges._merge_tables
-- FIXME: use of 'liquidclass' feels wrong (non-extensible); in the meanwhile,
-- it indicates the "source" node name of a liquid, as sponge absorbs both
-- flowing liquids and actual liquid sources, and compatible liquids are
-- determined by their ultimate source type.
-- absorption strategies are based on queueing up a list of node changes (influenced by set_node() arguments).
-- helper function for absorption strategies
-- returns 3 values: boolean, string, table
local function node_qualifies_for_sponging(scanpos, criteria)
local scannode = minetest.get_node(scanpos)
local scandef = minetest.registered_nodes[scannode.name]
local qualified = false
local liquidclass = scandef.liquid_alternative_source
if liquidclass then
for liquidsource, sponge_name in pairs(criteria) do
if liquidsource == liquidclass then
qualified = true
break
end
end
end
-- change to dry form.
local planstep
if qualified then
-- TODO: this should be the non-waterlogged form of node, retrieved by table or function.
local dry_nodename = "air"
local dry_node = { name = dry_nodename }
planstep = { pos=scanpos, node=dry_node }
end
return qualified, liquidclass, planstep
end
-- absorption pattern 2: sponge reaches out to 7 blocks (taxicab distance) along contiguous blocks of liquid.
-- absorbs maximum 135 blocks, closest blocks first.
-- boundary encompasses 15*15*15=3375 blocks; octahedral volume is 2703(?) blocks.
-- upwards of 2703 get_node() calls, and 135 set_node() calls.
-- may warrant use of voxel manipulator.
-- returns 2 values: table, string
-- Breadth-First Search.
-- pos: world position of center of absorption (sponge).
-- criteria: table of acceptable liquid => sponge type when absorbing that.
local function absorption_strategy2(pos, criteria)
-- plan is list of {pos, node}
local plan = {}
-- radius of search (taxicab distance).
local r = 7
-- remaining number of blocks that may be absorbed (countdown).
local absorption_limit = 135
-- visitation chart while searching continguous adjacent blocks.
-- prevent unnecessary backtracking in BFS.
local visited = {}
for i=-r,r do
visited[i] = {}
for j=-r,r do
visited[i][j] = {}
-- now visited[i][j][k] valid
end
end
visited[0][0][0] = true
-- breadth-first search for water nodes to absorb; map out contiguous blocks of liquids.
-- FIXME: this algorithm is fairly dumb and slow.
-- rx,ry,rz - relative Cartesian coordinates
local rx, ry, rz
-- d - distance (search depth)
local d
-- liquidclass - type of liquid to absorb (do not absorb mismatched).
-- start off as nil => seek a liquid to absorb.
-- once a(n acceptable) liquid is found, absorb only that liquid.
-- the resulting web sponge is specified in `criteria`
local liquidclass = nil
-- BFS visitation queue: list of { rx,ry,rz,d }
local queue = { [1]={0,0,0,0} }
local loop_steps = 0
while #queue > 0 do
loop_steps = loop_steps + 1
-- flag to prune searching.
local no_prune = true
-- next node to search.
rx, ry, rz, d = queue[1][1], queue[1][2], queue[1][3], queue[1][4]
table.remove(queue, 1)
-- don't scan center (the sponge).
local nodeliquid, planstep
if d > 0 then
-- scan node.
local scanpos = {x=pos.x+rx, y=pos.y+ry, z=pos.z+rz}
no_prune, nodeliquid, planstep = node_qualifies_for_sponging(scanpos, criteria)
end
if no_prune then
-- potentially absorbable.
if liquidclass == nil then
-- first liquid type found.
liquidclass = nodeliquid
end
if liquidclass == nodeliquid then
table.insert(plan, planstep)
-- count down absorption limit (max 135 absorbed).
absorption_limit = absorption_limit - 1
if absorption_limit <= 0 then
-- terminate all searches.
no_prune, queue = false, {}
break
end
else
-- mismatched liquid (no go); prune search.
no_prune = false
end
end
-- adjacent nodes.
if d < r and no_prune then
-- prioritize top to bottom.
if ry < r then
if not visited[rx][ry+1][rz] then
visited[rx][ry+1][rz] = true
table.insert(queue, {rx, ry+1, rz, d+1})
end
end
if ry > -r then
if not visited[rx][ry-1][rz] then
visited[rx][ry-1][rz] = true
table.insert(queue, {rx, ry-1, rz, d+1})
end
end
-- prioritize north to south.
if rz < r then
if not visited[rx][ry][rz+1] then
visited[rx][ry][rz+1] = true
table.insert(queue, {rx, ry, rz+1, d+1})
end
end
if rz > -r then
if not visited[rx][ry][rz-1] then
visited[rx][ry][rz-1] = true
table.insert(queue, {rx, ry, rz-1, d+1})
end
end
-- prioritize east to west.
if rx < r then
if not visited[rx+1][ry][rz] then
visited[rx+1][ry][rz] = true
table.insert(queue, {rx+1, ry, rz, d+1})
end
end
if rx > -r then
if not visited[rx-1][ry][rz] then
visited[rx-1][ry][rz] = true
table.insert(queue, {rx-1, ry, rz, d+1})
end
end
end
end
-- determine the wet sponge from the liquid type absorbed.
local new_spongename = criteria[liquidclass]
return plan, new_spongename
end
-- absorption strategy 1: any water block in surrounding 7x7x7 cube.
local function absorption_strategy1(pos, criteria)
local plan = {}
-- number of blocks found for each liquidclass
local scores = {}
-- all potential node changes (filter later)
local raw = {}
for i=-3,3 do
for j=-3,3 do
for k=-3,3 do
local scanpos = { x=pos.x+i, y=pos.y+j, z=pos.z+k }
local qualified, liquidclass, nodeplan = node_qualifies_for_sponging(scanpos, criteria)
if qualified then
-- change to dry form.
if scores[liquidclass] then
scores[liquidclass] = scores[liquidclass] + 1
else
scores[liquidclass] = 1
end
table.insert(raw, {liquidclass=liquidclass, nodeplan=nodeplan})
end
end
end
end
local maxscore, maxliquid = 0, nil
for ls, count in pairs(scores) do
if count > maxscore then
maxscore = count
maxliquid = ls
end
end
local filterclass = maxliquid
for i, planstep in next, raw do
if planstep.liquidclass == filterclass then
table.insert(plan, planstep.nodeplan)
end
end
local new_spongename = criteria[filterclass]
return plan, new_spongename
end
-- Calculate steps necessary to enact sponge-absorption behavior.
-- Uses minetest.get_node() to examine surrounding nodes.
-- return value is a list of pending changes, each entry is a table{pos,node} (the parameters to minetest.set_node).
-- returns 2 values: list of table{pos,node}, string
local function absorb_using_getset_node(node, pos)
local sponge_node = node
local nodedef = mcl_sponges.registered_sponges[sponge_node.name]
local plan = {}
local new_spongename
plan, new_spongename = absorption_strategy2(pos, {
["mcl_core:water_source"]="mcl_sponges:sponge_water",
["mclx_core:river_water_source"]="mcl_sponges:sponge_river_water",
})
return plan, new_spongename
end
-- Sponge absorption behavior at specified position, based on minetest.get_node() and minetest.set_node()
-- force_node: presume node is at position; sponges absorb liquids as soon as they are placed, but if there are no liquids, dry sponge should happen intead.
local function absorb_using_getset_pos(pos, force_node)
local sponge_node
if force_node == nil then
sponge_node = minetest.get_node(pos)
else
sponge_node = force_node
end
if not mcl_sponges.is_sponge_node(sponge_node) then
return false
end
local plan, new_spongename = absorb_using_getset_node(sponge_node, pos)
if not plan then
return false
end
for planid, planstep in ipairs(plan) do
minetest.set_node(planstep.pos, planstep.node)
end
if new_spongename then
local newnode = { name=new_spongename }
minetest.set_node(pos, newnode)
return true
else
return false
end
end
-- placeholder for sponge absorption behavior using Voxel Manipulator. Delete if this never happens.
local function absorb_using_voxel_manipulator_pos(pos, force_node)
end
mcl_sponges._absorb_using_getset_pos = absorb_using_getset_pos
mcl_sponges._absorb_using_voxmanip_pos = absorb_using_voxel_manipulator_pos
-- `force_node` is optional to help avoid multiple minetest.set_node() on the same position when trying to place dry sponge.
local function absorb_sponge_pos(pos, force_node)
return absorb_using_getset_pos(pos, force_node)
end
mcl_sponges._absorb_sponge_pos = absorb_using_getset_pos
-- NODE: dry sponge
mcl_sponges.register_sponge("mcl_sponges:sponge", {
description = S("Sponge"),
_tt_help = S("Removes water on contact"),
_doc_items_longdesc = S("Sponges are blocks which remove certain liquid nodes around them when they are placed or come in contact with liquid, turning it into a wet sponge."),
is_ground_content = false,
tiles = {"mcl_sponges_sponge.png"},
sounds = mcl_sounds.node_sound_dirt_defaults(),
groups = {handy=1, hoey=1, building_block=1, sponge=1, sponge_dry=1},
on_place = function(itemstack, placer, pointed_thing)
local pn = placer:get_player_name()
if pointed_thing.type ~= "node" then
return itemstack
end
-- Use pointed node's on_rightclick function first, if present
local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing)
if new_stack then
return new_stack
end
if minetest.is_protected(pointed_thing.above, pn) then
return itemstack
end
local pos = pointed_thing.above
local fallback_node = {name="mcl_sponges:sponge"}
if not absorb_sponge_pos(pos, fallback_node) then
minetest.set_node(pos, fallback_node)
end
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
return itemstack
end,
_mcl_blast_resistance = 0.6,
_mcl_hardness = 0.6,
})
function place_wet_sponge(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
-- Use pointed node's on_rightclick function first, if present
local node = minetest.get_node(pointed_thing.under)
local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing)
if new_stack then
return new_stack
end
local name = placer:get_player_name()
if minetest.is_protected(pointed_thing.above, name) then
return itemstack
end
-- wet sponges in the Nether immediately dry out.
if mcl_worlds.pos_to_dimension(pointed_thing.above) == "nether" then
minetest.item_place_node(ItemStack("mcl_sponges:sponge"), placer, pointed_thing)
local pos = pointed_thing.above
for n = 0, 25 do
minetest.add_particle({
pos = {x = pos.x + math.random(-1, 1)*math.random()/2, y = pos.y + 0.6, z = pos.z + math.random(-1, 1)*math.random()/2},
velocity = {x = 0, y = math.random(), z = 0},
acceleration = {x=0, y=0, z=0},
expirationtime = math.random(),
collisiondetection = false,
vertical = false,
size = math.random(2, 5),
texture = "mcl_particles_sponge"..math.random(1, 5)..".png",
})
end
if not minetest.is_creative_enabled(name) then
itemstack:take_item()
end
return itemstack
end
-- place normally
return minetest.item_place_node(itemstack, placer, pointed_thing)
end
-- NODE: Wet Sponge (Water)
-- FIXME: node definition members to indicate content of sponge.
-- TODO: mclx_core should overwrite description to read "Wet Sponge (Water)".
mcl_sponges.register_sponge("mcl_sponges:sponge_water",
merge_tables(mcl_sponges.registered_sponges["mcl_sponges:sponge"], {
description = S("Wet Sponge"),
_tt_help = S("Can be dried in furnace"),
_doc_items_longdesc = S("A wet sponge can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of a furnace, the water will pour into the bucket."),
is_ground_content = false,
sounds = mcl_sounds.node_sound_dirt_defaults(),
groups = {handy=1, hoey=1, building_block=1, sponge=1},
help = S("Can be dried in furnace"),
longdesc = S("A wet sponge can be dried in the furnace to turn it into (dry) sponge. When there's an empty bucket in the fuel slot of a furnace, the water will pour into the bucket."),
tiles = {"mcl_sponges_sponge_wet.png"},
liquidgroup = "legacity_water",
furnace_drying = true,
on_place = place_wet_sponge,
_sponge_liquid = "water",
})
)
minetest.register_craft({
type = "cooking",
output = "mcl_sponges:sponge",
recipe = "mcl_sponges:sponge_water",
cooktime = 10,
})
-- NODE: Wet Sponge (River Water)
-- TODO: move to mclx_core/sponges.lua
mcl_sponges.register_sponge("mcl_sponges:sponge_river_water",
merge_tables(mcl_sponges.registered_sponges["mcl_sponges:sponge_water"], {
description = S("Wet Sponge (River Water)"),
liquidgroup = "extra_water",
furnace_drying = true,
_sponge_liquid = "river_water",
})
)
minetest.register_craft({
type = "cooking",
output = "mcl_sponges:sponge",
recipe = "mcl_sponges:sponge_river_water",
cooktime = 10,
})
minetest.register_abm({
label = "Sponge water absorption",
nodenames = { "mcl_sponges:sponge" },
neighbors = { "group:water" }, -- FIXME
interval = 1,
chance = 1,
action = function(pos)
mcl_sponges.absorb_sponge_pos(pos)
end,
})
-- Backwards compatibility aliases.
minetest.register_alias("mcl_sponges:sponge_wet", "mcl_sponges:sponge_water")
minetest.register_alias("mcl_sponges:sponge_wet_river_water", "mcl_sponges:sponge_river_water")
minetest.register_alias("mcl_sponges:sponge_water_logged", "mcl_sponges:sponge_water")
minetest.register_alias("mcl_sponges:sponge_riverwater_logged", "mcl_sponges:sponge_river_water")

View File

@ -13,6 +13,8 @@ source._doc_items_entry_name = S("River Water")
-- Auto-expose entry only in valleys mapgen -- Auto-expose entry only in valleys mapgen
source._doc_items_hidden = minetest.get_mapgen_setting("mg_name") ~= "valleys" source._doc_items_hidden = minetest.get_mapgen_setting("mg_name") ~= "valleys"
source.post_effect_color = {a=192, r=0x2c, g=0x88, b=0x8c} source.post_effect_color = {a=192, r=0x2c, g=0x88, b=0x8c}
source.groups["legacity_water"] = nil
source.groups["extra_water"] = 1
source.tiles = { source.tiles = {
{name="default_river_water_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=5.0}} {name="default_river_water_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=5.0}}
} }
@ -33,6 +35,8 @@ flowing.liquid_alternative_source = "mclx_core:river_water_source"
flowing.liquid_renewable = false flowing.liquid_renewable = false
flowing.tiles = {"default_river_water_flowing_animated.png^[verticalframe:64:0"} flowing.tiles = {"default_river_water_flowing_animated.png^[verticalframe:64:0"}
flowing.post_effect_color = {a=192, r=0x2c, g=0x88, b=0x8c} flowing.post_effect_color = {a=192, r=0x2c, g=0x88, b=0x8c}
flowing.groups["legacity_water"] = nil
flowing.groups["extra_water"] = 1
flowing.special_tiles = { flowing.special_tiles = {
{ {
image="default_river_water_flowing_animated.png", image="default_river_water_flowing_animated.png",