Compare commits

...

71 Commits
lsr ... master

Author SHA1 Message Date
Wuzzy
1923b6acde Fix bad loading of enchanting 2024-12-02 18:34:23 +01:00
Wuzzy
d6942aa43b Fix typos in Chess readme 2024-12-02 17:27:32 +01:00
Wuzzy
31f37b0665 Add translator comments (form: "--~") 2024-12-02 05:30:07 +01:00
Wuzzy
80c611d640 Update German translation 2024-12-02 05:10:36 +01:00
Wuzzy
720dda3178 Update locale files 2024-12-02 05:10:07 +01:00
Wuzzy
fc81d35ccd Fix missing bracket 2024-12-02 05:09:18 +01:00
Wuzzy
ae27cb8f4f Make enchanted tools inherit groups form original 2024-12-02 05:03:47 +01:00
Wuzzy
78c81f5da6 Soup: Add ingredient blacklist 2024-12-02 03:52:09 +01:00
Wuzzy
e66f056590 Cauldron: Print soup ingredient items to console 2024-12-02 03:44:26 +01:00
Wuzzy
26a7dbb78f Fix broken hammer register 2024-12-02 03:12:33 +01:00
Wuzzy
34d2c56f6d Add initial mod API documentation 2024-12-02 03:06:21 +01:00
Wuzzy
7ac1756f09 Reduce ench. bug net uses 2024-12-02 02:28:52 +01:00
Wuzzy
2c426f53f6 Merge branch 'enchant_bugnet' into enchant_api 2024-12-02 02:28:11 +01:00
Wuzzy
5b1335dbea Reduce ench. steel hoe uses 2024-12-02 02:27:03 +01:00
Wuzzy
5e479b9ac5 Add enchanted bugnet 2024-12-02 02:18:20 +01:00
Wuzzy
4832eb0470 Add enchanted hammers 2024-12-02 01:46:03 +01:00
Wuzzy
2a2cfa4113 Move enchant registrations to separate file 2024-12-02 00:46:38 +01:00
Wuzzy
c81ed3725d Move tool enchants lower in file 2024-12-02 00:39:04 +01:00
Wuzzy
7a746e5660 Add enchanted steel hoe 2024-12-01 23:43:25 +01:00
Wuzzy
f1cf8c3fb0 Add API to register custom tool enchantments 2024-12-01 23:41:26 +01:00
Wuzzy
32188e3eba Enchanting: Set enchantment strength in API 2024-12-01 22:08:11 +01:00
Wuzzy
e513314ae8 Refactor enchanting.lua for readability 2024-12-01 20:43:54 +01:00
Wuzzy
92f31e08cc Add public enchanting function 2024-12-01 20:37:41 +01:00
Wuzzy
8dfd5aade1 Remove dummy fields in enchanting 2024-12-01 20:09:43 +01:00
Wuzzy
a62ef6c183 Redo translation of enchanted tools 2024-12-01 20:08:56 +01:00
Wuzzy
2b91f0d013 Fix typo: "more damages" 2024-12-01 20:00:28 +01:00
Wuzzy
254ae5a4d5 Make enchant % translatable 2024-12-01 19:59:53 +01:00
Wuzzy
ed5b525dd8 Refactor enchanting tool registration 2024-12-01 19:54:45 +01:00
Wuzzy
06c2c9881a Raise min_minetest_version to 5.9 2024-12-01 17:56:06 +01:00
Wuzzy
617ab9b30e Merge branch 'somedumbguy-toolranks-support' 2024-12-01 17:53:34 +01:00
Wuzzy
4ce65f20e2 Update minetest.net to luanti.org link 2024-11-28 13:08:58 +01:00
Wuzzy
20e6a3b379 Rename Minetest to Luanti 2024-10-27 21:37:48 +01:00
Wuzzy
5502e5f052 Fix typo: "Your tool last longer" 2024-10-27 21:11:24 +01:00
Wuzzy
1f33988ac5 Fix sit_destruct calling funcs wrongly 2024-09-19 14:38:11 +02:00
Wuzzy
06e42034f3 Chessbot: Print out more errors in bad state 2024-09-19 14:17:26 +02:00
Wuzzy
2d5e149ba9 Increase bot move delay again 2024-09-19 14:07:31 +02:00
Wuzzy
0e3d242ec6 Merge branch 'chessbot_async' 2024-09-19 14:07:10 +02:00
Wuzzy
0ef5c3eee7 Chess: Fix crash if call get_figurine_id("") 2024-09-19 14:03:07 +02:00
Wuzzy
08991e877c Refactor chess code to access node meta less often 2024-09-19 13:28:58 +02:00
Wuzzy
1156940f99 Fix wrong naming convention for stairs 2024-09-19 10:58:53 +02:00
Wuzzy
ec7410b4e7 Register cut nodes instantly 2024-09-19 10:54:05 +02:00
Wuzzy
6ba25ff14c Simplify xdecor.register_cut documentation 2024-09-19 10:38:29 +02:00
Wuzzy
98cd448992 Doc xdecor.register_cut and check name collision 2024-09-19 10:36:15 +02:00
Wuzzy
2248c5aba6 Mark xdecor.register_cut as experimental 2024-09-19 10:23:28 +02:00
Wuzzy
46ccd93fc9 Add xdecor.register_cut 2024-09-19 10:08:32 +02:00
Wuzzy
454aa6ccc9 Refactor cuttable node registration method 2024-09-19 09:54:26 +02:00
Wuzzy
89c0c1f5a1 Clean up seat state after node destruct 2024-09-19 09:13:19 +02:00
Wuzzy
1ad835bd53 Can now sit down if clicking on side 2024-09-19 08:59:58 +02:00
Wuzzy
2e745748eb Use default animation speeds for sit/stand 2024-09-19 08:57:57 +02:00
Wuzzy
dde5e29a45 Add 'sittable' group to cushion and chair 2024-09-19 08:55:49 +02:00
Wuzzy
7a297813ca Rework sitting; no longer changes player physics 2024-09-19 08:55:21 +02:00
Wuzzy
06e4527ad9 Paintings at floor or ceiling can be rotated 90°
New MT 5.9.0 feature
2024-08-29 20:47:50 +02:00
Wuzzy
0ecd7a357d Fix flipped backside of painting 2024-08-29 20:36:36 +02:00
Wuzzy
2b41a41052 New bottom texture of cauldron+enchant/craftbench 2024-08-29 20:35:54 +02:00
Wuzzy
e39cfeae84 Mention decoration blocks in README 2024-07-25 11:17:10 +02:00
Wuzzy
ba85e514bf No longer set eye offset when sitting on chair
MTG is now doing the eye offset itself
2024-07-23 10:32:11 +02:00
Wuzzy
a84365d3e9 Add translatable mod description 2024-07-23 10:31:52 +02:00
Somedumbguy
b8222cdebe add toolranks to enchanted tools if the mod is enabled 2024-05-29 12:09:46 -04:00
Wuzzy
b981444b7c Fix crash when placing rope in non-creative 2024-03-08 14:55:43 +01:00
Wuzzy
569e4bfa78 Reduce max. rope extension length to 30 2024-03-08 14:49:24 +01:00
Wuzzy
3a896b4a90 Can't extend rope into protected area 2024-03-08 14:05:02 +01:00
Wuzzy
992616a3f0 Improve performance of placing very long ropes 2024-03-08 13:49:23 +01:00
Wuzzy
d88cfbf9d8 Improve curtain a bit 2024-03-08 13:06:30 +01:00
Wuzzy
e4d2154bac Turn curtain into a nodebox 2024-03-08 12:45:37 +01:00
Wuzzy
8610d1e88f Make red curtain darker 2024-03-08 12:37:05 +01:00
Wuzzy
4a10d2f68c Make trampoline a nodebox, add bottom texture 2024-03-08 12:27:24 +01:00
Wuzzy
bac5e5ebf1 Fix some minor mistakes in the Chess readme 2024-03-07 22:40:09 +01:00
Wuzzy
7b391dd8f3 Chess: Fix game not end if checkmate by promotion 2024-03-07 22:40:09 +01:00
Wuzzy
d7fab3bd96 Merge pull request 'Add Italian translation for chess' (#40) from Zughy/xdecor-libre:master into master
Reviewed-on: https://codeberg.org/Wuzzy/xdecor-libre/pulls/40
2024-03-07 20:20:04 +00:00
marco_a
b05c312968 Add Italian translation for chess 2024-03-07 00:11:56 +01:00
Wuzzy
0d8afaff76 Fix 'initial_properties' warning 2023-12-27 21:57:46 +01:00
31 changed files with 1385 additions and 651 deletions

32
API.md Normal file
View File

@ -0,0 +1,32 @@
# API for X-Decor-libre
X-Decor-libre is mostly self-contained but it allows for limited extension with
a simple API. Not that extensibility is not the main goal of this mod.
The function documentation can be found in the respective source code files
under the header "--[[ API FUNCTIONS ]]".
These are the features:
## Add custom tool enchantments
You can register tools to be able to be enchanted at the enchanting table.
See `src/enchanting.lua` for details.
## Add custom hammers
You can add a custom hammer for repairing tools at the workbench,
using custom stats.
See `src/workbench.lua` for details.
## EXPERIMENTAL: Add cut nodes
You can register "cut" node variants of an existing node which can
be created at the workbench.
This will add thin stairs, half stairs, panels, microcubes, etc.
THIS FEATURE IS EXPERIMENTAL!
See `src/workbench.lua` for details.

View File

@ -29,9 +29,9 @@ You need a chessboard to play. Craft yourself a chessboard like this:
BWB
sss
B = Black Dye
W = White Dye
s = Wooden Slab (from apple tree)
* B = Black Dye
* W = White Dye
* s = Wooden Slab (from apple tree)
Place the chessboard and examine it. You will see a close-up of the chessboard.
@ -64,8 +64,7 @@ It is written in a figurine long algebraic notation (see appendix).
The two boxes below the list of moves is where all the captured pieces
go. This has no gameplay significance but it may serve as a visual
aid to see how badly hurt the player's “armies” are. This section
may change
aid to see how badly hurt the player's “armies” are.
The top right corner is used for starting a new game. Press
“New Game” to start a new game. This ends the current game.
@ -121,7 +120,7 @@ a capturing move are identical. Only for the pawn it is different
If the square of the king is attacked, he and the player playing him
is considered to be in “check”.
If a player is in check, any move which would put or leave the own
While a player is in check, any move which would their own
king under attack is not allowed.
#### How to actually move
@ -149,9 +148,6 @@ The rook looks like a tower and can move to any of square that lies
in a straight horizontal or vertical line from it.
It cannot move beyond pieces that are in the way.
The rook can move on a square occupied by an opponent, which
w
The rook may be involved in Castling, see “King” below.
#### Bishop
@ -218,7 +214,7 @@ If all the conditions are met, heres how you castle:
Place the king two squares towards the rook you want to castle with.
This square is where the king will end up. The rook will then
automatically move towards the king and “jump” to the square
behind the king, from the rooks viewpoint.
behind the king, from the rooks viewpoint.
**Remember**: You *must* move the king (not the rook) if you want
to castle. If you move the rook instead, this is considered
@ -234,10 +230,12 @@ pieces have started).
The pawns basic moves are:
1. Single step: The pawn moves one step vertically towards the
opponents side. It is not possible to walk backwards.
opponents side.
2. Double step: Like a single step, but it moves two squares instead.
This is only possible from the pawns start position.
A pawn can never move backwards.
In both cases, the destination square must be empty as well as any crossed square.
The pawn cannot capture by a single or double step, however.
@ -289,7 +287,7 @@ is not taken, it will be gone from that point on.
##### Promotion
When a pawn reaches the other end of the chessboard (from its viewpoint)
When a pawn reaches the other end of the chessboard (from its viewpoint),
it will be promoted. A promotion is considered to be part of the move.
When promotion happens, the boxes where normally the captured pieces go
@ -300,7 +298,7 @@ Just click the corresponding button. These buttons only work for the
current player. Promotion is mandatory and no other moves are possible
until it is completed.
Once a piece was selected, the pawn will be replaced replaced, which
Once a piece was selected, the pawn will be replaced, which
immediately activates its powers. This ends the move.
### The end of the game
@ -438,8 +436,10 @@ dig the chessboard.
### The Chess Notation
The list of moves is in a special notation called “algebraic notation”. There are many
variants of it, so this section explains what it means in X-Decor-libre.
The chessboard interface shows a list of all moves on the right side.
The list of moves is written in a special notation called “algebraic notation”.
There are many variants of it, so this section explains what it means in X-Decor-libre.
This mod uses a longform figurine algebraic notation. “figurine” means that
icons are used for the chess pieces. “longform” means the start
@ -493,7 +493,7 @@ When a player castles, it is notated the following way:
#### Game completion
If the game completed, the end of the game showing the result is listed in a final separate line as:
If the game came to an end, the game result is written in a final separate line as:
* “10” if White won
* “01” if Black won
@ -501,11 +501,11 @@ If the game completed, the end of the game showing the result is listed in a fin
#### Example
1. d2—d4 e7—e6
1. d2d4 e7e6
2. ♔e1d2 ♛d8h4
3. d4d5 e6×d5
...
8. d8×d8♖ ♞b8-c6
8. d8×d8♖ ♞b8c6
9. e2e4 d4×e3 e.p.
Explanation of the moves:
@ -513,7 +513,7 @@ Explanation of the moves:
* 1.: First fullmove: White moves pawn from d2 to d4, Black moves pawn from e7 to e6
* 2.: Second fullmove: White moves king from e1 to d2, Black moves queen from d8 to h4
* 3.: Third fullmove: White moves pawn from d4 to d5, Black moves pawn from d6 to d5 and captures
* 8.: Eight fullmove: White moves pawn from d7 to d8, captures a piece and promotes it to rook, Black moves knight from b8 to c6
* 8.: Eighth fullmove: White moves pawn from d7 to d8, captures a piece and promotes it to rook, Black moves knight from b8 to c6
* 9.: Ninth fullmove: White moves pawn from e2 to e4, black moves pawn from d4 to e3 and captures en passant
#### Other symbols

View File

@ -1,14 +1,23 @@
## X-Decor-libre [`xdecor`] ##
[![ContentDB](https://content.minetest.net/packages/Wuzzy/xdecor/shields/downloads/)](https://content.minetest.net/packages/Wuzzy/xdecor/)
[![ContentDB](https://content.luanti.org/packages/Wuzzy/xdecor/shields/downloads/)](https://content.luanti.org/packages/Wuzzy/xdecor/)
X-Decor-libre is a libre Minetest mod which adds various decorative blocks
X-Decor-libre is a libre Luanti mod which adds various decorative blocks
as well as simple gimmicks.
This is a libre version (free software, free media) of the X-Decor mod for Minetest.
This is a libre version (free software, free media) of the X-Decor mod for Luanti.
It is the same as X-Decor, except with all the non-free files replaced and with
bugfixes. There are no new features.
## New blocks
This mod adds many decoration blocks: Flower pot, weathervane, radio, speaker,
wooden tile, new bricks, lamps, candles, new doors, packed ice, and more.
This mod also adds 7 new block shapes for many Minetest Game blocks. They can
be created by using the workbench. This includes panels, mini blocks and flat
stairs.
## Special nodes
Most blocks in this mod are purely decorative, but there are also many special
@ -34,11 +43,13 @@ blocks with special features:
* Pressure Plate: Step on it to activate doors next to it
* Chessboard: Play Chess against a player or the computer (see `CHESS_README.md`)
The radio and speaker are purely decorative and have no special functionality.
## For developers
X-Decor-libre can be extended in a limited fashion. See `API.md` for details.
### X-Decor-libre vs X-Decor
X-Decor is a popular mod in Minetest but it is (as the time of writing this text)
X-Decor is a popular mod in Luanti but it is (as the time of writing this text)
non-free software, there are various files under proprietary licenses.
The purpose of this repository is to provide the community a fully-free fork of
@ -100,7 +111,6 @@ Maintenance updates:
* Storage blocks now drop their inventory when exploded
* Made several strings translatable
* Translation updates
* Add support for playerphysics mod
* Add description to every setting
* Add tooltip extensions for some interactive items (uses `tt` mod)
* Add crafting guide support for `unified_inventory` mod (honey)

View File

@ -1,50 +1,76 @@
local mod_playerphysics = minetest.get_modpath("playerphysics") ~= nil
local mod_player_api = minetest.get_modpath("player_api") ~= nil
local function top_face(pointed_thing)
if not pointed_thing then return end
return pointed_thing.above.y > pointed_thing.under.y
local sitting = {}
local seats_occupied = {}
local function bottom_face(pointed_thing)
if not pointed_thing then
return
end
return pointed_thing.above.y < pointed_thing.under.y
end
local function stand_up(player_name)
if not mod_player_api then
return
end
local player = minetest.get_player_by_name(player_name)
if not player then
return
end
player_api.player_attached[player_name] = false
local old_anim = player_api.get_animation(player)
if old_anim and old_anim.animation == "sit" then
player_api.set_animation(player, "stand")
end
local hash = minetest.hash_node_position(sitting[player_name])
seats_occupied[hash] = nil
sitting[player_name] = nil
minetest.log("action", "[xdecor] "..player_name.." stands up at "..minetest.pos_to_string(player:get_pos(), 0))
end
--[[ Used when player interacts with "sittable" node to sit down
or stand up when interacting with that node again. Should
be used in `on_rightclick` handler
* `pos`: Position where to sit down player (MUST only use integers for coordinates!)
* `node`: Node table of node to sit on
* `clicker`: Player who interacted with node (from `on_rightclick`)
* `pointed_thing`: From `on_rightclick` ]]
function xdecor.sit(pos, node, clicker, pointed_thing)
if not mod_player_api then return end
if not top_face(pointed_thing) then return end
if not mod_player_api then
return
end
-- Can't sit down if bottom face was pointed at
if bottom_face(pointed_thing) then
return
end
local player_name = clicker:get_player_name()
local objs = minetest.get_objects_inside_radius(pos, 0.1)
local vel = clicker:get_velocity()
local ctrl = clicker:get_player_control()
for _, obj in pairs(objs) do
if obj:is_player() and obj:get_player_name() ~= player_name then
return
end
end
-- Stand up if sitting
if sitting[player_name] then
stand_up(player_name)
if player_api.player_attached[player_name] then
clicker:set_pos(pos)
clicker:set_eye_offset(vector.new(), vector.new())
if mod_playerphysics then
playerphysics.remove_physics_factor(clicker, "speed", "xdecor:sit_speed")
playerphysics.remove_physics_factor(clicker, "jump", "xdecor:sit_jump")
else
clicker:set_physics_override({speed = 1, jump = 1})
end
player_api.player_attached[player_name] = false
player_api.set_animation(clicker, "stand", 30)
elseif not player_api.player_attached[player_name] and node.param2 <= 3 and
-- Sit down if not sitting and not attached
elseif not sitting[player_name] and not player_api.player_attached[player_name] and node.param2 <= 3 and
not ctrl.sneak and vector.equals(vel, vector.new()) then
clicker:set_eye_offset({x = 0, y = -7, z = 2}, vector.new())
if mod_playerphysics then
playerphysics.add_physics_factor(clicker, "speed", "xdecor:sit_speed", 0)
playerphysics.add_physics_factor(clicker, "jump", "xdecor:sit_jump", 0)
else
clicker:set_physics_override({speed = 0, jump = 0})
-- Can't sit down on note already occupied by player
local hash = minetest.hash_node_position(pos)
if seats_occupied[hash] then
return
end
clicker:set_pos(pos)
player_api.player_attached[player_name] = true
player_api.set_animation(clicker, "sit", 30)
player_api.set_animation(clicker, "sit")
sitting[player_name] = table.copy(pos)
seats_occupied[hash] = player_name
clicker:set_pos(pos)
if node.param2 == 0 then
clicker:set_look_horizontal(0)
@ -55,19 +81,74 @@ function xdecor.sit(pos, node, clicker, pointed_thing)
elseif node.param2 == 3 then
clicker:set_look_horizontal(math.pi/2)
end
minetest.log("action", "[xdecor] "..player_name.." sits down at "..minetest.pos_to_string(pos, 0))
end
end
-- Called when `digger` (a player object) wants to
-- dig a node at pos. Returns true if it's allowed,
-- false otherwise. This checks if the node at pos
-- is an occupied sittable node.
-- Can be used for the `can_dig` node function.
function xdecor.sit_dig(pos, digger)
if not mod_player_api then
return true
end
for _, player in pairs(minetest.get_objects_inside_radius(pos, 0.1)) do
if player:is_player() and
player_api.player_attached[player:get_player_name()] then
return false
end
local hash = minetest.hash_node_position(pos)
if seats_occupied[hash] then
return false
end
return true
end
-- To be called when a seat (sittable node) got destroyed
-- to clean up state. Precisely, this should be used
-- as the `after_destruct` handler.
function xdecor.sit_destruct(pos)
local hash = minetest.hash_node_position(pos)
local occupier = seats_occupied[hash]
if occupier then
stand_up(occupier)
seats_occupied[hash] = nil
sitting[occupier] = nil
end
end
-- Automatically cause players to stand up if they pressed a control
-- or moved away from the seat
minetest.register_globalstep(function(dtime)
local to_stand_up = {}
for player_name, sitting_pos in pairs(sitting) do
local player = minetest.get_player_by_name(player_name)
if player then
local ctrl = player:get_player_control()
if ctrl.up or ctrl.down or ctrl.left or ctrl.right or ctrl.sneak or ctrl.jump then
table.insert(to_stand_up, player_name)
elseif vector.distance(player:get_pos(), sitting_pos) > 0.55 then
table.insert(to_stand_up, player_name)
end
end
end
for s=1, #to_stand_up do
stand_up(to_stand_up[s])
end
end)
-- Force player to stand on death (to the seat is released)
minetest.register_on_dieplayer(function(player)
local player_name = player:get_player_name()
if sitting[player_name] then
stand_up(player_name)
end
end)
minetest.register_on_leaveplayer(function(player)
local player_name = player:get_player_name()
if sitting[player_name] then
local hash = minetest.hash_node_position(sitting[player_name])
seats_occupied[hash] = nil
sitting[player_name] = nil
end
end)

View File

@ -12,6 +12,7 @@ dofile(modpath .. "/handlers/registration.lua")
dofile(modpath .. "/src/nodes.lua")
dofile(modpath .. "/src/recipes.lua")
-- Load modules that can be enabled and disabled by settings
local subpart = {
"chess",
"cooking",
@ -21,14 +22,23 @@ local subpart = {
"mailbox",
"mechanisms",
"rope",
-- Workbench MUST be loaded after all other subparts that register nodes
-- last for the default 'cut node' registrations to work
"workbench",
}
for _, name in ipairs(subpart) do
local enable = minetest.settings:get_bool("enable_xdecor_" .. name)
if enable or enable == nil then
local enable = minetest.settings:get_bool("enable_xdecor_" .. name, true)
if enable then
dofile(modpath .. "/src/" .. name .. ".lua")
end
end
--print(string.format("[xdecor] loaded in %.2f ms", (os.clock()-t)*1000))
-- Special case: enchanted tools. This code is split from enchanting to
-- deal with loading order.
-- Enchanted tools registered last because they depend on previous
-- subparts
local enable_enchanting = minetest.settings:get_bool("enable_xdecor_enchanting", true)
if enable_enchanting then
dofile(modpath .. "/src/enchanted_tools.lua")
end

View File

@ -1,15 +1,41 @@
# textdomain: xdecor
A libre decoration mod meant to be simple and well-featured.=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Weak Computer=
Weak Computer 1=
Weak Computer 2=
Chess=
Chess Debug=
Select a game mode=
Select a mode:=
Singleplayer=
Multiplayer=
Bot vs Bot=
check=
checkmate=
resigned=
winner=
loser=
draw=
PROMOTION@nFOR BLACK!=
Promote pawn to:=
PROMOTION@nFOR WHITE!=
DRAW CLAIM@nBY WHITE!=
DRAW CLAIM@nBY BLACK!=
The player has invoked the 50-move rule for the next move. The next move might draw the game.=
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=
New game=
Resign=
Select a color:=
White=
Black=
Invoke the 50-move rule for your next move=
Invoke the 50-move rule and draw the game=
Invoke the threefold repetition rule and draw the game=
Invoke the threefold repetition rule for your next move=
You have checkmated @1. You win!=
You were checkmated by @1. You lose!=
The game ended up in a stalemate! It's a draw!=
@ -54,27 +80,6 @@ White Queen=
Black Queen=
White King=
Black King=
Select a game mode=
Select a mode:=
Singleplayer=
Multiplayer=
Bot vs Bot=
PROMOTION@nFOR BLACK!=
Promote pawn to:=
PROMOTION@nFOR WHITE!=
DRAW CLAIM@nBY WHITE!=
DRAW CLAIM@nBY BLACK!=
The player has invoked the 50-move rule for the next move. The next move might draw the game.=
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=
New game=
Resign=
Select a color:=
White=
Black=
Invoke the 50-move rule for your next move=
Invoke the 50-move rule and draw the game=
Invoke the threefold repetition rule and draw the game=
Invoke the threefold repetition rule for your next move=
Light a fire below to heat it up=
Use a bowl to eat the soup=
Drop foods inside to make a soup=
@ -100,40 +105,33 @@ Bowl of soup=
Efficiency=
Durability=
Sharpness=
@1 (+@2%)=
Your weapon inflicts more damage=
Your tool lasts longer=
Your tool digs faster=
Enchantment Table=
Enchant your tools with mese crystals=
Enchanted @1 @2@n@3=
Enchanted @1 @2=
Steel=
Bronze=
Mese=
Diamond=
Axe=
Pickaxe=
Shovel=
Sword=
Your weapon inflicts more damages=
Your tool last longer=
Your tool digs faster=
Artificial Hive=
Bees live here and produce honey=
Honey=
Made by bees=
Enchanted @1@n@2=
Enchanted @1=
The bees are busy making honey.=
The bees are looking for flowers.=
The bees want to pollinate more flowers.=
The bees are idle.=
The bees are resting.=
Artificial Hive=
Bees live here and produce honey=
Honey=
Made by bees=
@1 (owned by @2)=
Item Frame=
For presenting a single item=
@1's Mailbox=
The mailbox is full.=
Mailbox=
Lets other players give you things=
× @1=
Mailbox=
Last donators=
Send your goods to@n@1=
@1's Mailbox=
The mailbox is full.=
Lets other players give you things=
Opens doors when stepped on=
Wooden Pressure Plate=
Stone Pressure Plate=
@ -196,10 +194,6 @@ Television=
Wood Framed Glass=
Radio=
Speaker=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Rope=
Nanoslab=
Micropanel=
@ -211,13 +205,13 @@ Slab=
Double Panel=
Half-Stair=
Stair=
Work Bench=
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Hammer=
Repairs tools at the work bench=
Cut=
Repair=
Crafting=
Storage=
Back=
Work Bench=
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Repairs tools at the work bench=
Hammer=

View File

@ -1,15 +1,41 @@
# textdomain: xdecor
A libre decoration mod meant to be simple and well-featured.=Eine freie simple Dekorationsmod mit netten Features.
@1 Stair=@1treppe
Inner @1 Stair=Innere @1treppe
Outer @1 Stair=Äußere @1treppe
@1 Slab=@1platte
Weak Computer=Schwacher Computer
Weak Computer 1=Schwacher Computer 1
Weak Computer 2=Schwacher Computer 2
Chess=Schach
Chess Debug=Schachdebug
Select a game mode=Wählen Sie einen Spielmodus
Select a mode:=Modus wählen:
Singleplayer=Einzelspieler
Multiplayer=Mehrspieler
Bot vs Bot=Bot vs. Bot
check=Schach
checkmate=Schachmatt
resigned=aufgegeben
winner=Sieger
loser=Verlierer
draw=Remis
PROMOTION@nFOR BLACK!=UMWANDLUNG@nFÜR SCHWARZ!
Promote pawn to:=Bauer umwandeln zu:
PROMOTION@nFOR WHITE!=UMWANDLUNG@nFÜR WEISS!
DRAW CLAIM@nBY WHITE!=REMISANSPRUCH@nVON WEISS!
DRAW CLAIM@nBY BLACK!=REMISANSPRUCH@nVON SCHWARZ!
The player has invoked the 50-move rule for the next move. The next move might draw the game.=Der Spieler will für den nächsten Zug die 50-Züge-Regel anwenden. Der nächste Zug könnte die Partie remis enden lassen.
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=Der Spieler will für den nächsten Zug die Regel für wiederholte Stellungen anwenden. Der nächste Zug könnte die Partie remis enden lassen.
New game=Neues Spiel
Resign=Aufgeben
Select a color:=Farbe wählen:
White=Weiß
Black=Schwarz
Invoke the 50-move rule for your next move=50-Züge-Regel für den nächsten Zug anwenden
Invoke the 50-move rule and draw the game=50-Züge-Regel anwenden und die Partie remis enden lassen
Invoke the threefold repetition rule and draw the game=Stellungswiederholungsregel anwenden und die Partie remis enden lassen
Invoke the threefold repetition rule for your next move=Stellungswiederholungsregel für den nächsten Zug anwenden
You have checkmated @1. You win!=Sie haben @1 schachmatt gesetzt. Sieg!
You were checkmated by @1. You lose!=Sie wurden von @1 schachmatt gesetzt. Niederlage!
The game ended up in a stalemate! It's a draw!=Das Partie endete in einem Patt. Das ist ein Remis!
@ -54,27 +80,6 @@ White Queen=Weiße Dame
Black Queen=Schwarze Dame
White King=Weißer König
Black King=Schwarzer König
Select a game mode=Wählen Sie einen Spielmodus
Select a mode:=Modus wählen:
Singleplayer=Einzelspieler
Multiplayer=Mehrspieler
Bot vs Bot=Bot vs. Bot
PROMOTION@nFOR BLACK!=UMWANDLUNG@nFÜR SCHWARZ!
Promote pawn to:=Bauer umwandeln zu:
PROMOTION@nFOR WHITE!=UMWANDLUNG@nFÜR WEISS!
DRAW CLAIM@nBY WHITE!=REMISANSPRUCH@nVON WEISS!
DRAW CLAIM@nBY BLACK!=REMISANSPRUCH@nVON SCHWARZ!
The player has invoked the 50-move rule for the next move. The next move might draw the game.=Der Spieler will für den nächsten Zug die 50-Züge-Regel anwenden. Der nächste Zug könnte die Partie remis enden lassen.
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=Der Spieler will für den nächsten Zug die Regel für wiederholte Stellungen anwenden. Der nächste Zug könnte die Partie remis enden lassen.
New game=Neues Spiel
Resign=Aufgeben
Select a color:=Farbe wählen:
White=Weiß
Black=Schwarz
Invoke the 50-move rule for your next move=50-Züge-Regel für den nächsten Zug anwenden
Invoke the 50-move rule and draw the game=50-Züge-Regel anwenden und die Partie remis enden lassen
Invoke the threefold repetition rule and draw the game=Stellungswiederholungsregel anwenden und die Partie remis enden lassen
Invoke the threefold repetition rule for your next move=Stellungswiederholungsregel für den nächsten Zug anwenden
Light a fire below to heat it up=Entfachen Sie unten ein Feuer, um ihn zu erhitzen
Use a bowl to eat the soup=Schüssel benutzen, um die Suppe zu essen
Drop foods inside to make a soup=Nahrungsmittel einwerfen, um Suppe zu machen
@ -100,40 +105,33 @@ Bowl of soup=Schüssel mit Suppe
Efficiency=Effizienz
Durability=Haltbarkeit
Sharpness=Schärfe
@1 (+@2%)=@1 (+@2%)
Your weapon inflicts more damage=Ihre Waffe richtet mehr Schaden an
Your tool lasts longer=Ihr Werkzeug hält länger
Your tool digs faster=Ihr Werkzeug arbeitet schneller
Enchantment Table=Zaubertisch
Enchant your tools with mese crystals=Werkzeuge mit Mesekristallen verzaubern
Enchanted @1 @2@n@3=@1@2 (verzaubert)@n@3
Enchanted @1 @2=@1@2 (verzaubert)
Steel=Eisen
Bronze=Bronze
Mese=Mese
Diamond=Diamant
Axe=axt
Pickaxe=spitzhacke
Shovel=schaufel
Sword=schwert
Your weapon inflicts more damages=Ihre Waffe richtet mehr Schaden an
Your tool last longer=Ihr Werkzeug hält länger
Your tool digs faster=Ihr Werkzeug arbeitet schneller
Artificial Hive=Künstlicher Bienenstock
Bees live here and produce honey=Hier leben Bienen, die Honig produzieren
Honey=Honig
Made by bees=Hergestellt von Bienen
Enchanted @1@n@2=@1 (verzaubert)@n@2
Enchanted @1=@1 (verzaubert)
The bees are busy making honey.=Die Bienen sind beschäftigt, Honig herzustellen.
The bees are looking for flowers.=Die Bienen halten nach Blumen Ausschau.
The bees want to pollinate more flowers.=Die Bienen wollen mehr Blumen bestäuben.
The bees are idle.=Die Bienen sind unbeschäftigt.
The bees are resting.=Die Bienen ruhen sich aus.
Artificial Hive=Künstlicher Bienenstock
Bees live here and produce honey=Hier leben Bienen, die Honig produzieren
Honey=Honig
Made by bees=Hergestellt von Bienen
@1 (owned by @2)=@1 (Eigentum von @2)
Item Frame=Gegenstandsrahmen
For presenting a single item=Präsentiert einen einzelnen Gegenstand
@1's Mailbox=Briefkasten von @1
The mailbox is full.=Der Briefkasten ist voll.
Mailbox=Briefkasten
Lets other players give you things=Hiermit kann man von anderen Spielern Dinge erhalten
× @1=× @1
Mailbox=Briefkasten
Last donators=Letzte Spender
Send your goods to@n@1=Senden Sie Ihre Waren an@n@1
@1's Mailbox=Briefkasten von @1
The mailbox is full.=Der Briefkasten ist voll.
Lets other players give you things=Hiermit kann man von anderen Spielern Dinge erhalten
Opens doors when stepped on=Öffnet Türen beim Betreten
Wooden Pressure Plate=Holzdruckplatte
Stone Pressure Plate=Steindruckplatte
@ -196,10 +194,6 @@ Television=Fernseher
Wood Framed Glass=Holzrahmenglas
Radio=Radio
Speaker=Lautsprecher
@1 Stair=@1treppe
Inner @1 Stair=Innere @1treppe
Outer @1 Stair=Äußere @1treppe
@1 Slab=@1platte
Rope=Seil
Nanoslab=nanoplatte
Micropanel=mikropaneel
@ -211,13 +205,13 @@ Slab=platte
Double Panel=doppelpaneel
Half-Stair=halbtreppe
Stair=Treppe
Work Bench=Werkbank
For cutting blocks, repairing tools with a hammer, crafting and storing items=Für Blockzuschnitt, Werkzeugreparatur mit Hammer, Fertigung und Lagerung
@1 @2=@1@2
Hammer=Hammer
Repairs tools at the work bench=Repariert Werkzeuge an der Werkbank
Cut=Zuschnitt
Repair=Reparatur
Crafting=Fertigung
Storage=Lager
Back=Zurück
Work Bench=Werkbank
For cutting blocks, repairing tools with a hammer, crafting and storing items=Für Blockzuschnitt, Werkzeugreparatur mit Hammer, Fertigung und Lagerung
@1 @2=@1@2
Repairs tools at the work bench=Repariert Werkzeuge an der Werkbank
Hammer=Hammer

View File

@ -1,15 +1,41 @@
# textdomain: xdecor
A libre decoration mod meant to be simple and well-featured.=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Weak Computer=
Weak Computer 1=
Weak Computer 2=
Chess=Echecs
Chess Debug=
Select a game mode=
Select a mode:=Sélectionnez un mode de jeu:
Singleplayer=Solo
Multiplayer=Multijoueur
Bot vs Bot=
check=échec
checkmate=
resigned=
winner=
loser=
draw=
PROMOTION@nFOR BLACK!=
Promote pawn to:=
PROMOTION@nFOR WHITE!=
DRAW CLAIM@nBY WHITE!=
DRAW CLAIM@nBY BLACK!=
The player has invoked the 50-move rule for the next move. The next move might draw the game.=
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=
New game=Nouvelle partie
Resign=
Select a color:=
White=
Black=
Invoke the 50-move rule for your next move=
Invoke the 50-move rule and draw the game=
Invoke the threefold repetition rule and draw the game=
Invoke the threefold repetition rule for your next move=
You have checkmated @1. You win!=
You were checkmated by @1. You lose!=
The game ended up in a stalemate! It's a draw!=
@ -54,27 +80,6 @@ White Queen=Reine blanche
Black Queen=Reine noire
White King=Roi blanc
Black King=Roi noir
Select a game mode=
Select a mode:=Sélectionnez un mode de jeu:
Singleplayer=Solo
Multiplayer=Multijoueur
Bot vs Bot=
PROMOTION@nFOR BLACK!=
Promote pawn to:=
PROMOTION@nFOR WHITE!=
DRAW CLAIM@nBY WHITE!=
DRAW CLAIM@nBY BLACK!=
The player has invoked the 50-move rule for the next move. The next move might draw the game.=
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=
New game=Nouvelle partie
Resign=
Select a color:=
White=
Black=
Invoke the 50-move rule for your next move=
Invoke the 50-move rule and draw the game=
Invoke the threefold repetition rule and draw the game=
Invoke the threefold repetition rule for your next move=
Light a fire below to heat it up=
Use a bowl to eat the soup=Utilisez un bol pour boire la soupe
Drop foods inside to make a soup=Placez des ingrédients à lintérieur pour faire une soupe
@ -100,40 +105,33 @@ Bowl of soup=Bol de soupe
Efficiency=Efficacité
Durability=Durabilité
Sharpness=Tranchant
@1 (+@2%)=
Your weapon inflicts more damage=Votre arme inflige plus de dégâts
Your tool lasts longer=Votre outil dure plus longtemps
Your tool digs faster=Votre outil creuse plus vite
Enchantment Table=Table denchantements
Enchant your tools with mese crystals=
Enchanted @1 @2@n@3=@2 en @1 enchantée@n@3
Enchanted @1 @2=@2 en @1 enchantée
Steel=Fer
Bronze=Bronze
Mese=Mese
Diamond=Diamant
Axe=Hache
Pickaxe=Pioche
Shovel=Pelle
Sword=Épée
Your weapon inflicts more damages=Votre arme inflige plus de dégâts
Your tool last longer=Votre outil dure plus longtemps
Your tool digs faster=Votre outil creuse plus vite
Artificial Hive=Ruche artificielle
Bees live here and produce honey=
Honey=Miel
Made by bees=
Enchanted @1@n@2=
Enchanted @1=
The bees are busy making honey.=
The bees are looking for flowers.=
The bees want to pollinate more flowers.=
The bees are idle.=
The bees are resting.=
Artificial Hive=Ruche artificielle
Bees live here and produce honey=
Honey=Miel
Made by bees=
@1 (owned by @2)=@1 (propriété de @2)
Item Frame=Cadre
For presenting a single item=
@1's Mailbox=Boite aux lettres de @1
The mailbox is full.=La boite aux lettres est pleine.
Mailbox=Boite aux lettres
Lets other players give you things=
× @1=
Mailbox=Boite aux lettres
Last donators=Derniers donateurs
Send your goods to@n@1=Envoyer vos biens à@n@1
@1's Mailbox=Boite aux lettres de @1
The mailbox is full.=La boite aux lettres est pleine.
Lets other players give you things=
Opens doors when stepped on=
Wooden Pressure Plate=Plaque de pression en bois
Stone Pressure Plate=Plaque de pression en pierre
@ -196,10 +194,6 @@ Television=Télévision
Wood Framed Glass=Verre encadré par du bois
Radio=
Speaker=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Rope=Corde
Nanoslab=
Micropanel=
@ -211,21 +205,22 @@ Slab=
Double Panel=
Half-Stair=
Stair=
Work Bench=Atelier
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Hammer=Marteau
Repairs tools at the work bench=
Cut=Couper
Repair=Réparer
Crafting=Fabrication
Storage=Stockage
Back=Retour
Work Bench=Atelier
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Repairs tools at the work bench=
Hammer=Marteau
##### not used anymore #####
Dumb AI=IA stupide
Enchanted @1 @2@n@3=@2 en @1 enchantée@n@3
Enchanted @1 @2=@2 en @1 enchantée
You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1=Vous ne pouvez pas mettre à zéro léchiquier, une partie a été commencée. Si ce nest pas votre tour de jouer, réessayez dans @1
You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1=Vous ne pouvez pas récupérer léchiquier, une partie à été commencée. Remettez le à zéro si vous cest votre tour de jouer, ou réessayez dans @1
Cauldron (idle)=Chaudron (inactif)

View File

@ -1,47 +1,75 @@
# textdomain: xdecor
Weak Computer=
Weak Computer 1=
Weak Computer 2=
# author: Zughy (chess)
# Nota per chi traduce: ho usato italiano inclusivo (ə per il singolare) e usato il participio presente per giocatore e spettatore (=giocante e osservante) come esperimento di inclusività. Per gli apostrofi ho usato ` (un - un' -> un`)
A libre decoration mod meant to be simple and well-featured.=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Weak Computer=Computer facile
Weak Computer 1=Computer facile 1
Weak Computer 2=Computer facile 2
Chess=Scacchi
Chess Debug=
Chess Debug=Debug scacchi
Select a game mode=Seleziona modalità di gioco
Select a mode:=Seleziona una modalità:
Singleplayer=Giocante singolə
Multiplayer=Multigiocante
Bot vs Bot=Bot contro Bot
check=scacco
checkmate=
resigned=
winner=
loser=
draw=
You have checkmated @1. You win!=
You were checkmated by @1. You lose!=
The game ended up in a stalemate! It's a draw!=
The game ended up in a dead position! It's a draw!=
No piece was captured and no pawn was moved for 75 consecutive moves of each player. It's a draw!=
You have drawn the game by invoking the 50-move rule.=
@1 has drawn the game by invoking the 50-move rule.=
You have failed to make a game-drawing move. The game continues.=
@1 made a draw claim using the 50-move rule but it was false. The game continues.=
The exact same position has occured 5 times. It's a draw!=
You have drawn the game by invoking the threefold repetition rule.=
@1 has drawn the game by invoking the threefold repetition rule.=
@1 made a draw claim using the threefold repetition rule but it was false. The game continues.=
checkmate=scacco matto
resigned=arresə
winner=vince
loser=perde
draw=patta
PROMOTION@nFOR BLACK!=PROMOZIONE@nPER IL NERO!
Promote pawn to:=Promuovi pedone a:
PROMOTION@nFOR WHITE!=PROMOZIONE@nPER IL BIANCO!
DRAW CLAIM@nBY WHITE!=PATTA DICHIARATA@nDAL BIANCO!
DRAW CLAIM@nBY BLACK!=PATTA DICHIARATA@nDAL NERO!
The player has invoked the 50-move rule for the next move. The next move might draw the game.=Lə giocante ha invocato la regola delle 50 mosse per la prossima mossa. Quest'ultima potrebbe portare a una patta.
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=Lə giocante ha invocato la regola della tripla ripetizione per la prossima mossa. Quest'ultima potrebbe portare a una patta
New game=Nuova partita
Resign=Arrenditi
Select a color:=Seleziona un colore:
White=Bianco
Black=Nero
Invoke the 50-move rule for your next move=Invoca la regola delle 50 mosse per la tua prossima mossa
Invoke the 50-move rule and draw the game=Invoca la regola delle 50 mosse e chiudi in patta
Invoke the threefold repetition rule and draw the game=Invoca la regola della tripla ripetizione e chiudi in patta
Invoke the threefold repetition rule for your next move=Invoca la regola della tripla ripetizione per la tua prossima mossa
You have checkmated @1. You win!=Scacco matto a @1. Hai vinto!
You were checkmated by @1. You lose!=Scacco matto da @1. Hai perso!
The game ended up in a stalemate! It's a draw!=È uno stallo! Patta!
The game ended up in a dead position! It's a draw!=È una posizione morta! Patta!
No piece was captured and no pawn was moved for 75 consecutive moves of each player. It's a draw!=Nessun giocante ha catturato pezzi né mosso pedoni per 75 mosse consecutive. Patta!
You have drawn the game by invoking the 50-move rule.=Hai chiuso in patta con l'invocazione della regola delle 50 mosse.
@1 has drawn the game by invoking the 50-move rule.=@1 ha chiuso in patta con l'invocazione della regola delle 50 mosse.
You have failed to make a game-drawing move. The game continues.=Non sei riuscitə a fare una mossa che portasse a una patta. Il gioco continua.
@1 made a draw claim using the 50-move rule but it was false. The game continues.=@1 ha tentato la patta con la regola delle 50 mosse ma ha fallito. La partita continua.
The exact same position has occured 5 times. It's a draw!=La stessa identica mossa si è ripetuta per 5 volte. Patta!
You have drawn the game by invoking the threefold repetition rule.=Hai chiuso in patta con l'invocazione della regola della tripla ripetizione.
@1 has drawn the game by invoking the threefold repetition rule.=@1 ha chiuso in patta con l'invocazione della regola della tripla ripetizione.
@1 made a draw claim using the threefold repetition rule but it was false. The game continues.=@1 ha tentato la patta con la regola della tripla ripetizione ma ha fallito. La partita continua.
Chess Board=Scacchiera
Someone else plays white pieces!=Qualcun altro gioca con il bianco!
It's not your turn!=
Someone else plays black pieces!=Qualcun altro gioca con il nero!
Black cannot move first!=
@1 s=
@1 min @2 s=
You can't reset the chessboard, a game has been started. Try again in @1.=
Resigning is not possible yet.=
You have resigned.=
@1 has resigned. You win!=
You can't resign, you're not playing in this game.=
You can't claim a draw, it's not your turn!=
You're only a spectator in this game of Chess.=
This isn't the time for promotion.=
It's not your turn! This promotion is meant for the other player.=
You can't dig the chessboard, a game has been started. Reset it first or dig it again in @1.=
You can't dig the chessboard, a game has been started. Try it again in @1.=
Play a game of Chess against another player or the computer=
Someone else plays white pieces!=Qualcun`altrə sta già giocando con il bianco!
It's not your turn!=Non è il tuo turno!
Someone else plays black pieces!=Qualcun`altrə sta già giocando con il nero!
Black cannot move first!=Il nero non può muovere per primo!
@1 s=@1 s
@1 min @2 s=@1 min @2 s
You can't reset the chessboard, a game has been started. Try again in @1.=Non puoi ripristinare la scacchiera, c'è una partita in corso. Riprova tra @1.
Resigning is not possible yet.=Non ci si può ancora arrendere.
You have resigned.=Ti sei arresə.
@1 has resigned. You win!=@1 si è arresə. Hai vinto!
You can't resign, you're not playing in this game.=Non ti puoi arrendere, non stai giocando in questa partita.
You can't claim a draw, it's not your turn!=Non puoi chiamare patta, non è il tuo turno!
You're only a spectator in this game of Chess.=Sei solo un`osservante in questa partita di scacchi.
This isn't the time for promotion.=Non è il momento per una promozione.
It's not your turn! This promotion is meant for the other player.=Non è il tuo turno! Questa promozione spetta all'altrə giocante.
You can't dig the chessboard, a game has been started. Reset it first or dig it again in @1.=Non puoi rimuovere la scacchiera, c'è una partita in corso. Ripristinala prima, o riprova a rimuoverla in @1.
You can't dig the chessboard, a game has been started. Try it again in @1.=Non puoi rimuovere la scacchiera, c'è una partita in corso. Riprova tra @1.
Play a game of Chess against another player or the computer=Gioca una partita a scacchi contro un`altrə giocante o contro il computer
White Pawn=Pedone bianco
Black Pawn=Pedone nero
White Rook=Torre bianca
@ -54,27 +82,6 @@ White Queen=Regina bianca
Black Queen=Regina nera
White King=Re bianco
Black King=Re nero
Select a game mode=
Select a mode:=Selezionare una modalità
Singleplayer=Singolo giocatore
Multiplayer=Multigiocatore
Bot vs Bot=
PROMOTION@nFOR BLACK!=
Promote pawn to:=
PROMOTION@nFOR WHITE!=
DRAW CLAIM@nBY WHITE!=
DRAW CLAIM@nBY BLACK!=
The player has invoked the 50-move rule for the next move. The next move might draw the game.=
The player has invoked the threefold-repetition rule for the next move. The next move might draw the game.=
New game=Nuova partita
Resign=
Select a color:=
White=
Black=
Invoke the 50-move rule for your next move=
Invoke the 50-move rule and draw the game=
Invoke the threefold repetition rule and draw the game=
Invoke the threefold repetition rule for your next move=
Light a fire below to heat it up=
Use a bowl to eat the soup=Utilizzare una ciotola per mangiare la zuppa
Drop foods inside to make a soup=Mettere gli ingredienti all'interno per fare una zuppa
@ -100,40 +107,33 @@ Bowl of soup=Ciotola di zuppa
Efficiency=Efficacia
Durability=Durabilità
Sharpness=Affilatezza
@1 (+@2%)=
Your weapon inflicts more damage=La tua arma infligge più danno
Your tool lasts longer=Il tuo utensile dura di più
Your tool digs faster=Il tuo utensile scava più rapidamente
Enchantment Table=Tavolo per migliorie
Enchant your tools with mese crystals=
Enchanted @1 @2@n@3=@2 su @1 incantesimo@n@3
Enchanted @1 @2=@2 su @1 incantesimo
Steel=Acciaio
Bronze=Bronzo
Mese=Mese
Diamond=Diamante
Axe=Ascia
Pickaxe=Piccone
Shovel=Pala
Sword=Spada
Your weapon inflicts more damages=La tua arma infligge più danno
Your tool last longer=Il tuo utensile dura di più
Your tool digs faster=Il tuo utensile scava più rapidamente
Artificial Hive=Favo artificiale
Bees live here and produce honey=
Honey=Miele
Made by bees=
Enchanted @1@n@2=
Enchanted @1=
The bees are busy making honey.=
The bees are looking for flowers.=
The bees want to pollinate more flowers.=
The bees are idle.=
The bees are resting.=
Artificial Hive=Favo artificiale
Bees live here and produce honey=
Honey=Miele
Made by bees=
@1 (owned by @2)=@1 (proprietà di @2)
Item Frame=Teca
For presenting a single item=
@1's Mailbox=Cassetta delle lettere di @1
The mailbox is full.=La cassetta delle lettere è piena
Mailbox=Cassetta delle lettere
Lets other players give you things=
× @1=
Mailbox=Cassetta delle lettere
Last donators=Ultimi donatori
Send your goods to@n@1=Invia i tuoi item a@n@1
@1's Mailbox=Cassetta delle lettere di @1
The mailbox is full.=La cassetta delle lettere è piena
Lets other players give you things=
Opens doors when stepped on=
Wooden Pressure Plate=Placca di pressione di legno
Stone Pressure Plate=Placca di pressione di pietra
@ -196,10 +196,6 @@ Television=Televisione
Wood Framed Glass=Cornice in legno con vetro
Radio=
Speaker=
@1 Stair=
Inner @1 Stair=
Outer @1 Stair=
@1 Slab=
Rope=Corda
Nanoslab=
Micropanel=
@ -211,23 +207,22 @@ Slab=
Double Panel=
Half-Stair=
Stair=
Work Bench=Banco da lavoro
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Hammer=Martello
Repairs tools at the work bench=
Cut=Tagliare
Repair=Riparare
Crafting=Fabbricare
Storage=Conservare
Back=Indietro
Work Bench=Banco da lavoro
For cutting blocks, repairing tools with a hammer, crafting and storing items=
@1 @2=
Repairs tools at the work bench=
Hammer=Martello
##### not used anymore #####
Dumb AI=AI stupida
You can't reset the chessboard, a game has been started. If you aren't a current player, try again in @1=Non si può resettare la partita, un gioco è in corso. Se non si è uno dei giocatori, riprovare in @1
You can't dig the chessboard, a game has been started. Reset it first if you're a current player, or dig it again in @1=Non si può scavare la scacchiera, una partita è in corso. Resettarla se si è uno dei giocatori, o riprovare in @1
Enchanted @1 @2@n@3=@2 su @1 incantesimo@n@3
Enchanted @1 @2=@2 su @1 incantesimo
Cauldron (idle)=Calderone (inattivo)
Cauldron (active) - Drop foods inside to make a soup=Calderone (attivo) - Mettere gli ingredienti all'interno per fare una zuppa.
Cauldron (active) - Use a bowl to eat the soup=Calderone (actif) - Utilizzare una ciotola per mangiare la zuppa

View File

@ -1,6 +1,6 @@
name = xdecor
title = X-Decor-libre
description = A decoration mod meant to be simple and well-featured (libre version).
description = A libre decoration mod meant to be simple and well-featured.
depends = default, bucket, doors, farming, stairs, xpanes
optional_depends = playerphysics, player_api, fire, moreblocks, mesecons, unified_inventory, tt
min_minetest_version = 5.7.0
optional_depends = player_api, fire, moreblocks, mesecons, unified_inventory, tt, toolranks
min_minetest_version = 5.9

View File

@ -327,11 +327,10 @@ local function en_passant_to_string(double_step)
return s_en_passant
end
local function can_castle(meta, board, from_list, from_idx, to_idx)
local function can_castle(board, from_idx, to_idx, castlingRights)
local from_x, from_y = index_to_xy(from_idx)
local to_x, to_y = index_to_xy(to_idx)
local inv = meta:get_inventory()
local kingPiece = inv:get_stack(from_list, from_idx):get_name()
local kingPiece = board[from_idx]
local kingColor
if kingPiece:find("black") then
kingColor = "black"
@ -340,21 +339,21 @@ local function can_castle(meta, board, from_list, from_idx, to_idx)
end
local possible_castles = {
-- white queenside
{ y = 7, to_x = 2, rook_idx = 57, rook_goal = 60, acheck_dir = -1, color = "white", meta = "castlingWhiteL", rook_id = 1 },
{ y = 7, to_x = 2, rook_idx = 57, rook_goal = 60, acheck_dir = -1, color = "white", rightName = "castlingWhiteL", rook_id = 1 },
-- white kingside
{ y = 7, to_x = 6, rook_idx = 64, rook_goal = 62, acheck_dir = 1, color = "white", meta = "castlingWhiteR", rook_id = 2 },
{ y = 7, to_x = 6, rook_idx = 64, rook_goal = 62, acheck_dir = 1, color = "white", rightName = "castlingWhiteR", rook_id = 2 },
-- black queenside
{ y = 0, to_x = 2, rook_idx = 1, rook_goal = 4, acheck_dir = -1, color = "black", meta = "castlingBlackL", rook_id = 1 },
{ y = 0, to_x = 2, rook_idx = 1, rook_goal = 4, acheck_dir = -1, color = "black", rightName = "castlingBlackL", rook_id = 1 },
-- black kingside
{ y = 0, to_x = 6, rook_idx = 8, rook_goal = 6, acheck_dir = 1, color = "black", meta = "castlingBlackR", rook_id = 2 },
{ y = 0, to_x = 6, rook_idx = 8, rook_goal = 6, acheck_dir = 1, color = "black", rightName = "castlingBlackR", rook_id = 2 },
}
for p=1, #possible_castles do
local pc = possible_castles[p]
if pc.color == kingColor and pc.to_x == to_x and to_y == pc.y and from_y == pc.y then
local castlingMeta = meta:get_int(pc.meta)
local rookPiece = inv:get_stack(from_list, pc.rook_idx):get_name()
if castlingMeta == 1 and rookPiece == "realchess:rook_"..kingColor.."_"..pc.rook_id then
local castlingRightVal = castlingRights[pc.rightName]
local rookPiece = board[pc.rook_idx]
if castlingRightVal == 1 and rookPiece == "realchess:rook_"..kingColor.."_"..pc.rook_id then
-- Check if all squares between king and rook are empty
local empty_start, empty_end
if pc.acheck_dir == -1 then
@ -367,7 +366,7 @@ local function can_castle(meta, board, from_list, from_idx, to_idx)
empty_end = pc.rook_idx - 1
end
for i = empty_start, empty_end do
if inv:get_stack(from_list, i):get_name() ~= "" then
if board[i] ~= "" then
return false
end
end
@ -389,15 +388,15 @@ end
-- Checks if a square to check if there is a piece that can be captured en passant. Returns true if this
-- is the case, false otherwise.
-- Parameters:
-- * meta: chessboard node metadata
-- * board: chessboard table
-- * victim_color: color of the opponent to capture a piece from. "white" or "black". (so in White's turn, pass "black" here)
-- * victim_index: board index of the square where you expect the victim to be
local function can_capture_en_passant(meta, victim_color, victim_index)
local inv = meta:get_inventory()
local victimPiece = inv:get_stack("board", victim_index)
local double_step_index = meta:get_int("prevDoublePawnStepTo")
local victim_name = victimPiece:get_name()
if double_step_index ~= 0 and double_step_index == victim_index and victim_name:find(victim_color) and victim_name:sub(11,14) == "pawn" then
-- * prevDoublePawnStepTo: if a pawn did a double-step in the previous halfmove, this is the board index of the destination.
-- if no pawn made a double-step in the previous halfmove, this is nil or 0.
local function can_capture_en_passant(board, victim_color, victim_index, prevDoublePawnStepTo)
local victimPiece = board[victim_index]
local double_step_index = prevDoublePawnStepTo or 0
if double_step_index ~= 0 and double_step_index == victim_index and victimPiece:find(victim_color) and victimPiece:sub(11,14) == "pawn" then
return true
end
return false
@ -413,7 +412,7 @@ end
-- Any key with a numeric value is a possible destination.
-- The numeric value is a move rating for the bot and is 0 by default.
-- Example: { [4] = 0, [9] = 0 } -- can move to squares 4 and 9
local function get_theoretical_moves_from(meta, board, from_idx)
local function get_theoretical_moves_from(board, from_idx, prevDoublePawnStepTo, castlingRights)
local piece, color = board[from_idx]:match(":(%w+)_(%w+)")
if not piece then
return {}
@ -450,7 +449,7 @@ local function get_theoretical_moves_from(meta, board, from_idx)
can_capture = true
else
-- en passant
if can_capture_en_passant(meta, "black", xy_to_index(to_x, from_y)) then
if can_capture_en_passant(board, "black", xy_to_index(to_x, from_y), prevDoublePawnStepTo) then
can_capture = true
en_passant = true
end
@ -505,7 +504,7 @@ local function get_theoretical_moves_from(meta, board, from_idx)
can_capture = true
else
-- en passant
if can_capture_en_passant(meta, "white", xy_to_index(to_x, from_y)) then
if can_capture_en_passant(board, "white", xy_to_index(to_x, from_y), prevDoublePawnStepTo) then
can_capture = true
en_passant = true
end
@ -783,11 +782,10 @@ local function get_theoretical_moves_from(meta, board, from_idx)
-- KING
elseif piece == "king" then
local inv = meta:get_inventory()
-- King can't move to any attacked square
-- king_board simulates the board with the king moved already.
-- Required for the attacked() check to work
local king_board = realchess.board_to_table(inv)
local king_board = table.copy(board)
king_board[to_idx] = king_board[from_idx]
king_board[from_idx] = ""
if realchess.attacked(color, to_idx, king_board) then
@ -805,7 +803,7 @@ local function get_theoretical_moves_from(meta, board, from_idx)
end
if dx > 1 or dy > 1 then
local cc = can_castle(meta, board, "board", from_idx, to_idx)
local cc = can_castle(board, from_idx, to_idx, castlingRights)
if not cc then
moves[to_idx] = nil
end
@ -847,10 +845,10 @@ end
-- origin_index is the board index for the square to start the piece from (as string)
-- and this is the key for a list of destination indixes.
-- r1, r2, r3 ... are numeric values (normally 0) to "rate" this square for the bot.
function realchess.get_theoretical_moves_for(meta, board, player)
function realchess.get_theoretical_moves_for(board, player, prevDoublePawnStepTo, castlingRights)
local moves = {}
for i = 1, 64 do
local possibleMoves = get_theoretical_moves_from(meta, board, i)
local possibleMoves = get_theoretical_moves_from(board, i, prevDoublePawnStepTo, castlingRights)
if next(possibleMoves) then
local stack_name = board[i]
if stack_name:find(player) then
@ -1089,7 +1087,11 @@ end
local function get_figurine_id(piece_itemname)
local piece_s = piece_itemname:match(":(%w+_%w+)")
return figurines_str:match("(%d+)=chess_figurine_" .. piece_s)
if not piece_s then
return MOVES_LIST_SYMBOL_EMPTY
else
return figurines_str:match("(%d+)=chess_figurine_" .. piece_s)
end
end
@ -1678,17 +1680,17 @@ local function update_formspec(meta)
local turnWhite = minetest.colorize("#000001", playerWhiteDisplay)
-- several status words for the player
-- player is in check
--~ Chess: player is in check
local check_s = minetest.colorize("#FF8000", "["..S("check").."]")
-- player has been checkmated
--~ Chess: player has been checkmated
local mate_s = minetest.colorize("#FF0000", "["..S("checkmate").."]")
-- player has resigned
--~ Chess: player has resigned
local resign_s = minetest.colorize("#FF0000", "["..S("resigned").."]")
-- player has won
--~ Chess: player has won
local win_s = minetest.colorize("#26AB2B", "["..S("winner").."]")
-- player has lost
--~ Chess: player has lost
local lose_s = minetest.colorize("#FF0000", "["..S("loser").."]")
-- player has a draw
--~ Chess: player has a draw
local draw_s = minetest.colorize("#FF00FF", "["..S("draw").."]")
local status_black = ""
@ -1733,6 +1735,7 @@ local function update_formspec(meta)
if promotion == "black" then
eaten_img = ""
promotion_formstring =
--~ Chess: Shown when black player can promote a pawn. Space for text is limited.
"label[10.1,6.35;"..FS("PROMOTION\nFOR BLACK!").."]" ..
"animated_image[10.05,7.2;2,2;p_img_white;pawn_black_promo_anim.png;5;100]"
if botColor ~= "black" and botColor ~= "both" then
@ -1748,6 +1751,7 @@ local function update_formspec(meta)
elseif promotion == "white" then
eaten_img = ""
promotion_formstring =
--~ Chess: Shown when white player can promote a pawn. Space for text is limited.
"label[10.1,6.35;"..FS("PROMOTION\nFOR WHITE!").."]" ..
"animated_image[10.05,7.2;2,2;p_img_white;pawn_white_promo_anim.png;5;100]"
if botColor ~= "white" and botColor ~= "both" then
@ -1765,8 +1769,10 @@ local function update_formspec(meta)
local draw_claim_formstring = ""
if drawClaim ~= "" and gameResult == "" then
if lastMove == "black" or lastMove == "" then
--~ Chess: Shown when white player wants to claim a draw. Space for text is limited.
draw_claim_formstring = "label[10.1,6.35;"..FS("DRAW CLAIM\nBY WHITE!").."]"
else
--~ Chess: Shown when black player wants to claim a draw. Space for text is limited.
draw_claim_formstring = "label[10.1,6.35;"..FS("DRAW CLAIM\nBY BLACK!").."]"
end
if drawClaim == "50_move_rule" then
@ -1790,6 +1796,7 @@ local function update_formspec(meta)
if playerActionsAvailable and (playerWhite ~= "" and playerBlack ~= "") then
game_buttons = game_buttons .. "image_button[14.56,9.7;0.8,0.8;chess_resign.png;resign;]" ..
--~ Resign in Chess
"tooltip[resign;"..FS("Resign").."]"
end
@ -1810,12 +1817,14 @@ local function update_formspec(meta)
-- Will trigger "draw claim" mode in which player must do the final move that triggers the draw
game_buttons = game_buttons .. "image_button[13.36,9.7;0.8,0.8;chess_draw_50move_next.png;draw_50_moves;]"..
"tooltip[draw_50_moves;"..
--~ Chess
FS("Invoke the 50-move rule for your next move").."]"
elseif halfmoveClock >= DRAWCLAIM_LONGGAME_PLAYER then
-- When the 50 moves without capture / pawn move have occured occur.
-- Will insta-draw.
game_buttons = game_buttons .. "image_button[13.36,9.7;0.8,0.8;chess_draw_50move.png;draw_50_moves;]"..
"tooltip[draw_50_moves;"..
--~ Chess
FS("Invoke the 50-move rule and draw the game").."]"
end
@ -1828,12 +1837,14 @@ local function update_formspec(meta)
-- Will insta-draw.
game_buttons = game_buttons .. "image_button[12.36,9.7;0.8,0.8;chess_draw_repeat3.png;draw_repeat_3;]"..
"tooltip[draw_repeat_3;"..
--~ Chess
FS("Invoke the threefold repetition rule and draw the game").."]"
elseif maxRepeatedPositions >= 2 then
-- If the same position may be about to occur 3 times.
-- Will trigger "draw claim" mode in which player must do the final move that triggers the draw.
game_buttons = game_buttons .. "image_button[12.36,9.7;0.8,0.8;chess_draw_repeat3_next.png;draw_repeat_3;]"..
"tooltip[draw_repeat_3;"..
--~ Chess
FS("Invoke the threefold repetition rule for your next move").."]"
end
end
@ -1893,19 +1904,26 @@ local function update_formspec(meta)
meta:set_string("formspec", formspec)
end
local function update_game_result(meta)
local function update_game_result(meta, lastMove)
local inv = meta:get_inventory()
local board_t = realchess.board_to_table(inv)
local playerWhite = meta:get_string("playerWhite")
local playerBlack = meta:get_string("playerBlack")
local prevDoublePawnStepTo = meta:get_int("prevDoublePawnStepTo")
local castlingRights = {
castlingWhiteR = meta:get_int("castlingWhiteR"),
castlingWhiteL = meta:get_int("castlingWhiteL"),
castlingBlackR = meta:get_int("castlingBlackR"),
castlingBlackL = meta:get_int("castlingBlackL"),
}
update_formspec(meta)
local blackCanMove = false
local whiteCanMove = false
local blackMoves = realchess.get_theoretical_moves_for(meta, board_t, "black")
local whiteMoves = realchess.get_theoretical_moves_for(meta, board_t, "white")
local blackMoves = realchess.get_theoretical_moves_for(board_t, "black", prevDoublePawnStepTo, castlingRights)
local whiteMoves = realchess.get_theoretical_moves_for(board_t, "white", prevDoublePawnStepTo, castlingRights)
if next(blackMoves) then
blackCanMove = true
end
@ -1913,9 +1931,6 @@ local function update_game_result(meta)
whiteCanMove = true
end
-- assume lastMove was updated *after* the player moved
local lastMove = meta:get_string("lastMove")
local black_king_idx, white_king_idx = realchess.locate_kings(board_t)
if not black_king_idx or not white_king_idx then
minetest.log("error", "[xdecor] Chess: Insufficient kings on chessboard!")
@ -1968,6 +1983,7 @@ local function update_game_result(meta)
meta:set_string("gameResult", "draw")
meta:set_string("gameResultReason", "stalemate")
add_special_to_moves_list(meta, "draw")
--~ Chess message
send_message_2(playerWhite, playerBlack, S("The game ended up in a stalemate! It's a draw!"), botColor)
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw by stalemate")
return
@ -1988,6 +2004,7 @@ local function update_game_result(meta)
meta:set_string("gameResult", "draw")
meta:set_string("gameResultReason", "stalemate")
add_special_to_moves_list(meta, "draw")
--~ Chess message
send_message_2(playerWhite, playerBlack, S("The game ended up in a stalemate! It's a draw!"), botColor)
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw by stalemate")
return
@ -1999,6 +2016,7 @@ local function update_game_result(meta)
meta:set_string("gameResult", "draw")
meta:set_string("gameResultReason", "dead_position")
add_special_to_moves_list(meta, "draw")
--~ Chess message
send_message_2(playerWhite, playerBlack, S("The game ended up in a dead position! It's a draw!"), botColor)
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw by dead position")
end
@ -2114,6 +2132,7 @@ local function update_game_result(meta)
meta:set_string("gameResult", "draw")
meta:set_string("gameResultReason", "same_position_5")
add_special_to_moves_list(meta, "draw")
--~ Chess message when the fivefold repetition has happened
local msg = S("The exact same position has occured 5 times. It's a draw!")
send_message_2(playerWhite, playerBlack, msg, botColor)
minetest.log("action", "[xdecor] Chess: A game between "..playerWhite.." and "..playerBlack.." ended in a draw because the same position has appeared 5 times")
@ -2233,6 +2252,7 @@ function realchess.move(meta, from_list, from_index, to_list, to_index, playerNa
local lastMove = meta:get_string("lastMove")
local playerWhite = meta:get_string("playerWhite")
local playerBlack = meta:get_string("playerBlack")
local prevDoublePawnStepTo = meta:get_int("prevDoublePawnStepTo")
local kingMoved = false
local thisMove -- Will replace lastMove when move is legal
@ -2349,7 +2369,8 @@ function realchess.move(meta, from_list, from_index, to_list, to_index, playerNa
can_capture = true
else
-- en passant
if can_capture_en_passant(meta, "black", xy_to_index(to_x, from_y)) then
local board = realchess.board_to_table(inv)
if can_capture_en_passant(board, "black", xy_to_index(to_x, from_y), prevDoublePawnStepTo) then
can_capture = true
en_passant_target = xy_to_index(to_x, from_y)
end
@ -2417,7 +2438,8 @@ function realchess.move(meta, from_list, from_index, to_list, to_index, playerNa
can_capture = true
else
-- en passant
if can_capture_en_passant(meta, "white", xy_to_index(to_x, from_y)) then
local board = realchess.board_to_table(inv)
if can_capture_en_passant(board, "white", xy_to_index(to_x, from_y), prevDoublePawnStepTo) then
can_capture = true
en_passant_target = xy_to_index(to_x, from_y)
end
@ -2669,9 +2691,15 @@ function realchess.move(meta, from_list, from_index, to_list, to_index, playerNa
local check = true
local inv = meta:get_inventory()
local board = realchess.board_to_table(inv)
local castlingRights = {
castlingWhiteR = meta:get_int("castlingWhiteR"),
castlingWhiteL = meta:get_int("castlingWhiteL"),
castlingBlackR = meta:get_int("castlingBlackR"),
castlingBlackL = meta:get_int("castlingBlackL"),
}
-- Castling
local cc, rook_start, rook_goal, rook_name = can_castle(meta, board, from_list, from_index, to_index)
local cc, rook_start, rook_goal, rook_name = can_castle(board, from_index, to_index, castlingRights)
if cc then
inv:set_stack(from_list, rook_goal, rook_name)
inv:set_stack(from_list, rook_start, "")
@ -2799,11 +2827,11 @@ local function timeout_format(timeout_limit)
local seconds = time_remaining % 60
if minutes == 0 then
-- number of seconds
--~ number of seconds
return S("@1 s", seconds)
end
-- number of minutes and seconds
--~ number of minutes and seconds
return S("@1 min @2 s", minutes, seconds)
end
@ -2885,6 +2913,7 @@ function realchess.fields(pos, _, fields, sender)
local lastMove = meta:get_string("lastMove")
if (playerName == playerWhite and playerWhite == "") or (playerName == playerBlack and playerBlack == "") then
-- Can't resign before the player name has been recorded
--~ Chess message when player tried to resign too early
send_message(playerName, S("Resigning is not possible yet."))
return
end
@ -3035,9 +3064,11 @@ function realchess.fields(pos, _, fields, sender)
local pcolor = promo:sub(-5)
local activePromo = meta:get_string("promotionActive")
if activePromo == "" then
--~ Chess message
send_message(playerName, S("This isn't the time for promotion."))
return
elseif activePromo ~= pcolor then
--~ Chess message
send_message(playerName, S("It's not your turn! This promotion is meant for the other player."))
return
end
@ -3045,6 +3076,7 @@ function realchess.fields(pos, _, fields, sender)
realchess.promote_pawn(meta, pcolor, promo:sub(1, -7))
return
else
--~ Chess message
send_message(playerName, S("It's not your turn! This promotion is meant for the other player."))
return
end
@ -3111,16 +3143,19 @@ function realchess.move_piece(meta, pieceFrom, from_list, from_index, to_list, t
add_to_eaten_list(meta, pieceTo)
end
local lastMove = meta:get_string("lastMove")
if lastMove == "" then lastMove = "black" end
local promo = meta:get_string("promotionActive") ~= ""
if not promo then
update_game_result(meta)
update_game_result(meta, lastMove)
lastMove = meta:get_string("lastMove")
if lastMove == "" then lastMove = "black" end
end
update_formspec(meta)
local botColor = meta:get_string("botColor")
if botColor == "" then botColor = "black" end
local lastMove = meta:get_string("lastMove")
if lastMove == "" then lastMove = "black" end
local mode = meta:get_string("mode")
local gameResult = meta:get_string("gameResult")
-- Let the bot play when it its turn
@ -3208,6 +3243,7 @@ function realchess.promote_pawn(meta, color, promoteTo)
meta:set_int("promotionPawnFromIdx", 0)
meta:set_int("promotionPawnToIdx", 0)
realchess.update_state(meta, from_idx, to_idx, color, promoteFrom:get_name(), pstr)
update_game_result(meta, color)
update_formspec(meta)
local botColor = meta:get_string("botColor")
@ -3270,13 +3306,13 @@ if ENABLE_CHESS_GAMES then
realchess.move(meta, from_list, from_index, to_list, to_index, playerName)
-- We always return 0 to disable all *builtin* inventory moves, since
-- we do it ourselves. This should be fine because there shouldn't be a
-- conflict between this mod and Minetest then.
-- conflict between this mod and Luanti then.
return 0
end
chessboarddef.allow_metadata_inventory_take = function() return 0 end
chessboarddef.allow_metadata_inventory_put = function() return 0 end
-- Note: There is no on_move function because we put the entire move handling
-- into the allow function above. The reason for this is of Minetest's
-- into the allow function above. The reason for this is of Luanti's
-- awkward behavior when swapping items.
minetest.register_lbm({

View File

@ -36,15 +36,60 @@ local function best_move(moves)
return tonumber(choice_from), choice_to
end
function chessbot.move(inv, meta)
local board_t = realchess.board_to_table(inv)
local lastMove = meta:get_string("lastMove")
local gameResult = meta:get_string("gameResult")
local botColor = meta:get_string("botColor")
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"
@ -60,62 +105,59 @@ function chessbot.move(inv, meta)
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
if (lastMove == opponentColor or ((botColor == "white" or botColor == "both") and lastMove == "")) and gameResult == "" then
local moves = realchess.get_theoretical_moves_for(meta, board_t, currentBotColor)
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
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
local pieceFrom = inv:get_stack("board", choice_from):get_name()
local pieceTo = inv:get_stack("board", choice_to):get_name()
minetest.after(BOT_DELAY_MOVE, function()
local gameResult = meta:get_string("gameResult")
if gameResult ~= "" then
return
end
local botColor = meta:get_string("botColor")
if botColor == "" then
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
end
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.promote(inv, meta, pawnIndex)
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
@ -124,9 +166,35 @@ function chessbot.promote(inv, meta, pawnIndex)
else
color = "black"
end
-- Always promote to queen
realchess.promote_pawn(meta, color, "queen")
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

View File

@ -1,8 +1,14 @@
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 = {
@ -21,13 +27,28 @@ local function set_infotext(meta, node)
end
end
-- Add more ingredients here that make a soup.
-- 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},
@ -36,12 +57,17 @@ cauldron.cbox = {
{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 minetest.get_item_group(nn, "fire") ~= 0 then
if is_fire(nn) then
return true
else
return false
@ -159,6 +185,23 @@ local function eatable(itemstring)
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)
@ -192,13 +235,12 @@ function cauldron.boiling_timer(pos)
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 food = itemstring:match(":([%w_]+)")
local item = ItemStack(itemstring)
local itemname = item:get_name()
for _, ingredient in ipairs(ingredients_list) do
if food and (eatable(itemstring) or food:find(ingredient)) then
ingredients[#ingredients + 1] = food
break
end
if is_ingredient(itemname) then
local basename = itemstring:match(":([%w_]+)")
table.insert(ingredients, basename)
end
end
end
@ -247,7 +289,7 @@ xdecor.register("cauldron_empty", {
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_sides.png"},
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,
@ -264,7 +306,7 @@ xdecor.register("cauldron_idle", {
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_sides.png"},
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),
@ -278,7 +320,7 @@ xdecor.register("cauldron_idle_river_water", {
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_sides.png"},
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),
@ -293,7 +335,7 @@ xdecor.register("cauldron_idle_soup", {
is_ground_content = false,
on_rotate = screwdriver.rotate_simple,
drop = "xdecor:cauldron_empty",
tiles = {"xdecor_cauldron_top_idle_soup.png", "xdecor_cauldron_sides.png"},
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)
@ -320,6 +362,7 @@ xdecor.register("cauldron_boiling", {
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(),
@ -344,6 +387,7 @@ xdecor.register("cauldron_boiling_river_water", {
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(),
@ -370,6 +414,7 @@ xdecor.register("cauldron_soup", {
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(),
@ -447,3 +492,26 @@ minetest.register_lbm({
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
src/enchanted_tools.lua Normal file
View 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

View File

@ -1,69 +1,84 @@
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
local MESE_COST = 1
-- Force of the enchantments.
local enchanting = {
uses = 1.2, -- Durability
times = 0.1, -- Efficiency
damages = 1, -- Sharpness
}
local function cap(str) return
str:gsub("^%l", string.upper)
end
-- 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(enchant, orig_caps, fleshy)
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 * enchanting.uses)
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 -
enchanting.times)
bonus_defs.times)
end
if fleshy then
bonus.damages = to_percent(fleshy, fleshy + enchanting.damages)
bonus.damages = to_percent(fleshy, fleshy + bonus_defs.damages)
end
local specs = { -- not finished, to complete
durable = {"#00baff", " (+" .. bonus.durable .. "%)"},
fast = {"#74ff49", " (+" .. bonus.efficiency .. "%)"},
sharp = {"#ffff00", " (+" .. bonus.damages .. "%)"},
local specs = {
durable = bonus.durable,
fast = bonus.efficiency,
sharp = bonus.damages,
}
local enchant_loc = {
fast = S("Efficiency"),
durable = S("Durability"),
sharp = S("Sharpness"),
}
return minetest.colorize and minetest.colorize(specs[enchant][1],
enchant_loc[enchant] .. specs[enchant][2]) or
enchant_loc[enchant] .. specs[enchant][2]
local percent = specs[enchant]
return enchanting:get_tooltip_raw(enchant, percent)
end
local enchant_buttons = {
"image_button[3.6,0.67;4.75,0.85;bg_btn.png;fast;"..FS("Efficiency").."]" ..
"image_button[3.6,1.65;4.75,1.05;bg_btn.png;durable;"..FS("Durability").."]",
"image_button[3.6,2.8;4.75,0.85;bg_btn.png;sharp;"..FS("Sharpness").."]",
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, num)
function enchanting.formspec(pos, enchants)
local meta = minetest.get_meta(pos)
local formspec = [[
size[9,8.6;]
@ -80,27 +95,28 @@ function enchanting.formspec(pos, num)
listring[context;mese]
image[2,2.9;1,1;mese_layout.png]
]]
.."tooltip[sharp;"..FS("Your weapon inflicts more damages").."]"
.."tooltip[durable;"..FS("Your tool last longer").."]"
--~ 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)
formspec = formspec .. (enchant_buttons[num] or "")
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 tool_groups = {
"axe, pick, shovel",
"sword",
}
for idx, tools in ipairs(tool_groups) do
if tools:find(stackname:match(":(%w+)")) then
enchanting.formspec(pos, idx)
end
local enchants = available_tool_enchants[stackname]
if enchants then
enchanting.formspec(pos, enchants)
end
end
end
@ -114,7 +130,7 @@ function enchanting.fields(pos, _, fields, sender)
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
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
@ -122,7 +138,7 @@ function enchanting.fields(pos, _, fields, sender)
tool:replace(enchanted_tool)
tool:add_wear(orig_wear)
mese:take_item(mese_cost)
mese:take_item(MESE_COST)
inv:set_stack("mese", 1, mese)
inv:set_stack("tool", 1, tool)
end
@ -140,12 +156,13 @@ function enchanting.blast(pos)
end
local function allowed(tool)
if not tool then return end
for item in pairs(reg_tools) do
if item:find("enchanted_" .. tool) then
return true
end
if not tool then
return false
end
if reg_enchantable_tools[tool] then
return true
else
return false
end
end
@ -154,7 +171,7 @@ function enchanting.put(_, listname, _, stack)
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:match("[^:]+$")) then
elseif listname == "tool" and allowed(stackname) then
return 1
end
@ -248,13 +265,15 @@ xdecor.register("enchantment_table", {
})
minetest.register_entity("xdecor:book_open", {
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,
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({
@ -276,65 +295,112 @@ minetest.register_lbm({
end,
})
function enchanting:register_tools(mod, def)
for tool in pairs(def.tools) do
for material in def.materials:gmatch("[%w_]+") do
for enchant in def.tools[tool].enchants:gmatch("[%w_]+") do
local original_tool = reg_tools[mod .. ":" .. tool .. "_" .. material]
if not original_tool then break end
local original_toolcaps = original_tool.tool_capabilities
if original_toolcaps then
local original_damage_groups = original_toolcaps.damage_groups
local original_groupcaps = original_toolcaps.groupcaps
local groupcaps = table.copy(original_groupcaps)
local fleshy = original_damage_groups.fleshy
local full_punch_interval = original_toolcaps.full_punch_interval
local max_drop_level = original_toolcaps.max_drop_level
local group = next(original_groupcaps)
if enchant == "durable" then
groupcaps[group].uses = ceil(original_groupcaps[group].uses *
enchanting.uses)
elseif enchant == "fast" then
for i, time in pairs(original_groupcaps[group].times) do
groupcaps[group].times[i] = time - enchanting.times
end
elseif enchant == "sharp" then
fleshy = fleshy + enchanting.damages
end
local arg1 = def.material_desc[material] or cap(material)
local arg2 = def.tools[tool].desc or cap(tool)
local arg3 = self:get_tooltip(enchant, original_groupcaps[group], fleshy)
minetest.register_tool(":" .. mod .. ":enchanted_" .. tool .. "_" .. material .. "_" .. enchant, {
description = S("Enchanted @1 @2\n@3", arg1, arg2, arg3),
short_description = S("Enchanted @1 @2", arg1, arg2),
inventory_image = original_tool.inventory_image .. "^[colorize:violet:50",
wield_image = original_tool.wield_image,
groups = {not_in_creative_inventory = 1},
tool_capabilities = {
groupcaps = groupcaps, damage_groups = {fleshy = fleshy},
full_punch_interval = full_punch_interval,
max_drop_level = max_drop_level
}
})
end
end
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
enchanting:register_tools("default", {
materials = "steel, bronze, mese, diamond",
material_desc = {steel = S("Steel"), bronze = S("Bronze"), mese = S("Mese"), diamond = S("Diamond")},
tools = {
axe = {enchants = "durable, fast", desc = S("Axe")},
pick = {enchants = "durable, fast", desc = S("Pickaxe")},
shovel = {enchants = "durable, fast", desc = S("Shovel")},
sword = {enchants = "sharp", desc = S("Sword")}
},
})
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_too_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_too_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
@ -346,3 +412,95 @@ minetest.register_craft({
{"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

View File

@ -121,6 +121,7 @@ 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",

View File

@ -73,7 +73,9 @@ function itemframe.set_infotext(meta)
local owner = meta:get_string("owner")
if itemstring == "" then
if owner ~= "" then
meta:set_string("infotext", S("@1 (owned by @2)", S("Item Frame"), owner))
--~ 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
@ -158,6 +160,7 @@ 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,
@ -181,12 +184,14 @@ xdecor.register("itemframe", {
})
minetest.register_entity("xdecor:f_item", {
visual = "wielditem",
visual_size = {x = 0.33, y = 0.33},
collisionbox = {0,0,0,0,0,0},
pointable = false,
physical = false,
textures = {"air"},
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

View File

@ -61,7 +61,7 @@ function mailbox:formspec(pos, owner, is_owner)
-- List of donors. A line looks like this:
-- <donor name> <item icon> × <item count>
giver = giver .. "#FFFF00," .. giver_name .. "," .. i ..
-- Times a certain item count; used for the mailbox donor list
--~ 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 .. "=" ..
@ -180,6 +180,7 @@ 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",

View File

@ -57,6 +57,7 @@ end
function plate.register(material, desc, def)
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,
@ -98,6 +99,7 @@ plate.register("stone", "Stone", {
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,

View File

@ -200,7 +200,7 @@ 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},
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, {
@ -212,8 +212,8 @@ xdecor.register("chair", {
{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)
pos.y = pos.y + 0 -- Sitting position
xdecor.sit(pos, node, clicker, pointed_thing)
return itemstack
end,
@ -234,9 +234,11 @@ xdecor.register("cobweb", {
})
local curtain_colors = {
red = S("Red Curtain"),
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
@ -248,20 +250,27 @@ local cleanup_curtain_meta = function(_,_,_,drops)
end
end
for c, desc in pairs(curtain_colors) do
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 = {"wool_white.png"},
color = c,
inventory_image = "wool_white.png^[colorize:" .. c ..
":170^xdecor_curtain_open_overlay.png^[makealpha:255,126,126",
wield_image = "wool_white.png^[colorize:" .. c .. ":170",
drawtype = "signlike",
paramtype2 = "colorwallmounted",
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,
selection_box = {type = "wallmounted"},
on_rightclick = function(pos, node, _, itemstack)
minetest.set_node(pos, {name = "xdecor:curtain_open_" .. c, param2 = node.param2})
return itemstack
@ -269,15 +278,28 @@ for c, desc in pairs(curtain_colors) do
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 = {"wool_white.png^xdecor_curtain_open_overlay.png^[makealpha:255,126,126"},
color = c,
drawtype = "signlike",
paramtype2 = "colorwallmounted",
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,
selection_box = {type="wallmounted"},
drop = "xdecor:curtain_" .. c,
on_rightclick = function(pos, node, _, itemstack)
minetest.set_node(pos, {name="xdecor:curtain_" .. c, param2 = node.param2})
@ -289,8 +311,8 @@ for c, desc in pairs(curtain_colors) do
minetest.register_craft({
output = "xdecor:curtain_" .. c .. " 4",
recipe = {
{"", "wool:" .. c, ""},
{"", "wool:" .. c, ""}
{"", craft_item, ""},
{"", craft_item, ""}
}
})
end
@ -298,13 +320,13 @@ end
xdecor.register("cushion", {
description = S("Cushion"),
tiles = {"xdecor_cushion.png"},
groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -50},
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)
pos.y = pos.y + 0 -- Sitting position
xdecor.sit(pos, node, clicker, pointed_thing)
return itemstack
end
@ -658,11 +680,12 @@ local painting_box = {
xdecor.register("painting_1", {
description = S("Painting"),
tiles = {"xdecor_painting_1.png"},
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,
@ -711,9 +734,10 @@ xdecor.register("painting_1", {
for i = 2, 4 do
xdecor.register("painting_" .. i, {
tiles = {"xdecor_painting_" .. i .. ".png"},
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 = {
@ -806,11 +830,26 @@ xdecor.register("tatami", {
xdecor.register("trampoline", {
description = S("Trampoline"),
tiles = {"xdecor_trampoline.png", "mailbox_blank16.png", "xdecor_trampoline_sides.png"},
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 = xdecor.nodebox.slab_y(0.5),
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",
@ -901,6 +940,7 @@ xdecor.register("woodframed_glass", {
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

View File

@ -1,10 +1,16 @@
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
@ -15,32 +21,45 @@ function rope.place(itemstack, placer, pointed_thing)
end
local pos = pointed_thing.above
-- Check protection
if minetest.is_protected(pos, placer:get_player_name()) and
not minetest.check_player_privs(placer, "protection_bypass") then
minetest.record_protection_violation(pos, placer:get_player_name())
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 max. rope length to max. stack size
-- Prevents the rope to extend infinitely in Creative Mode
local max_ropes = itemstack:get_stack_max()
-- 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_placed = 0
while oldnode.name == "air" and not itemstack:is_empty() and ropes_placed < max_ropes do
local newnode = {name = stackname, param1 = 0}
minetest.set_node(pos, newnode)
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
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_placed = ropes_placed + 1
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_placed > 0 then
if ropes_to_place > 0 then
minetest.sound_play(ropesounds.place, {pos=start_pos}, true)
end
end

View File

@ -7,6 +7,9 @@ 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 = {
@ -35,7 +38,7 @@ end
-- Tools allowed to be repaired
function workbench:repairable(stack)
-- Explicitly registeded as repairable: Overrides everything else
-- Explicitly registered as repairable: Overrides everything else
if custom_repairable[stack] then
return true
end
@ -109,16 +112,16 @@ function workbench:get_output(inv, input, name)
inv:set_list("forms", output)
end
function workbench:register_special_cut(nodename, cutlist)
registered_cuttable_nodes[nodename] = true
special_cuts[nodename] = cutlist
end
local main_fs = "label[0.9,1.23;"..FS("Cut").."]"
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]
@ -216,9 +219,11 @@ function workbench.timer(pos)
return
end
local hammerdef = hammer:get_definition()
-- Tool's wearing range: 0-65535; 0 = new condition
tool:add_wear(-500)
hammer:add_wear(700)
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)
@ -230,7 +235,7 @@ 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 stackname == "xdecor:hammer") or
(listname == "hammer" and minetest.get_item_group(stackname, "repair_hammer") == 1) or
listname == "storage" then
return stack:get_count()
end
@ -255,7 +260,7 @@ function workbench.allow_move(pos, from_list, from_index, to_list, to_index, cou
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 stack:get_name() == "xdecor:hammer" then
if minetest.get_item_group(stack:get_name(), "repair_hammer") == 1 then
return count
end
end
@ -310,7 +315,7 @@ xdecor.register("workbench", {
is_ground_content = false,
sounds = default.node_sound_wood_defaults(),
tiles = {
"xdecor_workbench_top.png","xdecor_workbench_top.png",
"xdecor_workbench_top.png","xdecor_workbench_bottom.png",
"xdecor_workbench_sides.png", "xdecor_workbench_sides.png",
"xdecor_workbench_front.png", "xdecor_workbench_front.png"
},
@ -328,29 +333,11 @@ xdecor.register("workbench", {
allow_metadata_inventory_move = workbench.allow_move
})
minetest.register_on_mods_loaded(function()
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
registered_cuttable_nodes[nodename] = true
end
end
for _, d in ipairs(workbench.defs) do
for i = 1, #cuttable_nodes do
local node = cuttable_nodes[i]
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 d[3] then
if item_name and workbench_def[3] then
local groups = {}
local tiles
groups.not_in_creative_inventory = 1
@ -419,7 +406,7 @@ for i = 1, #cuttable_nodes do
end
end
local cutname = d[1]
local cutname = workbench_def[1]
local tiles_special_cut
if custom_tiles and custom_tiles[cutname] then
tiles_special_cut = custom_tiles[cutname]
@ -427,9 +414,14 @@ for i = 1, #cuttable_nodes do
tiles_special_cut = tiles
end
minetest.register_node(":" .. node .. "_" .. cutname, {
-- @1: Base node description (e.g. "Stone"); @2: modifier (e.g. "Nanoslab")
description = S("@1 @2", def.description, d[4]),
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",
@ -438,7 +430,7 @@ for i = 1, #cuttable_nodes do
use_texture_alpha = def.use_texture_alpha,
groups = groups,
is_ground_content = def.is_ground_content,
node_box = xdecor.pixelbox(16, d[3]),
node_box = xdecor.pixelbox(16, workbench_def[3]),
sunlight_propagates = true,
on_place = minetest.rotate_node
})
@ -453,32 +445,35 @@ for i = 1, #cuttable_nodes do
("stairs:stair_outer_%s"):format(item_name)
)
end
return true
end
end
end)
-- Craft items
minetest.register_tool("xdecor:hammer", {
description = S("Hammer"),
_tt_help = S("Repairs tools at the work bench"),
inventory_image = "xdecor_hammer.png",
wield_image = "xdecor_hammer.png",
on_use = function() do
return end
function workbench:register_cut(nodename, cutlist)
if registered_cuttable_nodes[nodename] then
minetest.log("error", "[xdecor] Workbench: Tried to register cut for node "..node..", 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
-- Recipes
minetest.register_craft({
output = "xdecor:hammer",
recipe = {
{"default:steel_ingot", "group:stick", "default:steel_ingot"},
{"", "group:stick", ""}
}
})
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 = {
@ -487,6 +482,121 @@ minetest.register_craft({
}
})
-- 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", ""}
}
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 273 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B