1
0
mirror of https://github.com/Sokomine/cottages.git synced 2025-07-13 13:20:22 +02:00

refactor, cleanup, API, bugfixes (#1)

This commit is contained in:
fluxionary
2022-10-09 14:13:47 -07:00
committed by flux
parent dbe69bcfaf
commit 846308ef5a
106 changed files with 5594 additions and 4596 deletions

513
modules/anvil/anvil.lua Normal file
View File

@ -0,0 +1,513 @@
local S = cottages.S
local F = minetest.formspec_escape
local FS = function(...) return F(S(...)) end
local anvil = cottages.anvil
local add_entity = minetest.add_entity
local get_node = minetest.get_node
local get_objects_in_area = minetest.get_objects_in_area
local serialize = minetest.serialize
local v_add = vector.add
local v_eq = vector.equals
local v_new = vector.new
local v_sub = vector.subtract
local get_safe_short_description = futil.get_safe_short_description
local resolve_item = futil.resolve_item
local has_stamina = cottages.has.stamina
local repair_amount = cottages.settings.anvil.repair_amount
local hammer_wear = cottages.settings.anvil.hammer_wear
local formspec_enabled = cottages.settings.anvil.formspec_enabled
local tool_hud_enabled = cottages.settings.anvil.tool_hud_enabled
local hud_timeout = cottages.settings.anvil.hud_timeout
local stamina_use = cottages.settings.anvil.stamina
local tool_entity_enabled = cottages.settings.anvil.tool_entity_enabled
local tool_entity_displacement = cottages.settings.anvil.tool_entity_displacement
local hud_info_by_puncher_name = {}
local function get_hud_image(tool)
local tool_def = tool:get_definition()
if tool_def then
return tool_def.inventory_image or tool_def.wield_image
end
end
function anvil.get_anvil_info(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local input = inv:get_stack("input", 1)
local wear = math.round((65536 - input:get_wear()) / 655.36)
if input:is_empty() then
return S("anvil")
elseif input:get_wear() > 0 then
return S("anvil; repairing @1 (@2%)", get_safe_short_description(input), wear)
else
return S("anvil; @1 is repaired", get_safe_short_description(input))
end
end
function anvil.get_anvil_fs_parts()
return {
("size[8,8]"),
("image[7,3;1,1;cottages_tool_steelhammer.png]"),
("label[2.5,1.0;%s]"):format(FS("Workpiece:")),
("label[6.0,2.7;%s]"):format(FS("Optional")),
("label[6.0,3.0;%s]"):format(FS("storage for")),
("label[6.0,3.3;%s]"):format(FS("your hammer")),
("label[0,0.0;%s]"):format(FS("Anvil")),
("label[0,3.0;%s]"):format(FS("Punch anvil with hammer to")),
("label[0,3.3;%s]"):format(FS("repair tool in workpiece-slot.")),
("list[context;input;2.5,1.5;1,1;]"),
("list[context;hammer;5,3;1,1;]"),
("list[current_player;main;0,4;8,4;]"),
("listring[context;hammer]"),
("listring[current_player;main]"),
("listring[context;input]"),
("listring[current_player;main]"),
}
end
local function sparks(pos)
pos.y = pos.y + tool_entity_displacement
minetest.add_particlespawner({
amount = 10,
time = 0.1,
minpos = pos,
maxpos = pos,
minvel = {x = 2, y = 3, z = 2},
maxvel = {x = -2, y = 1, z = -2},
minacc = {x = 0, y = -10, z = 0},
maxacc = {x = 0, y = -10, z = 0},
minexptime = 0.5,
maxexptime = 1,
minsize = 1,
maxsize = 1,
collisiondetection = true,
vertical = false,
texture = "cottages_anvil_spark.png",
})
end
local function update_hud(puncher, tool)
local puncher_name = puncher:get_player_name()
local damage_state = 40 - math.floor(40 * tool:get_wear() / 65535)
local hud_image = get_hud_image(tool)
local hud1, hud1_def, hud2, hud3, hud3_def
if hud_info_by_puncher_name[puncher_name] then
if tool_hud_enabled then
hud1, hud2, hud3 = unpack(hud_info_by_puncher_name[puncher_name])
hud1_def = puncher:hud_get(hud1)
else
hud2, hud3 = unpack(hud_info_by_puncher_name[puncher_name])
end
hud3_def = puncher:hud_get(hud3)
end
if hud3_def and hud3_def.name == "anvil_foreground" then
if tool_hud_enabled and hud1_def and hud1_def.name == "anvil_image" then
puncher:hud_change(hud1, "text", hud_image)
end
puncher:hud_change(hud3, "number", damage_state)
else
if tool_hud_enabled and hud_image then
hud1 = puncher:hud_add({
hud_elem_type = "image",
name = "anvil_image",
text = hud_image,
scale = {x = 15, y = 15},
position = {x = 0.5, y = 0.5},
alignment = {x = 0, y = 0}
})
end
hud2 = puncher:hud_add({
hud_elem_type = "statbar",
name = "anvil_background",
text = "default_cloud.png^[colorize:#ff0000:256",
number = 40,
direction = 0, -- left to right
position = {x = 0.5, y = 0.65},
alignment = {x = 0, y = 0},
offset = {x = -320, y = 0},
size = {x = 32, y = 32},
})
hud3 = puncher:hud_add({
hud_elem_type = "statbar",
name = "anvil_foreground",
text = "default_cloud.png^[colorize:#00ff00:256",
number = damage_state,
direction = 0, -- left to right
position = {x = 0.5, y = 0.65},
alignment = {x = 0, y = 0},
offset = {x = -320, y = 0},
size = {x = 32, y = 32},
})
end
if tool_hud_enabled then
hud_info_by_puncher_name[puncher_name] = {hud1, hud2, hud3, os.time() + hud_timeout}
else
hud_info_by_puncher_name[puncher_name] = {hud2, hud3, os.time() + hud_timeout}
end
end
function anvil.use_anvil(pos, puncher)
-- only punching with the hammer is supposed to work
local wielded = puncher:get_wielded_item()
if wielded:get_name() ~= resolve_item("cottages:hammer") then
return
end
local puncher_name = puncher:get_player_name()
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local tool = inv:get_stack("input", 1)
local tool_name = tool:get_name()
if tool:is_empty() then
return
elseif not anvil.can_repair(tool) then
-- just to make sure that tool really can't be repaired if it should not
-- (if the check of placing the item in the input slot failed somehow)
minetest.chat_send_player(puncher_name, S("@1 is not repairable by the anvil", tool_name))
elseif tool:get_wear() > 0 then
minetest.sound_play({name = "anvil_clang"}, {pos = pos})
sparks(pos)
-- do the actual repair
tool:add_wear(-repair_amount)
inv:set_stack("input", 1, tool)
-- damage the hammer slightly
wielded:add_wear(hammer_wear)
puncher:set_wielded_item(wielded)
update_hud(puncher, tool)
if has_stamina then
stamina.exhaust_player(puncher, stamina_use, "cottages:anvil")
end
else
-- tell the player when the job is done, but only once
if meta:get_int("informed") > 0 then
return
end
meta:set_int("informed", 1)
local tool_desc = tool:get_short_description() or tool:get_description()
minetest.chat_send_player(puncher_name, S("Your @1 has been repaired successfully.", tool_desc))
end
end
function anvil.rightclick_anvil(pos, clicker, itemstack)
if formspec_enabled or not (pos and itemstack) then
return
end
local meta = minetest.get_meta(pos)
meta:set_string("formspec", "")
local inv = meta:get_inventory()
local input_stack = inv:get_stack("input", 1)
local hammer_stack = inv:get_stack("hammer", 1)
local taken
if anvil.allow_metadata_inventory_take(pos, "input", 1, input_stack, clicker) > 0 then
taken = inv:remove_item("input", input_stack)
elseif anvil.allow_metadata_inventory_take(pos, "hammer", 1, hammer_stack, clicker) > 0 then
taken = inv:remove_item("hammer", hammer_stack)
end
local can_put = anvil.allow_metadata_inventory_put(pos, "input", 1, itemstack, clicker)
if can_put == 1 then
inv:add_item("input", itemstack)
itemstack:clear()
meta:set_int("informed", 0)
elseif taken and not itemstack:is_empty() then
-- put it back
inv:add_item("input", input_stack)
taken = nil
end
anvil.update_entity(pos)
return taken or itemstack
end
function anvil.get_entity(pos)
local to_return
for _, obj in ipairs(get_objects_in_area(v_sub(pos, 0.5), v_add(pos, 0.5))) do
local ent = obj:get_luaentity()
if ent and ent.name == "cottages:anvil_item" then
local ent_pos = ent.pos
if not ent_pos then
obj:remove()
elseif v_eq(ent_pos, pos) then
if to_return then
obj:remove()
else
to_return = obj
end
end
end
end
return to_return
end
function anvil.clear_entity(pos)
local obj = anvil.get_entity(pos)
if obj then
obj:remove()
end
end
function anvil.add_entity(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("input") then
return
end
local tool = inv:get_stack("input", 1)
local tool_name = tool:get_name()
local node = get_node(pos)
local entity_pos = v_add(pos, v_new(0, tool_entity_displacement, 0))
local obj = add_entity(entity_pos, "cottages:anvil_item", serialize({pos, tool_name}))
if obj then
local yaw = math.pi * 2 - node.param2 * math.pi / 2
obj:set_rotation({ x = -math.pi / 2, y = yaw, z = 0}) -- x is pitch
end
end
function anvil.update_entity(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local tool = inv:get_stack("input", 1)
local tool_name = tool:get_name()
local obj = anvil.get_entity(pos)
if tool:is_empty() and obj then
anvil.clear_entity(pos)
elseif obj then
local e = obj:get_luaentity()
if e.item ~= tool_name then
e.item = tool_name
obj:set_properties({wield_item = tool_name})
end
elseif tool_entity_enabled and not tool:is_empty() then
anvil.add_entity(pos)
end
end
function anvil.allow_metadata_inventory_put(pos, listname, index, stack, player)
local count = stack:get_count()
if count == 0 then
return count
end
local stack_name = stack:get_name()
if listname == "hammer" and stack_name ~= resolve_item("cottages:hammer") then
return 0
end
if listname == "input" then
local wear = stack:get_wear()
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if stack_name == resolve_item("cottages:hammer") and wear == 0 and inv:is_empty("hammer") then
-- we will move it to the hammer slot in on_metadata_inventory_put
return count
end
local player_name = player and player:get_player_name()
if wear == 0 or not stack:is_known() then
minetest.chat_send_player(player:get_player_name(), S("The workpiece slot is for damaged tools only."))
return 0
end
if not anvil.can_repair(stack) then
local description = stack:get_short_description() or stack:get_description()
minetest.chat_send_player(player_name, S("@1 cannot be repaired with an anvil.", description))
return 0
end
end
return count
end
function anvil.allow_metadata_inventory_take(pos, listname, index, stack, player)
return stack:get_count()
end
function anvil.allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local from_stack = inv:get_stack(from_list, from_index)
if anvil.allow_metadata_inventory_take(pos, from_list, from_index, from_stack, player) > 0
and anvil.allow_metadata_inventory_put(pos, to_list, to_index, from_stack, player) > 0 then
return count
end
return 0
end
function anvil.on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
if to_list == "input" then
local meta = minetest.get_meta(pos)
meta:set_int("informed", 0)
end
anvil.update_entity(pos)
end
function anvil.on_metadata_inventory_put(pos, listname, index, stack, player)
if listname == "input" and stack:get_name() == resolve_item("cottages:hammer") and stack:get_wear() == 0 then
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("hammer") then
inv:set_stack("hammer", 1, stack)
inv:set_stack("input", 1, ItemStack())
end
return
end
if listname == "input" then
local meta = minetest.get_meta(pos)
meta:set_int("informed", 0)
end
anvil.update_entity(pos)
end
function anvil.on_metadata_inventory_take(pos, listname, index, stack, player)
anvil.update_entity(pos)
end
function anvil.preserve_metadata(pos, oldnode, oldmeta, drops)
for _, item in ipairs(drops) do
if item:get_name() == "cottages:anvil" then
local drop_meta = item:get_meta()
local owner = oldnode:get_string("owner")
if owner == "" then
drop_meta:set_int("shared", 1)
drop_meta:set_string("description", S("Anvil (public)"))
elseif owner == " " then
drop_meta:set_int("shared", 2)
drop_meta:set_string("description", S("Anvil (protected)"))
end
end
end
return drops
end
cottages.api.register_machine("cottages:anvil", {
description = S("anvil"),
drawtype = "nodebox",
-- the nodebox model comes from realtest
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.3, 0.5, -0.4, 0.3},
{-0.35, -0.4, -0.25, 0.35, -0.3, 0.25},
{-0.3, -0.3, -0.15, 0.3, -0.1, 0.15},
{-0.35, -0.1, -0.2, 0.35, 0.1, 0.2},
},
},
tiles = {"cottages_stone.png^[colorize:#000:192"},
groups = {cracky = 2},
sounds = cottages.sounds.metal,
inv_info = {
input = 1,
hammer = 1,
},
use = anvil.use_anvil,
rightclick = anvil.rightclick_anvil,
get_fs_parts = formspec_enabled and anvil.get_anvil_fs_parts,
get_info = anvil.get_anvil_info,
on_metadata_inventory_move = anvil.on_metadata_inventory_move,
on_metadata_inventory_put = anvil.on_metadata_inventory_put,
on_metadata_inventory_take = anvil.on_metadata_inventory_take,
allow_metadata_inventory_move = anvil.allow_metadata_inventory_move,
allow_metadata_inventory_put = anvil.allow_metadata_inventory_put,
allow_metadata_inventory_take = anvil.allow_metadata_inventory_take,
})
-- clear hud info
minetest.register_globalstep(function()
local now = os.time()
for puncher_name, hud_info in pairs(hud_info_by_puncher_name) do
local puncher = minetest.get_player_by_name(puncher_name)
local hud1, hud2, hud3, hud_expire_time
if tool_hud_enabled then
hud1, hud2, hud3, hud_expire_time = unpack(hud_info)
else
hud2, hud3, hud_expire_time = unpack(hud_info)
end
if puncher then
if now > hud_expire_time then
if tool_hud_enabled then
local hud1_def = puncher:hud_get(hud1)
if hud1_def and hud1_def.name == "anvil_image" then
puncher:hud_remove(hud1)
end
end
local hud2_def = puncher:hud_get(hud2)
if hud2_def and hud2_def.name == "anvil_background" then
puncher:hud_remove(hud2)
end
local hud3_def = puncher:hud_get(hud3)
if hud3_def and hud3_def.name == "anvil_foreground" then
puncher:hud_remove(hud3)
end
hud_info_by_puncher_name[puncher_name] = nil
end
else
hud_info_by_puncher_name[puncher_name] = nil
end
end
end)

15
modules/anvil/api.lua Normal file
View File

@ -0,0 +1,15 @@
local api = cottages.anvil
function api.make_unrepairable(itemstring)
local def = minetest.registered_items[itemstring]
local groups = table.copy(def.groups or {})
groups.not_repaired_by_anvil = 1
minetest.override_item(itemstring, {groups = groups})
end
function api.can_repair(tool_stack)
if type(tool_stack) == "string" then
tool_stack = ItemStack(tool_stack)
end
return tool_stack:is_known() and minetest.get_item_group(tool_stack:get_name(), "not_repaired_by_anvil") == 0
end

27
modules/anvil/compat.lua Normal file
View File

@ -0,0 +1,27 @@
if cottages.has.technic then
-- make rechargeable technic tools unrepairable`
cottages.anvil.make_unrepairable("technic:water_can")
cottages.anvil.make_unrepairable("technic:lava_can")
cottages.anvil.make_unrepairable("technic:flashlight")
cottages.anvil.make_unrepairable("technic:battery")
cottages.anvil.make_unrepairable("technic:vacuum")
cottages.anvil.make_unrepairable("technic:prospector")
cottages.anvil.make_unrepairable("technic:sonic_screwdriver")
cottages.anvil.make_unrepairable("technic:chainsaw")
cottages.anvil.make_unrepairable("technic:laser_mk1")
cottages.anvil.make_unrepairable("technic:laser_mk2")
cottages.anvil.make_unrepairable("technic:laser_mk3")
cottages.anvil.make_unrepairable("technic:mining_drill")
cottages.anvil.make_unrepairable("technic:mining_drill_mk2")
cottages.anvil.make_unrepairable("technic:mining_drill_mk2_1")
cottages.anvil.make_unrepairable("technic:mining_drill_mk2_2")
cottages.anvil.make_unrepairable("technic:mining_drill_mk2_3")
cottages.anvil.make_unrepairable("technic:mining_drill_mk2_4")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3_1")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3_2")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3_3")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3_4")
cottages.anvil.make_unrepairable("technic:mining_drill_mk3_5")
end

56
modules/anvil/crafts.lua Normal file
View File

@ -0,0 +1,56 @@
local S = cottages.S
local ci = cottages.craftitems
if ci.steel then
minetest.register_craft({
output = "cottages:anvil",
recipe = {
{ci.steel, ci.steel, ci.steel},
{"", ci.steel, ""},
{ci.steel, ci.steel, ci.steel}},
})
minetest.register_craft({
output = "cottages:hammer",
recipe = {
{ci.steel},
{"cottages:anvil"},
{ci.stick}}
})
end
if ci.paper then
local function build_public_string()
local stack = ItemStack("cottages:anvil")
local meta = stack:get_meta()
meta:set_int("shared", 1)
meta:set_string("description", S("Anvil (public)"))
return stack:to_string()
end
local function build_protected_string()
local stack = ItemStack("cottages:anvil")
local meta = stack:get_meta()
meta:set_int("shared", 2)
meta:set_string("description", S("Anvil (protected)"))
return stack:to_string()
end
minetest.register_craft({
output = build_protected_string(),
type = "shapeless",
recipe = {"anvil:anvil", ci.paper}
})
minetest.register_craft({
output = build_public_string(),
type = "shapeless",
recipe = {build_protected_string(), ci.paper}
})
minetest.register_craft({
output = "anvil:anvil",
type = "shapeless",
recipe = {build_public_string(), ci.paper}
})
end

65
modules/anvil/entity.lua Normal file
View File

@ -0,0 +1,65 @@
local anvil = cottages.anvil
local deserialize = minetest.deserialize
local serialize = minetest.serialize
minetest.register_entity("cottages:anvil_item", {
hp_max = 1,
visual = "wielditem",
visual_size = {x = .33, y = .33},
collisionbox = {0, 0, 0, 0, 0, 0},
physical = false,
get_staticdata = function(self)
return serialize({self.pos, self.item})
end,
on_activate = function(self, staticdata, dtime_s)
local pos, item = unpack(deserialize(staticdata))
local obj = self.object
if not (pos and item and minetest.get_node(pos).name == "cottages:anvil") then
obj:remove()
return
end
self.pos = pos -- *MUST* set before calling api.get_entity
local other_obj = anvil.get_entity(pos)
if other_obj and obj ~= other_obj then
obj:remove()
return
end
self.item = item
obj:set_properties({wield_item = item})
end,
})
if cottages.settings.anvil.tool_entity_enabled then
-- automatically restore entities lost due to /clearobjects or similar
if cottages.has.node_entity_queue then
node_entity_queue.api.register_node_entity_loader("cottages:anvil", anvil.update_entity)
else
minetest.register_lbm({
name = "cottages:anvil_item_restoration",
nodenames = {"cottages:anvil"},
run_at_every_load = true,
action = function(pos, node, active_object_count, active_object_count_wider)
anvil.update_entity(pos)
end,
})
end
else
minetest.register_lbm({
name = "cottages:anvil_item_removal",
nodenames = {"cottages:anvil"},
run_at_every_load = true,
action = function(pos, node, active_object_count, active_object_count_wider)
anvil.clear_entity(pos)
end,
})
end

22
modules/anvil/hammer.lua Normal file
View File

@ -0,0 +1,22 @@
local S = cottages.S
-- the hammer for the anvil
minetest.register_tool("cottages:hammer", {
description = S("Steel hammer for repairing tools on the anvil"),
image = "cottages_tool_steelhammer.png",
inventory_image = "cottages_tool_steelhammer.png",
tool_capabilities = {
full_punch_interval = 0.8,
max_drop_level = 1,
groupcaps = {
-- about equal to a stone pick (it's not intended as a tool)
cracky = {times = {[2] = 2.00, [3] = 1.20}, uses = 30, maxlevel = 1},
},
damage_groups = {fleshy = 6},
}
})
if cottages.settings.anvil.disable_hammer_repair then
cottages.anvil.make_unrepairable("cottages:hammer")
end

8
modules/anvil/init.lua Normal file
View File

@ -0,0 +1,8 @@
cottages.anvil = {}
cottages.dofile("modules", "anvil", "api")
cottages.dofile("modules", "anvil", "anvil")
cottages.dofile("modules", "anvil", "entity")
cottages.dofile("modules", "anvil", "hammer")
cottages.dofile("modules", "anvil", "crafts")
cottages.dofile("modules", "anvil", "compat")

121
modules/barrel/api.lua Normal file
View File

@ -0,0 +1,121 @@
local max_liquid_amount = cottages.settings.barrel.max_liquid_amount
local api = cottages.barrel
api.bucket_empty_by_bucket_full = {}
api.bucket_full_by_empty_and_liquid = {}
api.liquid_by_bucket_full = {}
api.name_by_liquid = {}
api.texture_by_liquid = {}
api.input_sound_by_liquid = {}
api.output_sound_by_liquid = {}
function api.get_barrel_liquid(pos)
local meta = minetest.get_meta(pos)
return meta:get("liquid")
end
function api.set_barrel_liquid(pos, liquid)
local meta = minetest.get_meta(pos)
meta:set_string("liquid", liquid)
end
function api.get_liquid_amount(pos)
local meta = minetest.get_meta(pos)
return meta:get_int("amount")
end
function api.increase_liquid_amount(pos)
local meta = minetest.get_meta(pos)
meta:set_int("amount", meta:get_int("amount") + 1)
end
function api.decrease_liquid_amount(pos)
local meta = minetest.get_meta(pos)
local amount = meta:get_int("amount") - 1
meta:set_int("amount", amount)
if amount == 0 then
api.set_barrel_liquid(pos, "")
end
end
local function empty_and_liquid(bucket_empty, liquid)
return table.concat({bucket_empty, liquid}, "::")
end
function api.register_barrel_liquid(def)
api.liquid_by_bucket_full[def.bucket_full] = def.liquid
api.bucket_empty_by_bucket_full[def.bucket_full] = def.bucket_empty
api.bucket_full_by_empty_and_liquid[empty_and_liquid(def.bucket_empty, def.liquid)] = def.bucket_full
api.name_by_liquid[def.liquid] = def.liquid_name
api.texture_by_liquid[def.liquid] = def.liquid_texture
api.input_sound_by_liquid[def.liquid] = def.liquid_input_sound
api.output_sound_by_liquid[def.liquid] = def.liquid_output_sound
end
function api.get_bucket_liquid(bucket_full)
return api.liquid_by_bucket_full[bucket_full]
end
function api.get_bucket_empty(liquid)
return api.bucket_empty_by_liquid[liquid]
end
function api.get_bucket_empty(bucket_full)
return api.bucket_empty_by_bucket_full[bucket_full]
end
function api.get_bucket_full(bucket_empty, liquid)
return api.bucket_full_by_empty_and_liquid[empty_and_liquid(bucket_empty, liquid)]
end
function api.can_fill(pos, bucket_empty)
local liquid = api.get_barrel_liquid(pos)
return liquid and api.get_bucket_full(bucket_empty, liquid)
end
function api.can_drain(pos, bucket_full)
local barrel_liquid = api.get_barrel_liquid(pos)
local liquid_amount = api.get_liquid_amount(pos)
local bucket_liquid = api.get_bucket_liquid(bucket_full)
if (not bucket_liquid) or liquid_amount >= max_liquid_amount then
return false
end
return bucket_liquid and ((not barrel_liquid) or barrel_liquid == bucket_liquid)
end
function api.add_barrel_liquid(pos, bucket_full)
local liquid = api.get_bucket_liquid(bucket_full)
if not api.get_barrel_liquid(pos) then
api.set_barrel_liquid(pos, liquid)
end
api.increase_liquid_amount(pos)
minetest.sound_play(
{name = api.input_sound_by_liquid[liquid]},
{pos = pos, loop = false, gain = 0.5, pitch = 2.0}
)
return api.get_bucket_empty(bucket_full)
end
function api.drain_barrel_liquid(pos, bucket_empty)
local liquid = api.get_barrel_liquid(pos)
api.decrease_liquid_amount(pos)
minetest.sound_play(
{name = api.output_sound_by_liquid[liquid]},
{pos = pos, loop = false, gain = 0.5, pitch = 2.0}
)
return api.get_bucket_full(bucket_empty, liquid)
end

168
modules/barrel/barrel.lua Normal file
View File

@ -0,0 +1,168 @@
local S = cottages.S
local F = minetest.formspec_escape
local FS = function(...) return F(S(...)) end
local max_liquid_amount = cottages.settings.barrel.max_liquid_amount
local barrel = cottages.barrel
function barrel.get_barrel_info(pos)
local liquid = barrel.get_barrel_liquid(pos)
if liquid then
return ("%s (%i/%i)"):format(
barrel.name_by_liquid[liquid],
barrel.get_liquid_amount(pos),
max_liquid_amount
)
else
return S("Empty")
end
end
function barrel.get_barrel_fs_parts(pos)
local parts = {
("size[8,9]"),
("label[0,0.0;%s]"):format(FS("barrel (liquid storage)")),
("label[3,0;%s]"):format(FS("fill:")),
("list[context;input;3,0.5;1,1;]"),
("label[5,3.3;%s]"):format(FS("drain:")),
("list[context;output;5,3.8;1,1;]"),
("list[current_player;main;0,5;8,4;]"),
("listring[context;output]"),
("listring[current_player;main]"),
("listring[context;input]"),
("listring[current_player;main]"),
}
local liquid = barrel.get_barrel_liquid(pos)
local liquid_amount = barrel.get_liquid_amount(pos)
if liquid then
local liquid_texture = barrel.texture_by_liquid[liquid]
table.insert(parts, ("image[2.6,2;2,3;%s^[resize:99x99^[lowpart:%s:%s]"):format(
F(cottages.textures.furniture),
math.floor(99 * liquid_amount / max_liquid_amount),
F(liquid_texture .. futil.escape_texture("^[resize:99x99"))
))
table.insert(parts, ("tooltip[2.6,2;2,3;%s]"):format(
F(("%s (%i/%i)"):format(
barrel.name_by_liquid[liquid],
barrel.get_liquid_amount(pos),
max_liquid_amount
)))
)
else
table.insert(parts, ("image[2.6,2;2,3;%s^[resize:99x99^[lowpart:%s:%s]"):format(
F(cottages.textures.furniture),
0,
F(cottages.textures.furniture .. futil.escape_texture("^[resize:99x99"))
))
end
return parts
end
function barrel.can_dig(pos, player)
return barrel.get_liquid_amount(pos) == 0
end
function barrel.allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local to_stack = inv:get_stack(to_list, to_index)
if not to_stack:is_empty() then
return 0
end
local from_stack = inv:get_stack(from_list, from_index)
local item = from_stack:get_name()
if to_list == "input" then
if barrel.can_drain(pos, item) then
return 1
end
elseif to_list == "output" then
if barrel.can_fill(pos, item) then
return 1
end
end
return 0
end
function barrel.allow_metadata_inventory_put(pos, listname, index, stack, player)
local item = stack:get_name()
if listname == "input" then
if barrel.can_drain(pos, item) then
return 1
end
elseif listname == "output" then
if barrel.can_fill(pos, item) then
return 1
end
end
return 0
end
function barrel.on_metadata_inventory_put(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local name = stack:get_name()
if listname == "input" then
local empty = barrel.add_barrel_liquid(pos, name)
inv:set_stack(listname, index, empty)
elseif listname == "output" then
local full = barrel.drain_barrel_liquid(pos, name)
inv:set_stack(listname, index, full)
end
end
function barrel.on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local stack = inv:get_stack(to_list, to_index)
barrel.on_metadata_inventory_put(pos, to_list, to_index, stack, player)
end
cottages.api.register_machine("cottages:barrel", {
description = S("barrel"),
paramtype = "light",
paramtype2 = "facedir",
drawtype = "mesh",
mesh = "cottages_barrel_closed.obj",
tiles = {"cottages_barrel.png"},
is_ground_content = false,
groups = {
snappy = 1,
choppy = 2,
oddly_breakable_by_hand = 1,
flammable = 2
},
sounds = cottages.sounds.wood,
inv_info = {
input = 1,
output = 1,
},
can_dig = barrel.can_dig,
get_fs_parts = barrel.get_barrel_fs_parts,
get_info = barrel.get_barrel_info,
allow_metadata_inventory_move = barrel.allow_metadata_inventory_move,
allow_metadata_inventory_put = barrel.allow_metadata_inventory_put,
on_metadata_inventory_move = barrel.on_metadata_inventory_move,
on_metadata_inventory_put = barrel.on_metadata_inventory_put,
})

41
modules/barrel/compat.lua Normal file
View File

@ -0,0 +1,41 @@
local api = cottages.barrel
if cottages.has.bucket and cottages.has.default then
local S = minetest.get_translator("default")
if minetest.registered_items["bucket:bucket_water"] then
api.register_barrel_liquid({
liquid = "default:water_source",
liquid_name = S("Water"),
liquid_texture = "default_water.png",
liquid_input_sound = cottages.sounds.water_empty,
liquid_output_sound = cottages.sounds.water_fill,
bucket_empty = "bucket:bucket_empty",
bucket_full = "bucket:bucket_water",
})
end
if minetest.registered_items["bucket:bucket_river_water"] then
api.register_barrel_liquid({
liquid = "default:river_water_source",
liquid_name = S("River Water"),
liquid_texture = "default_river_water.png",
liquid_input_sound = cottages.sounds.water_empty,
liquid_output_sound = cottages.sounds.water_fill,
bucket_empty = "bucket:bucket_empty",
bucket_full = "bucket:bucket_river_water",
})
end
if minetest.registered_items["bucket:bucket_lava"] then
api.register_barrel_liquid({
liquid = "default:lava_source",
liquid_name = S("Lava"),
liquid_input_sound = cottages.sounds.lava_empty,
liquid_output_sound = cottages.sounds.lava_fill,
liquid_texture = "default_lava.png",
bucket_empty = "bucket:bucket_empty",
bucket_full = "bucket:bucket_lava",
})
end
end

View File

@ -0,0 +1,23 @@
local api = cottages.barrel
local rotations = {
3 * 4,
2 * 4,
4 * 4,
1 * 4,
}
minetest.register_lbm({
label = "Convert lying barrels",
name = "cottages:convert_lying_barrels",
nodenames = {"cottages:barrel_lying", "cottages:barrel_lying_open"},
run_at_every_load = false,
action = function(pos, node)
node.name = string.gsub(node.name, "_lying", "")
node.param2 = rotations[node.param2 + 1] or 0
minetest.swap_node(pos, node)
api.update_infotext(pos)
api.update_formspec(pos)
end
})

36
modules/barrel/crafts.lua Normal file
View File

@ -0,0 +1,36 @@
local ci = cottages.craftitems
if ci.wood and ci.steel then
minetest.register_craft({
output = "cottages:barrel",
recipe = {
{ci.wood, ci.wood, ci.wood},
{ci.steel, "", ci.steel},
{ci.wood, ci.wood, ci.wood},
},
})
minetest.register_craft({
output = "cottages:barrel_open",
recipe = {
{ci.wood, "", ci.wood},
{ci.steel, "", ci.steel},
{ci.wood, ci.wood, ci.wood},
},
})
end
minetest.register_craft({
output = "cottages:tub 2",
recipe = {
{"cottages:barrel"},
},
})
minetest.register_craft({
output = "cottages:barrel",
recipe = {
{"cottages:tub"},
{"cottages:tub"},
},
})

8
modules/barrel/init.lua Normal file
View File

@ -0,0 +1,8 @@
cottages.barrel = {}
cottages.dofile("modules", "barrel", "api")
cottages.dofile("modules", "barrel", "barrel")
cottages.dofile("modules", "barrel", "nodes")
cottages.dofile("modules", "barrel", "convert")
cottages.dofile("modules", "barrel", "crafts")
cottages.dofile("modules", "barrel", "compat")

44
modules/barrel/nodes.lua Normal file
View File

@ -0,0 +1,44 @@
local S = cottages.S
-- this barrel is opened at the top
minetest.register_node("cottages:barrel_open", {
description = S("Barrel (Open)"),
drawtype = "mesh",
paramtype = "light",
paramtype2 = "facedir",
mesh = "cottages_barrel.obj",
tiles = {"cottages_barrel.png"},
is_ground_content = false,
groups = {
snappy = 1,
choppy = 2,
oddly_breakable_by_hand = 1,
flammable = 2,
},
})
-- let's hope "tub" is the correct english word for "bottich"
minetest.register_node("cottages:tub", {
description = S("tub"),
paramtype = "light",
drawtype = "mesh",
mesh = "cottages_tub.obj",
tiles = {"cottages_barrel.png"},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.1, 0.5},
}},
collision_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.1, 0.5},
}},
groups = {
snappy = 1,
choppy = 2,
oddly_breakable_by_hand = 1,
flammable = 2
},
is_ground_content = false,
})

23
modules/doorlike/abms.lua Normal file
View File

@ -0,0 +1,23 @@
-- open shutters in the morning
minetest.register_abm({
nodenames = {"cottages:window_shutter_closed"},
interval = 20, -- change this to 600 if your machine is too slow
chance = 3, -- not all people wake up at the same time!
action = function(pos)
if not cottages.doorlike.is_night() then
cottages.doorlike.shutter_open(pos)
end
end
})
-- close them at night
minetest.register_abm({
nodenames = {"cottages:window_shutter_open"},
interval = 20, -- change this to 600 if your machine is too slow
chance = 2,
action = function(pos)
if cottages.doorlike.is_night() then
cottages.doorlike.shutter_close(pos)
end
end
})

163
modules/doorlike/api.lua Normal file
View File

@ -0,0 +1,163 @@
local S = cottages.S
local api = cottages.doorlike
local stamina_use = cottages.settings.doorlike.stamina
local has_stamina = cottages.has.stamina
-- propagate shutting/closing of window shutters to window shutters below/above this one
local offsets = {
vector.new(0, 1, 0),
vector.new(0, 2, 0),
vector.new(0, 3, 0),
}
function api.shutter_operate(pos, old_node_state_name, new_node_state_name)
local new_node = {name = new_node_state_name}
local old_node = minetest.get_node(pos)
new_node.param2 = old_node.param2
minetest.swap_node(pos, {name = new_node_state_name, param2 = old_node.param2})
local stop_up = false
local stop_down = false
for _, offset in ipairs(offsets) do
local npos = pos + offset
old_node = minetest.get_node(npos)
if old_node.name == old_node_state_name and not stop_up then
new_node.param2 = old_node.param2
minetest.swap_node(npos, new_node)
else
stop_up = true
end
npos = pos - offset
old_node = minetest.get_node(npos)
if old_node.name == old_node_state_name and not stop_down then
new_node.param2 = old_node.param2
minetest.swap_node(npos, new_node)
else
stop_down = true
end
end
end
function api.shutter_open(pos, puncher)
api.shutter_operate(pos, "cottages:window_shutter_closed", "cottages:window_shutter_open")
if has_stamina then
stamina.exhaust_player(puncher, stamina_use, "cottages:shutter")
end
end
function api.shutter_close(pos, puncher)
api.shutter_operate(pos, "cottages:window_shutter_open", "cottages:window_shutter_closed")
if has_stamina then
stamina.exhaust_player(puncher, stamina_use, "cottages:shutter")
end
end
function api.is_night()
-- at this time, sleeping in a bed is not possible
return minetest.get_timeofday() < 0.2 or minetest.get_timeofday() > 0.805
end
-----------------------------------------------------------------------------------------------------------
-- a hatch; nodebox definition taken from realtest
-----------------------------------------------------------------------------------------------------------
-- hatches rotate around their axis
-- old facedir: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23
local new_facedirs = {10, 19, 4, 13, 2, 18, 22, 14, 20, 16, 0, 12, 11, 3, 7, 21, 9, 23, 5, 1, 8, 15, 6, 17}
local node_box = {
{-0.49, -0.55, -0.49, -0.3, -0.45, 0.45},
{0.3, -0.55, -0.3, 0.49, -0.45, 0.45},
{0.49, -0.55, -0.49, -0.3, -0.45, -0.3},
{-0.075, -0.55, -0.3, 0.075, -0.45, 0.3},
{-0.3, -0.55, -0.075, -0.075, -0.45, 0.075},
{0.075, -0.55, -0.075, 0.3, -0.45, 0.075},
{-0.3, -0.55, 0.3, 0.3, -0.45, 0.45},
-- hinges
{-0.45, -0.530, 0.45, -0.15, -0.470, 0.525},
{0.15, -0.530, 0.45, 0.45, -0.470, 0.525},
-- handle
{-0.05, -0.60, -0.35, 0.05, -0.40, -0.45},
}
local function rotate(unrotated)
local rotated = {}
for _, row in ipairs(unrotated) do
local x1, y1, z1, x2, y2, z2 = unpack(row)
local tmp = x1
x1 = -x2
x2 = -tmp
tmp = y1
y1 = -z2
z2 = -y2
y2 = -z1
z1 = -tmp
table.insert(rotated, {x1, y1, z1, x2, y2, z2})
end
return rotated
end
function api.register_hatch(nodename, description, texture, receipe_item, def)
if cottages.has.doors then
def = def or {}
def.description = S(description)
def.tile_front = texture
def.tile_side = texture
def.groups = def.groups or {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2}
def.nodebox_closed = {
type = "fixed",
fixed = node_box,
}
def.nodebox_opened = {
type = "fixed",
fixed = rotate(node_box),
}
doors.register_trapdoor(nodename, def)
else
minetest.register_node(nodename, {
description = S(description), -- not that there are any other...
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = {texture},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = node_box,
},
selection_box = {
type = "fixed",
fixed = {-0.5, -0.55, -0.5, 0.5, -0.45, 0.5},
},
on_rightclick = function(pos, node, puncher)
if has_stamina then
stamina.exhaust_player(puncher, stamina_use, nodename)
end
minetest.swap_node(pos, {name = node.name, param2 = new_facedirs[node.param2 + 1]})
end,
is_ground_content = false,
on_place = minetest.rotate_node,
})
end
minetest.register_craft({
output = nodename,
recipe = {
{"", "", receipe_item},
{receipe_item, cottages.craftitems.stick, ""},
}
})
end

View File

@ -0,0 +1,74 @@
local ci = cottages.craftitems
-- transform opend and closed shutters into each other for convenience
minetest.register_craft({
output = "cottages:window_shutter_open",
recipe = {
{"cottages:window_shutter_closed"},
}
})
minetest.register_craft({
output = "cottages:window_shutter_closed",
recipe = {
{"cottages:window_shutter_open"},
}
})
if ci.wood then
minetest.register_craft({
output = "cottages:window_shutter_open",
recipe = {
{ci.wood, "", ci.wood},
}
})
end
-- transform one half door into another
minetest.register_craft({
output = "cottages:half_door",
recipe = {
{"cottages:half_door_inverted"},
}
})
minetest.register_craft({
output = "cottages:half_door_inverted",
recipe = {
{"cottages:half_door"},
}
})
if ci.wood and ci.door then
minetest.register_craft({
output = "cottages:half_door 2",
recipe = {
{"", ci.wood, ""},
{"", ci.door, ""},
}
})
end
-- transform open and closed versions into into another for convenience
minetest.register_craft({
output = "cottages:gate_closed",
recipe = {
{"cottages:gate_open"},
}
})
minetest.register_craft({
output = "cottages:gate_open",
recipe = {
{"cottages:gate_closed"},
}
})
if ci.stick and ci.wood then
minetest.register_craft({
output = "cottages:gate_closed",
recipe = {
{ci.stick, ci.stick, ci.wood},
}
})
end

View File

@ -0,0 +1,6 @@
cottages.doorlike = {}
cottages.dofile("modules", "doorlike", "api")
cottages.dofile("modules", "doorlike", "nodes")
cottages.dofile("modules", "doorlike", "crafts")
cottages.dofile("modules", "doorlike", "abms")

229
modules/doorlike/nodes.lua Normal file
View File

@ -0,0 +1,229 @@
local S = cottages.S
-- window shutters - they cover half a node to each side
minetest.register_node("cottages:window_shutter_open", {
description = S("opened window shutters"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
-- larger than one node but slightly smaller than a half node so that wallmounted torches pose no problem
node_box = {
type = "fixed",
fixed = {
{-0.90, -0.5, 0.4, -0.45, 0.5, 0.5},
{0.45, -0.5, 0.4, 0.9, 0.5, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.9, -0.5, 0.4, 0.9, 0.5, 0.5},
},
},
on_rightclick = function(pos, node, puncher)
cottages.doorlike.shutter_close(pos, puncher)
end,
is_ground_content = false,
})
minetest.register_node("cottages:window_shutter_closed", {
description = S("closed window shutters"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, not_in_creative_inventory = 1},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, 0.4, -0.05, 0.5, 0.5},
{0.05, -0.5, 0.4, 0.5, 0.5, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, 0.4, 0.5, 0.5, 0.5},
},
},
on_rightclick = function(pos, node, puncher)
cottages.doorlike.shutter_open(pos, puncher)
end,
is_ground_content = false,
drop = "cottages:window_shutter_open",
})
minetest.register_node("cottages:half_door", {
description = S("half door"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, 0.4, 0.48, 0.5, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, 0.4, 0.48, 0.5, 0.5},
},
},
on_rightclick = function(pos, node, puncher)
local node2 = minetest.get_node({x = pos.x, y = (pos.y + 1), z = pos.z})
local param2 = node.param2
if param2 % 4 == 1 then
param2 = param2 + 1; --2
elseif param2 % 4 == 2 then
param2 = param2 - 1; --1
elseif param2 % 4 == 3 then
param2 = param2 - 3; --0
elseif param2 % 4 == 0 then
param2 = param2 + 3; --3
end
minetest.swap_node(pos, {name = "cottages:half_door", param2 = param2})
-- if the node above consists of a door of the same type, open it as well
-- Note: doors beneath this one are not opened!
-- It is a special feature of these doors that they can be opend partly
if node2 ~= nil and node2.name == node.name and node2.param2 == node.param2 then
minetest.swap_node({x = pos.x, y = (pos.y + 1), z = pos.z}, {name = "cottages:half_door", param2 = param2})
end
end,
is_ground_content = false,
})
minetest.register_node("cottages:half_door_inverted", {
description = S("half door inverted"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.48, 0.5, -0.4},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.48, 0.5, -0.4},
},
},
on_rightclick = function(pos, node, puncher)
local node2 = minetest.get_node({x = pos.x, y = (pos.y + 1), z = pos.z})
local param2 = node.param2
if param2 % 4 == 1 then
param2 = param2 - 1; --0
elseif param2 % 4 == 0 then
param2 = param2 + 1; --1
elseif param2 % 4 == 2 then
param2 = param2 + 1; --3
elseif param2 % 4 == 3 then
param2 = param2 - 1; --2
end
minetest.swap_node(pos, {name = "cottages:half_door_inverted", param2 = param2})
-- open upper parts of this door (if there are any)
if node2 ~= nil and node2.name == node.name and node2.param2 == node.param2 then
minetest.swap_node({x = pos.x, y = (pos.y + 1), z = pos.z},
{name = "cottages:half_door_inverted", param2 = param2})
end
end,
is_ground_content = false,
})
minetest.register_node("cottages:gate_closed", {
description = S("closed fence gate"),
drawtype = "nodebox",
tiles = {cottages.textures.furniture},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.85, -0.25, -0.02, 0.85, -0.05, 0.02},
{-0.85, 0.15, -0.02, 0.85, 0.35, 0.02},
{-0.80, -0.05, -0.02, -0.60, 0.15, 0.02},
{0.60, -0.05, -0.02, 0.80, 0.15, 0.02},
{-0.15, -0.05, -0.02, 0.15, 0.15, 0.02},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.85, -0.25, -0.1, 0.85, 0.35, 0.1},
},
},
on_rightclick = function(pos, node, puncher)
minetest.swap_node(pos, {name = "cottages:gate_open", param2 = node.param2})
end,
is_ground_content = false,
})
minetest.register_node("cottages:gate_open", {
description = S("opened fence gate"),
drawtype = "nodebox",
tiles = {cottages.textures.furniture},
paramtype = "light",
paramtype2 = "facedir",
drop = "cottages:gate_closed",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2, not_in_creative_inventory = 1},
node_box = {
type = "fixed",
fixed = {
{-0.85, -0.5, -0.25, 0.85, -0.46, -0.05},
{-0.85, -0.5, 0.15, 0.85, -0.46, 0.35},
{-0.80, -0.5, -0.05, -0.60, -0.46, 0.15},
{0.60, -0.5, -0.05, 0.80, -0.46, 0.15},
{-0.15, -0.5, -0.05, 0.15, -0.46, 0.15},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.85, -0.5, -0.25, 0.85, -0.3, 0.35},
},
},
on_rightclick = function(pos, node, puncher)
minetest.swap_node(pos, {name = "cottages:gate_closed", param2 = node.param2})
end,
is_ground_content = false,
})
-- further alternate hatch materials: wood, tree, copper_block
cottages.doorlike.register_hatch(
"cottages:hatch_wood",
"wooden hatch",
"cottages_minimal_wood.png",
cottages.craftitems.slab_wood,
{
groups = {node = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 2},
sounds = cottages.sounds.wood,
}
)
cottages.doorlike.register_hatch(
"cottages:hatch_steel",
"metal hatch",
"cottages_steel_block.png",
cottages.craftitems.steel,
{
groups = {node = 1, cracky = 1, level = 2},
sounds = cottages.sounds.metal,
sound_open = "doors_steel_door_open",
sound_close = "doors_steel_door_close",
protected = true,
}
)

331
modules/feldweg/api.lua Normal file
View File

@ -0,0 +1,331 @@
local S = cottages.S
local api = cottages.feldweg
local box_slope = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
{-0.5, -0.25, -0.25, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.25, 0.5},
{-0.5, 0.25, 0.25, 0.5, 0.5, 0.5}
}
}
local box_slope_long = {
type = "fixed",
fixed = {
{-0.5, -0.5, -1.5, 0.5, -0.10, 0.5},
{-0.5, -0.25, -1.3, 0.5, -0.25, 0.5},
{-0.5, -0.25, -1.0, 0.5, 0, 0.5},
{-0.5, 0, -0.5, 0.5, 0.25, 0.5},
{-0.5, 0.25, 0, 0.5, 0.5, 0.5}
}
}
local function simplify_tile(tile)
if type(tile) == "string" then
return tile
elseif type(tile) == "table" then
if type(tile.name) == "string" then
return tile.name
else
error(("weird tile %q"):dump(tile))
end
else
error(("weird tile %q"):dump(tile))
end
end
local function get_textures(tiles, special)
if #tiles == 1 then
local tile1 = simplify_tile(tiles[1])
return tile1, tile1, tile1, tile1, "cottages_feldweg_surface.png^" .. (special or tile1)
elseif #tiles == 2 then
local tile1 = simplify_tile(tiles[1])
local tile2 = simplify_tile(tiles[2])
return tile1, tile2, tile1, tile1, "cottages_feldweg_surface.png^" .. (special or tile1)
elseif #tiles == 3 then
local tile1 = simplify_tile(tiles[1])
local tile2 = simplify_tile(tiles[2])
local tile3 = simplify_tile(tiles[3])
return tile1, tile2, tile3, tile3, "cottages_feldweg_surface.png^" .. (special or tile1)
else
error(("not implemented: %i tiles"):format(#tiles))
end
end
local function register_feldweg(name, base_def, def)
minetest.register_node(name, {
description = def.description,
paramtype = "light",
paramtype2 = "facedir",
legacy_facedir_simple = true,
drawtype = "mesh",
mesh = def.mesh,
tiles = def.tiles,
collision_box = def.collision_box,
selection_box = def.selection_box,
is_ground_content = false,
groups = base_def.groups,
sounds = base_def.sounds,
})
minetest.register_craft({
output = name .. " " .. def.output_amount,
recipe = def.recipe
})
minetest.register_craft({
output = def.reverts_to,
recipe = {
{name},
}
})
end
function api.register_feldweg(node, suffix, special)
local def = minetest.registered_nodes[node]
local texture_top, texture_bottom, texture_side, texture_side_with_dent, texture_edges =
get_textures(def.tiles, special)
local desc = futil.get_safe_short_description(node)
local feldweg_name = "cottages:feldweg" .. suffix
register_feldweg(feldweg_name, def, {
description = S("dirt road on @1", desc),
mesh = "feldweg.obj",
tiles = {
texture_side_with_dent,
texture_side,
texture_bottom,
texture_top,
"cottages_feldweg_surface.png",
texture_edges
},
recipe = {
{"", "cottages:wagon_wheel", ""},
{node, node, node},
},
output_amount = 3,
reverts_to = node,
})
register_feldweg("cottages:feldweg_crossing" .. suffix, def, {
description = S("dirt road crossing on @1", desc),
mesh = "feldweg-crossing.obj",
tiles = {
texture_side_with_dent,
texture_bottom,
texture_top,
"cottages_feldweg_surface.png",
texture_edges
},
recipe = {
{"", feldweg_name, ""},
{feldweg_name, feldweg_name, feldweg_name},
{"", feldweg_name, ""},
},
output_amount = 5,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_t_junction" .. suffix, def, {
description = S("dirt road t junction on @1", desc),
mesh = "feldweg-T-junction.obj",
tiles = {
texture_side_with_dent,
texture_side,
texture_bottom,
texture_top,
"cottages_feldweg_surface.png",
texture_edges
},
recipe = {
{"", feldweg_name, ""},
{"", feldweg_name, ""},
{feldweg_name, feldweg_name, feldweg_name},
},
output_amount = 5,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_curve" .. suffix, def, {
description = S("dirt road curve on @1", desc),
mesh = "feldweg-curve.obj",
tiles = {
texture_side,
texture_top,
texture_side,
"cottages_feldweg_surface.png",
texture_bottom,
texture_edges
},
recipe = {
{feldweg_name, "", ""},
{feldweg_name, "", ""},
{feldweg_name, feldweg_name, feldweg_name},
},
output_amount = 5,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_end" .. suffix, def, {
description = S("dirt road end on @1", desc),
mesh = "feldweg_end.obj",
tiles = {
texture_side_with_dent,
texture_side,
texture_bottom,
texture_top,
texture_edges,
"cottages_feldweg_surface.png"
},
recipe = {
{feldweg_name, "", feldweg_name},
{feldweg_name, feldweg_name, feldweg_name},
},
output_amount = 5,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_45" .. suffix, def, {
description = S("dirt road 45º on @1", desc),
mesh = "feldweg_45.b3d",
tiles = {
"cottages_feldweg_surface.png",
texture_edges,
texture_side,
texture_bottom,
texture_top,
},
recipe = {
{feldweg_name, "", feldweg_name},
{"", feldweg_name, ""},
{feldweg_name, "", feldweg_name},
},
output_amount = 5,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_s_45" .. suffix, def, {
description = S("dirt road 45º edge on @1", desc),
mesh = "feldweg_s_45.b3d",
tiles = {
texture_top,
texture_side,
texture_bottom,
"cottages_feldweg_surface.png",
texture_edges,
},
recipe = {
{feldweg_name, ""},
{"", feldweg_name},
},
output_amount = 2,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_d_45" .. suffix, def, {
description = S("dirt road 45º double edge on @1", desc),
mesh = "feldweg_d_45.b3d",
tiles = {
texture_side,
texture_bottom,
texture_top,
texture_edges,
"cottages_feldweg_surface.png",
},
recipe = {
{feldweg_name, "", feldweg_name},
{"", feldweg_name, ""},
},
output_amount = 3,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_l_curve" .. suffix, def, {
description = S("dirt road left curve on @1", desc),
mesh = "feldweg_l_45_curve.b3d",
tiles = {
texture_side,
texture_bottom,
texture_top,
texture_edges,
"cottages_feldweg_surface.png",
},
recipe = {
{"", "", feldweg_name},
{feldweg_name, feldweg_name, ""},
},
output_amount = 3,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_r_curve" .. suffix, def, {
description = S("dirt road right curve on @1", desc),
mesh = "feldweg_r_45_curve.b3d",
tiles = {
texture_side,
texture_bottom,
texture_top,
texture_edges,
"cottages_feldweg_surface.png",
},
recipe = {
{feldweg_name, "", ""},
{"", feldweg_name, feldweg_name},
},
output_amount = 3,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_slope" .. suffix, def, {
description = S("dirt road slope on @1", desc),
mesh = "feldweg_slope.obj",
tiles = {
texture_side_with_dent,
texture_side,
texture_bottom,
texture_top,
"cottages_feldweg_surface.png",
texture_edges
},
collision_box = box_slope,
selection_box = box_slope,
recipe = {
{feldweg_name, ""},
{feldweg_name, feldweg_name},
},
output_amount = 3,
reverts_to = feldweg_name,
})
register_feldweg("cottages:feldweg_slope_long" .. suffix, def, {
description = S("dirt road slope long on @1", desc),
mesh = "feldweg_slope_long.obj",
tiles = {
texture_side_with_dent,
texture_side,
texture_bottom,
texture_top,
"cottages_feldweg_surface.png",
texture_edges
},
collision_box = box_slope_long,
selection_box = box_slope_long,
recipe = {
{feldweg_name, "", ""},
{feldweg_name, feldweg_name, feldweg_name},
},
output_amount = 4,
reverts_to = feldweg_name,
})
end

View File

@ -0,0 +1,5 @@
cottages.feldweg.register_feldweg("default:dirt_with_grass", "", "cottages_feldweg_edges.png")
cottages.feldweg.register_feldweg("default:gravel", "_gravel")
cottages.feldweg.register_feldweg("default:dirt_with_coniferous_litter", "_coniferous")
cottages.feldweg.register_feldweg("default:dirt_with_snow", "_snow")
cottages.feldweg.register_feldweg("default:dirt_with_dry_grass", "_dry")

View File

@ -0,0 +1,2 @@
cottages.feldweg.register_feldweg("ethereal:bamboo_dirt", "_bamboo")

View File

@ -0,0 +1,18 @@
local S = cottages.S
stairs.register_stair_and_slab(
"feldweg",
"cottages:feldweg",
{crumbly = 3},
{
"cottages_feldweg.png",
"default_dirt.png",
"default_grass.png",
"default_grass.png",
"cottages_feldweg.png",
"cottages_feldweg.png"
},
S("Dirt Road Stairs"),
S("Dirt Road, half height"),
cottages.sounds.dirt
)

15
modules/feldweg/init.lua Normal file
View File

@ -0,0 +1,15 @@
cottages.feldweg = {}
cottages.dofile("modules", "feldweg", "api")
if cottages.has.default then
cottages.dofile("modules", "feldweg", "compat_default")
end
if cottages.has.ethereal then
cottages.dofile("modules", "feldweg", "compat_ethereal")
end
if cottages.has.stairs then
cottages.dofile("modules", "feldweg", "compat_stairs")
end

48
modules/fences/crafts.lua Normal file
View File

@ -0,0 +1,48 @@
local ci = cottages.craftitems
if ci.fence then
minetest.register_craft({
output = "cottages:fence_small 3",
recipe = {
{ci.fence, ci.fence},
}
})
end
-- xfences can be configured to replace normal fences - which makes them uncraftable
if minetest.get_modpath("xfences") then
minetest.register_craft({
output = "cottages:fence_small 3",
recipe = {
{"xfences:fence", "xfences:fence"},
}
})
end
minetest.register_craft({
output = "cottages:fence_corner",
recipe = {
{"cottages:fence_small", "cottages:fence_small"},
}
})
minetest.register_craft({
output = "cottages:fence_small 2",
recipe = {
{"cottages:fence_corner"},
}
})
minetest.register_craft({
output = "cottages:fence_end",
recipe = {
{"cottages:fence_small", "cottages:fence_small", "cottages:fence_small"},
}
})
minetest.register_craft({
output = "cottages:fence_small 3",
recipe = {
{"cottages:fence_end"},
}
})

4
modules/fences/init.lua Normal file
View File

@ -0,0 +1,4 @@
cottages.fences = {}
cottages.dofile("modules", "fences", "nodes")
cottages.dofile("modules", "fences", "crafts")

108
modules/fences/nodes.lua Normal file
View File

@ -0,0 +1,108 @@
-- 22.01.13 Changed texture to that of the wood from the minimal development game
local S = cottages.S
minetest.register_node("cottages:fence_small", {
description = S("small fence"),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.45, -0.35, 0.46, 0.45, -0.20, 0.50},
{-0.45, 0.00, 0.46, 0.45, 0.15, 0.50},
{-0.45, 0.35, 0.46, 0.45, 0.50, 0.50},
{-0.50, -0.50, 0.46, -0.45, 0.50, 0.50},
{0.45, -0.50, 0.46, 0.50, 0.50, 0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.50, -0.50, 0.4, 0.50, 0.50, 0.5},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:fence_corner", {
description = S("small fence corner"),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.45, -0.35, 0.46, 0.45, -0.20, 0.50},
{-0.45, 0.00, 0.46, 0.45, 0.15, 0.50},
{-0.45, 0.35, 0.46, 0.45, 0.50, 0.50},
{-0.50, -0.50, 0.46, -0.45, 0.50, 0.50},
{0.45, -0.50, 0.46, 0.50, 0.50, 0.50},
{0.46, -0.35, -0.45, 0.50, -0.20, 0.45},
{0.46, 0.00, -0.45, 0.50, 0.15, 0.45},
{0.46, 0.35, -0.45, 0.50, 0.50, 0.45},
{0.46, -0.50, -0.50, 0.50, 0.50, -0.45},
{0.46, -0.50, 0.45, 0.50, 0.50, 0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.50, -0.50, -0.5, 0.50, 0.50, 0.5},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:fence_end", {
description = S("small fence end"),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.45, -0.35, 0.46, 0.45, -0.20, 0.50},
{-0.45, 0.00, 0.46, 0.45, 0.15, 0.50},
{-0.45, 0.35, 0.46, 0.45, 0.50, 0.50},
{-0.50, -0.50, 0.46, -0.45, 0.50, 0.50},
{0.45, -0.50, 0.46, 0.50, 0.50, 0.50},
{0.46, -0.35, -0.45, 0.50, -0.20, 0.45},
{0.46, 0.00, -0.45, 0.50, 0.15, 0.45},
{0.46, 0.35, -0.45, 0.50, 0.50, 0.45},
{0.46, -0.50, -0.50, 0.50, 0.50, -0.45},
{0.46, -0.50, 0.45, 0.50, 0.50, 0.50},
{-0.50, -0.35, -0.45, -0.46, -0.20, 0.45},
{-0.50, 0.00, -0.45, -0.46, 0.15, 0.45},
{-0.50, 0.35, -0.45, -0.46, 0.50, 0.45},
{-0.50, -0.50, -0.50, -0.46, 0.50, -0.45},
{-0.50, -0.50, 0.45, -0.46, 0.50, 0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.50, -0.50, -0.5, 0.50, 0.50, 0.5},
},
},
is_ground_content = false,
})

294
modules/furniture/api.lua Normal file
View File

@ -0,0 +1,294 @@
local S = cottages.S
local pts = minetest.pos_to_string
local api = cottages.furniture
local attached_to = {}
local attached_at = {}
function api.allow_attach(pos, player)
if not minetest.is_player(player) then
return false
end
if attached_to[player] then
-- allow re-attaching to the same spot, but not a different spot
for _, p2 in ipairs(attached_to[player]) do
if vector.equals(pos, p2) then
return true
end
end
return false
end
local ps = pts(pos)
if attached_at[ps] and attached_at[ps] ~= player then
-- disallow multiple people to attach to the same spot
return false
end
return true
end
function api.get_up(player)
local player_name = player:get_player_name()
if cottages.has.player_monoids then
player_monoids.speed:del_change(player, "cottages:furniture")
player_monoids.jump:del_change(player, "cottages:furniture")
player_monoids.gravity:del_change(player, "cottages:furniture")
else
player:set_physics_override(1, 1, 1)
end
player_api.player_attached[player_name] = nil
player_api.set_animation(player, "stand")
if attached_to[player] then
for _, pos in ipairs(attached_to[player]) do
attached_at[pos] = nil
end
attached_to[player] = nil
end
player:set_eye_offset({x = 0, y = 0, z = 0}, {x = 0, y = 0, z = 0})
end
function api.stop_moving(player)
if cottages.has.player_monoids then
player_monoids.speed:add_change(player, 0, "cottages:furniture")
player_monoids.jump:add_change(player, 0, "cottages:furniture")
player_monoids.gravity:add_change(player, 0, "cottages:furniture")
else
player:set_physics_override(0, 0, 0)
end
end
function api.sit_on_bench(pos, node, player)
if not (cottages.has.player_api and api.allow_attach(pos, player)) then
return
end
local animation = player_api.get_animation(player)
if not animation then
-- certain versions of minetest have a broken API
return
elseif animation.animation == "sit" then
api.get_up(player)
else
-- the bench is not centered; prevent the player from sitting on air
local player_pos = {x = pos.x, y = pos.y, z = pos.z}
local player_name = player:get_player_name()
if node.param2 == 0 then
player_pos.z = player_pos.z + 0.3
elseif node.param2 == 1 then
player_pos.x = player_pos.x + 0.3
elseif node.param2 == 2 then
player_pos.z = player_pos.z - 0.3
elseif node.param2 == 3 then
player_pos.x = player_pos.x - 0.3
end
api.stop_moving(player)
player_api.set_animation(player, "sit")
player_api.player_attached[player_name] = true
player:set_eye_offset({x = 0, y = -7, z = 2}, {x = 0, y = 0, z = 0})
player:set_pos(player_pos)
attached_to[player] = {pos}
attached_at[pts(pos)] = player
end
end
function api.is_head(node_name)
return node_name == "cottages:bed_head" or node_name == "cottages:sleeping_mat_head"
end
function api.is_bed(node_name)
return node_name == "cottages:bed_head" or node_name == "cottages:bed_foot"
end
function api.is_mat(node_name)
return node_name == "cottages:sleeping_mat_head" or node_name == "cottages:sleeping_mat"
end
function api.is_head_of(foot_name, head_name)
if foot_name == "cottages:bed_foot" then
return head_name == "cottages:bed_head"
elseif foot_name == "cottages:sleeping_mat" then
return head_name == "cottages:sleeping_mat_head"
end
end
function api.is_foot_of(head_name, foot_name)
if head_name == "cottages:bed_head" then
return foot_name == "cottages:bed_foot"
elseif head_name == "cottages:sleeping_mat_head" then
return foot_name == "cottages:sleeping_mat"
end
end
function api.is_valid_bed(pos, node)
local head_pos = vector.copy(pos)
local foot_pos = vector.copy(pos)
if api.is_head(node.name) then
if node.param2 == 0 then
foot_pos.z = foot_pos.z - 1
elseif node.param2 == 1 then
foot_pos.x = foot_pos.x - 1
elseif node.param2 == 2 then
foot_pos.z = foot_pos.z + 1
elseif node.param2 == 3 then
foot_pos.x = foot_pos.x + 1
end
local foot_node = minetest.get_node(foot_pos)
if api.is_foot_of(node.name, foot_node.name) and node.param2 == foot_node.param2 then
return head_pos, foot_pos
end
else
if node.param2 == 2 then
head_pos.z = pos.z - 1
elseif node.param2 == 3 then
head_pos.x = pos.x - 1
elseif node.param2 == 0 then
head_pos.z = pos.z + 1
elseif node.param2 == 1 then
head_pos.x = pos.x + 1
end
local head_node = minetest.get_node(head_pos)
if api.is_head_of(node.name, head_node.name) and node.param2 == head_node.param2 then
return head_pos, foot_pos
end
end
end
function api.sleep_in_bed(pos, node, player)
if not (cottages.has.player_api and api.allow_attach(pos, player)) then
return
end
local player_name = player:get_player_name()
local head_pos, foot_pos = api.is_valid_bed(pos, node)
for _, p in ipairs({head_pos, foot_pos}) do
if p then
for y = 1, 2 do
local node_above = minetest.get_node(vector.add(p, {x = 0, y = y, z = 0}))
if node_above.name ~= "air" then
minetest.chat_send_player(
player_name,
S("This place is too narrow for sleeping. At least for you!")
)
return
end
end
end
end
local animation = player_api.get_animation(player)
if not animation then
-- certain versions of minetest have a broken API
return
end
if attached_to[player] then
if animation.animation == "lay" then
api.get_up(player)
minetest.chat_send_player(player_name, "That was enough sleep for now. You stand up again.")
elseif animation.animation == "sit" then
if head_pos and foot_pos then
player_api.set_animation(player, "lay")
player:set_eye_offset({x = 0, y = -14, z = 2}, {x = 0, y = 0, z = 0})
minetest.chat_send_player(player_name, S("You lie down and take a nap. A right-click will wake you up."))
else
api.get_up(player)
minetest.chat_send_player(player_name, S("That was enough sitting around for now. You stand up again."))
end
end
else
-- sit on the bed before lying down
api.stop_moving(player)
player_api.set_animation(player, "sit")
player_api.player_attached[player_name] = true
local sleep_pos = vector.copy(pos)
local bed_type = api.is_bed(node.name) and "bed" or "mat"
if bed_type == "bed" then
-- set the right height for the bed
sleep_pos.y = sleep_pos.y + 0.4
elseif bed_type == "mat" then
sleep_pos.y = sleep_pos.y - 0.4
end
if head_pos and foot_pos then
sleep_pos.x = (head_pos.x + foot_pos.x) / 2
sleep_pos.z = (head_pos.z + foot_pos.z) / 2
end
player:set_eye_offset({x = 0, y = -7, z = 2}, {x = 0, y = 0, z = 0})
player:set_pos(sleep_pos)
if head_pos and foot_pos then
attached_to[player] = {head_pos, foot_pos}
attached_at[pts(head_pos)] = player
attached_at[pts(foot_pos)] = player
minetest.chat_send_player(
player_name,
S("Aaah! What a comfortable @1. A second right-click will let you sleep.", bed_type)
)
else
attached_to[player] = {pos}
attached_at[pts(pos)] = player
minetest.chat_send_player(
player_name,
S("Comfortable, but not good enough for a nap. Right-click again if you want to get back up.")
)
end
end
end
function api.break_attach(pos)
local player = attached_at[pts(pos)]
if player then
api.get_up(player)
end
end
minetest.register_on_leaveplayer(function(player)
if attached_to[player] then
api.get_up(player)
end
end)
minetest.register_globalstep(function(dtime)
for player in pairs(attached_to) do
local c = player:get_player_control()
if c.up or c.down or c.left or c.right or c.jump then
api.get_up(player)
end
end
end)

View File

@ -0,0 +1,83 @@
local ci = cottages.craftitems
if ci.wool and ci.wood and ci.stick then
minetest.register_craft({
output = "cottages:bed_foot",
recipe = {
{ci.wool, "", "", },
{ci.wood, "", "", },
{ci.stick, "", "", }
}
})
minetest.register_craft({
output = "cottages:bed_head",
recipe = {
{"", "", ci.wool, },
{"", ci.stick, ci.wood, },
{"", "", ci.stick, }
}
})
end
minetest.register_craft({
output = "cottages:sleeping_mat 3",
recipe = {
{"cottages:wool_tent", "cottages:straw_mat", "cottages:straw_mat"}
}
})
minetest.register_craft({
output = "cottages:sleeping_mat_head",
recipe = {
{"cottages:sleeping_mat", "cottages:straw_mat"}
}
})
if ci.stick and ci.slab_wood then
minetest.register_craft({
output = "cottages:table",
recipe = {
{"", ci.slab_wood, "", },
{"", ci.stick, ""}
}
})
end
minetest.register_craft({
output = "cottages:bench",
recipe = {
{"", ci.wood, "", },
{ci.stick, "", ci.stick, }
}
})
if ci.stick and ci.wood then
minetest.register_craft({
output = "cottages:shelf",
recipe = {
{ci.stick, ci.wood, ci.stick, },
{ci.stick, ci.wood, ci.stick, },
{ci.stick, "", ci.stick}
}
})
end
if ci.stick and ci.clay then
minetest.register_craft({
output = "cottages:washing 2",
recipe = {
{ci.stick, },
{ci.clay, },
}
})
end
if ci.steel then
minetest.register_craft({
output = "cottages:stovepipe 2",
recipe = {
{ci.steel, "", ci.steel},
}
})
end

View File

@ -0,0 +1,5 @@
cottages.furniture = {}
cottages.dofile("modules", "furniture", "api")
cottages.dofile("modules", "furniture", "nodes")
cottages.dofile("modules", "furniture", "crafts")

326
modules/furniture/nodes.lua Normal file
View File

@ -0,0 +1,326 @@
local S = cottages.S
minetest.register_node("cottages:bed_foot", {
description = S("Bed (foot region)"),
drawtype = "nodebox",
tiles = {
"cottages_beds_bed_top_bottom.png",
cottages.textures.furniture,
"cottages_beds_bed_side.png",
"cottages_beds_bed_side.png",
"cottages_beds_bed_side.png",
"cottages_beds_bed_side.png"
},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.wood,
node_box = {
type = "fixed",
fixed = {
{-0.5, 0.0, -0.5, 0.5, 0.3, 0.5},
{-0.5, -0.5, -0.5, -0.4, 0.5, -0.4},
{0.4, -0.5, -0.5, 0.5, 0.5, -0.4},
{-0.4, 0.3, -0.5, 0.4, 0.5, -0.4},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.3, 0.5},
}
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.furniture.sleep_in_bed(pos, node, clicker)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
cottages.furniture.break_attach(pos)
end,
})
minetest.register_node("cottages:bed_head", {
description = S("Bed (head region)"),
drawtype = "nodebox",
tiles = {
"cottages_beds_bed_top_top.png",
cottages.textures.furniture,
"cottages_beds_bed_side_top_r.png",
"cottages_beds_bed_side_top_l.png",
cottages.textures.furniture,
"cottages_beds_bed_side.png"
},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.wood,
node_box = {
type = "fixed",
fixed = {
{-0.5, 0.0, -0.5, 0.5, 0.3, 0.5},
{-0.5, -0.5, 0.4, -0.4, 0.5, 0.5},
{0.4, -0.5, 0.4, 0.5, 0.5, 0.5},
{-0.4, 0.3, 0.4, 0.4, 0.5, 0.5},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.3, 0.5},
}
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.furniture.sleep_in_bed(pos, node, clicker)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
cottages.furniture.break_attach(pos)
end,
})
minetest.register_node("cottages:sleeping_mat", {
description = S("sleeping mat"),
drawtype = "nodebox",
tiles = {"cottages_sleepingmat.png"},
wield_image = "cottages_sleepingmat.png",
inventory_image = "cottages_sleepingmat.png",
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = {snappy = 3},
sounds = cottages.sounds.leaves,
node_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.5 + 1 / 16, 0.48},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.5 + 2 / 16, 0.48},
}
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.furniture.sleep_in_bed(pos, node, clicker)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
cottages.furniture.break_attach(pos)
end,
})
minetest.register_node("cottages:sleeping_mat_head", {
description = S("sleeping mat with pillow"),
drawtype = "nodebox",
tiles = {"cottages_sleepingmat.png"}, -- done by VanessaE
wield_image = "cottages_sleepingmat.png",
inventory_image = "cottages_sleepingmat.png",
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 3},
sounds = cottages.sounds.leaves,
node_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.5 + 1 / 16, 0.48},
{-0.34, -0.5 + 1 / 16, -0.12, 0.34, -0.5 + 2 / 16, 0.34},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.5 + 2 / 16, 0.48},
},
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.furniture.sleep_in_bed(pos, node, clicker)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
cottages.furniture.break_attach(pos)
end,
})
minetest.register_node("cottages:bench", {
drawtype = "nodebox",
description = S("simple wooden bench"),
tiles = {
"cottages_minimal_wood.png",
"cottages_minimal_wood.png",
"cottages_minimal_wood.png",
"cottages_minimal_wood.png",
"cottages_minimal_wood.png",
"cottages_minimal_wood.png"
},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 1, choppy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.wood,
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.15, 0.1, 0.5, -0.05, 0.5},
{-0.4, -0.5, 0.2, -0.3, -0.15, 0.4},
{0.3, -0.5, 0.2, 0.4, -0.15, 0.4},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, 0, 0.5, 0, 0.5},
}
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.furniture.sit_on_bench(pos, node, clicker)
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
cottages.furniture.break_attach(pos)
end,
})
minetest.register_node("cottages:table", {
description = S("table"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.1, -0.5, -0.1, 0.1, 0.3, 0.1},
{-0.5, 0.48, -0.5, 0.5, 0.4, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.4, 0.5},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:shelf", {
description = S("open storage shelf"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.3, -0.4, 0.5, 0.5},
{0.4, -0.5, -0.3, 0.5, 0.5, 0.5},
{-0.5, -0.2, -0.3, 0.5, -0.1, 0.5},
{-0.5, 0.3, -0.3, 0.5, 0.4, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
},
},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("formspec", [[
size[8,8]
list[context;main;0,0;8,3;]
list[current_player;main;0,4;8,4;]
listring[]
]])
meta:set_string("infotext", S("open storage shelf"))
local inv = meta:get_inventory()
inv:set_size("main", 24)
end,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:is_empty("main")
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", S("open storage shelf (in use)"))
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:is_empty("main") then
meta:set_string("infotext", S("open storage shelf (empty)"))
end
end,
is_ground_content = false,
})
minetest.register_node("cottages:stovepipe", {
description = S("stovepipe"),
drawtype = "nodebox",
tiles = {"cottages_steel_block.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{0.20, -0.5, 0.20, 0.45, 0.5, 0.45},
},
},
selection_box = {
type = "fixed",
fixed = {
{0.20, -0.5, 0.20, 0.45, 0.5, 0.45},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:washing", {
description = S("washing place"),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = {"cottages_clay.png"},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, -0.2, -0.2},
{-0.5, -0.5, -0.2, -0.4, 0.2, 0.5},
{0.4, -0.5, -0.2, 0.5, 0.2, 0.5},
{-0.4, -0.5, 0.4, 0.4, 0.2, 0.5},
{-0.4, -0.5, -0.2, 0.4, 0.2, -0.1},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.2, 0.5},
},
},
on_rightclick = function(pos, node, player)
-- works only with water beneath
local node_under = minetest.get_node({x = pos.x, y = (pos.y - 1), z = pos.z})
if minetest.get_item_group(node_under.name, "water") > 0 then
minetest.chat_send_player(
player:get_player_name(),
S("You feel much cleaner after some washing.")
)
else
minetest.chat_send_player(
player:get_player_name(),
S("Sorry. This washing place is out of water. Please place it above water!")
)
end
end,
})

26
modules/hay/crafts.lua Normal file
View File

@ -0,0 +1,26 @@
minetest.register_craft({
output = "cottages:hay_mat 9",
recipe = {
{"cottages:hay"},
},
})
minetest.register_craft({
output = "cottages:hay",
recipe = {
{"cottages:hay_mat", "cottages:hay_mat", "cottages:hay_mat"},
{"cottages:hay_mat", "cottages:hay_mat", "cottages:hay_mat"},
{"cottages:hay_mat", "cottages:hay_mat", "cottages:hay_mat"},
},
})
minetest.register_craft({
output = "cottages:hay",
recipe = {{"cottages:hay_bale"}},
})
minetest.register_craft({
output = "cottages:hay_bale",
recipe = {{"cottages:hay"}},
})

3
modules/hay/init.lua Normal file
View File

@ -0,0 +1,3 @@
cottages.dofile("modules", "hay", "nodes")
cottages.dofile("modules", "hay", "crafts")

57
modules/hay/nodes.lua Normal file
View File

@ -0,0 +1,57 @@
local S = cottages.S
minetest.register_node("cottages:hay_mat", {
drawtype = "nodebox",
paramtype2 = "leveled",
description = S("Some hay"),
tiles = {
cottages.textures.straw .. "^[multiply:#88BB88"
},
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
-- the bale is slightly smaller than a full node
is_ground_content = false,
node_box = {
type = "leveled", --"fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
}
},
-- make sure a placed hay block looks halfway reasonable
after_place_node = function(pos, placer, itemstack, pointed_thing)
minetest.swap_node(pos, {name = "cottages:hay_mat", param2 = math.random(2, 25)})
end,
})
-- hay block, similar to straw block
minetest.register_node("cottages:hay", {
description = S("Hay"),
tiles = {cottages.textures.straw .. "^[multiply:#88BB88"},
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
is_ground_content = false,
})
-- hay bales for hungry animals
minetest.register_node("cottages:hay_bale", {
drawtype = "nodebox",
description = S("Hay bale"),
tiles = {"cottages_darkage_straw_bale.png^[multiply:#88BB88"},
paramtype = "light",
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
-- the bale is slightly smaller than a full node
node_box = {
type = "fixed",
fixed = {
{-0.45, -0.5, -0.45, 0.45, 0.45, 0.45},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.45, -0.5, -0.45, 0.45, 0.45, 0.45},
}
},
is_ground_content = false,
})

View File

@ -0,0 +1,82 @@
local ci = cottages.craftitems
if ci.iron and ci.stick and ci.steel then
minetest.register_craft({
output = "cottages:wagon_wheel 3",
recipe = {
{ci.iron, ci.stick, ci.iron},
{ci.stick, ci.steel, ci.stick},
{ci.iron, ci.stick, ci.iron}
}
})
end
if ci.sand and ci.clay then
minetest.register_craft({
output = "cottages:loam 4",
recipe = {
{ci.sand},
{ci.clay}
}
})
end
minetest.register_craft({
output = "cottages:straw_ground 2",
recipe = {
{"cottages:straw_mat"},
{"cottages:loam"}
}
})
if ci.stick and ci.glass then
minetest.register_craft({
output = "cottages:glass_pane 4",
recipe = {
{ci.stick, ci.stick, ci.stick},
{ci.stick, ci.glass, ci.stick},
{ci.stick, ci.stick, ci.stick}
}
})
end
minetest.register_craft({
output = "cottages:glass_pane_side",
recipe = {
{"cottages:glass_pane"},
}
})
minetest.register_craft({
output = "cottages:glass_pane",
recipe = {
{"cottages:glass_pane_side"},
}
})
if ci.stick and ci.string then
minetest.register_craft({
output = "cottages:wood_flat 16",
recipe = {
{ci.stick, ci.string, ci.stick},
{ci.stick, "", ci.stick},
}
})
end
if ci.stick then
minetest.register_craft({
output = "cottages:wool_tent 2",
recipe = {
{ci.string, ci.string},
{"", ci.stick}
}
})
end
minetest.register_craft({
output = "cottages:wool",
recipe = {
{"cottages:wool_tent", "cottages:wool_tent"}
}
})

View File

@ -0,0 +1,3 @@
cottages.dofile("modules", "historic", "nodes")
cottages.dofile("modules", "historic", "crafts")

155
modules/historic/nodes.lua Normal file
View File

@ -0,0 +1,155 @@
local S = cottages.S
if cottages.has.wool and minetest.registered_nodes["wool:white"] then
minetest.register_alias("cottages:wool", "wool:white")
else
minetest.register_node("cottages:wool", {
description = "Wool",
tiles = {"cottages_wool.png"},
is_ground_content = false,
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, flammable = 3, wool = 1},
})
end
minetest.register_node("cottages:wool_tent", {
description = S("wool for tents"),
drawtype = "nodebox",
tiles = {"cottages_wool.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.50, 0.5, -0.5 + 1 / 16, 0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.50, 0.5, -0.5 + 1 / 16, 0.50},
},
},
is_ground_content = false,
on_place = minetest.rotate_node,
})
minetest.register_node("cottages:wood_flat", {
description = S("flat wooden planks"),
drawtype = "nodebox",
tiles = {"cottages_minimal_wood.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.50, 0.5, -0.5 + 1 / 16, 0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.50, 0.5, -0.5 + 1 / 16, 0.50},
},
},
is_ground_content = false,
on_place = minetest.rotate_node,
})
minetest.register_node("cottages:glass_pane", {
description = S("simple glass pane (centered)"),
drawtype = "nodebox",
tiles = {"cottages_glass_pane.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.05, 0.5, 0.5, 0.05},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.05, 0.5, 0.5, 0.05},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:glass_pane_side", {
description = S("simple glass pane"),
drawtype = "nodebox",
tiles = {"cottages_glass_pane.png"},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.40, 0.5, 0.5, -0.50},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.40, 0.5, 0.5, -0.50},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:straw_ground", {
description = S("straw ground for animals"),
tiles = {
cottages.straw_texture,
"cottages_loam.png",
"cottages_loam.png",
"cottages_loam.png",
"cottages_loam.png",
"cottages_loam.png"
},
groups = {snappy = 2, crumbly = 3, choppy = 2, oddly_breakable_by_hand = 2},
sounds = cottages.sounds.leaves,
is_ground_content = false,
})
minetest.register_node("cottages:loam", {
description = S("loam"),
tiles = {"cottages_loam.png"},
groups = {snappy = 2, crumbly = 3, choppy = 2, oddly_breakable_by_hand = 2},
sounds = cottages.sounds.dirt,
is_ground_content = false,
})
minetest.register_node("cottages:wagon_wheel", {
description = S("wagon wheel"),
drawtype = "signlike",
tiles = {"cottages_wagonwheel.png"},
inventory_image = "cottages_wagonwheel.png",
wield_image = "cottages_wagonwheel.png",
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
selection_box = {
type = "wallmounted",
},
groups = {choppy = 2, dig_immediate = 2, attached_node = 1},
legacy_wallmounted = true,
is_ground_content = false,
})
if cottages.has.stairs then
stairs.register_stair_and_slab("loam", "cottages:loam",
{snappy = 2, crumbly = 3, choppy = 2, oddly_breakable_by_hand = 2},
{"cottages_loam.png"},
S("Loam Stairs"),
S("Loam Slab"),
cottages.sounds.dirt
)
end

5
modules/init.lua Normal file
View File

@ -0,0 +1,5 @@
for module, settings in pairs(cottages.settings) do
if settings.enabled then
cottages.dofile("modules", module, "init")
end
end

19
modules/mining/crafts.lua Normal file
View File

@ -0,0 +1,19 @@
local ci = cottages.craftitems
if ci.cotton then
minetest.register_craft({
output = "cottages:rope",
recipe = {
{ci.cotton, ci.cotton, ci.cotton}
}
})
end
if ci.ladder and ci.rail then
minetest.register_craft({
output = "cottages:ladder_with_rope_and_rail 3",
recipe = {
{ci.ladder, "cottages:rope", ci.rail}
}
})
end

3
modules/mining/init.lua Normal file
View File

@ -0,0 +1,3 @@
cottages.dofile("modules", "mining", "nodes")
cottages.dofile("modules", "mining", "crafts")

70
modules/mining/nodes.lua Normal file
View File

@ -0,0 +1,70 @@
local S = cottages.S
minetest.register_node("cottages:rope", {
description = S("Rope"),
tiles = {"cottages_rope.png"},
groups = {
snappy = 3, choppy = 3, oddly_breakable_by_hand = 3,
},
walkable = false,
climbable = true,
paramtype = "light",
sunlight_propagates = true,
drawtype = "plantlike",
is_ground_content = false,
can_dig = function(pos, player)
local below = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
if below.name == "cottages:rope" then
if minetest.is_player(player) then
minetest.chat_send_player(
player:get_player_name(),
S("The entire rope would be too heavy. Start digging at its lowest end!")
)
end
return false
end
return true
end
})
if cottages.has.carts then
carts:register_rail("cottages:ladder_with_rope_and_rail", {
description = S("Ladder with \"rail support\""),
tiles = {
"default_ladder_wood.png^carts_rail_straight.png^cottages_rope.png"
},
inventory_image = "default_ladder_wood.png",
wield_image = "default_ladder_wood.png",
groups = carts:get_rail_groups(),
sounds = cottages.sounds.wood,
paramtype2 = "wallmounted",
legacy_wallmounted = true,
}, {})
else
minetest.register_node("cottages:ladder_with_rope_and_rail", {
description = S("Ladder with \"rail support\""),
inventory_image = "default_ladder_wood.png",
wield_image = "default_ladder_wood.png",
drawtype = "raillike",
tiles = {
"default_ladder_wood.png^carts_rail_straight.png^cottages_rope.png"
},
paramtype = "light",
paramtype2 = "wallmounted",
sunlight_propagates = true,
walkable = false,
climbable = true,
is_ground_content = false,
selection_box = {
type = "wallmounted",
},
groups = {
choppy = 2, oddly_breakable_by_hand = 3, rail = 1,
connect_to_raillike = minetest.raillike_group("rail"),
},
legacy_wallmounted = true,
sounds = cottages.sounds.wood,
})
end

View File

@ -0,0 +1,30 @@
local S = cottages.S
local ci = cottages.craftitems
if ci.stick then
minetest.register_craft({
output = "cottages:pitchfork",
recipe = {
{ci.stick, ci.stick, ci.stick},
{"", ci.stick, ""},
{"", ci.stick, ""},
}
})
end
if cottages.has.unified_inventory then
unified_inventory.register_craft_type("cottages:pitchfork", {
description = S("gathered w/ the pitchfork"),
icon = "cottages_pitchfork.png",
width = 1,
height = 1,
uses_crafting_grid = false,
})
unified_inventory.register_craft({
output = "cottages:hay_mat",
type = "cottages:pitchfork",
items = {"default:dirt_with_grass"},
width = 1,
})
end

View File

@ -0,0 +1,3 @@
cottages.dofile("modules", "pitchfork", "tool")
cottages.dofile("modules", "pitchfork", "crafts")

105
modules/pitchfork/tool.lua Normal file
View File

@ -0,0 +1,105 @@
local S = cottages.S
local has_stamina = cottages.has.stamina
local stamina_use = cottages.settings.pitchfork.stamina
minetest.register_node("cottages:pitchfork", {
description = S("Pitchfork (dig dirt with grass to get hay, place with right-click)"),
short_description = S("Pitchfork"),
inventory_image = "cottages_pitchfork.png",
wield_image = "cottages_pitchfork.png^[transformFYR180",
wield_scale = {x = 1.5, y = 1.5, z = 0.5},
stack_max = 1,
liquids_pointable = false,
tool_capabilities = {
full_punch_interval = 1.0,
max_drop_level = 1,
groupcaps = {
crumbly = {times={[2]=3.00, [3]=0.70}, maxlevel = 1, uses = 0, punch_attack_uses = 0, },
snappy = {times = {[2] = 0.40, [3] = 0.20}, maxlevel = 1, uses = 0, punch_attack_uses = 0, },
hay = {times = {[2] = 0.10, [3] = 0.10}, maxlevel = 1, uses = 0, punch_attack_uses = 0, },
},
damage_groups = {fleshy = 5}, -- slightly stronger than a stone sword
},
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
drop = "cottages:pitchfork",
groups = {snappy = 2, dig_immediate = 3, falling_node = 1, attached_node = 1},
sounds = cottages.sounds.wood,
visual_scale = 1.0,
tiles = {"default_wood.png^[transformR90"},
special_tiles = {},
post_effect_color = {a=0, r=0, g=0, b=0},
node_box = {
type = "fixed",
fixed = {
-- handle (goes a bit into the ground)
{-(1 / 32), -(11 / 16), -(1 / 32), (1 / 32), 16 / 16, (1 / 32)},
-- middle connection
{-(7 / 32), -(4 / 16), -(1 / 32), (7 / 32), -(2 / 16), (1 / 32)},
-- thongs
{-(7 / 32), -(11 / 16), -(1 / 32), -(5 / 32), -(4 / 16), (1 / 32)},
{(5 / 32), -(11 / 16), -(1 / 32), (7 / 32), -(4 / 16), (1 / 32)},
},
},
selection_box = {
type = "fixed",
fixed = {-0.3, -0.5, -0.1, 0.3, 1.0, 0.1}
},
})
local function override_on_dig(node_name, replacement)
local node_def = minetest.registered_nodes[node_name]
if not node_def and minetest.registered_nodes[replacement] then
return
end
local old_on_dig = node_def.on_dig
minetest.override_item(node_name, {
on_dig = function(pos, node, digger)
if not minetest.is_player(digger) then
return old_on_dig(pos, node, digger)
end
local wielded = digger:get_wielded_item()
if wielded:get_name() ~= "cottages:pitchfork" then
return old_on_dig(pos, node, digger)
end
local digger_name = digger:get_player_name()
if minetest.is_protected(pos, digger_name) then
return old_on_dig(pos, node, digger)
end
local pos_above = vector.add(pos, {x=0, y=1, z=0})
local node_above = minetest.get_node(pos_above)
if minetest.is_protected(pos_above, digger_name) or node_above.name ~= "air" then
return old_on_dig(pos, node, digger)
end
minetest.swap_node(pos, {name = replacement})
minetest.swap_node(pos_above, {name = "cottages:hay_mat", param2 = math.random(2, 25)})
if has_stamina then
stamina.exhaust_player(digger, stamina_use, "cottages:pitchfork")
end
return true
end,
})
end
override_on_dig("default:dirt_with_grass", "default:dirt")
minetest.register_alias("cottages:pitchfork_placed", "cottages:pitchfork")

111
modules/roof/api.lua Normal file
View File

@ -0,0 +1,111 @@
local S = cottages.S
local ci = cottages.craftitems
function cottages.roof.register_roof(name, material, tiles)
minetest.register_node("cottages:roof_" .. name, {
description = S("Roof " .. name),
drawtype = "nodebox",
tiles = tiles,
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
})
minetest.register_node("cottages:roof_connector_" .. name, {
description = S("Roof connector " .. name),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
tiles = tiles,
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
{-0.5, 0, 0, 0.5, 0.5, 0.5},
},
},
is_ground_content = false,
})
-- this one is the slab version of the above roof
minetest.register_node("cottages:roof_flat_" .. name, {
description = S("Roof (flat) " .. name),
drawtype = "nodebox",
-- top, bottom, side1, side2, inner, outer
-- this one is from all sides - except from the underside - of the given material
tiles = {tiles[1], tiles[2], tiles[1], tiles[1], tiles[1], tiles[1]},
paramtype = "light",
paramtype2 = "facedir",
groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 2},
node_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0, 0.5},
},
},
is_ground_content = false,
})
minetest.register_craft({
output = "cottages:roof_" .. name .. " 6",
recipe = {
{"", "", material},
{"", material, ""},
{material, "", ""}
}
})
minetest.register_craft({
output = "cottages:roof_connector_" .. name,
recipe = {
{"cottages:roof_" .. name},
{ci.wood},
}
})
minetest.register_craft({
output = "cottages:roof_flat_" .. name .. " 2",
recipe = {
{"cottages:roof_" .. name, "cottages:roof_" .. name},
}
})
-- convert flat roofs back to normal roofs
minetest.register_craft({
output = "cottages:roof_" .. name,
recipe = {
{"cottages:roof_flat_" .. name, "cottages:roof_flat_" .. name}
}
})
end -- of cottages.register_roof( name, tiles, basic_material )

13
modules/roof/crafts.lua Normal file
View File

@ -0,0 +1,13 @@
local ci = cottages.craftitems
minetest.register_craft({
output = "cottages:reet",
recipe = {{ci.papyrus, ci.papyrus},
{ci.papyrus, ci.papyrus},
},
})
minetest.register_craft({
output = "cottages:slate_vertical",
recipe = {{ci.stone, ci.wood}}
})

5
modules/roof/init.lua Normal file
View File

@ -0,0 +1,5 @@
cottages.roof = {}
cottages.dofile("modules", "roof", "api")
cottages.dofile("modules", "roof", "nodes")
cottages.dofile("modules", "roof", "crafts")

86
modules/roof/nodes.lua Normal file
View File

@ -0,0 +1,86 @@
local S = cottages.S
local ci = cottages.craftitems
if cottages.settings.roof.use_farming_straw_stairs then
minetest.register_alias("cottages:roof_straw", "stairs:stair_straw")
minetest.register_alias("cottages:roof_connector_straw", "stairs:stair_straw")
minetest.register_alias("cottages:roof_flat_straw", "stairs:slab_straw")
else
cottages.roof.register_roof(
"straw",
"cottages:straw_mat",
{cottages.textures.straw, cottages.textures.straw,
cottages.textures.straw, cottages.textures.straw,
cottages.textures.straw, cottages.textures.straw}
)
end
cottages.roof.register_roof(
"reet",
ci.papyrus,
{"cottages_reet.png", "cottages_reet.png",
"cottages_reet.png", "cottages_reet.png",
"cottages_reet.png", "cottages_reet.png"}
)
cottages.roof.register_roof(
"wood",
ci.wood,
{cottages.textures.roof_wood, cottages.textures.roof_sides,
cottages.textures.roof_sides, cottages.textures.roof_sides,
cottages.textures.roof_sides, cottages.textures.roof_wood}
)
cottages.roof.register_roof(
"black",
ci.coal_lump,
{"cottages_homedecor_shingles_asphalt.png", cottages.textures.roof_sides,
cottages.textures.roof_sides, cottages.textures.roof_sides,
cottages.textures.roof_sides, "cottages_homedecor_shingles_asphalt.png"}
)
cottages.roof.register_roof(
"red",
ci.clay_brick,
{"cottages_homedecor_shingles_terracotta.png", cottages.textures.roof_sides,
cottages.textures.roof_sides, cottages.textures.roof_sides,
cottages.textures.roof_sides, "cottages_homedecor_shingles_terracotta.png"}
)
cottages.roof.register_roof(
"brown",
ci.dirt,
{"cottages_homedecor_shingles_wood.png", cottages.textures.roof_sides,
cottages.textures.roof_sides, cottages.textures.roof_sides,
cottages.textures.roof_sides, "cottages_homedecor_shingles_wood.png"}
)
cottages.roof.register_roof(
"slate",
ci.stone,
{"cottages_slate.png", cottages.textures.roof_sides,
"cottages_slate.png", "cottages_slate.png",
cottages.textures.roof_sides, "cottages_slate.png"}
)
--------
minetest.register_node("cottages:reet", {
description = S("Reed for thatching"),
tiles = {"cottages_reet.png"},
groups = {hay = 3, snappy = 3, choppy = 3, oddly_breakable_by_hand = 3, flammable = 3},
sounds = cottages.sounds.leaves,
is_ground_content = false,
})
minetest.register_node("cottages:slate_vertical", {
description = S("Vertical Slate"),
tiles = {"cottages_slate.png", cottages.textures.roof_sides,
"cottages_slate.png", "cottages_slate.png",
cottages.textures.roof_sides, "cottages_slate.png"},
paramtype2 = "facedir",
groups = {cracky = 2, stone = 1},
sounds = cottages.sounds.stone,
is_ground_content = false,
})

55
modules/straw/api.lua Normal file
View File

@ -0,0 +1,55 @@
local S = cottages.S
local api = cottages.straw
local has_ui = cottages.has.unified_inventory
if has_ui then
unified_inventory.register_craft_type("cottages:quern", {
description = S("quern-stone"),
icon = "cottages_quern.png",
width = 1,
height = 1,
uses_crafting_grid = false,
})
unified_inventory.register_craft_type("cottages:threshing", {
description = S("threshing floor"),
icon = "cottages_junglewood.png^farming_wheat.png",
width = 1,
height = 1,
uses_crafting_grid = false,
})
end
api.registered_quern_crafts = {}
function api.register_quern_craft(recipe)
api.registered_quern_crafts[recipe.input] = recipe.output
if has_ui then
unified_inventory.register_craft({
output = recipe.output,
type = "cottages:quern",
items = {recipe.input},
width = 1,
})
end
end
api.registered_threshing_crafts = {}
function api.register_threshing_craft(recipe)
api.registered_threshing_crafts[recipe.input] = recipe.output
if has_ui then
for _, output in ipairs(recipe.output) do
unified_inventory.register_craft({
output = output,
type = "cottages:threshing",
items = {recipe.input},
width = 1,
})
end
end
end

93
modules/straw/crafts.lua Normal file
View File

@ -0,0 +1,93 @@
local ci = cottages.craftitems
minetest.register_craft({
output = "cottages:straw_mat 6",
recipe = {
{ci.stone, "", ""},
{"farming:wheat", "farming:wheat", "farming:wheat", },
},
replacements = {{ci.stone, ci.seed_wheat .. " 3"}},
})
-- this is a better way to get straw mats
minetest.register_craft({
output = "cottages:threshing_floor",
recipe = {
{ci.junglewood, ci.chest_locked, ci.junglewood, },
{ci.junglewood, ci.stone, ci.junglewood, },
},
})
-- and a way to turn wheat seeds into flour
minetest.register_craft({
output = "cottages:quern",
recipe = {
{ci.stick, ci.stone, "", },
{"", ci.steel, "", },
{"", ci.stone, "", },
},
})
minetest.register_craft({
output = "cottages:straw_bale",
recipe = {
{"cottages:straw_mat"},
{"cottages:straw_mat"},
{"cottages:straw_mat"},
},
})
minetest.register_craft({
output = "cottages:straw",
recipe = {
{"cottages:straw_bale"},
},
})
minetest.register_craft({
output = "cottages:straw_bale",
recipe = {
{"cottages:straw"},
},
})
minetest.register_craft({
output = "cottages:straw_mat 3",
recipe = {
{"cottages:straw_bale"},
},
})
---------------------------------
if ci.flour then
if ci.seed_barley then
cottages.straw.register_quern_craft({input = ci.seed_barley, output = ci.flour})
end
if ci.seed_oat then
cottages.straw.register_quern_craft({input = ci.seed_oat, output = ci.flour})
end
if ci.seed_rye then
cottages.straw.register_quern_craft({input = ci.seed_rye, output = ci.flour})
end
if ci.seed_wheat then
cottages.straw.register_quern_craft({input = ci.seed_wheat, output = ci.flour})
end
end
if ci.rice and ci.rice_flour then
cottages.straw.register_quern_craft({input = ci.rice, output = ci.rice_flour})
end
if ci.barley and ci.seed_barley then
cottages.straw.register_threshing_craft({input = ci.barley, output = {ci.seed_barley, ci.straw_mat}})
end
if ci.oat and ci.seed_oat then
cottages.straw.register_threshing_craft({input = ci.oat, output = {ci.seed_oat, ci.straw_mat}})
end
if ci.rye and ci.seed_rye then
cottages.straw.register_threshing_craft({input = ci.rye, output = {ci.seed_rye, ci.straw_mat}})
end
if ci.wheat and ci.seed_wheat then
cottages.straw.register_threshing_craft({input = ci.wheat, output = {ci.seed_wheat, ci.straw_mat}})
end

7
modules/straw/init.lua Normal file
View File

@ -0,0 +1,7 @@
cottages.straw = {}
cottages.dofile("modules", "straw", "api")
cottages.dofile("modules", "straw", "nodes")
cottages.dofile("modules", "straw", "quern")
cottages.dofile("modules", "straw", "threshing")
cottages.dofile("modules", "straw", "crafts")

71
modules/straw/nodes.lua Normal file
View File

@ -0,0 +1,71 @@
local S = cottages.S
if not (minetest.registered_nodes["farming:straw"]) then
minetest.register_node("cottages:straw", {
drawtype = "normal",
description = S("straw"),
tiles = {cottages.textures.straw},
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
-- the bale is slightly smaller than a full node
is_ground_content = false,
})
else
minetest.register_alias("cottages:straw", "farming:straw")
end
minetest.register_node("cottages:straw_mat", {
description = S("layer of straw"),
drawtype = "nodebox",
tiles = {cottages.textures.straw}, -- done by VanessaE
wield_image = cottages.textures.straw,
inventory_image = cottages.textures.straw,
sunlight_propagates = true,
paramtype = "light",
paramtype2 = "facedir",
walkable = false,
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
node_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.45, 0.48},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.48, -0.5, -0.48, 0.48, -0.25, 0.48},
}
},
is_ground_content = false,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
return cottages.sleep_in_bed(pos, node, clicker, itemstack, pointed_thing)
end
})
-- straw bales are a must for farming environments; if you for some reason do not have the darkage mod installed, this
-- here gets you a straw bale
minetest.register_node("cottages:straw_bale", {
drawtype = "nodebox",
description = S("straw bale"),
tiles = {"cottages_darkage_straw_bale.png"},
paramtype = "light",
groups = {hay = 3, snappy = 2, oddly_breakable_by_hand = 2, flammable = 3},
sounds = cottages.sounds.leaves,
-- the bale is slightly smaller than a full node
node_box = {
type = "fixed",
fixed = {
{-0.45, -0.5, -0.45, 0.45, 0.45, 0.45},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.45, -0.5, -0.45, 0.45, 0.45, 0.45},
}
},
is_ground_content = false,
})

180
modules/straw/quern.lua Normal file
View File

@ -0,0 +1,180 @@
local straw = cottages.straw
local S = cottages.S
local F = minetest.formspec_escape
local FS = function(...) return F(S(...)) end
local get_safe_short_description = futil.get_safe_short_description
local has_stamina = cottages.has.stamina
local stamina_use = cottages.settings.straw.quern_stamina
local quern_min_per_turn = cottages.settings.straw.quern_min_per_turn
local quern_max_per_turn = cottages.settings.straw.quern_max_per_turn
function straw.get_quern_fs_parts()
return {
("size[8,8]"),
("image[0,1;1,1;%s]"):format(F(cottages.textures.wheat_seed)),
("label[0,0.5;%s]"):format(FS("Input:")),
("label[3,0.5;%s]"):format(FS("Output:")),
("label[0,-0.3;%s]"):format(FS("Quern")),
("label[0,2.5;%s]"):format(FS("Punch this hand-driven quern")),
("label[0,3.0;%s]"):format(FS("to grind suitable items.")),
("list[context;seeds;1,1;1,1;]"),
("list[context;flour;4,1;2,2;]"),
("list[current_player;main;0,4;8,4;]"),
("listring[current_player;main]"),
("listring[context;seeds]"),
("listring[current_player;main]"),
("listring[context;flour]"),
}
end
function straw.get_quern_info(pos)
local meta = minetest.get_meta(pos)
if meta:get_int("used") == 0 then
return S("quern, powered by punching")
else
local inv = meta:get_inventory()
local input = inv:get_stack("seeds", 1)
local count = input:get_count()
if count > 0 then
local input_description = get_safe_short_description(input)
return S("quern, @1 @2 remaining", count, input_description)
else
return S("quern, none remaining")
end
end
end
local function get_quern_results(input)
local item = input:get_name()
local output_def = straw.registered_quern_crafts[item]
if type(output_def) == "string" then
return {ItemStack(output_def)}
elseif type(output_def) == "table" and #output_def > 0 then
local outputs = {}
for _, output_item in ipairs(output_def) do
if type(output_item) == "string" then
table.insert(outputs, ItemStack(output_item))
elseif type(output_item) == "table" then
local chance
output_item, chance = unpack(output_item)
if math.random() <= chance then
table.insert(outputs, ItemStack(output_item))
end
end
end
return outputs
elseif type(output_def) == "function" then
return output_def()
end
end
function straw.use_quern(pos, player)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local input = inv:get_stack("seeds", 1)
if input:is_empty() then
return
end
local input_count = input:get_count()
local number_to_process = math.min(math.random(quern_min_per_turn, quern_max_per_turn), input_count)
local above = vector.add(pos, vector.new(0, 1, 0))
for _ = 1, number_to_process do
local results = get_quern_results(input:take_item(1))
for _, result in ipairs(results) do
local leftovers = inv:add_item("flour", result)
if not leftovers:is_empty() then
minetest.add_item(above, leftovers)
end
end
end
inv:set_stack("seeds", 1, input)
local node = minetest.get_node(pos)
node.param2 = (node.param2 + 1) % 4
minetest.swap_node(pos, node)
minetest.add_particlespawner({
amount = 30,
time = 0.1,
collisiondetection = true,
texture = cottages.textures.dust,
minsize = 1,
maxsize = 1,
minexptime = 0.4,
maxexptime = 0.8,
minpos = vector.subtract(pos, 0.1),
maxpos = vector.add(pos, vector.new(0.1, 0, 0.1)),
minvel = vector.new(-1, -0.5, -1),
maxvel = vector.new(1, 0.5, 1),
minacc = vector.new(0, -3, 0),
maxacc = vector.new(0, -3, 0),
})
minetest.sound_play(
{name = cottages.sounds.use_quern},
{pos = pos, gain = 1, pitch = 0.25},
true
)
if has_stamina then
stamina.exhaust_player(player, stamina_use, "cottages:quern")
end
return true
end
cottages.api.register_machine("cottages:quern", {
description = S("quern-stone\npunch to operate"),
short_description = S("quern-stone"),
drawtype = "mesh",
mesh = "cottages_quern.obj",
tiles = {"cottages_stone.png"},
selection_box = {type = "fixed", fixed = {{-0.50, -0.5, -0.50, 0.50, 0.25, 0.50}}},
groups = {cracky = 2},
sounds = cottages.sounds.stone,
inv_info = {
seeds = 1,
flour = 4,
},
update_infotext = straw.update_quern_infotext,
update_formspec = straw.update_quern_formspec,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "flour" then
return 0
end
if listname == "seeds" and not cottages.straw.registered_quern_crafts[stack:get_name()] then
return 0
end
return stack:get_count()
end,
use = straw.use_quern,
get_fs_parts = straw.get_quern_fs_parts,
get_info = straw.get_quern_info,
})

243
modules/straw/threshing.lua Normal file
View File

@ -0,0 +1,243 @@
local straw = cottages.straw
local S = cottages.S
local F = minetest.formspec_escape
local FS = function(...) return F(S(...)) end
local get_safe_short_description = futil.get_safe_short_description
local has_stamina = cottages.has.stamina
local stamina_use = cottages.settings.straw.threshing_stamina
local threshing_min_per_punch = cottages.settings.straw.threshing_min_per_punch
local threshing_max_per_punch = cottages.settings.straw.threshing_max_per_punch
function straw.get_threshing_fs_parts()
return {
("size[8,8]"),
("image[3,1;1,1;%s]"):format(F(cottages.textures.stick)),
("image[0,1;1,1;%s]"):format(F(cottages.textures.wheat)),
("label[1,0.5;%s]"):format(FS("Input:")),
("label[3,0.0;%s]"):format(FS("Output:")),
("label[0,0;%s]"):format(FS("Threshing Floor")),
("label[0,2.5;%s]"):format(FS("Punch threshing floor with a stick")),
("label[0,3.0;%s]"):format(FS("to get straw and seeds from wheat.")),
("list[context;harvest;1,1;2,1;]"),
("list[context;straw;4,0;2,2;]"),
("list[context;seeds;4,2;2,2;]"),
("list[current_player;main;0,4;8,4;]"),
("listring[current_player;main]"),
("listring[context;harvest]"),
("listring[current_player;main]"),
("listring[context;straw]"),
("listring[current_player;main]"),
("listring[context;seeds]"),
}
end
function straw.get_threshing_info(pos)
local meta = minetest.get_meta(pos)
if meta:get_int("used") == 0 then
return S("threshing floor")
else
local inv = meta:get_inventory()
local input1 = inv:get_stack("harvest", 1)
local input2 = inv:get_stack("harvest", 2)
local count = input1:get_count() + input2:get_count()
if count > 0 then
local input_description
if input1:is_empty() then
input_description = get_safe_short_description(input2)
else
input_description = get_safe_short_description(input1)
end
return S("threshing floor, @1 @2 remaining", count, input_description)
else
return S("threshing floor, none remaining")
end
end
end
local function get_threshing_results(input)
local item = input:get_name()
local output_def = straw.registered_threshing_crafts[item]
if type(output_def) == "string" then
return {ItemStack(output_def)}
elseif type(output_def) == "table" and #output_def > 0 then
local outputs = {}
for _, output_item in ipairs(output_def) do
if type(output_item) == "string" then
table.insert(outputs, ItemStack(output_item))
elseif type(output_item) == "table" then
local chance
output_item, chance = unpack(output_item)
if math.random() <= chance then
table.insert(outputs, ItemStack(output_item))
end
end
end
return outputs
elseif type(output_def) == "function" then
return output_def()
end
end
function straw.use_threshing(pos, player)
-- only punching with a normal stick is supposed to work
local wielded = player:get_wielded_item()
if minetest.get_item_group(wielded:get_name(), "stick") == 0 then
return
end
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
local input1 = inv:get_stack("harvest", 1)
local input2 = inv:get_stack("harvest", 2)
local input_count = input1:get_count() + input2:get_count()
if input_count == 0 then
return
end
local number_to_process = math.min(math.random(threshing_min_per_punch, threshing_max_per_punch), input_count)
for _ = 1, number_to_process do
local results
if input1:is_empty() then
results = get_threshing_results(input2:take_item(1))
else
results = get_threshing_results(input1:take_item(1))
end
for _, result in ipairs(results) do
local leftovers = inv:add_item("straw", result)
if not leftovers:is_empty() then
leftovers = inv:add_item("seeds", result)
if not leftovers:is_empty() then
minetest.add_item(pos, leftovers)
end
end
end
end
inv:set_stack("harvest", 1, input1)
inv:set_stack("harvest", 2, input2)
local particle_pos = vector.subtract(pos, vector.new(0, 0.25, 0))
minetest.add_particlespawner({
amount = 10,
time = 0.1,
collisiondetection = true,
texture = cottages.textures.straw,
minsize = 1,
maxsize = 1,
minexptime = 0.2,
maxexptime = 0.4,
minpos = vector.subtract(particle_pos, 0.1),
maxpos = vector.add(particle_pos, 0.1),
minvel = vector.new(-3, 1, -3),
maxvel = vector.new(3, 2, 3),
minacc = vector.new(0, -10, 0),
maxacc = vector.new(0, -10, 0),
})
minetest.add_particlespawner({
amount = 10,
time = 0.1,
collisiondetection = true,
texture = cottages.textures.wheat_seed,
minsize = 1,
maxsize = 1,
minexptime = 0.2,
maxexptime = 0.4,
minpos = vector.subtract(particle_pos, 0.1),
maxpos = vector.add(particle_pos, 0.1),
minvel = vector.new(-3, 0.5, -3),
maxvel = vector.new(3, 1, 3),
minacc = vector.new(0, -10, 0),
maxacc = vector.new(0, -10, 0),
})
minetest.sound_play(
{name = cottages.sounds.use_thresher},
{pos = particle_pos, gain = 1, pitch = 0.5},
true
)
if has_stamina then
stamina.exhaust_player(player, stamina_use, "cottages:quern")
end
return true
end
cottages.api.register_machine("cottages:threshing_floor", {
description = S("threshing floor\npunch with a stick to operate"),
short_description = S("threshing floor"),
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.50, -0.5, -0.50, 0.50, -0.40, 0.50},
{-0.50, -0.4, -0.50, -0.45, -0.20, 0.50},
{0.45, -0.4, -0.50, 0.50, -0.20, 0.50},
{-0.45, -0.4, -0.50, 0.45, -0.20, -0.45},
{-0.45, -0.4, 0.45, 0.45, -0.20, 0.50},
}
},
selection_box = {
type = "fixed",
fixed = {
{-0.50, -0.5, -0.50, 0.50, -0.20, 0.50},
}
},
tiles = {
"cottages_junglewood.png^farming_wheat.png",
"cottages_junglewood.png",
"cottages_junglewood.png^" .. cottages.textures.stick
},
groups = {cracky = 2, choppy = 2},
sounds = cottages.sounds.wood,
is_ground_content = false,
inv_info = {
harvest = 2,
straw = 4,
seeds = 4,
},
update_infotext = straw.update_threshing_infotext,
update_formspec = straw.update_threshing_formspec,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "straw" or listname == "seeds" then
return 0
end
if not cottages.straw.registered_threshing_crafts[stack:get_name()] then
return 0
end
return stack:get_count()
end,
use = straw.use_threshing,
get_fs_parts = straw.get_threshing_fs_parts,
get_info = straw.get_threshing_info,
})

92
modules/water/api.lua Normal file
View File

@ -0,0 +1,92 @@
local ci = cottages.craftitems
local s = cottages.sounds
local settings = cottages.settings.water
local api = cottages.water
local sound_handles_by_pos = {}
local particlespawner_ids_by_pos = {}
function api.add_filling_effects(pos)
local entity_pos = vector.add(pos, vector.new(0, 1/4, 0))
local spos = minetest.pos_to_string(pos)
local previous_handle = sound_handles_by_pos[spos]
if previous_handle then
minetest.sound_stop(previous_handle)
end
sound_handles_by_pos[spos] = minetest.sound_play(
{name = s.water_fill},
{pos = entity_pos, loop = true, gain = 0.5, pitch = 2.0}
)
local previous_id = particlespawner_ids_by_pos[spos]
if previous_id then
minetest.delete_particlespawner(previous_id)
end
local particle_pos = vector.add(pos, vector.new(0, 1/2 + 1/16, 0))
particlespawner_ids_by_pos[spos] = minetest.add_particlespawner({
amount = 10,
time = 0,
collisiondetection = false,
texture = "bubble.png",
minsize = 1,
maxsize = 1,
minexptime = 0.4,
maxexptime = 0.4,
minpos = particle_pos,
maxpos = particle_pos,
minvel = vector.new(-0.1, -0.2, -0.01),
maxvel = vector.new(0.1, -0.2, 0.1),
minacc = vector.new(0, -2, 0),
maxacc = vector.new(0, -2, 0),
})
end
function api.fill_bucket(pos)
local entity_pos = vector.add(pos, vector.new(0, 1/4, 0))
for _, obj in ipairs(minetest.get_objects_inside_radius(entity_pos, .1)) do
local ent = obj:get_luaentity()
if ent and ent.name == "cottages:bucket_entity" then
local props = obj:get_properties()
props.wield_item = ci.bucket_filled
obj:set_properties(props)
end
end
local meta = minetest.get_meta(pos)
meta:set_string("bucket", ci.bucket_filled)
local spos = minetest.pos_to_string(pos)
local handle = sound_handles_by_pos[spos]
if handle then
minetest.sound_stop(handle)
end
local id = particlespawner_ids_by_pos[spos]
if id then
minetest.delete_particlespawner(id)
end
end
function api.initialize_entity(pos)
local meta = minetest.get_meta(pos)
local bucket = meta:get("bucket")
if bucket then
local entity_pos = vector.add(pos, vector.new(0, 1/4, 0))
local obj = minetest.add_entity(entity_pos, "cottages:bucket_entity")
local props = obj:get_properties()
props.wield_item = bucket
obj:set_properties(props)
if bucket == ci.bucket then
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
timer:start(settings.well_fill_time)
end
api.add_filling_effects(pos)
end
end
end

12
modules/water/crafts.lua Normal file
View File

@ -0,0 +1,12 @@
local ci = cottages.craftitems
if ci.stick and ci.tree and ci.stick and ci.bucket then
minetest.register_craft({
output = "cottages:water_gen",
recipe = {
{ci.stick, "", ""},
{ci.tree, ci.bucket, ci.tree},
{ci.tree, ci.tree, ci.tree},
}
})
end

14
modules/water/entity.lua Normal file
View File

@ -0,0 +1,14 @@
local ci = cottages.craftitems
minetest.register_entity("cottages:bucket_entity", {
initial_properties = {
visual = "wielditem",
automatic_rotate = 1,
wield_item = ci.bucket,
visual_size = {x = 0.33, y = 0.33},
collisionbox = {0, 0, 0, 0, 0, 0},
pointable = false,
physical = false,
static_save = false,
},
})

10
modules/water/init.lua Normal file
View File

@ -0,0 +1,10 @@
if not (cottages.craftitems.bucket and cottages.craftitems.bucket_filled) then
return
end
cottages.water = {}
cottages.dofile("modules", "water", "api")
cottages.dofile("modules", "water", "entity")
cottages.dofile("modules", "water", "well")
cottages.dofile("modules", "water", "crafts")

174
modules/water/well.lua Normal file
View File

@ -0,0 +1,174 @@
local F = minetest.formspec_escape
local S = cottages.S
local FS = function(...) return F(S(...)) end
local s = cottages.sounds
local t = cottages.textures
local water = cottages.water
local ci = cottages.craftitems
local well_fill_time = cottages.settings.water.well_fill_time
function water.get_well_fs_parts(pos)
return {
("size[8,9]"),
("label[3.0,0.0;%s]"):format(FS("Tree trunk well")),
("label[0,0.7;%s]"):format(FS("Punch the well while wielding an empty bucket.")),
("label[0,1.0;%s]"):format(FS("Your bucket will slowly be filled with river water.")),
("label[0,1.3;%s]"):format(FS("Punch again to get the bucket back when it is full.")),
("label[0,1.9;%s]"):format(FS("Punch well with full water bucket in order to empty bucket.")),
("label[1.0,2.9;%s]"):format(FS("Internal bucket storage (passive storage only):")),
("item_image[0,2.8;1.0,1.0;%s]"):format(F(ci.bucket)),
("item_image[0,3.8;1.0,1.0;%s]"):format(F(ci.bucket_filled)),
("list[context;main;1,3.3;8,1;]"),
("list[current_player;main;0,4.85;8,4;]"),
("listring[]"),
}
end
function water.get_well_info(pos)
return S("Tree trunk well")
end
function water.use_well(pos, puncher)
local player_name = puncher:get_player_name()
local meta = minetest.get_meta(pos)
local pinv = puncher:get_inventory()
local bucket = meta:get("bucket")
local entity_pos = vector.add(pos, vector.new(0, 1/4, 0))
if not bucket then
local wielded = puncher:get_wielded_item()
local wielded_name = wielded:get_name()
if wielded_name == ci.bucket then
meta:set_string("bucket", wielded_name)
minetest.add_entity(entity_pos, "cottages:bucket_entity")
pinv:remove_item("main", "bucket:bucket_empty")
local timer = minetest.get_node_timer(pos)
timer:start(well_fill_time)
water.add_filling_effects(pos)
elseif wielded_name == ci.bucket_filled then
-- empty a bucket
pinv:remove_item("main", ci.bucket_filled)
pinv:add_item("main", ci.bucket)
minetest.sound_play(
{name = s.water_empty},
{pos = entity_pos, gain = 0.5, pitch = 2.0},
true
)
end
elseif bucket == ci.bucket then
minetest.chat_send_player(player_name, S("Please wait until your bucket has been filled."))
local timer = minetest.get_node_timer(pos)
if not timer:is_started() then
timer:start(well_fill_time)
water.add_filling_effects(pos)
end
elseif bucket == ci.bucket_filled then
meta:set_string("bucket", "")
for _, obj in ipairs(minetest.get_objects_inside_radius(entity_pos, .1)) do
local ent = obj:get_luaentity()
if ent and ent.name == "cottages:bucket_entity" then
obj:remove()
end
end
pinv:add_item("main", ci.bucket_filled)
end
end
cottages.api.register_machine("cottages:water_gen", {
description = S("Tree Trunk Well"),
tiles = {t.tree_top, ("%s^[transformR90"):format(t.tree), ("%s^[transformR90"):format(t.tree)},
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
groups = {choppy = 2, cracky = 1, flammable = 2},
sounds = cottages.sounds.wood,
inv_info = {
main = 6,
},
node_box = {
type = "fixed",
fixed = {
-- floor of water bassin
{-0.5, -0.5 + (3 / 16), -0.5, 0.5, -0.5 + (4 / 16), 0.5},
-- walls
{-0.5, -0.5 + (3 / 16), -0.5, 0.5, (4 / 16), -0.5 + (2 / 16)},
{-0.5, -0.5 + (3 / 16), -0.5, -0.5 + (2 / 16), (4 / 16), 0.5},
{0.5, -0.5 + (3 / 16), 0.5, 0.5 - (2 / 16), (4 / 16), -0.5},
{0.5, -0.5 + (3 / 16), 0.5, -0.5 + (2 / 16), (4 / 16), 0.5 - (2 / 16)},
-- feet
{-0.5 + (3 / 16), -0.5, -0.5 + (3 / 16), -0.5 + (6 / 16), -0.5 + (3 / 16), 0.5 - (3 / 16)},
{0.5 - (3 / 16), -0.5, -0.5 + (3 / 16), 0.5 - (6 / 16), -0.5 + (3 / 16), 0.5 - (3 / 16)},
-- real pump
{0.5 - (4 / 16), -0.5, -(2 / 16), 0.5, 0.5 + (4 / 16), (2 / 16)},
-- water pipe inside wooden stem
{0.5 - (8 / 16), 0.5 + (1 / 16), -(1 / 16), 0.5, 0.5 + (3 / 16), (1 / 16)},
-- where the water comes out
{0.5 - (15 / 32), 0.5, -(1 / 32), 0.5 - (12 / 32), 0.5 + (1 / 16), (1 / 32)},
},
},
selection_box = {
type = "fixed",
fixed = {-0.5, -0.5, -0.5, 0.5, 0.5 + (4 / 16), 0.5}
},
get_fs_parts = water.get_well_fs_parts,
get_info = water.get_well_info,
can_dig = function(pos, player)
local meta = minetest.get_meta(pos)
return not meta:get("bucket")
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local sname = stack:get_name()
if sname ~= ci.bucket and sname ~= ci.bucket_filled then
return 0
end
return stack:get_count()
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
return stack:get_count()
end,
on_timer = function(pos, elapsed)
water.fill_bucket(pos)
end,
use = water.use_well,
})
minetest.register_lbm({
name = "cottages:add_well_entity",
label = "Initialize entity to cottages well",
nodenames = {"cottages:water_gen"},
run_at_every_load = true,
action = function(pos, node)
water.initialize_entity(pos)
end
})