forked from VoxeLibre/VoxeLibre
Compare commits
17 Commits
master
...
sponge-api
Author | SHA1 | Date |
---|---|---|
Phaethon H | ef3820de79 | |
Phaethon H | 9df16d8dc3 | |
Phaethon H | 6c900aac9a | |
AFCMS | 6cb54ceeea | |
AFCMS | 77c62f4d43 | |
AFCMS | f798698b4c | |
AFCMS | e8bc475388 | |
AFCMS | b733f520b2 | |
AFCMS | 7187ca67e7 | |
AFCMS | 4f0a3b625b | |
AFCMS | d94fc9e696 | |
AFCMS | 75689afdb4 | |
AFCMS | 14c19c915f | |
AFCMS | 451a59c8a8 | |
AFCMS | de8ce5b68e | |
AFCMS | 58f989ca74 | |
AFCMS | 717da6dd7c |
|
@ -95,7 +95,7 @@ S("• When water is directly below lava, the water turns into stone."),
|
|||
liquid_range = 7,
|
||||
post_effect_color = {a=209, r=0x03, g=0x3C, b=0x5C},
|
||||
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,
|
||||
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
|
||||
_mcl_hardness = -1,
|
||||
|
|
|
@ -353,15 +353,17 @@ local function furnace_node_timer(pos, elapsed)
|
|||
|
||||
-- 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 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")
|
||||
fuellist = inv:get_list("fuel")
|
||||
-- Also for river water
|
||||
elseif srclist[1]:get_name() == "mcl_sponges:sponge_wet_river_water" then
|
||||
elseif mcl_sponges.has_sponge_liquid(sponge_name, "river_water") then
|
||||
inv:set_stack("fuel", 1, "mcl_buckets:bucket_river_water")
|
||||
fuellist = inv:get_list("fuel")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
srclist = inv:get_list("src")
|
||||
src_time = 0
|
||||
|
|
|
@ -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).
|
||||
|
|
@ -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
|
||||
|
|
@ -1,205 +1,9 @@
|
|||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
local absorb = function(pos)
|
||||
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
|
||||
mcl_sponges = {}
|
||||
|
||||
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
|
||||
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
|
||||
dofile(modpath .. "/api.lua")
|
||||
dofile(modpath .. "/register.lua")
|
||||
|
||||
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,
|
||||
})
|
||||
|
|
|
@ -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")
|
||||
|
|
@ -13,6 +13,8 @@ source._doc_items_entry_name = S("River Water")
|
|||
-- Auto-expose entry only in valleys mapgen
|
||||
source._doc_items_hidden = minetest.get_mapgen_setting("mg_name") ~= "valleys"
|
||||
source.post_effect_color = {a=192, r=0x2c, g=0x88, b=0x8c}
|
||||
source.groups["legacity_water"] = nil
|
||||
source.groups["extra_water"] = 1
|
||||
source.tiles = {
|
||||
{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.tiles = {"default_river_water_flowing_animated.png^[verticalframe:64:0"}
|
||||
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 = {
|
||||
{
|
||||
image="default_river_water_flowing_animated.png",
|
||||
|
|
Loading…
Reference in New Issue