Charakterbewegungen hinzugefügt, Deko hinzugefügt, Kochrezepte angepasst
This commit is contained in:
parent
95945c0306
commit
a0c893ca0b
1124 changed files with 64294 additions and 763 deletions
3385
mods/xdecor/src/chess.lua
Normal file
3385
mods/xdecor/src/chess.lua
Normal file
File diff suppressed because it is too large
Load diff
200
mods/xdecor/src/chessbot.lua
Normal file
200
mods/xdecor/src/chessbot.lua
Normal file
|
@ -0,0 +1,200 @@
|
|||
local chessbot = {}
|
||||
|
||||
local realchess = xdecor.chess
|
||||
|
||||
-- Delay in seconds for a bot moving a piece (excluding choosing a promotion)
|
||||
local BOT_DELAY_MOVE = 1.0
|
||||
-- Delay in seconds for a bot promoting a piece
|
||||
local BOT_DELAY_PROMOTE = 1.0
|
||||
|
||||
local function best_move(moves)
|
||||
local value, choices = 0, {}
|
||||
|
||||
for from, _ in pairs(moves) do
|
||||
for to, val in pairs(_) do
|
||||
if val > value then
|
||||
value = val
|
||||
choices = {{
|
||||
from = from,
|
||||
to = to
|
||||
}}
|
||||
elseif val == value then
|
||||
choices[#choices + 1] = {
|
||||
from = from,
|
||||
to = to
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #choices == 0 then
|
||||
return nil
|
||||
end
|
||||
local random = math.random(1, #choices)
|
||||
local choice_from, choice_to = choices[random].from, choices[random].to
|
||||
|
||||
return tonumber(choice_from), choice_to
|
||||
end
|
||||
|
||||
function chessbot.choose_move(board_t, meta_t)
|
||||
local lastMove = meta_t["lastMove"]
|
||||
local gameResult = meta_t["gameResult"]
|
||||
local botColor = meta_t["botColor"]
|
||||
local prevDoublePawnStepTo = meta_t["prevDoublePawnStepTo"]
|
||||
local castlingRights = {
|
||||
castlingWhiteR = meta_t["castlingWhiteR"],
|
||||
castlingWhiteL = meta_t["castlingWhiteL"],
|
||||
castlingBlackR = meta_t["castlingBlackR"],
|
||||
castlingBlackL = meta_t["castlingBlackL"],
|
||||
}
|
||||
|
||||
if botColor == "" then
|
||||
return
|
||||
end
|
||||
local currentBotColor, opponentColor
|
||||
if botColor == "black" then
|
||||
currentBotColor = "black"
|
||||
opponentColor = "white"
|
||||
elseif botColor == "white" then
|
||||
currentBotColor = "white"
|
||||
opponentColor = "black"
|
||||
elseif botColor == "both" then
|
||||
opponentColor = lastMove
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentBotColor = "white"
|
||||
else
|
||||
currentBotColor = "black"
|
||||
end
|
||||
end
|
||||
if (lastMove == opponentColor or ((botColor == "white" or botColor == "both") and lastMove == "")) and gameResult == "" then
|
||||
|
||||
local moves = realchess.get_theoretical_moves_for(board_t, currentBotColor, prevDoublePawnStepTo, castlingRights)
|
||||
local safe_moves, safe_moves_count = realchess.get_king_safe_moves(moves, board_t, currentBotColor)
|
||||
if safe_moves_count == 0 then
|
||||
-- No safe move: stalemate or checkmate
|
||||
end
|
||||
local choice_from, choice_to = best_move(safe_moves)
|
||||
if choice_from == nil then
|
||||
-- No best move: stalemate or checkmate
|
||||
return
|
||||
end
|
||||
|
||||
return choice_from, choice_to
|
||||
else
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.choose_move was apparently called in an invalid game state!")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
chessbot.perform_move = function(choice_from, choice_to, meta)
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local botColor = meta:get_string("botColor")
|
||||
local currentBotColor, opponentColor
|
||||
local botName
|
||||
if botColor == "black" then
|
||||
currentBotColor = "black"
|
||||
opponentColor = "white"
|
||||
elseif botColor == "white" then
|
||||
currentBotColor = "white"
|
||||
opponentColor = "black"
|
||||
elseif botColor == "both" then
|
||||
opponentColor = lastMove
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentBotColor = "white"
|
||||
else
|
||||
currentBotColor = "black"
|
||||
end
|
||||
end
|
||||
|
||||
-- Bot resigns if no move chosen
|
||||
if not choice_from or not choice_to then
|
||||
realchess.resign(meta, currentBotColor)
|
||||
return
|
||||
end
|
||||
|
||||
if currentBotColor == "white" then
|
||||
botName = meta:get_string("playerWhite")
|
||||
else
|
||||
botName = meta:get_string("playerBlack")
|
||||
end
|
||||
|
||||
local gameResult = meta:get_string("gameResult")
|
||||
if gameResult ~= "" then
|
||||
return
|
||||
end
|
||||
local botColor = meta:get_string("botColor")
|
||||
if botColor == "" then
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.perform_move: botColor in meta string was empty!")
|
||||
return
|
||||
end
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local lastMoveTime = meta:get_int("lastMoveTime")
|
||||
if lastMoveTime > 0 or lastMove == "" then
|
||||
-- Set the bot name if not set already
|
||||
if currentBotColor == "black" and meta:get_string("playerBlack") == "" then
|
||||
meta:set_string("playerBlack", botName)
|
||||
elseif currentBotColor == "white" and meta:get_string("playerWhite") == "" then
|
||||
meta:set_string("playerWhite", botName)
|
||||
end
|
||||
|
||||
-- Make a move
|
||||
local moveOK = realchess.move(meta, "board", choice_from, "board", choice_to, botName)
|
||||
if not moveOK then
|
||||
minetest.log("error", "[xdecor] Chess: Bot tried to make an invalid move from "..
|
||||
realchess.index_to_notation(choice_from).." to "..realchess.index_to_notation(choice_to))
|
||||
end
|
||||
-- Bot resigns if it tried to make an invalid move
|
||||
if not moveOK then
|
||||
realchess.resign(meta, currentBotColor)
|
||||
end
|
||||
else
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.perform_move: No last move!")
|
||||
end
|
||||
end
|
||||
|
||||
function chessbot.choose_promote(board_t, pawnIndex)
|
||||
-- Bot always promotes to queen
|
||||
return "queen"
|
||||
end
|
||||
|
||||
function chessbot.perform_promote(meta, promoteTo)
|
||||
minetest.after(BOT_DELAY_PROMOTE, function()
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local color
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
color = "white"
|
||||
else
|
||||
color = "black"
|
||||
end
|
||||
realchess.promote_pawn(meta, color, promoteTo)
|
||||
end)
|
||||
end
|
||||
|
||||
function chessbot.move(inv, meta)
|
||||
local board_t = realchess.board_to_table(inv)
|
||||
local meta_t = {
|
||||
lastMove = meta:get_string("lastMove"),
|
||||
gameResult = meta:get_string("gameResult"),
|
||||
botColor = meta:get_string("botColor"),
|
||||
prevDoublePawnStepTo = meta:get_int("prevDoublePawnStepTo"),
|
||||
castlingWhiteL = meta:get_int("castlingWhiteL"),
|
||||
castlingWhiteR = meta:get_int("castlingWhiteR"),
|
||||
castlingBlackL = meta:get_int("castlingBlackL"),
|
||||
castlingBlackR = meta:get_int("castlingBlackR"),
|
||||
}
|
||||
local choice_from, choice_to = chessbot.choose_move(board_t, meta_t)
|
||||
minetest.after(BOT_DELAY_MOVE, function()
|
||||
chessbot.perform_move(choice_from, choice_to, meta)
|
||||
end)
|
||||
end
|
||||
|
||||
function chessbot.promote(inv, meta, pawnIndex)
|
||||
local board_t = realchess.board_to_table(inv)
|
||||
local promoteTo = chessbot.choose_promote(board_t, pawnIndex)
|
||||
if not promoteTo then
|
||||
promoteTo = "queen"
|
||||
end
|
||||
chessbot.perform_promote(meta, promoteTo)
|
||||
end
|
||||
|
||||
return chessbot
|
517
mods/xdecor/src/cooking.lua
Normal file
517
mods/xdecor/src/cooking.lua
Normal file
|
@ -0,0 +1,517 @@
|
|||
local cauldron, sounds = {}, {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Set to true to print soup ingredients and fire nodes to console
|
||||
local DEBUG_RECOGNIZED_ITEMS = false
|
||||
|
||||
--~ cauldron hint
|
||||
local hint_fire = S("Light a fire below to heat it up")
|
||||
--~ cauldron hint
|
||||
local hint_eat = S("Use a bowl to eat the soup")
|
||||
--~ cauldron hint
|
||||
local hint_recipe = S("Drop foods inside to make a soup")
|
||||
|
||||
local infotexts = {
|
||||
["xdecor:cauldron_empty"] = S("Cauldron (empty)"),
|
||||
["xdecor:cauldron_idle"] = S("Cauldron (cold water)").."\n"..hint_fire,
|
||||
["xdecor:cauldron_idle_river_water"] = S("Cauldron (cold river water)").."\n"..hint_fire,
|
||||
["xdecor:cauldron_idle_soup"] = S("Cauldron (cold soup)").."\n"..hint_eat,
|
||||
["xdecor:cauldron_boiling"] = S("Cauldron (boiling water)").."\n"..hint_recipe,
|
||||
["xdecor:cauldron_boiling_river_water"] = S("Cauldron (boiling river water)").."\n"..hint_recipe,
|
||||
["xdecor:cauldron_soup"] = S("Cauldron (boiling soup)").."\n"..hint_eat,
|
||||
}
|
||||
|
||||
local function set_infotext(meta, node)
|
||||
if infotexts[node.name] then
|
||||
meta:set_string("infotext", infotexts[node.name])
|
||||
end
|
||||
end
|
||||
|
||||
-- HACKY list of soup ingredients.
|
||||
-- The cauldron will check if any of these strings are contained in the itemname
|
||||
-- after the ":".
|
||||
local ingredients_list = {
|
||||
"apple", "mushroom", "honey", "pumpkin", "egg", "bread", "meat",
|
||||
"chicken", "carrot", "potato", "melon", "rhubarb", "cucumber",
|
||||
"corn", "beans", "berries", "grapes", "tomato", "wheat"
|
||||
}
|
||||
|
||||
-- List of items that can never be soup ingredients. Overwrites anything else.
|
||||
local non_ingredients = {
|
||||
-- xdecor
|
||||
"xdecor:bowl_soup",
|
||||
-- Minetest Game: default
|
||||
"default:apple_mark", "default:blueberry_bush_leaves_with_berries",
|
||||
-- Minetest Game: farming
|
||||
"farming:seed_wheat",
|
||||
"farming:wheat_1", "farming:wheat_2", "farming:wheat_3", "farming:wheat_4",
|
||||
"farming:wheat_5", "farming:wheat_6", "farming:wheat_7", "farming:wheat_8",
|
||||
}
|
||||
local non_ingredients_keyed = table.key_value_swap(non_ingredients)
|
||||
|
||||
cauldron.cbox = {
|
||||
{0, 0, 0, 16, 16, 0},
|
||||
{0, 0, 16, 16, 16, 0},
|
||||
{0, 0, 0, 0, 16, 16},
|
||||
{16, 0, 0, 0, 16, 16},
|
||||
{0, 0, 0, 16, 8, 16}
|
||||
}
|
||||
|
||||
-- Returns true is given item is a fire
|
||||
local function is_fire(itemstring)
|
||||
return minetest.get_item_group(itemstring, "fire") ~= 0
|
||||
end
|
||||
|
||||
-- Returns true if the node at pos is above fire
|
||||
local function is_heated(pos)
|
||||
local below_node = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||||
local nn = minetest.get_node(below_node).name
|
||||
-- Check fire group
|
||||
if is_fire(nn) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.stop_sound(pos)
|
||||
local spos = minetest.hash_node_position(pos)
|
||||
if sounds[spos] then
|
||||
minetest.sound_stop(sounds[spos])
|
||||
sounds[spos] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.start_sound(pos)
|
||||
local spos = minetest.hash_node_position(pos)
|
||||
-- Stop sound if one already exists.
|
||||
-- Only 1 sound per position at maximum allowed.
|
||||
if sounds[spos] then
|
||||
cauldron.stop_sound(pos)
|
||||
end
|
||||
sounds[spos] = minetest.sound_play("xdecor_boiling_water", {
|
||||
pos = pos,
|
||||
max_hear_distance = 5,
|
||||
gain = 0.8,
|
||||
loop = true
|
||||
})
|
||||
end
|
||||
|
||||
function cauldron.idle_construct(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
set_infotext(meta, node)
|
||||
timer:start(10.0)
|
||||
cauldron.stop_sound(pos)
|
||||
end
|
||||
|
||||
function cauldron.boiling_construct(pos)
|
||||
cauldron.start_sound(pos)
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(5.0)
|
||||
end
|
||||
|
||||
|
||||
function cauldron.filling(pos, node, clicker, itemstack)
|
||||
local inv = clicker:get_inventory()
|
||||
local wield_item = clicker:get_wielded_item():get_name()
|
||||
|
||||
do
|
||||
if wield_item == "bucket:bucket_empty" and node.name:sub(-6) ~= "_empty" then
|
||||
local bucket_item
|
||||
if node.name:sub(-11) == "river_water" then
|
||||
bucket_item = "bucket:bucket_river_water 1"
|
||||
else
|
||||
bucket_item = "bucket:bucket_water 1"
|
||||
end
|
||||
if itemstack:get_count() > 1 then
|
||||
if inv:room_for_item("main", bucket_item) then
|
||||
itemstack:take_item()
|
||||
inv:add_item("main", bucket_item)
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(),
|
||||
S("No room in your inventory to add a bucket of water."))
|
||||
return itemstack
|
||||
end
|
||||
else
|
||||
itemstack:replace(bucket_item)
|
||||
end
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2})
|
||||
|
||||
elseif minetest.get_item_group(wield_item, "water_bucket") == 1 and node.name:sub(-6) == "_empty" then
|
||||
local newnode
|
||||
if wield_item == "bucket:bucket_river_water" then
|
||||
newnode = "xdecor:cauldron_idle_river_water"
|
||||
else
|
||||
newnode = "xdecor:cauldron_idle"
|
||||
end
|
||||
minetest.set_node(pos, {name = newnode, param2 = node.param2})
|
||||
itemstack:replace("bucket:bucket_empty")
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.idle_timer(pos)
|
||||
if not is_heated(pos) then
|
||||
return true
|
||||
end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name:sub(-4) == "soup" then
|
||||
node.name = "xdecor:cauldron_soup"
|
||||
elseif node.name:sub(-11) == "river_water" then
|
||||
node.name = "xdecor:cauldron_boiling_river_water"
|
||||
else
|
||||
node.name = "xdecor:cauldron_boiling"
|
||||
end
|
||||
minetest.set_node(pos, node)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Ugly hack to determine if an item has the function `minetest.item_eat` in its definition.
|
||||
local function eatable(itemstring)
|
||||
local item = itemstring:match("[%w_:]+")
|
||||
local on_use_def = minetest.registered_items[item].on_use
|
||||
if not on_use_def then return end
|
||||
|
||||
return string.format("%q", string.dump(on_use_def)):find("item_eat")
|
||||
end
|
||||
|
||||
-- Checks if the given item can be used as ingredient for the soup
|
||||
local function is_ingredient(itemstring)
|
||||
if non_ingredients_keyed[itemstring] then
|
||||
return false
|
||||
end
|
||||
local basename = itemstring:match(":([%w_]+)")
|
||||
if not basename then
|
||||
return false
|
||||
end
|
||||
for _, ingredient in ipairs(ingredients_list) do
|
||||
if eatable(itemstring) or basename:find(ingredient) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function cauldron.boiling_timer(pos)
|
||||
-- Cool down cauldron if there is no fire
|
||||
local node = minetest.get_node(pos)
|
||||
if not is_heated(pos) then
|
||||
local newnode
|
||||
if node.name:sub(-4) == "soup" then
|
||||
newnode = "xdecor:cauldron_idle_soup"
|
||||
elseif node.name:sub(-11) == "river_water" then
|
||||
newnode = "xdecor:cauldron_idle_river_water"
|
||||
else
|
||||
newnode = "xdecor:cauldron_idle"
|
||||
end
|
||||
minetest.set_node(pos, {name = newnode, param2 = node.param2})
|
||||
return true
|
||||
end
|
||||
|
||||
if node.name:sub(-4) == "soup" then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Cooking:
|
||||
|
||||
-- Count the ingredients in the cauldron
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
if not next(objs) then
|
||||
return true
|
||||
end
|
||||
|
||||
local ingredients = {}
|
||||
for _, obj in pairs(objs) do
|
||||
if obj and not obj:is_player() and obj:get_luaentity().itemstring then
|
||||
local itemstring = obj:get_luaentity().itemstring
|
||||
local item = ItemStack(itemstring)
|
||||
local itemname = item:get_name()
|
||||
|
||||
if is_ingredient(itemname) then
|
||||
local basename = itemstring:match(":([%w_]+)")
|
||||
table.insert(ingredients, basename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove ingredients and turn liquid into soup
|
||||
if #ingredients >= 2 then
|
||||
for _, obj in pairs(objs) do
|
||||
obj:remove()
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_soup", param2 = node.param2})
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function cauldron.take_soup(pos, node, clicker, itemstack)
|
||||
local inv = clicker:get_inventory()
|
||||
local wield_item = clicker:get_wielded_item()
|
||||
local item_name = wield_item:get_name()
|
||||
|
||||
if item_name == "xdecor:bowl" or item_name == "farming:bowl" then
|
||||
if wield_item:get_count() > 1 then
|
||||
if inv:room_for_item("main", "xdecor:bowl_soup 1") then
|
||||
itemstack:take_item()
|
||||
inv:add_item("main", "xdecor:bowl_soup 1")
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(),
|
||||
S("No room in your inventory to add a bowl of soup."))
|
||||
return itemstack
|
||||
end
|
||||
else
|
||||
itemstack:replace("xdecor:bowl_soup 1")
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2})
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
xdecor.register("cauldron_empty", {
|
||||
description = S("Cauldron"),
|
||||
_tt_help = S("For storing water and cooking soup"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1,cauldron=1},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_empty.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle", {
|
||||
description = S("Cauldron with Water (cold)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_idle.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:cauldron_empty",
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.idle_construct,
|
||||
on_timer = cauldron.idle_timer,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle_river_water", {
|
||||
description = S("Cauldron with River Water (cold)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_idle_river_water.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:cauldron_empty",
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.idle_construct,
|
||||
on_timer = cauldron.idle_timer,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle_soup", {
|
||||
description = S("Cauldron with Soup (cold)"),
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
tiles = {"xdecor_cauldron_top_idle_soup.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(10.0)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
on_timer = cauldron.idle_timer,
|
||||
on_rightclick = cauldron.take_soup,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_boiling", {
|
||||
description = S("Cauldron with Water (boiling)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_boiling_water.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.boiling_construct,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_boiling_river_water", {
|
||||
description = S("Cauldron with River Water (boiling)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_boiling_river_water.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.boiling_construct,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
|
||||
xdecor.register("cauldron_soup", {
|
||||
description = S("Cauldron with Soup (boiling)"),
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_soup.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_construct = function(pos)
|
||||
cauldron.start_sound(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(5.0)
|
||||
end,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_rightclick = cauldron.take_soup,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Craft items
|
||||
|
||||
minetest.register_craftitem("xdecor:bowl", {
|
||||
description = S("Bowl"),
|
||||
inventory_image = "xdecor_bowl.png",
|
||||
wield_image = "xdecor_bowl.png",
|
||||
groups = {food_bowl = 1, flammable = 2},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("xdecor:bowl_soup", {
|
||||
description = S("Bowl of soup"),
|
||||
inventory_image = "xdecor_bowl_soup.png",
|
||||
wield_image = "xdecor_bowl_soup.png",
|
||||
groups = {},
|
||||
stack_max = 1,
|
||||
on_use = minetest.item_eat(30, "xdecor:bowl")
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:bowl 3",
|
||||
recipe = {
|
||||
{"group:wood", "", "group:wood"},
|
||||
{"", "group:wood", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cauldron_empty",
|
||||
recipe = {
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Restart boiling cauldron sounds",
|
||||
name = "xdecor:restart_boiling_cauldron_sounds",
|
||||
nodenames = {"xdecor:cauldron_boiling", "xdecor:cauldron_boiling_river_water", "xdecor:cauldron_soup"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
cauldron.start_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update cauldron infotexts",
|
||||
name = "xdecor:update_cauldron_infotexts",
|
||||
nodenames = {"group:cauldron"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
set_infotext(meta, node)
|
||||
end,
|
||||
})
|
||||
|
||||
if DEBUG_RECOGNIZED_ITEMS then
|
||||
-- Print all soup ingredients and fire nodes
|
||||
-- in console
|
||||
minetest.register_on_mods_loaded(function()
|
||||
local ingredients = {}
|
||||
local fires = {}
|
||||
for k,v in pairs(minetest.registered_items) do
|
||||
if is_ingredient(k) then
|
||||
table.insert(ingredients, k)
|
||||
end
|
||||
if is_fire(k) then
|
||||
table.insert(fires, k)
|
||||
end
|
||||
end
|
||||
table.sort(ingredients)
|
||||
table.sort(fires)
|
||||
local str_i = table.concat(ingredients, ", ")
|
||||
local str_f = table.concat(fires, ", ")
|
||||
print("[xdecor] List of ingredients for soup: "..str_i)
|
||||
print("[xdecor] List of nodes that can heat cauldron: "..str_f)
|
||||
end)
|
||||
end
|
115
mods/xdecor/src/enchanted_tools.lua
Normal file
115
mods/xdecor/src/enchanted_tools.lua
Normal file
|
@ -0,0 +1,115 @@
|
|||
-- Register enchanted tools.
|
||||
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Number of uses for the (normal) steel hoe from Minetest Game (as of 01/12/20224)
|
||||
-- This is technically redundant because we cannot access that number
|
||||
-- directly, but it's unlikely to change in future because Minetest Game is
|
||||
-- unlikely to change.
|
||||
local STEEL_HOE_USES = 500
|
||||
|
||||
-- Modifier of the steel hoe uses for the enchanted steel hoe
|
||||
local STEEL_HOE_USES_MODIFIER = 2.2
|
||||
|
||||
-- Modifier of the bug net uses for the enchanted bug net
|
||||
local BUG_NET_USES_MODIFIER = 4
|
||||
|
||||
-- Multiplies by much faster the fast hammer repairs
|
||||
local HAMMER_FAST_MODIFIER = 1.3
|
||||
|
||||
-- Reduces the wear taken by the hammer for a single repair step
|
||||
-- (absolute value)
|
||||
local HAMMER_DURABLE_MODIFIER = 100
|
||||
|
||||
-- Register enchantments for default tools from Minetest Game
|
||||
local materials = {"steel", "bronze", "mese", "diamond"}
|
||||
local tooltypes = {
|
||||
{ "axe", { "durable", "fast" }, "choppy" },
|
||||
{ "pick", { "durable", "fast" }, "cracky" },
|
||||
{ "shovel", { "durable", "fast" }, "crumbly" },
|
||||
{ "sword", { "sharp" }, nil },
|
||||
}
|
||||
for t=1, #tooltypes do
|
||||
for m=1, #materials do
|
||||
local tooltype = tooltypes[t][1]
|
||||
local enchants = tooltypes[t][2]
|
||||
local dig_group = tooltypes[t][3]
|
||||
local material = materials[m]
|
||||
xdecor.register_enchantable_tool("default:"..tooltype.."_"..material, {
|
||||
enchants = enchants,
|
||||
dig_group = dig_group,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Register enchantment for bug net
|
||||
xdecor.register_enchantable_tool("fireflies:bug_net", {
|
||||
enchants = { "durable" },
|
||||
dig_group = "catchable",
|
||||
bonuses = {
|
||||
uses = BUG_NET_USES_MODIFIER,
|
||||
}
|
||||
})
|
||||
|
||||
-- Register enchanted steel hoe (more durability)
|
||||
if farming.register_hoe then
|
||||
local percent = math.round((STEEL_HOE_USES_MODIFIER - 1) * 100)
|
||||
local hitem = ItemStack("farming:hoe_steel")
|
||||
local hdesc = hitem:get_short_description() or "farming:hoe_steel"
|
||||
local ehdesc, ehsdesc = xdecor.enchant_description(hdesc, "durable", percent)
|
||||
farming.register_hoe(":farming:enchanted_hoe_steel_durable", {
|
||||
description = ehdesc,
|
||||
short_description = ehsdesc,
|
||||
inventory_image = xdecor.enchant_texture("farming_tool_steelhoe.png"),
|
||||
max_uses = STEEL_HOE_USES * STEEL_HOE_USES_MODIFIER,
|
||||
groups = {hoe = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
xdecor.register_custom_enchantable_tool("farming:hoe_steel", {
|
||||
durable = "farming:enchanted_hoe_steel_durable",
|
||||
})
|
||||
end
|
||||
|
||||
-- Register enchanted hammer (more durbility and efficiency)
|
||||
local hammerdef = minetest.registered_items["xdecor:hammer"]
|
||||
if hammerdef then
|
||||
local hitem = ItemStack("xdecor:hammer")
|
||||
local hdesc = hitem:get_short_description() or "xdecor:hammer"
|
||||
local repair = hammerdef._xdecor_hammer_repair
|
||||
local repair_cost = hammerdef._xdecor_hammer_repair_cost
|
||||
|
||||
-- Durable hammer (reduces wear taken by each repair step)
|
||||
local d_repair_cost_modified = repair_cost - HAMMER_DURABLE_MODIFIER
|
||||
local d_percent = math.round(100 - d_repair_cost_modified/repair_cost * 100)
|
||||
local d_ehdesc, d_ehsdesc = xdecor.enchant_description(hdesc, "durable", d_percent)
|
||||
|
||||
xdecor.register_hammer("xdecor:enchanted_hammer_durable", {
|
||||
description = d_ehdesc,
|
||||
short_description = d_ehsdesc,
|
||||
image = xdecor.enchant_texture("xdecor_hammer.png"),
|
||||
repair_cost = d_repair_cost_modified,
|
||||
groups = {repair_hammer = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
-- Fast hammer (increases both repair amount and repair cost per
|
||||
-- repair step by an equal amount)
|
||||
local f_repair_modified = math.round(repair * HAMMER_FAST_MODIFIER)
|
||||
local repair_diff = f_repair_modified - repair
|
||||
local f_repair_cost_modified = repair_cost + repair_diff
|
||||
local f_percent = math.round(HAMMER_FAST_MODIFIER * 100 - 100)
|
||||
local f_ehdesc, f_ehsdesc = xdecor.enchant_description(hdesc, "fast", f_percent)
|
||||
|
||||
xdecor.register_hammer("xdecor:enchanted_hammer_fast", {
|
||||
description = f_ehdesc,
|
||||
short_description = f_ehsdesc,
|
||||
image = xdecor.enchant_texture("xdecor_hammer.png"),
|
||||
repair = f_repair_modified,
|
||||
repair_cost = f_repair_cost_modified,
|
||||
groups = {repair_hammer = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
xdecor.register_custom_enchantable_tool("xdecor:hammer", {
|
||||
durable = "xdecor:enchanted_hammer_durable",
|
||||
fast = "xdecor:enchanted_hammer_fast",
|
||||
})
|
||||
end
|
506
mods/xdecor/src/enchanting.lua
Normal file
506
mods/xdecor/src/enchanting.lua
Normal file
|
@ -0,0 +1,506 @@
|
|||
local enchanting = {}
|
||||
|
||||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local NS = function(s) return s end
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
local ceil, abs, random = math.ceil, math.abs, math.random
|
||||
local reg_tools = minetest.registered_tools
|
||||
local reg_enchantable_tools = {}
|
||||
local available_tool_enchants = {}
|
||||
|
||||
-- Cost in Mese crystal(s) for enchanting.
|
||||
local MESE_COST = 1
|
||||
|
||||
-- Default strenth of the enchantments
|
||||
local DEFAULT_ENCHANTING_USES = 1.2 -- Durability
|
||||
local DEFAULT_ENCHANTING_TIMES = 0.1 -- Efficiency
|
||||
local DEFAULT_ENCHANTING_DAMAGES = 1 -- Sharpness
|
||||
|
||||
local function to_percent(orig_value, final_value)
|
||||
return abs(ceil(((final_value - orig_value) / orig_value) * 100))
|
||||
end
|
||||
|
||||
function enchanting:get_tooltip_raw(enchant, percent)
|
||||
local specs = {
|
||||
durable = "#00baff",
|
||||
fast = "#74ff49",
|
||||
sharp = "#ffff00",
|
||||
}
|
||||
local enchant_loc = {
|
||||
--~ Enchantment
|
||||
fast = S("Efficiency"),
|
||||
--~ Enchantment
|
||||
durable = S("Durability"),
|
||||
--~ Enchantment
|
||||
sharp = S("Sharpness"),
|
||||
}
|
||||
|
||||
if minetest.colorize then
|
||||
--~ Tooltip in format "<enchantment name> (+<bonus>%)", e.g. "Efficiency (+5%)"
|
||||
return minetest.colorize(specs[enchant], S("@1 (+@2%)", enchant_loc[enchant], percent))
|
||||
else
|
||||
return S("@1 (+@2%)", enchant_loc[enchant], percent)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function enchanting:get_tooltip(enchant, orig_caps, fleshy, bonus_defs)
|
||||
local bonus = {durable = 0, efficiency = 0, damages = 0}
|
||||
|
||||
if orig_caps then
|
||||
bonus.durable = to_percent(orig_caps.uses, orig_caps.uses * bonus_defs.uses)
|
||||
local sum_caps_times = 0
|
||||
for i=1, #orig_caps.times do
|
||||
sum_caps_times = sum_caps_times + orig_caps.times[i]
|
||||
end
|
||||
local average_caps_time = sum_caps_times / #orig_caps.times
|
||||
bonus.efficiency = to_percent(average_caps_time, average_caps_time -
|
||||
bonus_defs.times)
|
||||
end
|
||||
|
||||
if fleshy then
|
||||
bonus.damages = to_percent(fleshy, fleshy + bonus_defs.damages)
|
||||
end
|
||||
|
||||
local specs = {
|
||||
durable = bonus.durable,
|
||||
fast = bonus.efficiency,
|
||||
sharp = bonus.damages,
|
||||
}
|
||||
local percent = specs[enchant]
|
||||
return enchanting:get_tooltip_raw(enchant, percent)
|
||||
end
|
||||
|
||||
local enchant_buttons = {
|
||||
fast = "image_button[3.6,0.67;4.75,0.85;bg_btn.png;fast;"..FS("Efficiency").."]",
|
||||
durable = "image_button[3.6,1.65;4.75,1.05;bg_btn.png;durable;"..FS("Durability").."]",
|
||||
sharp = "image_button[3.6,2.8;4.75,0.85;bg_btn.png;sharp;"..FS("Sharpness").."]",
|
||||
}
|
||||
|
||||
function enchanting.formspec(pos, enchants)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local formspec = [[
|
||||
size[9,8.6;]
|
||||
no_prepend[]
|
||||
bgcolor[#080808BB;true]
|
||||
listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]
|
||||
background9[0,0;9,9;ench_ui.png;6]
|
||||
list[context;tool;0.9,2.9;1,1;]
|
||||
list[context;mese;2,2.9;1,1;]
|
||||
list[current_player;main;0.55,4.5;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;tool]
|
||||
listring[current_player;main]
|
||||
listring[context;mese]
|
||||
image[2,2.9;1,1;mese_layout.png]
|
||||
]]
|
||||
--~ Sharpness enchantment
|
||||
.."tooltip[sharp;"..FS("Your weapon inflicts more damage").."]"
|
||||
--~ Durability enchantment
|
||||
.."tooltip[durable;"..FS("Your tool lasts longer").."]"
|
||||
--~ Efficiency enchantment
|
||||
.."tooltip[fast;"..FS("Your tool digs faster").."]"
|
||||
..default.gui_slots .. default.get_hotbar_bg(0.55, 4.5)
|
||||
|
||||
if enchants then
|
||||
for e=1, #enchants do
|
||||
formspec = formspec .. enchant_buttons[enchants[e]]
|
||||
end
|
||||
end
|
||||
meta:set_string("formspec", formspec)
|
||||
end
|
||||
|
||||
function enchanting.on_put(pos, listname, _, stack)
|
||||
if listname == "tool" then
|
||||
local stackname = stack:get_name()
|
||||
local enchants = available_tool_enchants[stackname]
|
||||
if enchants then
|
||||
enchanting.formspec(pos, enchants)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.fields(pos, _, fields, sender)
|
||||
if not next(fields) or fields.quit then return end
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local tool = inv:get_stack("tool", 1)
|
||||
local mese = inv:get_stack("mese", 1)
|
||||
local orig_wear = tool:get_wear()
|
||||
local mod, name = tool:get_name():match("(.*):(.*)")
|
||||
local enchanted_tool = (mod or "") .. ":enchanted_" .. (name or "") .. "_" .. next(fields)
|
||||
|
||||
if mese:get_count() >= MESE_COST and reg_tools[enchanted_tool] then
|
||||
minetest.sound_play("xdecor_enchanting", {
|
||||
to_player = sender:get_player_name(),
|
||||
gain = 0.8
|
||||
})
|
||||
|
||||
tool:replace(enchanted_tool)
|
||||
tool:add_wear(orig_wear)
|
||||
mese:take_item(MESE_COST)
|
||||
inv:set_stack("mese", 1, mese)
|
||||
inv:set_stack("tool", 1, tool)
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.dig(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("tool") and inv:is_empty("mese")
|
||||
end
|
||||
|
||||
function enchanting.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"tool", "mese"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
local function allowed(tool)
|
||||
if not tool then
|
||||
return false
|
||||
end
|
||||
if reg_enchantable_tools[tool] then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.put(_, listname, _, stack)
|
||||
local stackname = stack:get_name()
|
||||
if listname == "mese" and (stackname == "default:mese_crystal" or
|
||||
stackname == "imese:industrial_mese_crystal") then
|
||||
return stack:get_count()
|
||||
elseif listname == "tool" and allowed(stackname) then
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function enchanting.on_take(pos, listname)
|
||||
if listname == "tool" then
|
||||
enchanting.formspec(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", S("Enchantment Table"))
|
||||
enchanting.formspec(pos)
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("tool", 1)
|
||||
inv:set_size("mese", 1)
|
||||
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open")
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(0.5)
|
||||
end
|
||||
|
||||
function enchanting.destruct(pos)
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 0.9)) do
|
||||
if obj and obj:get_luaentity() and
|
||||
obj:get_luaentity().name == "xdecor:book_open" then
|
||||
obj:remove()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.timer(pos)
|
||||
local minp = {x = pos.x - 2, y = pos.y, z = pos.z - 2}
|
||||
local maxp = {x = pos.x + 2, y = pos.y + 1, z = pos.z + 2}
|
||||
|
||||
local bookshelves = minetest.find_nodes_in_area(minp, maxp, "default:bookshelf")
|
||||
if #bookshelves == 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
local bookshelf_pos = bookshelves[random(1, #bookshelves)]
|
||||
local x = pos.x - bookshelf_pos.x
|
||||
local y = bookshelf_pos.y - pos.y
|
||||
local z = pos.z - bookshelf_pos.z
|
||||
|
||||
if tostring(x .. z):find(2) then
|
||||
minetest.add_particle({
|
||||
pos = bookshelf_pos,
|
||||
velocity = {x = x, y = 2 - y, z = z},
|
||||
acceleration = {x = 0, y = -2.2, z = 0},
|
||||
expirationtime = 1,
|
||||
size = 1.5,
|
||||
glow = 5,
|
||||
texture = "xdecor_glyph" .. random(1,18) .. ".png"
|
||||
})
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
xdecor.register("enchantment_table", {
|
||||
description = S("Enchantment Table"),
|
||||
_tt_help = S("Enchant your tools with mese crystals"),
|
||||
tiles = {
|
||||
"xdecor_enchantment_top.png", "xdecor_enchantment_bottom.png",
|
||||
"xdecor_enchantment_side.png", "xdecor_enchantment_side.png",
|
||||
"xdecor_enchantment_side.png", "xdecor_enchantment_side.png"
|
||||
},
|
||||
groups = {cracky = 1, level = 1},
|
||||
is_ground_content = false,
|
||||
light_source = 6,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = enchanting.dig,
|
||||
on_blast = enchanting.blast,
|
||||
on_timer = enchanting.timer,
|
||||
on_construct = enchanting.construct,
|
||||
on_destruct = enchanting.destruct,
|
||||
on_receive_fields = enchanting.fields,
|
||||
on_metadata_inventory_put = enchanting.on_put,
|
||||
on_metadata_inventory_take = enchanting.on_take,
|
||||
allow_metadata_inventory_put = enchanting.put,
|
||||
allow_metadata_inventory_move = function()
|
||||
return 0
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_entity("xdecor:book_open", {
|
||||
initial_properties = {
|
||||
visual = "sprite",
|
||||
visual_size = {x=0.75, y=0.75},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
pointable = false,
|
||||
physical = false,
|
||||
textures = {"xdecor_book_open.png"},
|
||||
static_save = false,
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "recreate book entity",
|
||||
name = "xdecor:create_book_entity",
|
||||
nodenames = {"xdecor:enchantment_table"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.9)
|
||||
|
||||
for _, obj in ipairs(objs) do
|
||||
local e = obj:get_luaentity()
|
||||
if e and e.name == "xdecor:book_open" then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open")
|
||||
end,
|
||||
})
|
||||
|
||||
function enchanting:enchant_texture(img)
|
||||
if img == nil or img == "" or type(img) ~= "string" then
|
||||
return "no_texture.png"
|
||||
else
|
||||
return "("..img.. ")^[colorize:violet:50"
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting:register_tool(original_tool_name, def)
|
||||
local original_tool = reg_tools[original_tool_name]
|
||||
if not original_tool then
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool for non-existing tool: "..original_tool_name)
|
||||
return
|
||||
end
|
||||
local original_toolcaps = original_tool.tool_capabilities
|
||||
if not original_toolcaps then
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool for tool without tool_capabilities: "..original_tool_name)
|
||||
return
|
||||
end
|
||||
local original_damage_groups = original_toolcaps.damage_groups
|
||||
local original_groupcaps = original_toolcaps.groupcaps
|
||||
local original_basename = original_tool_name:match(".*:(.*)")
|
||||
local toolitem = ItemStack(original_tool_name)
|
||||
local original_desc = toolitem:get_short_description() or original_tool_name
|
||||
local groups
|
||||
if def.groups then
|
||||
groups = table.copy(def.groups)
|
||||
elseif original_tool.groups then
|
||||
groups = table.copy(original_tool.groups)
|
||||
else
|
||||
groups = {}
|
||||
end
|
||||
groups.not_in_creative_inventory = 1
|
||||
for _, enchant in ipairs(def.enchants) do
|
||||
local groupcaps = table.copy(original_groupcaps)
|
||||
local full_punch_interval = original_toolcaps.full_punch_interval
|
||||
local max_drop_level = original_toolcaps.max_drop_level
|
||||
local dig_group = def.dig_group
|
||||
local fleshy
|
||||
|
||||
if not def.bonuses then
|
||||
def.bonuses = {}
|
||||
end
|
||||
local bonus_defs = {
|
||||
uses = def.bonuses.uses or DEFAULT_ENCHANTING_USES,
|
||||
times = def.bonuses.times or DEFAULT_ENCHANTING_TIMES,
|
||||
damages = def.bonuses.damages or DEFAULT_ENCHANTING_DAMAGES,
|
||||
}
|
||||
|
||||
if enchant == "durable" then
|
||||
groupcaps[dig_group].uses = ceil(original_groupcaps[dig_group].uses *
|
||||
bonus_defs.uses)
|
||||
elseif enchant == "fast" then
|
||||
for i, time in pairs(original_groupcaps[dig_group].times) do
|
||||
groupcaps[dig_group].times[i] = time - bonus_defs.times
|
||||
end
|
||||
elseif enchant == "sharp" then
|
||||
fleshy = original_damage_groups.fleshy
|
||||
fleshy = fleshy + bonus_defs.damages
|
||||
else
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool with unsupported enchant: "..tostring(enchant))
|
||||
return
|
||||
end
|
||||
|
||||
local arg1 = original_desc
|
||||
local arg2 = self:get_tooltip(enchant, original_groupcaps[dig_group], fleshy, bonus_defs)
|
||||
local enchantedTool = original_tool.mod_origin .. ":enchanted_" .. original_basename .. "_" .. enchant
|
||||
|
||||
local invimg = original_tool.inventory_image
|
||||
invimg = enchanting:enchant_texture(invimg)
|
||||
local wieldimg = original_tool.wield_image
|
||||
if wieldimg == nil or wieldimg == "" then
|
||||
wieldimg = invimg
|
||||
end
|
||||
minetest.register_tool(":" .. enchantedTool, {
|
||||
--~ Enchanted tool description, e.g. "Enchanted Diamond Sword". @1 is the original tool name, @2 is the enchantment text, e.g. "Durability (+20%)"
|
||||
description = S("Enchanted @1\n@2", arg1, arg2),
|
||||
--~ Enchanted tool description, e.g. "Enchanted Diamond Sword"
|
||||
short_description = S("Enchanted @1", arg1),
|
||||
inventory_image = invimg,
|
||||
wield_image = wieldimg,
|
||||
groups = groups,
|
||||
tool_capabilities = {
|
||||
groupcaps = groupcaps, damage_groups = {fleshy = fleshy},
|
||||
full_punch_interval = full_punch_interval,
|
||||
max_drop_level = max_drop_level
|
||||
},
|
||||
pointabilities = original_tool.pointabilities,
|
||||
})
|
||||
if minetest.get_modpath("toolranks") then
|
||||
toolranks.add_tool(enchantedTool)
|
||||
end
|
||||
end
|
||||
available_tool_enchants[original_tool_name] = table.copy(def.enchants)
|
||||
reg_enchantable_tools[original_tool_name] = true
|
||||
end
|
||||
|
||||
function enchanting:register_custom_tool(original_tool_name, enchanted_tools)
|
||||
if not available_tool_enchants[original_tool_name] then
|
||||
available_tool_enchants[original_tool_name] = {}
|
||||
end
|
||||
for enchant, v in pairs(enchanted_tools) do
|
||||
table.insert(available_tool_enchants[original_tool_name], enchant)
|
||||
end
|
||||
reg_enchantable_tools[original_tool_name] = true
|
||||
end
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:enchantment_table",
|
||||
recipe = {
|
||||
{"", "default:book", ""},
|
||||
{"default:diamond", "default:obsidian", "default:diamond"},
|
||||
{"default:obsidian", "default:obsidian", "default:obsidian"}
|
||||
}
|
||||
})
|
||||
|
||||
--[[ API FUNCTIONS ]]
|
||||
|
||||
--[[
|
||||
Register one or more enchantments for an already defined tool.
|
||||
This will register a new tool for each enchantment. The new tools will
|
||||
have the following changes over the original:
|
||||
* New description and short_description
|
||||
* Apply a purple glow on wield_image and inventory_image using
|
||||
"(<original_texture_string>)^[colorize:purple"
|
||||
* Change tool_capabilities and damage_groups, depending on
|
||||
enchantments.
|
||||
* Have groups set to { not_in_creative_inventory = 1 }
|
||||
|
||||
The new tools will follow this naming scheme:
|
||||
|
||||
<original_mod>:enchanted_<original_basename>_<enchantment>
|
||||
|
||||
e.g. example:sword_diamond with the enchantment "sharp" will
|
||||
have "example:enchanted_sword_diamond_sharp" added.
|
||||
|
||||
You must make sure this name is available before calling this
|
||||
function.
|
||||
|
||||
Arguments:
|
||||
* toolname: Itemstring of original tool to enchant
|
||||
* def: Definition table with the following fields:
|
||||
* enchants: a list of strings, one for each enchantment to add.
|
||||
there must be at least one enchantment.
|
||||
Available enchantments:
|
||||
* "durable": Durability (tool lasts longer)
|
||||
* "fast": Efficiency (tool digs faster)
|
||||
* "sharp": Sharpness (more damage using the damage group "fleshy")
|
||||
* dig_group: Must be specified if Durability or Efficiency is used.
|
||||
This defines the tool's digging group that enchantment will improve.
|
||||
* bonuses: optional table to customize the enchantment "strengths":
|
||||
* uses: multiplies number of uses (Durability) (default: 1.2)
|
||||
* times: subtracts from digging time; higher = faster (Efficiency) (default: 0.1)
|
||||
* damages: adds to damage (Sharpness) (default: 1)
|
||||
* groups: optional table specifying all item groups. If specified,
|
||||
this should at least contain `not_in_creative_inventory=1`.
|
||||
If unspecified (recommended), the enchanted tools will inherit all
|
||||
groups from the original tool, plus they receive `not_in_creative_inventory=1`
|
||||
]]
|
||||
xdecor.register_enchantable_tool = function(toolname, def)
|
||||
enchanting:register_tool(toolname, def)
|
||||
end
|
||||
|
||||
--[[ Registers a custom tool enchantment.
|
||||
Here, you are fully free to design the tool yourself.
|
||||
|
||||
The enchanted tools should follow these guidelines:
|
||||
|
||||
1) Use xdecor.enchant_description to generate the description and short_description
|
||||
2) Use xdecor.enchant_texture to generate the inventory_image and wield_image
|
||||
3) Set groups to { not_in_creative_inventory = 1 }
|
||||
|
||||
Arguments:
|
||||
* toolname: Itemstring of original tool to enchant
|
||||
* enchanted_tools: Table of enchanted tools.
|
||||
* The keys are enchantment names from "enchants" in xdecor.register_enchantable_tool
|
||||
* The values are the itemstrings of the enchanted tools for those
|
||||
enchantments
|
||||
]]
|
||||
xdecor.register_custom_enchantable_tool = function(toolname, enchanted_tools)
|
||||
enchanting:register_custom_tool(toolname, enchanted_tools)
|
||||
end
|
||||
|
||||
-- Takes a texture (string) and applies an "enchanting" modifier on it.
|
||||
-- Useful when you want to register custom tool enchantments.
|
||||
xdecor.enchant_texture = function(texture)
|
||||
return enchanting:enchant_texture(texture)
|
||||
end
|
||||
|
||||
--[[
|
||||
Takes a description of a normal tool and modifies it for the enchanted tool variant.
|
||||
Arguments:
|
||||
* description: Original description to modify
|
||||
* enchant: Enchantment type. One of the enchantment names from "enchants" in xdecor.register_enchantable_tool
|
||||
* percent: Percentage to display
|
||||
|
||||
Returns: <description>, <short_description>
|
||||
|
||||
-- Useful when you want to register custom tool enchantments.
|
||||
]]
|
||||
xdecor.enchant_description = function(description, enchant, percent)
|
||||
local append = enchanting:get_tooltip_raw(enchant, percent)
|
||||
local desc = S("Enchanted @1\n@2", description, append)
|
||||
local short_desc S("Enchanted @1", description)
|
||||
return desc, short_desc
|
||||
end
|
||||
|
204
mods/xdecor/src/hive.lua
Normal file
204
mods/xdecor/src/hive.lua
Normal file
|
@ -0,0 +1,204 @@
|
|||
local hive = {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
local HONEY_MAX = 16
|
||||
local NEEDED_FLOWERS = 3
|
||||
local TIMER_MIN = 64
|
||||
local TIMER_MAX = 128
|
||||
|
||||
local text_busy = FS("The bees are busy making honey.")
|
||||
local text_noflowers = FS("The bees are looking for flowers.")
|
||||
local text_fewflowers = FS("The bees want to pollinate more flowers.")
|
||||
local text_idle = FS("The bees are idle.")
|
||||
local text_sleep = FS("The bees are resting.")
|
||||
|
||||
function hive.set_formspec(meta, status)
|
||||
local statustext
|
||||
if status == "busy" then
|
||||
statustext = text_busy
|
||||
elseif status == "noflowers" then
|
||||
statustext = text_noflowers
|
||||
elseif status == "fewflowers" then
|
||||
statustext = text_fewflowers
|
||||
elseif status == "idle" then
|
||||
statustext = text_idle
|
||||
elseif status == "sleep" then
|
||||
statustext = text_sleep
|
||||
end
|
||||
|
||||
local formspec = "size[8,6;]"
|
||||
.."label[0.5,0;"..statustext.."]"
|
||||
..[[ image[6,1;1,1;hive_bee.png]
|
||||
image[5,1;1,1;hive_layout.png]
|
||||
list[context;honey;5,1;1,1;]
|
||||
list[current_player;main;0,2.35;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;honey] ]] ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0,2.35)
|
||||
meta:set_string("formspec", formspec)
|
||||
end
|
||||
|
||||
local function count_flowers(pos)
|
||||
local radius = 4
|
||||
local minp = vector.add(pos, -radius)
|
||||
local maxp = vector.add(pos, radius)
|
||||
local flowers = minetest.find_nodes_in_area_under_air(minp, maxp, "group:flower")
|
||||
return #flowers
|
||||
end
|
||||
|
||||
local function is_sleeptime()
|
||||
local time = (minetest.get_timeofday() or 0) * 24000
|
||||
if time < 5500 or time > 18500 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function hive.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
local status = "idle"
|
||||
local flowers = count_flowers(pos)
|
||||
if is_sleeptime() then
|
||||
status = "sleep"
|
||||
elseif flowers >= NEEDED_FLOWERS then
|
||||
status = "busy"
|
||||
elseif flowers > 0 then
|
||||
status = "fewflowers"
|
||||
else
|
||||
status = "noflowers"
|
||||
end
|
||||
hive.set_formspec(meta, status)
|
||||
meta:set_string("infotext", S("Artificial Hive"))
|
||||
inv:set_size("honey", 1)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(math.random(TIMER_MIN, TIMER_MAX))
|
||||
end
|
||||
|
||||
function hive.timer(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if is_sleeptime() then
|
||||
hive.set_formspec(meta, "sleep")
|
||||
return true
|
||||
end
|
||||
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local honeystack = inv:get_stack("honey", 1)
|
||||
local honey = honeystack:get_count()
|
||||
|
||||
local flowers = count_flowers(pos)
|
||||
|
||||
if flowers >= NEEDED_FLOWERS and honey < HONEY_MAX then
|
||||
if honey == HONEY_MAX - 1 then
|
||||
hive.set_formspec(meta, "idle")
|
||||
else
|
||||
hive.set_formspec(meta, "busy")
|
||||
end
|
||||
inv:add_item("honey", "xdecor:honey")
|
||||
elseif honey == HONEY_MAX then
|
||||
hive.set_formspec(meta, "idle")
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
return true
|
||||
end
|
||||
if flowers == 0 then
|
||||
hive.set_formspec(meta, "noflowers")
|
||||
elseif flowers < NEEDED_FLOWERS then
|
||||
hive.set_formspec(meta, "fewflowers")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function hive.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"honey"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
xdecor.register("hive", {
|
||||
description = S("Artificial Hive"),
|
||||
--~ Tooltip of artificial hive
|
||||
_tt_help = S("Bees live here and produce honey"),
|
||||
tiles = {"xdecor_hive_top.png", "xdecor_hive_top.png",
|
||||
"xdecor_hive_side.png", "xdecor_hive_side.png",
|
||||
"xdecor_hive_side.png", "xdecor_hive_front.png"},
|
||||
groups = {choppy=3, oddly_breakable_by_hand=2, flammable=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = hive.construct,
|
||||
on_timer = hive.timer,
|
||||
on_blast = hive.blast,
|
||||
|
||||
can_dig = function(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("honey")
|
||||
end,
|
||||
|
||||
on_punch = function(_, _, puncher)
|
||||
puncher:set_hp(puncher:get_hp() - 2)
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_put = function()
|
||||
return 0
|
||||
end,
|
||||
|
||||
on_metadata_inventory_take = function(pos, list, index, stack)
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
local remainstack = inv:get_stack(list, index)
|
||||
-- Trigger if taking anything from full honey slot
|
||||
if remainstack:get_count() + stack:get_count() >= HONEY_MAX then
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(math.random(TIMER_MIN, TIMER_MAX))
|
||||
if not is_sleeptime() and count_flowers(pos) >= NEEDED_FLOWERS then
|
||||
local meta = minetest.get_meta(pos)
|
||||
hive.set_formspec(meta, "busy")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Craft items
|
||||
|
||||
minetest.register_craftitem("xdecor:honey", {
|
||||
description = S("Honey"),
|
||||
inventory_image = "xdecor_honey.png",
|
||||
wield_image = "xdecor_honey.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
groups = {
|
||||
food_honey = 1,
|
||||
food_sugar = 1,
|
||||
flammable = 2,
|
||||
},
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hive",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"default:paper", "default:paper", "default:paper"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
if minetest.get_modpath("unified_inventory") then
|
||||
unified_inventory.register_craft_type("xdecor:hive", {
|
||||
description = S("Made by bees"),
|
||||
icon = "hive_bee.png",
|
||||
width = 1,
|
||||
height = 1,
|
||||
uses_crafting_grid = false
|
||||
})
|
||||
|
||||
unified_inventory.register_craft({
|
||||
output = "xdecor:honey",
|
||||
type = "xdecor:hive",
|
||||
items = {"xdecor:hive"},
|
||||
width = 1
|
||||
})
|
||||
end
|
249
mods/xdecor/src/itemframe.lua
Normal file
249
mods/xdecor/src/itemframe.lua
Normal file
|
@ -0,0 +1,249 @@
|
|||
-- Item frames.
|
||||
|
||||
-- Hint:
|
||||
-- If your item appears behind or too far in front of the item frame, add
|
||||
-- _xdecor_itemframe_offset = <number>
|
||||
-- to your item definition to fix it.
|
||||
|
||||
local itemframe, tmp = {}, {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
screwdriver = screwdriver or {}
|
||||
|
||||
local function remove_item(pos, node)
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
if not objs then return end
|
||||
|
||||
for _, obj in pairs(objs) do
|
||||
local ent = obj:get_luaentity()
|
||||
if obj and ent and ent.name == "xdecor:f_item" then
|
||||
obj:remove() break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local facedir = {
|
||||
[0] = {x = 0, y = 0, z = 1},
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = 0, y = 0, z = -1},
|
||||
{x = -1, y = 0, z = 0}
|
||||
}
|
||||
|
||||
local function update_item(pos, node)
|
||||
remove_item(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local itemstring = meta:get_string("item")
|
||||
local posad = facedir[node.param2]
|
||||
if not posad or itemstring == "" then return end
|
||||
|
||||
local itemdef = ItemStack(itemstring):get_definition()
|
||||
local offset_plus = 0
|
||||
if itemdef and itemdef._xdecor_itemframe_offset then
|
||||
offset_plus = itemdef._xdecor_itemframe_offset
|
||||
offset_plus = math.min(6, math.max(-6, offset_plus))
|
||||
end
|
||||
local offset = (6.5+offset_plus)/16
|
||||
|
||||
pos = vector.add(pos, vector.multiply(posad, offset))
|
||||
tmp.nodename = node.name
|
||||
tmp.texture = ItemStack(itemstring):get_name()
|
||||
|
||||
local entity = minetest.add_entity(pos, "xdecor:f_item")
|
||||
local yaw = (math.pi * 2) - node.param2 * (math.pi / 2)
|
||||
entity:set_yaw(yaw)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(15.0)
|
||||
end
|
||||
|
||||
local function drop_item(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local item = meta:get_string("item")
|
||||
if item == "" then return end
|
||||
|
||||
minetest.add_item(pos, item)
|
||||
meta:set_string("item", "")
|
||||
remove_item(pos, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
end
|
||||
|
||||
function itemframe.set_infotext(meta)
|
||||
local itemstring = meta:get_string("item")
|
||||
local owner = meta:get_string("owner")
|
||||
if itemstring == "" then
|
||||
if owner ~= "" then
|
||||
--~ Item frame infotext. @1 = item frame name, @2 = owner name (player)
|
||||
meta:set_string("infotext", S("@1 (owned by @2)",
|
||||
S("Item Frame"), owner))
|
||||
else
|
||||
meta:set_string("infotext", S("Item Frame"))
|
||||
end
|
||||
else
|
||||
local itemstack = ItemStack(itemstring)
|
||||
local tooltip = itemstack:get_short_description()
|
||||
if tooltip == "" then
|
||||
tooltip = itemstack:get_name()
|
||||
end
|
||||
if itemstring == "" then
|
||||
tooltip = S("Item Frame")
|
||||
end
|
||||
if owner ~= "" then
|
||||
meta:set_string("infotext", S("@1 (owned by @2)", tooltip, owner))
|
||||
else
|
||||
meta:set_string("infotext", tooltip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function itemframe.after_place(pos, placer, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local name = placer:get_player_name()
|
||||
meta:set_string("owner", name)
|
||||
itemframe.set_infotext(meta)
|
||||
end
|
||||
|
||||
function itemframe.timer(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local num = #minetest.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
if num == 0 and meta:get_string("item") ~= "" then
|
||||
update_item(pos, node)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function itemframe.rightclick(pos, node, clicker, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = clicker:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
if not admin and (player_name ~= owner or not itemstack) then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
drop_item(pos, node)
|
||||
local itemstring = itemstack:take_item():to_string()
|
||||
meta:set_string("item", itemstring)
|
||||
itemframe.set_infotext(meta)
|
||||
update_item(pos, node)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function itemframe.punch(pos, node, puncher)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = puncher:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
if admin and player_name == owner then
|
||||
drop_item(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
function itemframe.dig(pos, player)
|
||||
if not player then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = player and player:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
return admin or player_name == owner
|
||||
end
|
||||
|
||||
function itemframe.blast(pos)
|
||||
return
|
||||
end
|
||||
|
||||
xdecor.register("itemframe", {
|
||||
description = S("Item Frame"),
|
||||
--~ Item frame tooltip
|
||||
_tt_help = S("For presenting a single item"),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_rotate = screwdriver.disallow,
|
||||
sunlight_propagates = true,
|
||||
inventory_image = "xdecor_itemframe.png",
|
||||
node_box = xdecor.nodebox.slab_z(0.9375),
|
||||
tiles = {
|
||||
"xdecor_wood.png", "xdecor_wood.png", "xdecor_wood.png",
|
||||
"xdecor_wood.png", "xdecor_wood.png", "xdecor_itemframe.png"
|
||||
},
|
||||
after_place_node = itemframe.after_place,
|
||||
on_timer = itemframe.timer,
|
||||
on_rightclick = itemframe.rightclick,
|
||||
on_punch = itemframe.punch,
|
||||
can_dig = itemframe.dig,
|
||||
on_blast = itemframe.blast,
|
||||
after_destruct = remove_item,
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
})
|
||||
|
||||
minetest.register_entity("xdecor:f_item", {
|
||||
initial_properties = {
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 0.33, y = 0.33},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
pointable = false,
|
||||
physical = false,
|
||||
textures = {"air"},
|
||||
},
|
||||
on_activate = function(self, staticdata)
|
||||
local pos = self.object:get_pos()
|
||||
if minetest.get_node(pos).name ~= "xdecor:itemframe" then
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
if tmp.nodename and tmp.texture then
|
||||
self.nodename = tmp.nodename
|
||||
tmp.nodename = nil
|
||||
self.texture = tmp.texture
|
||||
tmp.texture = nil
|
||||
elseif staticdata and staticdata ~= "" then
|
||||
local data = staticdata:split(";")
|
||||
if data and data[1] and data[2] then
|
||||
self.nodename = data[1]
|
||||
self.texture = data[2]
|
||||
end
|
||||
end
|
||||
if self.texture then
|
||||
self.object:set_properties({
|
||||
textures = {self.texture}
|
||||
})
|
||||
end
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
if self.nodename and self.texture then
|
||||
return self.nodename .. ";" .. self.texture
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:itemframe",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "default:paper", "group:stick"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update itemframe infotexts",
|
||||
name = "xdecor:update_itemframe_infotexts",
|
||||
nodenames = {"xdecor:itemframe"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
itemframe.set_infotext(meta)
|
||||
end,
|
||||
})
|
||||
|
211
mods/xdecor/src/mailbox.lua
Normal file
211
mods/xdecor/src/mailbox.lua
Normal file
|
@ -0,0 +1,211 @@
|
|||
local mailbox = {}
|
||||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
|
||||
-- Max. length of the list of givers in mailbox formspec
|
||||
local GIVER_LIST_LENGTH = 7
|
||||
|
||||
local function get_img(img)
|
||||
if not img then return end
|
||||
local img_name = img:match("(.*)%.png")
|
||||
|
||||
if img_name then
|
||||
return img_name .. ".png"
|
||||
end
|
||||
end
|
||||
|
||||
local function img_col(stack)
|
||||
local def = minetest.registered_items[stack]
|
||||
if not def then
|
||||
return ""
|
||||
end
|
||||
|
||||
if def.inventory_image ~= "" then
|
||||
local img = get_img(def.inventory_image)
|
||||
if img then
|
||||
return img
|
||||
end
|
||||
end
|
||||
|
||||
if def.tiles then
|
||||
local tile, img = def.tiles[1]
|
||||
if type(tile) == "table" then
|
||||
img = get_img(tile.name)
|
||||
elseif type(tile) == "string" then
|
||||
img = get_img(tile)
|
||||
end
|
||||
|
||||
if img then
|
||||
return img
|
||||
end
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
function mailbox:formspec(pos, owner, is_owner)
|
||||
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
|
||||
local meta = minetest.get_meta(pos)
|
||||
local giver, img = "", ""
|
||||
|
||||
if is_owner then
|
||||
for i = 1, GIVER_LIST_LENGTH do
|
||||
local giving = meta:get_string("giver" .. i)
|
||||
if giving ~= "" then
|
||||
local stack = meta:get_string("stack" .. i)
|
||||
local giver_name = giving:sub(1,12)
|
||||
local stack_name = stack:match("[%w_:]+")
|
||||
local stack_count = stack:match("%s(%d+)") or 1
|
||||
|
||||
-- List of donors. A line looks like this:
|
||||
-- <donor name> <item icon> × <item count>
|
||||
giver = giver .. "#FFFF00," .. giver_name .. "," .. i ..
|
||||
--~ Used in the mailbox donor list. Will be displayed as item icon followed by this string. @1 = item count
|
||||
",#FFFFFF," .. FS("× @1", stack_count) .. ","
|
||||
|
||||
img = img .. i .. "=" ..
|
||||
img_col(stack_name) .. "^\\[resize:16x16,"
|
||||
end
|
||||
end
|
||||
|
||||
return "size[9.5,9]"
|
||||
.."label[0,0;"..FS("Mailbox").."]"
|
||||
.."label[6,0;"..FS("Last donators").."]"
|
||||
..[[ box[6,0.72;3.3,3.9;#555555]
|
||||
listring[current_player;main]
|
||||
list[current_player;main;0.75,5.25;8,4;]
|
||||
tableoptions[background=#00000000;highlight=#00000000;border=false] ]] ..
|
||||
"tablecolumns[color;text;image," .. img .. "0;color;text]" ..
|
||||
"table[6,0.75;3.3,4;givers;" .. giver .. "]" ..
|
||||
"list[nodemeta:" .. spos .. ";mailbox;0,0.75;6,4;]" ..
|
||||
"listring[nodemeta:" .. spos .. ";mailbox]" ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0.75, 5.25)
|
||||
end
|
||||
|
||||
return "size[8,5]" ..
|
||||
"list[current_player;main;0,1.25;8,4;]" ..
|
||||
"label[0,0;"..FS("Send your goods to\n@1",
|
||||
(minetest.colorize and
|
||||
minetest.colorize("#FFFF00", owner) or owner)) .. "]" ..
|
||||
"list[nodemeta:" .. spos .. ";drop;3.5,0;1,1;]" ..
|
||||
"listring[]" ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0, 1.25)
|
||||
end
|
||||
|
||||
function mailbox.dig(pos, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string("owner")
|
||||
local player_name = player and player:get_player_name()
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
return inv:is_empty("mailbox") and player_name == owner
|
||||
end
|
||||
|
||||
function mailbox.blast(pos)
|
||||
return
|
||||
end
|
||||
|
||||
function mailbox.after_place_node(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = placer:get_player_name()
|
||||
|
||||
meta:set_string("owner", player_name)
|
||||
meta:set_string("infotext", S("@1's Mailbox", player_name))
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("mailbox", 6 * 4)
|
||||
inv:set_size("drop", 1)
|
||||
end
|
||||
|
||||
function mailbox.rightclick(pos, node, clicker, itemstack, pointed_thing)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player = clicker:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
|
||||
minetest.show_formspec(player, "xdecor:mailbox",
|
||||
mailbox:formspec(pos, owner, (player == owner)))
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function mailbox.put(pos, listname, _, stack, player)
|
||||
if listname == "drop" then
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
if inv:room_for_item("mailbox", stack) then
|
||||
return -1
|
||||
else
|
||||
minetest.chat_send_player(player:get_player_name(),
|
||||
S("The mailbox is full."))
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function mailbox.on_put(pos, listname, _, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
if listname == "drop" and inv:room_for_item("mailbox", stack) then
|
||||
inv:set_list("drop", {})
|
||||
inv:add_item("mailbox", stack)
|
||||
|
||||
for i = GIVER_LIST_LENGTH, 2, -1 do
|
||||
meta:set_string("giver" .. i, meta:get_string("giver" .. (i - 1)))
|
||||
meta:set_string("stack" .. i, meta:get_string("stack" .. (i - 1)))
|
||||
end
|
||||
|
||||
meta:set_string("giver1", player:get_player_name())
|
||||
meta:set_string("stack1", stack:to_string())
|
||||
end
|
||||
end
|
||||
|
||||
function mailbox.allow_take(pos, listname, index, stack, player)
|
||||
if listname == "drop" then
|
||||
return 0
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
if player:get_player_name() ~= meta:get_string("owner") then
|
||||
return 0
|
||||
end
|
||||
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
function mailbox.allow_move(pos)
|
||||
return 0
|
||||
end
|
||||
|
||||
xdecor.register("mailbox", {
|
||||
description = S("Mailbox"),
|
||||
--~ Mailbox tooltip
|
||||
_tt_help = S("Lets other players give you things"),
|
||||
tiles = {"xdecor_mailbox_top.png", "xdecor_mailbox_bottom.png",
|
||||
"xdecor_mailbox_side.png", "xdecor_mailbox_side.png",
|
||||
"xdecor_mailbox.png", "xdecor_mailbox.png"},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = mailbox.dig,
|
||||
on_blast = mailbox.blast,
|
||||
on_rightclick = mailbox.rightclick,
|
||||
allow_metadata_inventory_take = mailbox.allow_take,
|
||||
allow_metadata_inventory_move = mailbox.allow_move,
|
||||
on_metadata_inventory_put = mailbox.on_put,
|
||||
allow_metadata_inventory_put = mailbox.put,
|
||||
after_place_node = mailbox.after_place_node
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:mailbox",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"dye:red", "default:paper", "dye:red"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
325
mods/xdecor/src/mechanisms.lua
Normal file
325
mods/xdecor/src/mechanisms.lua
Normal file
|
@ -0,0 +1,325 @@
|
|||
-- Thanks to sofar for helping with that code.
|
||||
|
||||
local plate = {}
|
||||
screwdriver = screwdriver or {}
|
||||
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local ALPHA_OPAQUE = minetest.features.use_texture_alpha_string_modes and "opaque" or false
|
||||
|
||||
-- Number of seconds an actuator (pressure plate, lever) stays active.
|
||||
-- After this time, it will return to the disabled state again.
|
||||
local DISABLE_ACTUATOR_AFTER = 2.0
|
||||
|
||||
-- Effect area of pressure plates and levers. Doors within this area
|
||||
-- can be affected.
|
||||
local PRESSURE_PLATE_AREA_MIN = {x = -2, y = 0, z = -2}
|
||||
local PRESSURE_PLATE_AREA_MAX = {x = 2, y = 0, z = 2}
|
||||
local LEVER_AREA_MIN = {x = -2, y = -1, z = -2}
|
||||
local LEVER_AREA_MAX = {x = 2, y = 1, z = 2}
|
||||
|
||||
-- Pressure plates check for players within this radius
|
||||
local PRESSURE_PLATE_PLAYER_RADIUS = 0.8
|
||||
-- Interval in seconds that pressure plates check for players
|
||||
local PRESSURE_PLATE_CHECK_TIMER = 0.1
|
||||
|
||||
local function door_open(pos_door, player)
|
||||
local door = doors.get(pos_door)
|
||||
if not door then
|
||||
return
|
||||
end
|
||||
door:open(player)
|
||||
end
|
||||
|
||||
local function door_close(pos_door, player)
|
||||
local door = doors.get(pos_door)
|
||||
if not door then
|
||||
return
|
||||
end
|
||||
door:close(player)
|
||||
end
|
||||
|
||||
-- Returns true if the door node at pos is currently next to any
|
||||
-- active actuator node (lever, pressure plate)
|
||||
local function door_is_actuatored(pos_door)
|
||||
local minp = vector.add(LEVER_AREA_MIN, pos_door)
|
||||
local maxp = vector.add(LEVER_AREA_MAX, pos_door)
|
||||
local levers = minetest.find_nodes_in_area(minp, maxp, "group:lever")
|
||||
for l=1, #levers do
|
||||
local lnode = minetest.get_node(levers[l])
|
||||
if minetest.get_item_group(lnode.name, "xdecor_actuator") == 2 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
minp = vector.add(PRESSURE_PLATE_AREA_MIN, pos_door)
|
||||
maxp = vector.add(PRESSURE_PLATE_AREA_MAX, pos_door)
|
||||
local pressure_plates = minetest.find_nodes_in_area(minp, maxp, "group:pressure_plate")
|
||||
for p=1, #pressure_plates do
|
||||
local pnode = minetest.get_node(pressure_plates[p])
|
||||
if minetest.get_item_group(pnode.name, "xdecor_actuator") == 2 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function actuator_timeout(pos_actuator, actuator_area_min, actuator_area_max)
|
||||
local actuator = minetest.get_node(pos_actuator)
|
||||
|
||||
-- Get name of last player that triggered the actuator
|
||||
local meta = minetest.get_meta(pos_actuator)
|
||||
local last_triggerer_str = meta:get_string("last_triggerer")
|
||||
local last_triggerer_obj = minetest.get_player_by_name(last_triggerer_str)
|
||||
|
||||
-- Turn off actuator
|
||||
if minetest.get_item_group(actuator.name, "xdecor_actuator") == 2 then
|
||||
local def = minetest.registered_nodes[actuator.name]
|
||||
if def._xdecor_actuator_off then
|
||||
minetest.set_node(pos_actuator, { name = def._xdecor_actuator_off, param2 = actuator.param2 })
|
||||
end
|
||||
end
|
||||
|
||||
-- Close neighboring doors that are no longer next to any active actuator
|
||||
local minp = vector.add(actuator_area_min, pos_actuator)
|
||||
local maxp = vector.add(actuator_area_max, pos_actuator)
|
||||
local doors = minetest.find_nodes_in_area(minp, maxp, "group:door")
|
||||
for d=1, #doors do
|
||||
if not door_is_actuatored(doors[d]) then
|
||||
local dnode = minetest.get_node(doors[d])
|
||||
local ddef = minetest.registered_nodes[dnode.name]
|
||||
if (ddef.protected and last_triggerer_obj) or (not ddef.protected) then
|
||||
door_close(doors[d], last_triggerer_obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function actuator_activate(pos_actuator, actuator_area_min, actuator_area_max, player)
|
||||
local player_name = player:get_player_name()
|
||||
local actuator = minetest.get_node(pos_actuator)
|
||||
local ga = minetest.get_item_group(actuator.name, "xdecor_actuator")
|
||||
if ga == 2 then
|
||||
-- No-op if actuator is already active
|
||||
return
|
||||
elseif ga == 1 then
|
||||
local def = minetest.registered_nodes[actuator.name]
|
||||
-- Turn actuator on
|
||||
if def._xdecor_actuator_on then
|
||||
minetest.set_node(pos_actuator, { name = def._xdecor_actuator_on, param2 = actuator.param2 })
|
||||
|
||||
-- Store name of last player that triggered the actuator
|
||||
local meta = minetest.get_meta(pos_actuator)
|
||||
meta:set_string("last_triggerer", player_name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Turn on neighboring doors
|
||||
local minp = vector.add(actuator_area_min, pos_actuator)
|
||||
local maxp = vector.add(actuator_area_max, pos_actuator)
|
||||
local doors = minetest.find_nodes_in_area(minp, maxp, "group:door")
|
||||
for i = 1, #doors do
|
||||
door_open(doors[i], player)
|
||||
end
|
||||
end
|
||||
|
||||
function plate.construct(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(PRESSURE_PLATE_CHECK_TIMER)
|
||||
end
|
||||
|
||||
function plate.has_player_standing_on(pos)
|
||||
local objs = minetest.get_objects_inside_radius(pos, PRESSURE_PLATE_PLAYER_RADIUS)
|
||||
for _, player in pairs(objs) do
|
||||
if player:is_player() then
|
||||
return true, player
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function plate.timer(pos)
|
||||
if not doors.get then
|
||||
return true
|
||||
end
|
||||
local ok, player = plate.has_player_standing_on(pos)
|
||||
if ok then
|
||||
actuator_activate(pos, PRESSURE_PLATE_AREA_MIN, PRESSURE_PLATE_AREA_MAX, player)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function plate.construct_on(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end
|
||||
|
||||
function plate.timer_on(pos)
|
||||
if plate.has_player_standing_on(pos) then
|
||||
-- If player is still standing on active pressure plate, restart timer
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
return
|
||||
end
|
||||
|
||||
actuator_timeout(pos, PRESSURE_PLATE_AREA_MIN, PRESSURE_PLATE_AREA_MAX)
|
||||
end
|
||||
|
||||
function plate.register(material, desc, def)
|
||||
local groups
|
||||
if def.groups then
|
||||
groups = table.copy(def.groups)
|
||||
else
|
||||
groups = {}
|
||||
end
|
||||
groups.pressure_plate = 1
|
||||
groups.xdecor_actuator = 1
|
||||
xdecor.register("pressure_" .. material .. "_off", {
|
||||
description = def.description or (desc .. " Pressure Plate"),
|
||||
--~ Pressure plate tooltip
|
||||
_tt_help = S("Opens doors when stepped on"),
|
||||
tiles = {"xdecor_pressure_" .. material .. ".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 1, 14}}),
|
||||
groups = groups,
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = plate.construct,
|
||||
on_timer = plate.timer,
|
||||
_xdecor_actuator_off = "xdecor:pressure_"..material.."_off",
|
||||
_xdecor_actuator_on = "xdecor:pressure_"..material.."_on",
|
||||
})
|
||||
local groups_on = table.copy(groups)
|
||||
groups_on.xdecor_actuator = 2
|
||||
groups_on.pressure_plate = 2
|
||||
xdecor.register("pressure_" .. material .. "_on", {
|
||||
tiles = {"xdecor_pressure_" .. material .. ".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 0.4, 14}}),
|
||||
groups = groups_on,
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds,
|
||||
drop = "xdecor:pressure_" .. material .. "_off",
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = plate.construct_on,
|
||||
on_timer = plate.timer_on,
|
||||
_xdecor_actuator_off = "xdecor:pressure_"..material.."_off",
|
||||
_xdecor_actuator_on = "xdecor:pressure_"..material.."_on",
|
||||
})
|
||||
end
|
||||
|
||||
plate.register("wood", "Wooden", {
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
description = S("Wooden Pressure Plate"),
|
||||
})
|
||||
|
||||
plate.register("stone", "Stone", {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2},
|
||||
description = S("Stone Pressure Plate"),
|
||||
})
|
||||
|
||||
xdecor.register("lever_off", {
|
||||
description = S("Lever"),
|
||||
--~ Lever tooltip
|
||||
_tt_help = S("Opens doors when pulled"),
|
||||
tiles = {"xdecor_lever_off.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, lever = 1, xdecor_actuator = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
if not doors.get then
|
||||
return itemstack
|
||||
end
|
||||
actuator_activate(pos, LEVER_AREA_MIN, LEVER_AREA_MAX, clicker)
|
||||
return itemstack
|
||||
end,
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
_xdecor_actuator_off = "xdecor:lever_off",
|
||||
_xdecor_actuator_on = "xdecor:lever_on",
|
||||
})
|
||||
|
||||
xdecor.register("lever_on", {
|
||||
tiles = {"xdecor_lever_on.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, lever = 2, xdecor_actuator = 2, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
-- Prevent placing nodes on activated lever with the place key
|
||||
-- for consistent behavior with the lever in "off" state.
|
||||
-- The player may still place nodes using [Sneak].
|
||||
return itemstack
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end,
|
||||
on_timer = function(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
actuator_timeout(pos, LEVER_AREA_MIN, LEVER_AREA_MAX)
|
||||
end,
|
||||
drop = "xdecor:lever_off",
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
_xdecor_actuator_off = "xdecor:lever_off",
|
||||
_xdecor_actuator_on = "xdecor:lever_on",
|
||||
})
|
||||
|
||||
-- Make sure the node timers of active actuators are still
|
||||
-- active when these nodes load again. If not, start them
|
||||
-- again to trigger their timer action, which is expected
|
||||
-- to turn off the actuator soon.
|
||||
minetest.register_lbm({
|
||||
label = "Restart actuator timers (X-Decor-libre)",
|
||||
name = "xdecor:restart_actuator_timers",
|
||||
nodenames = { "group:xdecor_actuator" },
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local g = minetest.get_item_group(node.name, "xdecor_actuator")
|
||||
if g ~= 2 then
|
||||
return
|
||||
end
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if not timer:is_started() then
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:pressure_stone_off",
|
||||
type = "shapeless",
|
||||
recipe = {"group:stone", "group:stone"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:pressure_wood_off",
|
||||
type = "shapeless",
|
||||
recipe = {"group:wood", "group:wood"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:lever_off",
|
||||
recipe = {
|
||||
{"group:stick"},
|
||||
{"group:stone"}
|
||||
}
|
||||
})
|
962
mods/xdecor/src/nodes.lua
Normal file
962
mods/xdecor/src/nodes.lua
Normal file
|
@ -0,0 +1,962 @@
|
|||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local ALPHA_CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true
|
||||
local ALPHA_OPAQUE = minetest.features.use_texture_alpha_string_modes and "opaque" or false
|
||||
|
||||
local function register_pane(name, desc, def)
|
||||
xpanes.register_pane(name, {
|
||||
description = desc,
|
||||
tiles = {"xdecor_" .. name .. ".png"},
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
textures = def.textures or {"xdecor_" .. name .. ".png", "" ,"xdecor_" .. name .. ".png"},
|
||||
inventory_image = "xdecor_" .. name .. ".png",
|
||||
wield_image = "xdecor_" .. name .. ".png",
|
||||
groups = def.groups,
|
||||
sounds = def.sounds or default.node_sound_defaults(),
|
||||
recipe = def.recipe
|
||||
})
|
||||
end
|
||||
|
||||
register_pane("bamboo_frame", S("Bamboo Frame"), {
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, pane = 1, flammable = 2},
|
||||
recipe = {
|
||||
{"default:papyrus", "default:papyrus", "default:papyrus"},
|
||||
{"default:papyrus", "farming:cotton", "default:papyrus"},
|
||||
{"default:papyrus", "default:papyrus", "default:papyrus"}
|
||||
},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
register_pane("chainlink", S("Chainlink"), {
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, pane = 1},
|
||||
recipe = {
|
||||
{"default:steel_ingot", "", "default:steel_ingot"},
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"default:steel_ingot", "", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
register_pane("rusty_bar", S("Rusty Iron Bars"), {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
textures = {"xdecor_rusty_bar.png", "", "xdecor_rusty_bar_top.png"},
|
||||
groups = {cracky = 2, pane = 1},
|
||||
recipe = {
|
||||
{"", "default:dirt", ""},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"},
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
register_pane("wood_frame", S("Wood Frame"), {
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
textures = {"xdecor_wood_frame.png", "", "xdecor_wood_frame_top.png"},
|
||||
groups = {choppy = 2, pane = 1, flammable = 2},
|
||||
recipe = {
|
||||
{"group:wood", "group:stick", "group:wood"},
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:wood", "group:stick", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
xdecor.register("baricade", {
|
||||
description = S("Barricade"),
|
||||
drawtype = "plantlike",
|
||||
paramtype2 = "facedir",
|
||||
inventory_image = "xdecor_baricade.png",
|
||||
tiles = {"xdecor_baricade.png"},
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
damage_per_second = 4,
|
||||
selection_box = xdecor.nodebox.slab_y(0.3),
|
||||
collision_box = xdecor.pixelbox(2, {{0, 0, 1, 2, 2, 0}})
|
||||
})
|
||||
|
||||
xdecor.register("barrel", {
|
||||
description = S("Barrel"),
|
||||
tiles = {"xdecor_barrel_top.png", "xdecor_barrel_top.png", "xdecor_barrel_sides.png"},
|
||||
on_place = minetest.rotate_node,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults()
|
||||
})
|
||||
|
||||
local function blast_storage(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"main"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
local function register_storage(name, desc, def)
|
||||
xdecor.register(name, {
|
||||
description = desc,
|
||||
_tt_help = def._tt_help,
|
||||
inventory = {size = def.inv_size or 24},
|
||||
infotext = desc,
|
||||
tiles = def.tiles,
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
node_box = def.node_box,
|
||||
on_rotate = def.on_rotate,
|
||||
on_place = def.on_place,
|
||||
on_blast = blast_storage,
|
||||
groups = def.groups or {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
register_storage("cabinet", S("Wooden Cabinet"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_front.png"
|
||||
}
|
||||
})
|
||||
|
||||
register_storage("cabinet_half", S("Half Wooden Cabinet"), {
|
||||
inv_size = 8,
|
||||
_tt_help = S("8 inventory slots"),
|
||||
node_box = xdecor.nodebox.slab_y(0.5, 0.5),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_sides.png",
|
||||
"xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_front.png"
|
||||
}
|
||||
})
|
||||
|
||||
if minetest.get_modpath("moreblocks") then
|
||||
minetest.register_alias("xdecor:empty_shelf", "moreblocks:empty_shelf")
|
||||
else
|
||||
-- Node renamed from "Empty Shelf" because it was misleading.
|
||||
-- (you can still put things in it, making it non-empty)
|
||||
register_storage("empty_shelf", S("Plain Shelf"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"default_wood.png", "default_wood.png", "default_wood.png",
|
||||
"default_wood.png", "default_wood.png^xdecor_empty_shelf.png"
|
||||
},
|
||||
})
|
||||
|
||||
-- Update infotext of old empty_shelf nodes to "Plain Shelf"
|
||||
minetest.register_lbm({
|
||||
label = "Update plain shelf infotext",
|
||||
name = "xdecor:empty_shelf_to_plain_shelf",
|
||||
nodenames = {"xdecor:empty_shelf"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", S("Plain Shelf"))
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
register_storage("multishelf", S("Multi Shelf"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"default_wood.png", "default_wood.png", "default_wood.png",
|
||||
"default_wood.png", "default_wood.png^xdecor_multishelf.png"
|
||||
},
|
||||
})
|
||||
|
||||
xdecor.register("candle", {
|
||||
description = S("Candle"),
|
||||
light_source = 12,
|
||||
drawtype = "torchlike",
|
||||
inventory_image = "xdecor_candle_inv.png",
|
||||
wield_image = "xdecor_candle_wield.png",
|
||||
paramtype2 = "wallmounted",
|
||||
walkable = false,
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_candle_floor.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
},
|
||||
{
|
||||
name = "xdecor_candle_hanging.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
},
|
||||
{
|
||||
name = "xdecor_candle_wall.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.25, -0.3, -0.25, 0.25, 0.5, 0.25},
|
||||
wall_bottom = {-0.25, -0.5, -0.25, 0.25, 0.1, 0.25},
|
||||
wall_side = {-0.5, -0.35, -0.15, -0.15, 0.4, 0.15}
|
||||
}
|
||||
})
|
||||
|
||||
xdecor.register("chair", {
|
||||
description = S("Chair"),
|
||||
tiles = {"xdecor_wood.png"},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2, sittable = 1},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{3, 0, 11, 2, 16, 2},
|
||||
{11, 0, 11, 2, 16, 2},
|
||||
{5, 9, 11.5, 6, 6, 1},
|
||||
{3, 0, 3, 2, 6, 2},
|
||||
{11, 0, 3, 2, 6, 2},
|
||||
{3, 6, 3, 10, 2, 8}
|
||||
}),
|
||||
can_dig = xdecor.sit_dig,
|
||||
after_destruct = xdecor.sit_destruct,
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
xdecor.sit(pos, node, clicker, pointed_thing)
|
||||
return itemstack
|
||||
end,
|
||||
_xdecor_itemframe_offset = -1.5,
|
||||
})
|
||||
|
||||
xdecor.register("cobweb", {
|
||||
description = S("Cobweb"),
|
||||
drawtype = "plantlike",
|
||||
tiles = {"xdecor_cobweb.png"},
|
||||
inventory_image = "xdecor_cobweb.png",
|
||||
move_resistance = 8,
|
||||
walkable = false,
|
||||
selection_box = {type = "regular"},
|
||||
groups = {snappy = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_leaves_defaults()
|
||||
})
|
||||
|
||||
local curtain_colors = {
|
||||
red = { S("Red Curtain"), "wool_red.png", "wool:red" },
|
||||
}
|
||||
|
||||
local CURTAIN_OFFSET = 1/16
|
||||
|
||||
-- For preserve_metadata for curtains.
|
||||
-- Erases metadata from the drops
|
||||
-- because the item metadata should be empty
|
||||
-- to allow proper item stacking.
|
||||
local cleanup_curtain_meta = function(_,_,_,drops)
|
||||
for d=1, #drops do
|
||||
local meta = drops[d]:get_meta()
|
||||
meta:set_string("palette_index", "")
|
||||
end
|
||||
end
|
||||
|
||||
for c, info in pairs(curtain_colors) do
|
||||
local desc = info[1]
|
||||
local base_texture = info[2]
|
||||
local craft_item = info[3]
|
||||
xdecor.register("curtain_" .. c, {
|
||||
description = desc,
|
||||
walkable = false,
|
||||
tiles = {base_texture, "("..base_texture..")^[transformFY", base_texture},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
inventory_image = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126",
|
||||
wield_image = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126",
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "wallmounted",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -0.5+CURTAIN_OFFSET, 0.5, 0.5 },
|
||||
wall_top = { -0.5, 0.5-CURTAIN_OFFSET, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, -0.5+CURTAIN_OFFSET, 0.5 },
|
||||
},
|
||||
groups = {dig_immediate = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
on_rightclick = function(pos, node, _, itemstack)
|
||||
minetest.set_node(pos, {name = "xdecor:curtain_open_" .. c, param2 = node.param2})
|
||||
return itemstack
|
||||
end,
|
||||
preserve_metadata = cleanup_curtain_meta,
|
||||
})
|
||||
|
||||
local open_tile = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126"
|
||||
xdecor.register("curtain_open_" .. c, {
|
||||
tiles = {
|
||||
open_tile,
|
||||
"("..open_tile..")^[transformFY",
|
||||
base_texture,
|
||||
base_texture,
|
||||
base_texture.."^xdecor_curtain_open_overlay_top.png^[makealpha:255,126,126",
|
||||
base_texture.."^xdecor_curtain_open_overlay_bottom.png^[makealpha:255,126,126",
|
||||
},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "wallmounted",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -0.5+CURTAIN_OFFSET, 0.5, 0.5 },
|
||||
wall_top = { -0.5, 0.5-CURTAIN_OFFSET, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, -0.5+CURTAIN_OFFSET, 0.5 },
|
||||
},
|
||||
walkable = false,
|
||||
groups = {dig_immediate = 3, flammable = 3, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
drop = "xdecor:curtain_" .. c,
|
||||
on_rightclick = function(pos, node, _, itemstack)
|
||||
minetest.set_node(pos, {name="xdecor:curtain_" .. c, param2 = node.param2})
|
||||
return itemstack
|
||||
end,
|
||||
preserve_metadata = cleanup_curtain_meta,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:curtain_" .. c .. " 4",
|
||||
recipe = {
|
||||
{"", craft_item, ""},
|
||||
{"", craft_item, ""}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("cushion", {
|
||||
description = S("Cushion"),
|
||||
tiles = {"xdecor_cushion.png"},
|
||||
groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -50, sittable = 1},
|
||||
is_ground_content = false,
|
||||
on_place = minetest.rotate_node,
|
||||
node_box = xdecor.nodebox.slab_y(0.5),
|
||||
can_dig = xdecor.sit_dig,
|
||||
after_destruct = xdecor.sit_destruct,
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
xdecor.sit(pos, node, clicker, pointed_thing)
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
xdecor.register("cushion_block", {
|
||||
description = S("Cushion Block"),
|
||||
tiles = {"xdecor_cushion.png"},
|
||||
groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -75},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
local function door_access(name)
|
||||
return name:find("prison")
|
||||
end
|
||||
|
||||
local xdecor_doors = {
|
||||
japanese = {
|
||||
recipe = {
|
||||
{"group:wood", "default:paper"},
|
||||
{"default:paper", "group:wood"},
|
||||
{"group:wood", "default:paper"}
|
||||
},
|
||||
desc = S("Japanese Door"),
|
||||
},
|
||||
prison = {
|
||||
recipe = {
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat",},
|
||||
{"xpanes:bar_flat", "default:steel_ingot",},
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat"}
|
||||
},
|
||||
desc = S("Prison Door"),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sound_open = "xpanes_steel_bar_door_open",
|
||||
sound_close = "xpanes_steel_bar_door_close",
|
||||
gain_open = 0.18,
|
||||
gain_close = 0.16,
|
||||
},
|
||||
rusty_prison = {
|
||||
recipe = {
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",},
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",},
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat"}
|
||||
},
|
||||
desc = S("Rusty Prison Door"),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sound_open = "xpanes_steel_bar_door_open",
|
||||
sound_close = "xpanes_steel_bar_door_close",
|
||||
gain_open = 0.21,
|
||||
gain_close = 0.19,
|
||||
},
|
||||
screen = {
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"xpanes:chainlink_flat", "xpanes:chainlink_flat"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Screen Door"),
|
||||
},
|
||||
slide = {
|
||||
recipe = {
|
||||
{"default:paper", "default:paper"},
|
||||
{"default:paper", "default:paper"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Paper Door"),
|
||||
},
|
||||
woodglass = {
|
||||
recipe = {
|
||||
{"default:glass", "default:glass"},
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Woodglass Door"),
|
||||
},
|
||||
}
|
||||
|
||||
local mesecons_register
|
||||
|
||||
if minetest.global_exists("mesecon") then
|
||||
mesecons_register = { effector = {
|
||||
action_on = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:open()
|
||||
end
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:close()
|
||||
end
|
||||
end,
|
||||
rules = mesecon.rules.pplate
|
||||
}}
|
||||
end
|
||||
|
||||
for name, def in pairs(xdecor_doors) do
|
||||
if not doors.register then break end
|
||||
doors.register(name .. "_door", {
|
||||
tiles = {
|
||||
{name = "xdecor_" .. name .. "_door.png", backface_culling = true}
|
||||
},
|
||||
description = def.desc,
|
||||
inventory_image = "xdecor_" .. name .. "_door_inv.png",
|
||||
sounds = def.sounds,
|
||||
sound_open = def.sound_open,
|
||||
sound_close = def.sound_close,
|
||||
gain_open = def.gain_open,
|
||||
gain_close = def.gain_close,
|
||||
protected = door_access(name),
|
||||
groups = {choppy = 2, cracky = 2, oddly_breakable_by_hand = 1, door = 1, node = 1},
|
||||
recipe = def.recipe,
|
||||
mesecons = mesecons_register,
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("enderchest", {
|
||||
description = S("Ender Chest"),
|
||||
_tt_help = S("Interdimensional inventory"),
|
||||
tiles = {
|
||||
"xdecor_enderchest_top.png", "xdecor_enderchest_top.png",
|
||||
"xdecor_enderchest_side.png", "xdecor_enderchest_side.png",
|
||||
"xdecor_enderchest_side.png", "xdecor_enderchest_front.png"
|
||||
},
|
||||
groups = {cracky = 1, choppy = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", [[ size[8,9]
|
||||
list[current_player;enderchest;0,0;8,4;]
|
||||
list[current_player;main;0,5;8,4;]
|
||||
listring[current_player;enderchest]
|
||||
listring[current_player;main] ]]
|
||||
.. xdecor.xbg .. default.get_hotbar_bg(0,5))
|
||||
|
||||
meta:set_string("infotext", S("Ender Chest"))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local inv = player:get_inventory()
|
||||
inv:set_size("enderchest", 8*4)
|
||||
end)
|
||||
|
||||
xdecor.register("ivy", {
|
||||
description = S("Ivy"),
|
||||
drawtype = "signlike",
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
groups = {snappy = 3, attached_node = 1, plant = 1, flammable = 3},
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {type="wallmounted"},
|
||||
tiles = {"xdecor_ivy.png"},
|
||||
inventory_image = "xdecor_ivy.png",
|
||||
wield_image = "xdecor_ivy.png",
|
||||
sounds = default.node_sound_leaves_defaults()
|
||||
})
|
||||
|
||||
xdecor.register("rooster", {
|
||||
description = S("Weathercock"),
|
||||
drawtype = "torchlike",
|
||||
inventory_image = "xdecor_rooster.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_rooster.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
-- Lantern which attaches to the floor.
|
||||
-- Has a hanging variant
|
||||
xdecor.register("lantern", {
|
||||
description = S("Lantern"),
|
||||
light_source = 13,
|
||||
drawtype = "plantlike",
|
||||
inventory_image = "xdecor_lantern_inv.png",
|
||||
wield_image = "xdecor_lantern_inv.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 3},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_lantern.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = xdecor.pixelbox(16, {{4, 0, 4, 8, 16, 8}}),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
-- Check protection
|
||||
if minetest.is_protected(pointed_thing.above, placer:get_player_name()) and
|
||||
not minetest.check_player_privs(placer, "protection_bypass") then
|
||||
minetest.record_protection_violation(pointed_thing.above, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Decide whether the lantern attaches the the floor
|
||||
-- (default) or the ceiling.
|
||||
local leftover, place_pos, nodename
|
||||
local up = vector.new(pointed_thing.above.x, pointed_thing.above.y+1, pointed_thing.above.z)
|
||||
local upnode = minetest.get_node(up)
|
||||
local updef = minetest.registered_nodes[upnode.name]
|
||||
local down = vector.new(pointed_thing.above.x, pointed_thing.above.y-1, pointed_thing.above.z)
|
||||
local downnode = minetest.get_node(down)
|
||||
local downdef = minetest.registered_nodes[downnode.name]
|
||||
local sound_play = false
|
||||
if pointed_thing.under.y > pointed_thing.above.y then
|
||||
nodename = "xdecor:lantern_hanging"
|
||||
if downdef and not downdef.walkable then
|
||||
sound_play = true
|
||||
end
|
||||
elseif downdef and not downdef.walkable and updef and updef.walkable then
|
||||
nodename = "xdecor:lantern_hanging"
|
||||
sound_play = true
|
||||
else
|
||||
nodename = "xdecor:lantern"
|
||||
end
|
||||
leftover, place_pos = minetest.item_place_node(ItemStack(nodename), placer, pointed_thing)
|
||||
if place_pos == nil then
|
||||
return
|
||||
end
|
||||
if leftover:get_count() == 0 and
|
||||
not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
if sound_play then
|
||||
minetest.sound_play(default.node_sound_metal_defaults().place, {pos=place_pos}, true)
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
-- Same as lantern, but attaches to ceiling
|
||||
xdecor.register("lantern_hanging", {
|
||||
description = S("Hanging Lantern"),
|
||||
light_source = 13,
|
||||
drawtype = "plantlike",
|
||||
inventory_image = "xdecor_lantern_inv.png^xdecor_lantern_hanging_overlay_inv.png",
|
||||
wield_image = "xdecor_lantern_inv.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 4, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_lantern.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = xdecor.pixelbox(16, {{4, 0, 4, 8, 16, 8}}),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:lantern",
|
||||
})
|
||||
|
||||
-- Update legacy lantern (back when they were wallmounted)
|
||||
-- that are hanging to the proper node.
|
||||
minetest.register_lbm({
|
||||
label = "Update hanging lanterns",
|
||||
name = "xdecor:update_hanging_lanterns",
|
||||
nodenames = {"xdecor:lantern"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
if node.param2 == 0 then -- wallmounted 0 value means attached to the ceiling
|
||||
-- Only convert the node if it needs to hang
|
||||
-- (walkable node above, non-walkable node below)
|
||||
local up = vector.new(pos.x, pos.y+1, pos.z)
|
||||
local upnode = minetest.get_node(up)
|
||||
local updef = minetest.registered_nodes[upnode.name]
|
||||
local down = vector.new(pos.x, pos.y-1, pos.z)
|
||||
local downnode = minetest.get_node(down)
|
||||
local downdef = minetest.registered_nodes[downnode.name]
|
||||
if updef and updef.walkable and downdef and not downdef.walkable then
|
||||
minetest.swap_node(pos, {name="xdecor:lantern_hanging"})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local xdecor_lightbox = {
|
||||
iron = S("Steel Lattice Light Box"),
|
||||
wooden = S("Wooden Cross Light Box"),
|
||||
wooden2 = S("Wooden Rhombus Light Box"),
|
||||
}
|
||||
|
||||
for l, desc in pairs(xdecor_lightbox) do
|
||||
xdecor.register(l .. "_lightbox", {
|
||||
description = desc,
|
||||
tiles = {"xdecor_" .. l .. "_lightbox.png"},
|
||||
groups = {cracky = 3, choppy = 3, oddly_breakable_by_hand = 2},
|
||||
is_ground_content = false,
|
||||
light_source = 13,
|
||||
sounds = default.node_sound_glass_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
local xdecor_potted = {
|
||||
dandelion_white = S("Potted White Dandelion"),
|
||||
dandelion_yellow = S("Potted Yellow Dandelion"),
|
||||
geranium = S("Potted Geranium"),
|
||||
rose = S("Potted Rose"),
|
||||
tulip = S("Potted Tulip"),
|
||||
viola = S("Potted Viola"),
|
||||
}
|
||||
|
||||
for f, desc in pairs(xdecor_potted) do
|
||||
xdecor.register("potted_" .. f, {
|
||||
description = desc,
|
||||
walkable = false,
|
||||
groups = {snappy = 3, flammable = 3, plant = 1, flower = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_" .. f .. "_pot.png"},
|
||||
inventory_image = "xdecor_" .. f .. "_pot.png",
|
||||
drawtype = "plantlike",
|
||||
sounds = default.node_sound_leaves_defaults({
|
||||
place = default.node_sound_stone_defaults().place,
|
||||
dug = default.node_sound_stone_defaults().dug,
|
||||
}),
|
||||
selection_box = xdecor.nodebox.slab_y(0.3)
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:potted_" .. f,
|
||||
recipe = {
|
||||
{"default:clay_brick", "flowers:" .. f, "default:clay_brick"},
|
||||
{"", "default:clay_brick", ""}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
local painting_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125},
|
||||
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
|
||||
}
|
||||
|
||||
xdecor.register("painting_1", {
|
||||
description = S("Painting"),
|
||||
tiles = {"xdecor_painting_1.png","xdecor_painting_1.png^[transformR180","xdecor_painting_1.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
inventory_image = "xdecor_painting_empty.png",
|
||||
wield_image = "xdecor_painting_empty.png",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = painting_box,
|
||||
node_placement_prediction = "",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
-- Check protection
|
||||
if minetest.is_protected(pointed_thing.above, placer:get_player_name()) and
|
||||
not minetest.check_player_privs(placer, "protection_bypass") then
|
||||
minetest.record_protection_violation(pointed_thing.above, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local num = math.random(4)
|
||||
local leftover, place_pos = minetest.item_place_node(
|
||||
ItemStack("xdecor:painting_" .. num), placer, pointed_thing)
|
||||
|
||||
if not place_pos then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if leftover:get_count() == 0 and
|
||||
not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
-- Play 'place' sound manually
|
||||
minetest.sound_play(default.node_sound_wood_defaults().place, {pos=place_pos}, true)
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
for i = 2, 4 do
|
||||
xdecor.register("painting_" .. i, {
|
||||
tiles = {"xdecor_painting_"..i..".png","xdecor_painting_"..i..".png^[transformR180","xdecor_painting_"..i..".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
drop = "xdecor:painting_1",
|
||||
sunlight_propagates = true,
|
||||
groups = {
|
||||
choppy = 3,
|
||||
oddly_breakable_by_hand = 2,
|
||||
flammable = 2,
|
||||
attached_node = 1,
|
||||
not_in_creative_inventory = 1
|
||||
},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = painting_box
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("stonepath", {
|
||||
description = S("Garden Stone Path"),
|
||||
tiles = {"default_stone.png"},
|
||||
groups = {snappy = 3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{8, 0, 8, 6, .5, 6}, {1, 0, 1, 6, .5, 6},
|
||||
{1, 0, 10, 5, .5, 5}, {10, 0, 2, 4, .5, 4}
|
||||
}),
|
||||
selection_box = xdecor.nodebox.slab_y(0.05)
|
||||
})
|
||||
|
||||
local function register_hard_node(name, desc, def)
|
||||
def = def or {}
|
||||
xdecor.register(name, {
|
||||
description = desc,
|
||||
tiles = def.tiles or {"xdecor_" .. name .. ".png"},
|
||||
groups = def.groups or {cracky = 1},
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds or default.node_sound_stone_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
register_hard_node("cactusbrick", S("Cactus Brick"))
|
||||
register_hard_node("coalstone_tile", S("Coal Stone Tile"))
|
||||
register_hard_node("desertstone_tile", S("Polished Desert Stone Block"))
|
||||
register_hard_node("hard_clay", S("Hardened Clay"))
|
||||
register_hard_node("moonbrick", S("Moon Brick"))
|
||||
register_hard_node("stone_rune", S("Runestone"))
|
||||
|
||||
-- renamed from stone_tile to fix naming collision with moreblocks
|
||||
-- mod for the registrations under the 'stairs:' namespace
|
||||
register_hard_node("stone_tile_x", S("Polished Stone Block"), {
|
||||
tiles = {"xdecor_stone_tile.png"},
|
||||
})
|
||||
xdecor.register_legacy_aliases("stone_tile", "stone_tile_x")
|
||||
|
||||
register_hard_node("packed_ice", S("Packed Ice"), {
|
||||
groups = {cracky = 1, cools_lava = 1, slippery = 3},
|
||||
sounds = default.node_sound_glass_defaults()
|
||||
})
|
||||
|
||||
-- renamed from wood_tile to fix naming collision with moreblocks
|
||||
-- mod for the registrations under the 'stairs:' namespace
|
||||
register_hard_node("wood_tile_x", S("Wooden Tile"), {
|
||||
groups = {choppy = 1, wood = 1, flammable = 2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
tiles = {"xdecor_wood_tile.png"},
|
||||
})
|
||||
xdecor.register_legacy_aliases("wood_tile", "wood_tile_x")
|
||||
|
||||
xdecor.register("table", {
|
||||
description = S("Table"),
|
||||
tiles = {"xdecor_wood.png"},
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{0, 14, 0, 16, 2, 16}, {5.5, 0, 5.5, 5, 14, 6}
|
||||
})
|
||||
})
|
||||
|
||||
xdecor.register("tatami", {
|
||||
description = S("Tatami"),
|
||||
tiles = {"xdecor_tatami.png"},
|
||||
wield_image = "xdecor_tatami.png",
|
||||
groups = {snappy = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
node_box = xdecor.nodebox.slab_y(0.0625)
|
||||
})
|
||||
|
||||
xdecor.register("trampoline", {
|
||||
description = S("Trampoline"),
|
||||
tiles = {"xdecor_trampoline.png", "xdecor_trampoline_bottom.png", "xdecor_trampoline_sides.png"},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 1, fall_damage_add_percent = -80, bouncy = 90},
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5, -1/16, -0.5, 0.5, 0, 0.5 }, -- bouncy top
|
||||
{ -0.5, -0.5, -0.5, -3/16, 0, -3/16 }, -- leg 1
|
||||
{ 3/16, -0.5, -0.5, 0.5, 0, -3/16 }, -- leg 2
|
||||
{ -0.5, -0.5, 3/16, -3/16, 0, 0.5 }, -- leg 3
|
||||
{ 3/16, -0.5, 3/16, 0.5, 0, 0.5 }, -- leg 4
|
||||
{ -3/16, -5/16, -0.5, 3/16, -1/16, -7/16 }, -- connector 1
|
||||
{ -0.5, -5/16, -3/16, -7/16, -1/16, 3/16 }, -- connector 2
|
||||
{ -3/16, -5/16, 7/16, 3/16, -1/16, 0.5 }, -- connector 3
|
||||
{ 7/16, -5/16, -3/16, 0.5, -1/16, 3/16 }, -- connector 4
|
||||
},
|
||||
},
|
||||
selection_box = xdecor.nodebox.slab_y(0.5),
|
||||
collision_box = xdecor.nodebox.slab_y(0.5),
|
||||
sounds = default.node_sound_defaults({
|
||||
footstep = {
|
||||
name = "xdecor_bouncy",
|
||||
gain = 0.8
|
||||
},
|
||||
dig = default.node_sound_wood_defaults().dig,
|
||||
}),
|
||||
})
|
||||
|
||||
xdecor.register("tv", {
|
||||
description = S("Television"),
|
||||
light_source = 11,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_television_left.png^[transformR270",
|
||||
"xdecor_television_left.png^[transformR90",
|
||||
"xdecor_television_left.png^[transformFX",
|
||||
"xdecor_television_left.png", "xdecor_television_back.png",
|
||||
{
|
||||
name = "xdecor_television_front_animated.png",
|
||||
animation = {type = "vertical_frames", length = 80.0}
|
||||
}
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
xdecor.register("woodframed_glass", {
|
||||
description = S("Wood Framed Glass"),
|
||||
drawtype = "glasslike_framed",
|
||||
sunlight_propagates = true,
|
||||
tiles = {"xdecor_woodframed_glass.png", "xdecor_woodframed_glass_detail.png"},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
_xdecor_custom_noncube_tiles = {
|
||||
stair = {
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
stair_inner = {
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR270",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
},
|
||||
stair_outer = {
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR90",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_outer_stairside.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR90",
|
||||
"xdecor_woodframed_glass_outer_stairside.png",
|
||||
},
|
||||
halfstair = {
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
"xdecor_woodframed_glass_split.png^[transformR90",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
},
|
||||
slab = {
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
cube = { "xdecor_woodframed_glass_cube.png" },
|
||||
thinstair = { "xdecor_woodframed_glass_split.png" },
|
||||
micropanel = { "xdecor_woodframed_glass_split.png" },
|
||||
panel = {
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
local devices = {
|
||||
{ "radio", S("Radio"), default.node_sound_metal_defaults() },
|
||||
--~ as in "loudspeaker"
|
||||
{ "speaker", S("Speaker"), default.node_sound_metal_defaults() },
|
||||
}
|
||||
for _, v in pairs(devices) do
|
||||
xdecor.register(v[1], {
|
||||
description = v[2],
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_" .. v[1] .. "_top.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_back.png",
|
||||
"xdecor_" .. v[1] .. "_front.png",
|
||||
},
|
||||
groups = {cracky = 2, not_cuttable = 1},
|
||||
is_ground_content = false,
|
||||
sounds = v[3],
|
||||
})
|
||||
end
|
405
mods/xdecor/src/recipes.lua
Normal file
405
mods/xdecor/src/recipes.lua
Normal file
|
@ -0,0 +1,405 @@
|
|||
minetest.register_craft({
|
||||
output = "xdecor:baricade",
|
||||
recipe = {
|
||||
{"group:stick", "", "group:stick"},
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"group:stick", "", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:barrel",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:candle",
|
||||
recipe = {
|
||||
{"default:torch"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cabinet",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"doors:trapdoor", "", "doors:trapdoor"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cabinet_half 2",
|
||||
recipe = {
|
||||
{"xdecor:cabinet"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cactusbrick",
|
||||
recipe = {
|
||||
{"default:brick", "default:cactus"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:chair",
|
||||
recipe = {
|
||||
{"group:stick", "", ""},
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:coalstone_tile 4",
|
||||
recipe = {
|
||||
{"default:coalblock", "default:stone"},
|
||||
{"default:stone", "default:coalblock"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cobweb",
|
||||
recipe = {
|
||||
{"farming:string", "", "farming:string"},
|
||||
{"", "farming:string", ""},
|
||||
{"farming:string", "", "farming:string"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cushion 3",
|
||||
recipe = {
|
||||
{"wool:red", "wool:red", "wool:red"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cushion_block",
|
||||
recipe = {
|
||||
{"xdecor:cushion"},
|
||||
{"xdecor:cushion"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:desertstone_tile 4",
|
||||
recipe = {
|
||||
{"default:desert_stone_block", "default:desert_stone_block"},
|
||||
{"default:desert_stone_block", "default:desert_stone_block"},
|
||||
}
|
||||
})
|
||||
|
||||
if not minetest.get_modpath("moreblocks") then
|
||||
minetest.register_craft({
|
||||
output = "xdecor:empty_shelf",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"", "", ""},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:enderchest",
|
||||
recipe = {
|
||||
{"", "default:obsidian", ""},
|
||||
{"default:obsidian", "default:chest", "default:obsidian"},
|
||||
{"", "default:obsidian", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hard_clay",
|
||||
recipe = {
|
||||
{"default:clay", "default:clay"},
|
||||
{"default:clay", "default:clay"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:iron_lightbox",
|
||||
recipe = {
|
||||
{"xpanes:bar_flat", "default:torch", "xpanes:bar_flat"},
|
||||
{"xpanes:bar_flat", "default:glass", "xpanes:bar_flat"},
|
||||
{"xpanes:bar_flat", "default:torch", "xpanes:bar_flat"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:ivy 4",
|
||||
recipe = {
|
||||
{"group:leaves"},
|
||||
{"group:leaves"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:lantern",
|
||||
recipe = {
|
||||
{"default:iron_lump"},
|
||||
{"default:torch"},
|
||||
{"default:iron_lump"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:moonbrick",
|
||||
recipe = {
|
||||
{"default:brick", "default:stone"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:multishelf",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"group:vessel", "group:book", "group:vessel"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:packed_ice",
|
||||
recipe = {
|
||||
{"", "default:ice", ""},
|
||||
{"default:ice", "", "default:ice"},
|
||||
{"", "default:ice", ""},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:painting_1",
|
||||
recipe = {
|
||||
{"default:sign_wall_wood", "group:dye"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:radio",
|
||||
type = "shapeless",
|
||||
recipe = {"xdecor:speaker", "xdecor:speaker"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:rooster",
|
||||
recipe = {
|
||||
{"default:gold_ingot", "", "default:gold_ingot"},
|
||||
{"", "default:gold_ingot", ""},
|
||||
{"default:gold_ingot", "", "default:gold_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:speaker",
|
||||
recipe = {
|
||||
{"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"},
|
||||
{"default:copper_ingot", "", "default:copper_ingot"},
|
||||
{"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stone_tile_x 4",
|
||||
recipe = {
|
||||
{"default:stone_block", "default:stone_block"},
|
||||
{"default:stone_block", "default:stone_block"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stone_rune 4",
|
||||
recipe = {
|
||||
{"default:stone_block", "default:stone_block", "default:stone_block"},
|
||||
{"default:stone_block", "", "default:stone_block"},
|
||||
{"default:stone_block", "default:stone_block", "default:stone_block"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stonepath 16",
|
||||
recipe = {
|
||||
{"stairs:slab_cobble", "", "stairs:slab_cobble"},
|
||||
{"", "stairs:slab_cobble", ""},
|
||||
{"stairs:slab_cobble", "", "stairs:slab_cobble"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:table",
|
||||
recipe = {
|
||||
{"stairs:slab_wood", "stairs:slab_wood", "stairs:slab_wood"},
|
||||
{"", "group:stick", ""},
|
||||
{"", "group:stick", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:tatami",
|
||||
recipe = {
|
||||
{"farming:wheat", "farming:wheat", "farming:wheat"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:trampoline",
|
||||
recipe = {
|
||||
{"farming:string", "farming:string", "farming:string"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:tv",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:glass", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:woodframed_glass",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "default:glass", "group:stick"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wood_tile_x 2",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"group:wood", "", "group:wood"},
|
||||
{"", "group:wood", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wooden_lightbox",
|
||||
recipe = {
|
||||
{"group:stick", "default:torch", "group:stick"},
|
||||
{"group:stick", "default:glass", "group:stick"},
|
||||
{"group:stick", "default:torch", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wooden2_lightbox",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"default:torch", "default:glass", "default:torch"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:empty_shelf",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:multishelf",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:cabinet",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:barrel",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:cabinet_half",
|
||||
burntime = 15,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:workbench",
|
||||
burntime = 15,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:table",
|
||||
burntime = 12,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:woodglass_door",
|
||||
burntime = 13,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:screen_door",
|
||||
burntime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:slide_door",
|
||||
burntime = 8,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xpanes:wood_frame_flat",
|
||||
burntime = 5,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xpanes:bamboo_frame_flat",
|
||||
burntime = 3,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:japanese_door",
|
||||
burntime = 8,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:chair",
|
||||
burntime = 6,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:baricade",
|
||||
burntime = 6,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:wood_tile_x",
|
||||
burntime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "realchess:chessboard",
|
||||
burntime = 4,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:painting_1",
|
||||
burntime = 3,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:tatami",
|
||||
burntime = 1,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:ivy",
|
||||
burntime = 1,
|
||||
})
|
||||
|
132
mods/xdecor/src/rope.lua
Normal file
132
mods/xdecor/src/rope.lua
Normal file
|
@ -0,0 +1,132 @@
|
|||
local rope = {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Maximum length a rope can extend to
|
||||
local MAX_ROPES = 30
|
||||
|
||||
local ropesounds = default.node_sound_leaves_defaults()
|
||||
|
||||
-- Code by Mirko K. (modified by Temperest, Wulfsdad, kilbith and Wuzzy) (License: GPL).
|
||||
function rope.place(itemstack, placer, pointed_thing)
|
||||
local creative = minetest.is_creative_enabled(placer:get_player_name())
|
||||
local protection_bypass = minetest.check_player_privs(placer, "protection_bypass")
|
||||
local pname = placer:get_player_name()
|
||||
if pointed_thing.type == "node" then
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
local pos = pointed_thing.above
|
||||
-- Check protection
|
||||
if minetest.is_protected(pos, pname) and not protection_bypass then
|
||||
minetest.record_protection_violation(pos, pname)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local oldnode = minetest.get_node(pos)
|
||||
local stackname = itemstack:get_name()
|
||||
-- Limit rope length to max. stack size or MAX_ROPES (whatever is smaller).
|
||||
-- Prevents the rope to extend infinitely in Creative Mode.
|
||||
local max_ropes = math.min(itemstack:get_stack_max(), MAX_ROPES)
|
||||
|
||||
-- Start placing ropes and extend it downwards until we hit an obstacle,
|
||||
-- run out of ropes or hit the maximum rope length.
|
||||
local start_pos = table.copy(pos)
|
||||
local ropes_to_place = 0
|
||||
local new_rope_nodes = {}
|
||||
while oldnode.name == "air" and (creative or (ropes_to_place < itemstack:get_count())) and ropes_to_place < max_ropes do
|
||||
-- Stop extending rope into protected area
|
||||
if minetest.is_protected(pos, pname) and not protection_bypass then
|
||||
break
|
||||
end
|
||||
|
||||
table.insert(new_rope_nodes, table.copy(pos))
|
||||
pos.y = pos.y - 1
|
||||
oldnode = minetest.get_node(pos)
|
||||
ropes_to_place = ropes_to_place + 1
|
||||
end
|
||||
local newnode = {name = stackname}
|
||||
if ropes_to_place == 1 then
|
||||
minetest.set_node(new_rope_nodes[1], newnode)
|
||||
else
|
||||
minetest.bulk_set_node(new_rope_nodes, newnode)
|
||||
end
|
||||
if not creative then
|
||||
itemstack:take_item(ropes_to_place)
|
||||
end
|
||||
|
||||
-- Play placement sound manually
|
||||
if ropes_to_place > 0 then
|
||||
minetest.sound_play(ropesounds.place, {pos=start_pos}, true)
|
||||
end
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function rope.remove(pos, oldnode, digger, rope_name)
|
||||
local num = 0
|
||||
local below = {x = pos.x, y = pos.y, z = pos.z}
|
||||
local digger_inv = digger:get_inventory()
|
||||
|
||||
while minetest.get_node(below).name == rope_name do
|
||||
minetest.remove_node(below)
|
||||
below.y = below.y - 1
|
||||
num = num + 1
|
||||
end
|
||||
|
||||
if num == 0 then return end
|
||||
|
||||
-- Play dig sound manually
|
||||
minetest.sound_play(ropesounds.dug, {pos=pos}, true)
|
||||
|
||||
-- Give/drop rope items
|
||||
local creative = minetest.is_creative_enabled(digger:get_player_name())
|
||||
if not creative or not digger_inv:contains_item("main", rope_name) then
|
||||
if creative then
|
||||
num = 1
|
||||
end
|
||||
local item = rope_name.." "..num
|
||||
local leftover = digger_inv:add_item("main", rope_name.." "..num)
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
xdecor.register("rope", {
|
||||
description = S("Rope"),
|
||||
drawtype = "plantlike",
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
groups = {dig_immediate = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_rope.png"},
|
||||
inventory_image = "xdecor_rope_inv.png",
|
||||
wield_image = "xdecor_rope_inv.png",
|
||||
selection_box = xdecor.pixelbox(8, {{3, 0, 3, 2, 8, 2}}),
|
||||
node_placement_prediction = "",
|
||||
on_place = rope.place,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos = vector.new(pos.x, pos.y-1, pos.z)
|
||||
rope.remove(pos, oldnode, digger, "xdecor:rope")
|
||||
end,
|
||||
sounds = ropesounds,
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:rope",
|
||||
recipe = {
|
||||
{"farming:string"},
|
||||
{"farming:string"},
|
||||
{"farming:string"}
|
||||
}
|
||||
})
|
602
mods/xdecor/src/workbench.lua
Normal file
602
mods/xdecor/src/workbench.lua
Normal file
|
@ -0,0 +1,602 @@
|
|||
local workbench = {}
|
||||
local registered_cuttable_nodes = {}
|
||||
local special_cuts = {}
|
||||
|
||||
screwdriver = screwdriver or {}
|
||||
local min, ceil = math.min, math.ceil
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
|
||||
local DEFAULT_HAMMER_REPAIR = 500
|
||||
local DEFAULT_HAMMER_REPAIR_COST = 700
|
||||
|
||||
|
||||
-- Nodeboxes definitions
|
||||
workbench.defs = {
|
||||
-- Name Yield Nodeboxes (X Y Z W H L) Description
|
||||
{"nanoslab", 16, {{ 0, 0, 0, 8, 1, 8 }}, S("Nanoslab")},
|
||||
{"micropanel", 16, {{ 0, 0, 0, 16, 1, 8 }}, S("Micropanel")},
|
||||
{"microslab", 8, {{ 0, 0, 0, 16, 1, 16 }}, S("Microslab")},
|
||||
{"thinstair", 8, {{ 0, 7, 0, 16, 1, 8 },
|
||||
{ 0, 15, 8, 16, 1, 8 }}, S("Thin Stair")},
|
||||
{"cube", 4, {{ 0, 0, 0, 8, 8, 8 }}, S("Cube")},
|
||||
{"panel", 4, {{ 0, 0, 0, 16, 8, 8 }}, S("Panel")},
|
||||
{"slab", 2, nil, S("Slab") },
|
||||
{"doublepanel", 2, {{ 0, 0, 0, 16, 8, 8 },
|
||||
{ 0, 8, 8, 16, 8, 8 }}, S("Double Panel")},
|
||||
{"halfstair", 2, {{ 0, 0, 0, 8, 8, 16 },
|
||||
{ 0, 8, 8, 8, 8, 8 }}, S("Half-Stair")},
|
||||
{"stair_outer", 1, nil, nil},
|
||||
{"stair", 1, nil, S("Stair")},
|
||||
{"stair_inner", 1, nil, nil},
|
||||
}
|
||||
|
||||
local custom_repairable = {}
|
||||
function xdecor:register_repairable(item)
|
||||
custom_repairable[item] = true
|
||||
end
|
||||
|
||||
-- Tools allowed to be repaired
|
||||
function workbench:repairable(stack)
|
||||
-- Explicitly registered as repairable: Overrides everything else
|
||||
if custom_repairable[stack] then
|
||||
return true
|
||||
end
|
||||
-- no repair if non-tool
|
||||
if not minetest.registered_tools[stack] then
|
||||
return false
|
||||
end
|
||||
-- no repair if disable_repair group
|
||||
if minetest.get_item_group(stack, "disable_repair") == 1 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Returns true if item can be cut into basic stairs and slabs
|
||||
function workbench:cuttable(itemname)
|
||||
local split = string.split(itemname, ":")
|
||||
if split and split[1] and split[2] then
|
||||
if minetest.registered_nodes["stairs:stair_"..split[2]] ~= nil or
|
||||
minetest.registered_nodes["stairs:slab_"..split[2]] ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if registered_cuttable_nodes[itemname] == true then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns true if item can be cut into xdecor extended shapes (thinslab, panel, cube, etc.)
|
||||
function workbench:cuttable_extended(itemname)
|
||||
return registered_cuttable_nodes[itemname] == true
|
||||
end
|
||||
|
||||
-- method to allow other mods to check if an item is repairable
|
||||
function xdecor:is_repairable(stack)
|
||||
return workbench:repairable(stack)
|
||||
end
|
||||
|
||||
function workbench:get_output(inv, input, name)
|
||||
local output = {}
|
||||
local extended = workbench:cuttable_extended(input:get_name())
|
||||
for i = 1, #self.defs do
|
||||
local nbox = self.defs[i]
|
||||
local cuttype = nbox[1]
|
||||
local count = nbox[2] * input:get_count()
|
||||
local max_count = input:get_stack_max()
|
||||
if count > max_count then
|
||||
-- Limit count to maximum multiple to avoid waste
|
||||
count = nbox[2] * math.floor(max_count / nbox[2])
|
||||
end
|
||||
local was_cut = false
|
||||
if extended or nbox[3] == nil then
|
||||
local item = name .. "_" .. cuttype
|
||||
|
||||
item = nbox[3] and item or "stairs:" .. cuttype .. "_" .. name:match(":(.*)")
|
||||
if minetest.registered_items[item] then
|
||||
output[i] = item .. " " .. count
|
||||
was_cut = true
|
||||
end
|
||||
end
|
||||
if not was_cut and special_cuts[input:get_name()] ~= nil then
|
||||
local cut = special_cuts[input:get_name()][cuttype]
|
||||
if cut then
|
||||
output[i] = cut .. " " .. count
|
||||
was_cut = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
inv:set_list("forms", output)
|
||||
end
|
||||
|
||||
local main_fs = ""..
|
||||
--~ Verb shown in workbench form where you can cut a node
|
||||
"label[0.9,1.23;"..FS("Cut").."]"
|
||||
--~ Verb shown in workbench form where you can repair an item
|
||||
.."label[0.9,2.23;"..FS("Repair").."]"
|
||||
..[[ box[-0.05,1;2.05,0.9;#555555]
|
||||
box[-0.05,2;2.05,0.9;#555555] ]]
|
||||
--~ Button in workbench form
|
||||
.."button[0,0;2,1;craft;"..FS("Crafting").."]"
|
||||
--~ Button in workbench form
|
||||
.."button[2,0;2,1;storage;"..FS("Storage").."]"
|
||||
..[[ image[3,1;1,1;gui_arrow.png]
|
||||
image[0,1;1,1;worktable_saw.png]
|
||||
image[0,2;1,1;worktable_anvil.png]
|
||||
image[3,2;1,1;hammer_layout.png]
|
||||
list[context;input;2,1;1,1;]
|
||||
list[context;tool;2,2;1,1;]
|
||||
list[context;hammer;3,2;1,1;]
|
||||
list[context;forms;4,0;4,3;]
|
||||
listring[current_player;main]
|
||||
listring[context;tool]
|
||||
listring[current_player;main]
|
||||
listring[context;hammer]
|
||||
listring[current_player;main]
|
||||
listring[context;forms]
|
||||
listring[current_player;main]
|
||||
listring[context;input]
|
||||
]]
|
||||
|
||||
local crafting_fs = "image[5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]"
|
||||
.."button[0,0;1.5,1;back;< "..FS("Back").."]"
|
||||
..[[ list[current_player;craft;2,0;3,3;]
|
||||
list[current_player;craftpreview;6,1;1,1;]
|
||||
listring[current_player;main]
|
||||
listring[current_player;craft]
|
||||
]]
|
||||
|
||||
local storage_fs = "list[context;storage;0,1;8,2;]"
|
||||
.."button[0,0;1.5,1;back;< "..FS("Back").."]"
|
||||
..[[listring[context;storage]
|
||||
listring[current_player;main]
|
||||
]]
|
||||
|
||||
local formspecs = {
|
||||
-- Main formspec
|
||||
main_fs,
|
||||
|
||||
-- Crafting formspec
|
||||
crafting_fs,
|
||||
|
||||
-- Storage formspec
|
||||
storage_fs,
|
||||
}
|
||||
|
||||
function workbench:set_formspec(meta, id)
|
||||
meta:set_string("formspec",
|
||||
"size[8,7;]list[current_player;main;0,3.25;8,4;]" ..
|
||||
formspecs[id] .. xdecor.xbg .. default.get_hotbar_bg(0,3.25))
|
||||
end
|
||||
|
||||
function workbench.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
inv:set_size("tool", 1)
|
||||
inv:set_size("input", 1)
|
||||
inv:set_size("hammer", 1)
|
||||
inv:set_size("forms", 4*3)
|
||||
inv:set_size("storage", 8*2)
|
||||
|
||||
meta:set_string("infotext", S("Work Bench"))
|
||||
workbench:set_formspec(meta, 1)
|
||||
end
|
||||
|
||||
function workbench.fields(pos, _, fields)
|
||||
if fields.quit then return end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local id = fields.back and 1 or fields.craft and 2 or fields.storage and 3
|
||||
if not id then return end
|
||||
|
||||
workbench:set_formspec(meta, id)
|
||||
end
|
||||
|
||||
function workbench.dig(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("input") and inv:is_empty("hammer") and
|
||||
inv:is_empty("tool") and inv:is_empty("storage")
|
||||
end
|
||||
|
||||
function workbench.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"input", "hammer", "tool", "storage"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
function workbench.timer(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local tool = inv:get_stack("tool", 1)
|
||||
local hammer = inv:get_stack("hammer", 1)
|
||||
|
||||
if tool:is_empty() or hammer:is_empty() or tool:get_wear() == 0 then
|
||||
timer:stop()
|
||||
return
|
||||
end
|
||||
|
||||
local hammerdef = hammer:get_definition()
|
||||
|
||||
-- Tool's wearing range: 0-65535; 0 = new condition
|
||||
tool:add_wear(-hammerdef._xdecor_hammer_repair or DEFAULT_HAMMER_REPAIR)
|
||||
hammer:add_wear(hammerdef._xdecor_hammer_repair_cost or DEFAULT_HAMMER_REPAIR_COST)
|
||||
|
||||
inv:set_stack("tool", 1, tool)
|
||||
inv:set_stack("hammer", 1, hammer)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function workbench.allow_put(pos, listname, index, stack, player)
|
||||
local stackname = stack:get_name()
|
||||
if (listname == "tool" and workbench:repairable(stackname)) or
|
||||
(listname == "input" and workbench:cuttable(stackname)) or
|
||||
(listname == "hammer" and minetest.get_item_group(stackname, "repair_hammer") == 1) or
|
||||
listname == "storage" then
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function workbench.on_put(pos, listname, index, stack, player)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
if listname == "input" then
|
||||
local input = inv:get_stack("input", 1)
|
||||
workbench:get_output(inv, input, stack:get_name())
|
||||
elseif listname == "tool" or listname == "hammer" then
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(3.0)
|
||||
end
|
||||
end
|
||||
|
||||
function workbench.allow_move(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
if (to_list == "storage" and from_list ~= "forms") then
|
||||
return count
|
||||
elseif (to_list == "hammer" and from_list == "tool") or (to_list == "tool" and from_list == "hammer") then
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
local stack = inv:get_stack(from_list, from_index)
|
||||
if minetest.get_item_group(stack:get_name(), "repair_hammer") == 1 then
|
||||
return count
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function workbench.on_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)
|
||||
local to_stack = inv:get_stack(to_list, to_index)
|
||||
|
||||
workbench.on_take(pos, from_list, from_index, from_stack, player)
|
||||
workbench.on_put(pos, to_list, to_index, to_stack, player)
|
||||
end
|
||||
|
||||
function workbench.allow_take(pos, listname, index, stack, player)
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
function workbench.on_take(pos, listname, index, stack, player)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local input = inv:get_stack("input", 1)
|
||||
local inputname = input:get_name()
|
||||
local stackname = stack:get_name()
|
||||
|
||||
if listname == "input" then
|
||||
if stackname == inputname and workbench:cuttable(inputname) then
|
||||
workbench:get_output(inv, input, stackname)
|
||||
else
|
||||
inv:set_list("forms", {})
|
||||
end
|
||||
elseif listname == "forms" then
|
||||
local fromstack = inv:get_stack(listname, index)
|
||||
if not fromstack:is_empty() and fromstack:get_name() ~= stackname then
|
||||
local player_inv = player:get_inventory()
|
||||
if player_inv:room_for_item("main", fromstack) then
|
||||
player_inv:add_item("main", fromstack)
|
||||
end
|
||||
end
|
||||
|
||||
input:take_item(ceil(stack:get_count() / workbench.defs[index][2]))
|
||||
inv:set_stack("input", 1, input)
|
||||
workbench:get_output(inv, input, inputname)
|
||||
end
|
||||
end
|
||||
|
||||
xdecor.register("workbench", {
|
||||
description = S("Work Bench"),
|
||||
_tt_help = S("For cutting blocks, repairing tools with a hammer, crafting and storing items"),
|
||||
groups = {cracky = 2, choppy = 2, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
tiles = {
|
||||
"xdecor_workbench_top.png","xdecor_workbench_bottom.png",
|
||||
"xdecor_workbench_sides.png", "xdecor_workbench_sides.png",
|
||||
"xdecor_workbench_front.png", "xdecor_workbench_front.png"
|
||||
},
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = workbench.dig,
|
||||
on_blast = workbench.blast,
|
||||
on_timer = workbench.timer,
|
||||
on_construct = workbench.construct,
|
||||
on_receive_fields = workbench.fields,
|
||||
on_metadata_inventory_put = workbench.on_put,
|
||||
on_metadata_inventory_take = workbench.on_take,
|
||||
on_metadata_inventory_move = workbench.on_move,
|
||||
allow_metadata_inventory_put = workbench.allow_put,
|
||||
allow_metadata_inventory_take = workbench.allow_take,
|
||||
allow_metadata_inventory_move = workbench.allow_move
|
||||
})
|
||||
|
||||
local function register_cut_raw(node, workbench_def)
|
||||
local mod_name, item_name = node:match("^(.-):(.*)")
|
||||
local def = minetest.registered_nodes[node]
|
||||
|
||||
if item_name and workbench_def[3] then
|
||||
local groups = {}
|
||||
local tiles
|
||||
groups.not_in_creative_inventory = 1
|
||||
|
||||
for k, v in pairs(def.groups) do
|
||||
if k ~= "wood" and k ~= "stone" and k ~= "level" then
|
||||
groups[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
if def.tiles then
|
||||
if #def.tiles > 1 and (def.drawtype:sub(1,5) ~= "glass") then
|
||||
tiles = def.tiles
|
||||
else
|
||||
tiles = {def.tiles[1]}
|
||||
end
|
||||
else
|
||||
tiles = {def.tile_images[1]}
|
||||
end
|
||||
|
||||
-- Erase `tileable_vertical=false` from tiles because it
|
||||
-- lead to buggy textures (e.g. with default:permafrost_with_moss)
|
||||
for t=1, #tiles do
|
||||
if type(tiles[t]) == "table" and tiles[t].tileable_vertical == false then
|
||||
tiles[t].tileable_vertical = nil
|
||||
end
|
||||
end
|
||||
|
||||
local custom_tiles = xdecor.glasscuts[node]
|
||||
if custom_tiles then
|
||||
if not custom_tiles.nanoslab then
|
||||
custom_tiles.nanoslab = custom_tiles.cube
|
||||
end
|
||||
if not custom_tiles.micropanel then
|
||||
custom_tiles.micropanel = custom_tiles.micropanel
|
||||
end
|
||||
if not custom_tiles.doublepanel then
|
||||
custom_tiles.doublepanel = custom_tiles.panel
|
||||
end
|
||||
end
|
||||
|
||||
if not minetest.registered_nodes["stairs:slab_" .. item_name] then
|
||||
if custom_tiles and (custom_tiles.slab or custom_tiles.stair) then
|
||||
if custom_tiles.stair then
|
||||
stairs.register_stair(item_name, node,
|
||||
groups, custom_tiles.stair, S("@1 Stair", def.description),
|
||||
def.sounds)
|
||||
stairs.register_stair_inner(item_name, node,
|
||||
groups, custom_tiles.stair_inner, "", def.sounds, nil, S("Inner @1 Stair", def.description))
|
||||
stairs.register_stair_outer(item_name, node,
|
||||
groups, custom_tiles.stair_outer, "", def.sounds, nil, S("Outer @1 Stair", def.description))
|
||||
end
|
||||
if custom_tiles.slab then
|
||||
stairs.register_slab(item_name, node,
|
||||
groups, custom_tiles.slab, S("@1 Slab", def.description),
|
||||
def.sounds)
|
||||
end
|
||||
else
|
||||
stairs.register_stair_and_slab(item_name, node,
|
||||
groups, tiles,
|
||||
S("@1 Stair", def.description),
|
||||
S("@1 Slab", def.description),
|
||||
def.sounds, nil,
|
||||
S("Inner @1 Stair", def.description),
|
||||
S("Outer @1 Stair", def.description))
|
||||
end
|
||||
end
|
||||
|
||||
local cutname = workbench_def[1]
|
||||
local tiles_special_cut
|
||||
if custom_tiles and custom_tiles[cutname] then
|
||||
tiles_special_cut = custom_tiles[cutname]
|
||||
else
|
||||
tiles_special_cut = tiles
|
||||
end
|
||||
|
||||
local cutnodename = node .. "_" .. cutname
|
||||
if minetest.registered_nodes[cutnodename] then
|
||||
minetest.log("error", "[xdecor] register_cut_raw: Refusing to register node "..cutnodename.." becaut it was already registered!")
|
||||
return false
|
||||
end
|
||||
minetest.register_node(":" .. cutnodename, {
|
||||
--~ Format of the description of a cut node. @1: Base node description (e.g. "Stone"); @2: modifier (e.g. "Nanoslab")
|
||||
description = S("@1 @2", def.description, workbench_def[4]),
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
sounds = def.sounds,
|
||||
tiles = tiles_special_cut,
|
||||
use_texture_alpha = def.use_texture_alpha,
|
||||
groups = groups,
|
||||
is_ground_content = def.is_ground_content,
|
||||
node_box = xdecor.pixelbox(16, workbench_def[3]),
|
||||
sunlight_propagates = true,
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
elseif item_name and mod_name then
|
||||
minetest.register_alias_force(
|
||||
("%s:%s_innerstair"):format(mod_name, item_name),
|
||||
("stairs:stair_inner_%s"):format(item_name)
|
||||
)
|
||||
minetest.register_alias_force(
|
||||
("%s:%s_outerstair"):format(mod_name, item_name),
|
||||
("stairs:stair_outer_%s"):format(item_name)
|
||||
)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function workbench:register_cut(nodename, cutlist)
|
||||
if registered_cuttable_nodes[nodename] then
|
||||
minetest.log("error", "[xdecor] Workbench: Tried to register cut for node "..nodename..", but it was already registered!")
|
||||
return false
|
||||
end
|
||||
local ok = true
|
||||
for _, d in ipairs(workbench.defs) do
|
||||
local ok = register_cut_raw(nodename, d)
|
||||
if not ok then
|
||||
ok = false
|
||||
end
|
||||
end
|
||||
registered_cuttable_nodes[nodename] = true
|
||||
return ok
|
||||
end
|
||||
|
||||
function workbench:register_special_cut(nodename, cutlist)
|
||||
if registered_cuttable_nodes[nodename] or special_cuts[nodename] then
|
||||
minetest.log("error", "[xdecor] Workbench: Tried to register special cut for node "..nodename..", but it was already registered!")
|
||||
return false
|
||||
end
|
||||
registered_cuttable_nodes[nodename] = true
|
||||
special_cuts[nodename] = cutlist
|
||||
end
|
||||
|
||||
-- Workbench craft
|
||||
minetest.register_craft({
|
||||
output = "xdecor:workbench",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
-- Register default cuttable blocks
|
||||
do
|
||||
local cuttable_nodes = {}
|
||||
|
||||
-- Nodes allowed to be cut:
|
||||
-- Only the regular, solid blocks without metas or explosivity
|
||||
-- from the xdecor or default mods.
|
||||
for nodename, def in pairs(minetest.registered_nodes) do
|
||||
local nodenamesplit = string.split(nodename, ":")
|
||||
local modname = nodenamesplit[1]
|
||||
if (modname == "xdecor" or modname == "default") and xdecor.stairs_valid_def(def) then
|
||||
cuttable_nodes[#cuttable_nodes + 1] = nodename
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #cuttable_nodes do
|
||||
local node = cuttable_nodes[i]
|
||||
workbench:register_cut(node)
|
||||
end
|
||||
end
|
||||
|
||||
-- Special cuts for cushion block and cabinet
|
||||
workbench:register_special_cut("xdecor:cushion_block", { slab = "xdecor:cushion" })
|
||||
workbench:register_special_cut("xdecor:cabinet", { slab = "xdecor:cabinet_half" })
|
||||
|
||||
--[[ API FUNCTIONS ]]
|
||||
|
||||
--[[ Register a custom hammer (for repairing).
|
||||
A hammer repair items at the work bench. The workbench repeatedly
|
||||
checks if a hammer and a repairable tool are in the slots. The hammer
|
||||
will repair the tool in regular intervals. This is called a "step".
|
||||
In each step, the hammer reduces the wear of the repairable
|
||||
tool but increases its own wear, each by a fixed amount.
|
||||
|
||||
This function allows you to register a custom hammer with custom
|
||||
name, item image and wear stats.
|
||||
|
||||
Arguments:
|
||||
* name: Internal itemname
|
||||
* def: Definition table:
|
||||
* description: Item `description`
|
||||
* image: Inventory image and wield image
|
||||
* groups: Item groups (MUST contain at least `repair_hammer = 1`)
|
||||
* repair: How much item wear the hammer repairs per step
|
||||
* repair_cost: How much item wear the hammer takes itself per step
|
||||
|
||||
Note: Mind the implication of repair_cost! If repair_cost is lower than
|
||||
repair, this means practically infinite durability if you have two
|
||||
hammers that repair each other. If repair_cost is higher than repair,
|
||||
then hammers will break eventually.
|
||||
]]
|
||||
function xdecor.register_hammer(name, def)
|
||||
minetest.register_tool(name, {
|
||||
description = def.description,
|
||||
_tt_help = S("Repairs tools at the work bench"),
|
||||
inventory_image = def.image,
|
||||
wield_image = def.image,
|
||||
on_use = function() do
|
||||
return end
|
||||
end,
|
||||
groups = def.groups,
|
||||
_xdecor_hammer_repair = def.repair or DEFAULT_HAMMER_REPAIR,
|
||||
_xdecor_hammer_repair_cost = def.repair_cost or DEFAULT_HAMMER_REPAIR_COST,
|
||||
})
|
||||
end
|
||||
|
||||
--[[ EXPERIMENTAL FUNCTION:
|
||||
Registers various 'cut' node variants for the node with the given nodename,
|
||||
which will be available in the workbench.
|
||||
This must only be called once per node. Calling it again is an error.
|
||||
|
||||
The following nodes will be registered:
|
||||
|
||||
* <nodename>_nanoslab
|
||||
* <nodename>_micropanel
|
||||
* <nodename>_microslab
|
||||
* <nodename>_thinstair
|
||||
* <nodename>_cube
|
||||
* <nodename>_panel
|
||||
* <nodename>_doublepanel
|
||||
* <nodename>_halfstair
|
||||
|
||||
You MUST make sure these names are not already taken before
|
||||
calling this function. Failing to do so is an error.
|
||||
|
||||
Additionally, a slab, stair, inner stair and outer stair
|
||||
will be registered by using the `stairs` mod if the slab
|
||||
node does not exist yet. Refer to the `stairs` mod documentation
|
||||
for details.
|
||||
|
||||
Returns true if all nodes were registered successfully,
|
||||
returns false (and writes to error log) if any error occurred.
|
||||
]]
|
||||
xdecor.register_cut = function(nodename)
|
||||
return workbench:register_cut(nodename)
|
||||
end
|
||||
|
||||
|
||||
--[[ END OF API FUNCTIONS ]]
|
||||
|
||||
|
||||
-- Register xdecor's built-in hammer
|
||||
xdecor.register_hammer("xdecor:hammer", {
|
||||
description = S("Hammer"),
|
||||
image = "xdecor_hammer.png",
|
||||
groups = { repair_hammer = 1 },
|
||||
repair = DEFAULT_HAMMER_REPAIR,
|
||||
repair_cost = DEFAULT_HAMMER_REPAIR_COST,
|
||||
})
|
||||
|
||||
-- Hammer recipes
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hammer",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "group:stick", "default:steel_ingot"},
|
||||
{"", "group:stick", ""}
|
||||
}
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue