Charakterbewegungen hinzugefügt, Deko hinzugefügt, Kochrezepte angepasst
22
mods/xdecor/.gitignore
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
## Files related to minetest development cycle
|
||||
/*.patch
|
||||
# GNU Patch reject file
|
||||
*.rej
|
||||
|
||||
## Editors and Development environments
|
||||
*~
|
||||
*.swp
|
||||
*.bak*
|
||||
*.orig
|
||||
# Vim
|
||||
*.vim
|
||||
# Kate
|
||||
.*.kate-swp
|
||||
.swp.*
|
||||
# Eclipse (LDT)
|
||||
.project
|
||||
.settings/
|
||||
.buildpath
|
||||
.metadata
|
||||
# Idea IDE
|
||||
.idea/*
|
14
mods/xdecor/.luacheckrc
Normal file
|
@ -0,0 +1,14 @@
|
|||
allow_defined_top = true
|
||||
|
||||
read_globals = {
|
||||
"minetest",
|
||||
"vector", "ItemStack",
|
||||
"default",
|
||||
"stairs", "doors", "xpanes",
|
||||
"xdecor",
|
||||
table = {fields = {"copy"}},
|
||||
string = {fields = {"split"}},
|
||||
"unpack",
|
||||
"stairsplus",
|
||||
"mesecon"
|
||||
}
|
30
mods/xdecor/API.md
Normal file
|
@ -0,0 +1,30 @@
|
|||
# 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.
|
||||
|
||||
## 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.
|
||||
|
||||
See `src/workbench.lua` for details.
|
521
mods/xdecor/CHESS_README.md
Normal file
|
@ -0,0 +1,521 @@
|
|||
# Chess
|
||||
|
||||
## Introduction
|
||||
|
||||
You can play Chess in X-Decor-libre!
|
||||
|
||||
While the game of Chess is well-known and widespread and its
|
||||
rules are well-documented all over the Internet and elsewhere,
|
||||
the devil still lies in the detail.
|
||||
|
||||
In X-Decor-libre, the game of Chess is closely modeled after
|
||||
the FIDE Laws of Chess from January 2023. However, for a
|
||||
computer version of Chess, there are still some details
|
||||
that might need explanation.
|
||||
|
||||
## Objective
|
||||
|
||||
Chess is played between two players on a chessboard. One player plays
|
||||
with white pieces while the other one plays with black pieces.
|
||||
The goal of the game is to put the king of the opponent under attack
|
||||
in such a way they have no legal move. This is known as ‘checkmate’.
|
||||
It is not allowed to put one’s king in danger, to leave him in danger
|
||||
or to capture the opponent’s king.
|
||||
|
||||
## How to play
|
||||
|
||||
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)
|
||||
|
||||
Place the chessboard and examine it. You will see a close-up of the chessboard.
|
||||
|
||||
### The Chess interface
|
||||
|
||||
On the screen that pops up, you can choose to play against the
|
||||
computer (Singleplayer) or another player on the server (Multiplayer).
|
||||
You may also use the multiplayer option to play against yourself.
|
||||
The computer player is quite weak.
|
||||
|
||||
Click on the corresponding button to start the game.
|
||||
|
||||
Once the game has started, you see the following things:
|
||||
|
||||
To the left, the large chessboard consisting of 8×8 dark and white squares.
|
||||
The pieces are put on the chessboard. If there is no active game,
|
||||
the chessboard is empty.
|
||||
|
||||
During a game, the interface has the following meaning:
|
||||
|
||||
Above and below the chessboard, plaques show the name of the players.
|
||||
Above the chessboard is the player playing Black and below it
|
||||
the player playing White.
|
||||
An arrow left of the plaque shows whose turn it is. The name plaques
|
||||
may also show the “game status”, such as victory, checkmate (=loss),
|
||||
draw, being “in check”, etc.
|
||||
|
||||
On the right side, a list of moves that have been made is shown.
|
||||
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.
|
||||
|
||||
The top right corner is used for starting a new game. Press
|
||||
“New Game” to start a new game. This ends the current game.
|
||||
|
||||
The bottom right corner right corner is used for special
|
||||
player actions, such as resigning or claiming a draw.
|
||||
|
||||
Note that during a game, the buttons only work for the two players
|
||||
playing Chess. They don’t work for anyone else.
|
||||
|
||||
## The rules of Chess
|
||||
|
||||
### Starting a game
|
||||
|
||||
Select Singleplayer or Multiplayer. In Singleplayer, you choose
|
||||
the color you play as by clicking the corresponding button.
|
||||
|
||||
White always plays first.
|
||||
|
||||
In multiplayer, anyone can make the first move.
|
||||
The player making the first move as White will play as White,
|
||||
the player making the first move as Black will play as Black.
|
||||
After that, the players are “locked” to their colors and
|
||||
nobody else can play as White or Black.
|
||||
|
||||
### The chessboard
|
||||
|
||||
The chessboard is a board of 8×8 squares alternating between light
|
||||
and dark squares. Each square is either empty or holds exactly one
|
||||
chess piece.
|
||||
|
||||
### The Chess pieces and how they move
|
||||
|
||||
Each player starts with the same pieces on opposing sides of the board,
|
||||
only their color is different.
|
||||
|
||||
There are 4 types of moves you can make:
|
||||
|
||||
* Normal move: You pick up the piece and place it to an empty square
|
||||
* Capturing move: You pick up the piece and place it on top of an opposing piece
|
||||
Your piece will land on that square and the opponent’s piece is removed
|
||||
* En passant: Special capturing move of the pawn (see below)
|
||||
* Castling: Special king+rook move (see below)
|
||||
|
||||
It is not possible to place your piece on your own pieces.
|
||||
It is not possible to capture a king or your own pieces.
|
||||
Any square on which a piece could capture another piece in theory
|
||||
(even if it is actually empty) is considered to be “attacked”.
|
||||
|
||||
For most pieces, the rules for making a normal move and
|
||||
a capturing move are identical. Only for the pawn it is different
|
||||
(read below).
|
||||
|
||||
If the square of the king is attacked, he and the player playing him
|
||||
is considered to be in “check”.
|
||||
While a player is in check, any move which would their own
|
||||
king under attack is not allowed.
|
||||
|
||||
#### How to actually move
|
||||
|
||||
Each move can be made by either clicking on the piece and then clicking again
|
||||
on the destination. The destination is either an empty square or a square
|
||||
occupied by an opponent’s piece (which will be captured).
|
||||
You can also do the same via drag-and-drop.
|
||||
|
||||
Once you made a valid move by placing the piece to its destination, it is
|
||||
final and cannot be taken back. This ends your move and it’s your
|
||||
opponent’s turn (exception: promotion, see below).
|
||||
|
||||
If you pick up a piece and put it back, nothing happens, it is still
|
||||
your turn and you can still do your move normally. Also, if you try
|
||||
to make an invalid move, nothing happens as well.
|
||||
|
||||
(Nerd info: For the purposes of the FIDE Laws of Chess, pieces are never
|
||||
considered “touched” here. Thus, article 4 of the FIDE Laws of Chess has
|
||||
no effect.)
|
||||
|
||||
#### Rook
|
||||
|
||||
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 may be involved in Castling, see “King” below.
|
||||
|
||||
#### Bishop
|
||||
|
||||
The bishop can move to any square on a diagonal line from it.
|
||||
It cannot move beyond pieces that are in the way.
|
||||
|
||||
#### Queen
|
||||
|
||||
The queen combines the powers of the rook and bishop and can
|
||||
move to any square in a straight horizontal, vertical
|
||||
or diagonal line from it.
|
||||
It cannot move beyond pieces that are in the way.
|
||||
|
||||
#### Knight
|
||||
|
||||
The knight looks like a horse and can move to any square closest to
|
||||
it that is not in its same horizontal line (also known as “rank”),
|
||||
vertical line (also known as “file”), or diagonal of the board.
|
||||
To illustrate this:
|
||||
|
||||
..X.X..
|
||||
.X...X.
|
||||
...n...
|
||||
.X...X.
|
||||
..X.X..
|
||||
|
||||
In this diagram, “n” represents the knight and the Xes are all the
|
||||
possible squares it can theoretically reach. The dots are empty
|
||||
squares.
|
||||
|
||||
Unlike the other pieces, pieces are never “in the way” of the knight.
|
||||
You might say the knight can “jump over” them, if you will.
|
||||
|
||||
#### King
|
||||
|
||||
The king can move exactly one square in any direction: horizontally,
|
||||
vertically or diagonally. Also, the king can never move to any square that
|
||||
is attacked by an opponent’s piece.
|
||||
|
||||
The king also has a special move called “Castling”.
|
||||
|
||||
##### Castling
|
||||
|
||||
Castling is a special move in which two pieces move at once.
|
||||
Both the king and a rook move horizontally from their starting positions.
|
||||
The king will move two squares horizontally and a rook will be
|
||||
moved next to him.
|
||||
|
||||
Each player has two possible castling moves available, involving each
|
||||
of the 2 starting rooks.
|
||||
|
||||
Castling has several conditions:
|
||||
|
||||
- The king must not have moved yet
|
||||
- The rook you wish to castle with must not have moved yet
|
||||
- All of the squares between king and rook must be empty
|
||||
- The king must not be under attack
|
||||
- The king’s destination as well the square it crosses must not be under attack
|
||||
- You can castle only horizontally
|
||||
|
||||
If all the conditions are met, here’s 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 rook’s viewpoint.
|
||||
|
||||
**Remember**: You *must* move the king (not the rook) if you want
|
||||
to castle. If you move the rook instead, this is considered
|
||||
to be a regular move of the rook alone.
|
||||
|
||||
#### Pawn
|
||||
|
||||
The pawn has various ways to move.
|
||||
The pawn has a “walking direction”, it walks and captures towards
|
||||
the opponent’s side (i.e. the side on which the opponent’s
|
||||
pieces have started).
|
||||
|
||||
The pawn’s basic moves are:
|
||||
|
||||
1. Single step: The pawn moves one step vertically towards the
|
||||
opponent’s side.
|
||||
2. Double step: Like a single step, but it moves two squares instead.
|
||||
This is only possible from the pawn’s 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.
|
||||
|
||||
The capturing move of the pawn is different. To capture, the pawn has to
|
||||
move one step diagonally towards the opponent’s side, either left or right.
|
||||
|
||||
To illustrate, in the following diagram, the X’es represent the
|
||||
squares attacked by a white pawn (w) and a black pawn (b):
|
||||
|
||||
.X.X..b..
|
||||
..w..X.X.
|
||||
|
||||
##### En passant capture
|
||||
|
||||
An en passant capture is a pawn move that is available if a pawn
|
||||
of the current player stands on a square left or right from an
|
||||
opposing pawn that has made a double step in the previous move.
|
||||
|
||||
In this situation, the first pawn may move as if the second pawn
|
||||
had made a single step instead. This will be considered as a
|
||||
capturing move and the opposing pawn will be removed from the board.
|
||||
|
||||
|
||||
Consider this example: Here, “w” represents a white pawn, “b” a black pawn and “.”
|
||||
an empty square. White moves upwards and Black downwards. Consider this starting
|
||||
position:
|
||||
|
||||
b.
|
||||
..
|
||||
.w
|
||||
|
||||
Now, White does a double step:
|
||||
|
||||
bw
|
||||
..
|
||||
..
|
||||
|
||||
Black decides to do an en passant capture. For this, the black pawn moves one
|
||||
diagonal step towards the square just crossed by the opponent. The white
|
||||
pawn is captured and removed.
|
||||
|
||||
..
|
||||
.b
|
||||
..
|
||||
|
||||
Remember! An 'en passant' capture is only possible in the move directly after
|
||||
a pawn’s double step. So if the chance for a particular en passant capture
|
||||
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),
|
||||
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
|
||||
will turn into a prompt. The current player must choose a new
|
||||
piece to replace the pawn with:
|
||||
A queen, rook, bishop or knight of the same color.
|
||||
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, which
|
||||
immediately activates its powers. This ends the move.
|
||||
|
||||
### The end of the game
|
||||
|
||||
There are various ways for the game of Chess to end. A game always
|
||||
ends in victory of one player, or in a draw.
|
||||
|
||||
#### Checkmate
|
||||
Checkmating your opponent is the primary goal of Chess.
|
||||
The player who has checkmated the opponent king wins the game and ends it.
|
||||
|
||||
You are checkmated when it’s your turn, your own king is in check
|
||||
(i.e. under attack) and you have no valid move available.
|
||||
This immediately ends the game and your opponent wins.
|
||||
|
||||
#### Stalemate
|
||||
If it’s a player’s turn, but they have no possible move and their
|
||||
king is not in check, the game immediately ends in a draw.
|
||||
This is called a “stalemate”.
|
||||
|
||||
#### Resign
|
||||
During the game, the possibility of resigning arises. Resigning
|
||||
basically means “giving up” and this leads to an instant loss
|
||||
and the victory of your opponent.
|
||||
Resigning is available after one’s name has been recorded on
|
||||
the name plaque. Resigning is possible even when it’s not your turn.
|
||||
|
||||
To resign, click the skull icon in the bottom right.
|
||||
|
||||
#### Dead position
|
||||
If during the game, on the board there are only the following pieces left,
|
||||
the game ends in a draw:
|
||||
|
||||
* king versus king
|
||||
* king versus king and bishop
|
||||
* king versus king and knight
|
||||
* king and bishop versus king and bishop, and both bishops stand on squares of the same color
|
||||
|
||||
This is called a “dead position”. For example, a board with only a white
|
||||
and a black king is a draw.
|
||||
|
||||
NOTE: In general, a dead position is any position from which neither player can
|
||||
give checkmate, no matter how they move, but only those 4 cases above
|
||||
lead to an instant draw in X-Decor-libre because it is tricky to
|
||||
determine whether any position is “dead”.
|
||||
|
||||
However, dead positions are still guaranteed to end the game eventually
|
||||
due to the 75-move rule.
|
||||
|
||||
#### 50-move rule
|
||||
If in the last 50 consecutive moves of each player, no piece was
|
||||
captured and no pawn was moved, the player whose turn it is can invoke
|
||||
the 50-move rule to draw the game instantly.
|
||||
|
||||
When it’s your turn, and you believe your *next* move will satisfy
|
||||
the condition of the 50-move rule, you may also invoke this rule
|
||||
to draw the game, but in this case, you still have to make the move.
|
||||
If this move satisfies the 50-move rule, the game is drawn.
|
||||
But if not, this counts as a normal move, your turn ends and the
|
||||
game continues as normal.
|
||||
|
||||
A button on the bottom right will appear when this rule is available.
|
||||
The button is not shown when there are too few such moves for this
|
||||
draw claim to be successful.
|
||||
|
||||
The icon represents a barricade, as if the game of Chess itself
|
||||
has been blocked. This one will instantly draw the game.
|
||||
If you still would have to make the game-drawing move, the
|
||||
icon represents half a barricade.
|
||||
Note the tooltip.
|
||||
|
||||
Note the latter icon is no guarantee you can actually draw the
|
||||
game in the next move, only that such a draw claim is plausible.
|
||||
|
||||
#### 75-move rule
|
||||
If in the last 75 consecutive moves of each player, no piece was captured
|
||||
and no pawn was moved, the game automatically ends in a draw.
|
||||
|
||||
Exception: If the last move has lead to a checkmate. In this case, checkmate
|
||||
takes precedence.
|
||||
|
||||
#### Threefold repetition rule
|
||||
If the current position has appeared at least 3 times in the game
|
||||
the current player can invoke the threefold repetition rule to draw
|
||||
the game instantly.
|
||||
|
||||
Two positions are considered to be the same “same” if a position in which
|
||||
the chessboard has the same pieces of the same color on the same squares,
|
||||
it is the same player's turn, the castling rights are the same
|
||||
and the vulnerability of pawns to en passant captures (if any) is the same.
|
||||
|
||||
Pawns are considered “vulnerable” to an en passant capture immediately
|
||||
after a double step turn, no matter if is actually in danger of
|
||||
being captured that way.
|
||||
|
||||
This rule can also be invoked when you think your *next* move will
|
||||
lead to the 3rd (or more) repeated position in the game. This
|
||||
works similar as for the 50-move rule.
|
||||
|
||||
Like for the 50-move rule, a button appears on the bottom right
|
||||
once this rule can be invoked.
|
||||
|
||||
If the 3 same position has already occurred, the icon will
|
||||
represent 3 chess squares stacked on top of each other.
|
||||
If the game-drawing move still has to be made, the top
|
||||
square is a “ghost square”.
|
||||
|
||||
#### Fivefold repetition rule
|
||||
If the same position (as defined above) has appeared at for
|
||||
least 5 times, the game is drawn.
|
||||
|
||||
#### No agreeing to draw
|
||||
|
||||
Unlike in other Chess programs, the players cannot agree to draw.
|
||||
|
||||
#### Game result
|
||||
|
||||
Once the game has ended, the game result is shown on the name plaques of the
|
||||
players as well in chat (to the players only). From this point on, everyone
|
||||
(even spectators) can start a new game with “New Game”.
|
||||
|
||||
|
||||
## Resetting the chessboard
|
||||
|
||||
While a game of Chess is ongoing, the chessboard can’t be dug and the game
|
||||
can’t be stopped by other players. But to prevent two players blocking a
|
||||
chessboard forever, there is a 5-minute timer. If no player makes a move
|
||||
for 5 minutes, then the chessboard can be reset and dug by anyone.
|
||||
|
||||
Exception: Players with the `protection_bypass` privilege can always
|
||||
dig the chessboard.
|
||||
|
||||
|
||||
## Appendix
|
||||
|
||||
### The Chess Notation
|
||||
|
||||
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
|
||||
and end coordinates are shown in full.
|
||||
|
||||
Square coordinates are important in any Chess notation. In algebraic notation,
|
||||
each square is assigned coordinated with a letter from a to h,
|
||||
followed by a number from 1 to 8.
|
||||
Provided that the player playing White is on the “bottom” side of the chessboard,
|
||||
the squares are numbered from the bottom left square in ascending order.
|
||||
The horizontal lines (“ranks”) are numbered 1 to 8, starting from the bottom.
|
||||
The vertical lines (“files”) are numbered a to h, starting from the left.
|
||||
So from White's viewpoint, the bottom-left square is a1. The square above it
|
||||
is a2, then a3, a4, ... a8. The square right of a1 is b1, then c1, d1, ... h1.
|
||||
The top-right square is h8.
|
||||
|
||||
(Note that on a real chessboard, all of the coordinates are flipped from Black’s viewpoint
|
||||
because the board is rotated 180° from their view. In X-Decor-libre, this does not
|
||||
matter because the board is always aligned the same way.)
|
||||
|
||||
In the list of moves, each line shows 3 things: Move number, white’s move, black’s move (if made).
|
||||
The move number is a simple counter that increases after each move of *both* players, starting by 1.
|
||||
|
||||
In the notation, a move by a single player is called a “halfmove”. The two moves
|
||||
of each White and then Black are called a “fullmove”.
|
||||
|
||||
#### Normal moves
|
||||
|
||||
Normally, a halfmove is written like this, in this order:
|
||||
|
||||
1. Symbol of moved piece (called “figurine”)
|
||||
2. Start coordinates, a dash or cross, destination coordinates
|
||||
3. “e.p.”, if it was an en passant capture -OR- symbol of piece to which a pawn was promoted to
|
||||
|
||||
For number 1, the symbol is only shown if the piece is not a pawn.
|
||||
For number 2, the syntax for normal moves is like: “a1–a2”. This means the piece was moved from a1 to a2.
|
||||
The dash means it was a normal move.
|
||||
For capturing moves, the dash is replaced with a cross “×”. If it was an en passant capture, then
|
||||
“ e.p” is appended, like so: “a5×b4 e.p.”.
|
||||
If a pawn was promoted, the symbol of the new piece is appended.
|
||||
The figurines are always of the color of the player.
|
||||
|
||||
Both halfmoves on a line are separated by spacing.
|
||||
|
||||
#### Castling
|
||||
|
||||
When a player castles, it is notated the following way:
|
||||
|
||||
* “0–0” for castling with the rook on file h (“kingside castling”)
|
||||
* “0–0–0” for castling with the rook on file a (“queenside castling”)
|
||||
|
||||
#### Game completion
|
||||
|
||||
If the game came to an end, the game result is written in a final separate line as:
|
||||
|
||||
* “1–0” if White won
|
||||
* “0–1” if Black won
|
||||
* “½–½” in case of a draw
|
||||
|
||||
#### Example
|
||||
|
||||
1. d2–d4 e7–e6
|
||||
2. ♔e1–d2 ♛d8–h4
|
||||
3. d4–d5 e6×d5
|
||||
...
|
||||
8. d8×d8♖ ♞b8–c6
|
||||
9. e2–e4 d4×e3 e.p.
|
||||
|
||||
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.: 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
|
||||
|
||||
Other symbols are not used. So there are no special symbols for check and checkmate and no comments for moves considered good or bad.
|
63
mods/xdecor/LICENSE
Normal file
|
@ -0,0 +1,63 @@
|
|||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ Copyright (c) 2015-2021 kilbith <jeanpatrick.guerrero@gmail.com> │
|
||||
│ │
|
||||
│ Code: Modified BSD License │
|
||||
│ Textures: CC0 (credits: Gambit, kilbith, Cisoun) │
|
||||
│ │
|
||||
│ Textures (radio and speaker) by │
|
||||
│ MCL <temp1@cubesoftware.xyz> (CC BY 4.0 Int'l) │
|
||||
│ │
|
||||
│ Textures (Chess icons for the Chess notation) │
|
||||
│ originally by Wikimedia user Cbnurnett, │
|
||||
│ scaled down and edited by Wuzzy (CC BY-SA 3.0 Unported) │
|
||||
│ │
|
||||
│ Textures (hanging candle) by │
|
||||
│ Wuzzy (CC0) │
|
||||
│ │
|
||||
│ Textures (rooster) by │
|
||||
│ sirrobzeroone (CC0) │
|
||||
│ │
|
||||
│ Sounds: │
|
||||
│ - xdecor_boiling_water.ogg - by Audionautics - CC BY 3.0 │
|
||||
│ freesound.org/people/Audionautics/sounds/133901/ │
|
||||
│ - xdecor_bouncy.ogg - by Blender Foundation - CC BY 3.0 │
|
||||
│ opengameart.org/content/funny-comic-cartoon-bounce-sound │
|
||||
│ - xdecor_enchanting.ogg - by Kostas17, edit by Wuzzy - CC BY 3.0 │
|
||||
│ freesound.org/people/Kostas17/sounds/542825/ │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
|
||||
-- Modified BSD License --
|
||||
|
||||
Copyright (c) 2015-2021 kilbith <jeanpatrick.guerrero@gmail.com>
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the copyright holder nor the names of contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
-- End of Modified BSD License --
|
||||
|
||||
## References for other licenses:
|
||||
|
||||
* CC BY 3.0: http://creativecommons.org/licenses/by/3.0/
|
||||
* CC BY 4.0: http://creativecommons.org/licenses/by/4.0/
|
||||
* CC0: https://creativecommons.org/publicdomain/zero/1.0/
|
19
mods/xdecor/OLD_README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
Note: This is the original readme of the xdecor mod, added here for documentation/historic reasons.
|
||||
|
||||
## X-Decor ##
|
||||
|
||||
[](https://content.minetest.net/packages/jp/xdecor/)
|
||||
|
||||
A decoration mod meant to be simple and well-featured.
|
||||
It adds a bunch of cute cubes, various mechanisms and stuff for [cutting](https://forum.minetest.net/viewtopic.php?f=11&t=14085), [enchanting](https://forum.minetest.net/viewtopic.php?f=11&t=14087), cooking, etc.
|
||||
This mod is a lightweight alternative to HomeDecor and MoreBlocks.
|
||||
|
||||
### Requirements ###
|
||||
This mod requires at least version 5.1 of Minetest.
|
||||
|
||||
### Credits ###
|
||||
|
||||
Special thanks to Gambit for the textures from the PixelBOX pack for Minetest.
|
||||
Thanks to all contributors who keep this mod alive.
|
||||
|
||||

|
147
mods/xdecor/README.md
Normal file
|
@ -0,0 +1,147 @@
|
|||
## X-Decor-libre [`xdecor`] ##
|
||||
|
||||
[](https://content.luanti.org/packages/Wuzzy/xdecor/)
|
||||
|
||||
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 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
|
||||
blocks with special features:
|
||||
|
||||
* Workbench: Storage, crafting, cutting and repairing
|
||||
* Storage: 16 item slots for item storage
|
||||
* Craft: 3×3 crafting grid
|
||||
* Cut: Put a full cube-shaped block to create new shapes
|
||||
* Repair: Put a damaged tool and a hammer and wait for it to be repaired
|
||||
* Enchanting table: Upgrade your tools with mese crystals
|
||||
* Ender Chest: Interdimensional inventory that is the same no matter
|
||||
where you put the ender chest
|
||||
* Mailbox: Lets you receive items from other players
|
||||
* Item Frame: You can place an item into it to show it off
|
||||
* Cushion: Reduces fall damage
|
||||
* Cushion Block: Reduces fall damage even more
|
||||
* Trampoline: Jump on it to bounce off. Very low fall damage
|
||||
* Cauldron: For storing water and cooking soups
|
||||
* Recipe: Pour water in, light a fire below it and throw
|
||||
in some food items. Collect the soup with a bowl
|
||||
* Lever: Pull the lever to activate doors next to it
|
||||
* Pressure Plate: Step on it to activate doors next to it
|
||||
* Chessboard: Play Chess against a player or the computer (see `CHESS_README.md`)
|
||||
|
||||
## 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 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
|
||||
X-Decor with clearly documented licenses and to fix bugs. No new features are
|
||||
planned.
|
||||
|
||||
#### List of changes
|
||||
The following bugs of X-Decor (as of 01/07/2023) are fixed:
|
||||
|
||||
* Changed packed ice recipe to avoid recipe collision with Ethereal
|
||||
* Changed prison door recipe colliding with Minetest Game's Iron Bar Door
|
||||
* Beehives no longer show that the bees are busy when they're not
|
||||
* Fixed incorrect/incomplete node sounds
|
||||
* Fix poorly placed buttons in enchantment screen
|
||||
* Fix broken texture of cut Permafrost with Moss nodes
|
||||
* Fix awkward lantern rotation
|
||||
* Lanterns can no longer attach to sides
|
||||
* Fix item stacking issues of curtains
|
||||
* Cauldrons no longer turn river water to normal water
|
||||
* Fix boiling water in cauldrons not reliably cooling down
|
||||
* Fix boiling water sound not playing when rejoining
|
||||
* Fix cauldron with soup boiling forever
|
||||
* Fix cauldrons being heated up by fireflies
|
||||
* Fix rope and painting not compatible with itemframe
|
||||
* Fix itemframe, lever being offset when put into itemframe
|
||||
* Fix storage formspecs not closing if exploded
|
||||
* Show short item description in itemframe instead of itemstring
|
||||
* Minor typo fixes
|
||||
* Fix bad rope placement prediction
|
||||
* Fixed the broken Chess game
|
||||
|
||||
Maintenance updates:
|
||||
* HUGE rework of Chess to make it actually be like real Chess (more or less)
|
||||
* New supported Chess rules (based on the FIDE Laws of Chess)
|
||||
* En passant
|
||||
* Choose your pawn promotion
|
||||
* Fixed incomplete enforcement of castling rule
|
||||
* 50-turn rule and 75-turn rule
|
||||
* Threefold repetition rule and fivefold repetition rule
|
||||
* Announce the winner or loser, or a drawn game
|
||||
* Many technical improvements for Chess
|
||||
* Renamed blocks:
|
||||
* "Empty Shelf" to "Plain Shelf"
|
||||
* "Slide Door" to "Paper Door"
|
||||
* "Rooster" to "Weathercock"
|
||||
* "Stone Tile" to "Polished Stone Block"
|
||||
* "Desert Stone Tile" to "Polished Desert Stone Block"
|
||||
* "Iron Light Box" to "Steel Lattice Light Box"
|
||||
* "Wooden Light Box" to "Wooden Cross Light Box"
|
||||
* "Wooden Light Box 2" to "Wooden Rhombus Light Box"
|
||||
* Added fuel recipes for wooden-based things
|
||||
* Changed a few confusing recipes to make more sense
|
||||
* Improved textures for cut glass, obsidian glass, woodframed glass,
|
||||
permafrost with moss and permafrost with stones
|
||||
* Improved side texture of wood frame and rusty bar
|
||||
* Add honey and cushion block to creative inventory
|
||||
* Doors now count as nodes in creative inventory
|
||||
* Cobwebs are no longer considered (fake) liquids
|
||||
* Storage blocks now drop their inventory when exploded
|
||||
* Made several strings translatable
|
||||
* Translation updates
|
||||
* Add description to every setting
|
||||
* Add tooltip extensions for some interactive items (uses `tt` mod)
|
||||
* Add crafting guide support for `unified_inventory` mod (honey)
|
||||
* Rope no longer extends infinitely in Creative Mode
|
||||
* Added manual for Chess in `CHESS_README.md`
|
||||
|
||||
#### List of replaced files
|
||||
|
||||
This is the list of non-free files in the original X-Decor mod
|
||||
(as of commit 8b614b3513f2719d5975c883180c011cb7428c8d)
|
||||
that X-Decor-libre replaces:
|
||||
|
||||
* `textures/xdecor_candle_hanging.png`
|
||||
* `textures/xdecor_radio_back.png`
|
||||
* `textures/xdecor_radio_front.png`
|
||||
* `textures/xdecor_radio_side.png`
|
||||
* `textures/xdecor_radio_top.png`
|
||||
* `textures/xdecor_rooster.png`
|
||||
* `textures/xdecor_speaker_back.png`
|
||||
* `textures/xdecor_speaker_front.png`
|
||||
* `textures/xdecor_speaker_side.png`
|
||||
* `textures/xdecor_speaker_top.png`
|
||||
* `sounds/xdecor_enchanting.ogg`
|
||||
|
||||
(see `LICENSE` file for licensing).
|
||||
|
||||
## Technical information
|
||||
X-Decor-libre is a fork of X-Decor, from <https://github.com/minetest-mods/xdecor>,
|
||||
forked at Git commit ID 8b614b3513f2719d5975c883180c011cb7428c8d.
|
||||
|
||||
Note the technical mod name of X-Decor-libre is the same as for X-Decor: `xdecor`.
|
||||
This is because this mod is meant to be a drop-in-replacement.
|
||||
|
||||
The original readme of X-Decor can be found at `OLD_README.md`.
|
154
mods/xdecor/handlers/animations.lua
Normal file
|
@ -0,0 +1,154 @@
|
|||
local mod_player_api = minetest.get_modpath("player_api") ~= nil
|
||||
|
||||
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
|
||||
-- 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()
|
||||
|
||||
-- Stand up if sitting
|
||||
if sitting[player_name] then
|
||||
stand_up(player_name)
|
||||
|
||||
-- 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
|
||||
|
||||
-- Can't sit down on note already occupied by player
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
if seats_occupied[hash] then
|
||||
return
|
||||
end
|
||||
|
||||
player_api.player_attached[player_name] = true
|
||||
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)
|
||||
elseif node.param2 == 1 then
|
||||
clicker:set_look_horizontal(3*(math.pi/2))
|
||||
elseif node.param2 == 2 then
|
||||
clicker:set_look_horizontal(math.pi)
|
||||
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
|
||||
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)
|
170
mods/xdecor/handlers/glasscut.lua
Normal file
|
@ -0,0 +1,170 @@
|
|||
-- Tile definitions for cut nodes of glass nodes:
|
||||
-- * Woodframed Glass (this mod)
|
||||
-- * Glass (Minetest Game)
|
||||
-- * Obsidian Glass (Minetest Game)
|
||||
-- This is done so the glass nodes still look nice
|
||||
-- when cut.
|
||||
-- If we would only use the base glass tile, most
|
||||
-- cut nodes look horrible because there are no
|
||||
-- clear contours.
|
||||
|
||||
local template_suffixes_glass = {
|
||||
stair = {
|
||||
"_split.png",
|
||||
".png",
|
||||
"_stairside.png^[transformFX",
|
||||
"_stairside.png",
|
||||
".png",
|
||||
"_split.png",
|
||||
},
|
||||
stair_inner = {
|
||||
"_stairside.png^[transformR270",
|
||||
".png",
|
||||
"_stairside.png^[transformFX",
|
||||
".png",
|
||||
".png",
|
||||
"_stairside.png",
|
||||
},
|
||||
stair_outer = {
|
||||
"_stairside.png^[transformR90",
|
||||
".png",
|
||||
"_outer_stairside.png",
|
||||
"_stairside.png",
|
||||
"_stairside.png^[transformR90",
|
||||
"_outer_stairside.png",
|
||||
},
|
||||
halfstair = {
|
||||
"_cube.png",
|
||||
".png",
|
||||
"_stairside.png^[transformFX",
|
||||
"_stairside.png",
|
||||
"_split.png^[transformR90",
|
||||
"_cube.png",
|
||||
},
|
||||
slab = {
|
||||
".png",
|
||||
".png",
|
||||
"_split.png",
|
||||
},
|
||||
cube = { "_cube.png" },
|
||||
thinstair = { "_split.png" },
|
||||
micropanel = { "_split.png" },
|
||||
panel = {
|
||||
"_split.png",
|
||||
"_split.png",
|
||||
"_cube.png",
|
||||
"_cube.png",
|
||||
"_split.png",
|
||||
},
|
||||
}
|
||||
|
||||
-- Template for "grass-covered" and similar nodes.
|
||||
-- This is defined in a way so that the cut nodes
|
||||
-- still have a natural-looking grass cover.
|
||||
-- !TOP and !BOTTOM are special and will be
|
||||
-- replaced via function argument.
|
||||
|
||||
local template_suffixes_grasscover = {
|
||||
stair = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_stairside.png^[transformFX",
|
||||
"_stairside.png",
|
||||
".png",
|
||||
"_split.png",
|
||||
},
|
||||
stair_inner = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_stairside.png^[transformFX",
|
||||
".png",
|
||||
".png",
|
||||
"_stairside.png",
|
||||
},
|
||||
stair_outer = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_outer_stairside.png",
|
||||
"_stairside.png",
|
||||
"_stairside.png^[transformR90",
|
||||
"_outer_stairside.png",
|
||||
},
|
||||
halfstair = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_stairside.png^[transformFX",
|
||||
"_stairside.png",
|
||||
".png",
|
||||
"_cube.png",
|
||||
},
|
||||
slab = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_split.png",
|
||||
},
|
||||
cube = { "!TOP", "!BOTTOM", "_cube.png" },
|
||||
thinstair = { "!TOP", "!BOTTOM", "_cube.png" },
|
||||
micropanel = { "!TOP", "!BOTTOM", "!TOP" },
|
||||
nanoslab = { "!TOP", "!BOTTOM", "!TOP" },
|
||||
microslab = { "!TOP", "!BOTTOM", "!TOP" },
|
||||
panel = {
|
||||
"!TOP",
|
||||
"!BOTTOM",
|
||||
"_cube.png",
|
||||
"_cube.png",
|
||||
"_split.png",
|
||||
},
|
||||
}
|
||||
|
||||
local generate_tilenames_glass = function(prefix, default_texture)
|
||||
if not default_texture then
|
||||
default_texture = prefix
|
||||
end
|
||||
local cuts = {}
|
||||
for t, tiles in pairs(template_suffixes_glass) do
|
||||
cuts[t] = {}
|
||||
for i=1, #tiles do
|
||||
if tiles[i] == ".png" then
|
||||
cuts[t][i] = default_texture .. tiles[i]
|
||||
else
|
||||
cuts[t][i] = prefix .. tiles[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
return cuts
|
||||
end
|
||||
|
||||
local generate_tilenames_grasscover = function(prefix, default_texture, base, top, bottom)
|
||||
if not default_texture then
|
||||
default_texture = prefix
|
||||
end
|
||||
local cuts = {}
|
||||
for t, tiles in pairs(template_suffixes_grasscover) do
|
||||
cuts[t] = {}
|
||||
for i=1, #tiles do
|
||||
if tiles[i] == "!TOP" then
|
||||
cuts[t][i] = {name=top, align_style="world"}
|
||||
elseif tiles[i] == "!BOTTOM" then
|
||||
cuts[t][i] = {name=bottom, align_style="world"}
|
||||
else
|
||||
if tiles[i] == ".png" then
|
||||
cuts[t][i] = default_texture .. tiles[i]
|
||||
else
|
||||
cuts[t][i] = prefix .. tiles[i]
|
||||
end
|
||||
if base then
|
||||
cuts[t][i] = base .. "^" .. cuts[t][i]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return cuts
|
||||
end
|
||||
|
||||
xdecor.glasscuts = {
|
||||
["xdecor:woodframed_glass"] = generate_tilenames_glass("xdecor_woodframed_glass"),
|
||||
["default:glass"] = generate_tilenames_glass("stairs_glass", "default_glass"),
|
||||
["default:obsidian_glass"] = generate_tilenames_glass("stairs_obsidian_glass", "default_obsidian_glass"),
|
||||
["default:permafrost_with_moss"] = generate_tilenames_grasscover("xdecor_permafrost_moss", "default_moss_side", "default_permafrost.png", "default_moss.png", "default_permafrost.png"),
|
||||
["default:permafrost_with_stones"] = generate_tilenames_grasscover("xdecor_permafrost_stones", "default_stones_side", "default_permafrost.png", "default_permafrost.png^default_stones.png", "default_permafrost.png"),
|
||||
}
|
68
mods/xdecor/handlers/helpers.lua
Normal file
|
@ -0,0 +1,68 @@
|
|||
-- Returns the greatest numeric key in a table.
|
||||
function xdecor.maxn(T)
|
||||
local n = 0
|
||||
for k in pairs(T) do
|
||||
if k > n then
|
||||
n = k
|
||||
end
|
||||
end
|
||||
|
||||
return n
|
||||
end
|
||||
|
||||
-- Returns the length of an hash table.
|
||||
function xdecor.tablelen(T)
|
||||
local n = 0
|
||||
|
||||
for _ in pairs(T) do
|
||||
n = n + 1
|
||||
end
|
||||
|
||||
return n
|
||||
end
|
||||
|
||||
-- Deep copy of a table. Borrowed from mesecons mod (https://github.com/Jeija/minetest-mod-mesecons).
|
||||
function xdecor.tablecopy(T)
|
||||
if type(T) ~= "table" then
|
||||
return T -- No need to copy.
|
||||
end
|
||||
|
||||
local new = {}
|
||||
|
||||
for k, v in pairs(T) do
|
||||
if type(v) == "table" then
|
||||
new[k] = xdecor.tablecopy(v)
|
||||
else
|
||||
new[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
return new
|
||||
end
|
||||
|
||||
function xdecor.stairs_valid_def(def)
|
||||
return (def.drawtype == "normal" or def.drawtype:sub(1,5) == "glass") and
|
||||
(def.groups.cracky or def.groups.choppy) and
|
||||
not def.on_construct and
|
||||
not def.after_place_node and
|
||||
not def.on_rightclick and
|
||||
not def.on_blast and
|
||||
not def.allow_metadata_inventory_take and
|
||||
not (def.groups.not_in_creative_inventory == 1) and
|
||||
not (def.groups.not_cuttable == 1) and
|
||||
not def.groups.wool and
|
||||
(def.tiles and type(def.tiles[1]) == "string" and not
|
||||
def.tiles[1]:find("default_mineral")) and
|
||||
not def.mesecons and
|
||||
def.description and
|
||||
def.description ~= "" and
|
||||
def.light_source == 0
|
||||
end
|
||||
|
||||
function xdecor.get_inventory_drops(pos, listnames)
|
||||
local drops = {}
|
||||
for l=1, #listnames do
|
||||
default.get_inventory_drops(pos, listnames[l], drops)
|
||||
end
|
||||
return drops
|
||||
end
|
67
mods/xdecor/handlers/nodeboxes.lua
Normal file
|
@ -0,0 +1,67 @@
|
|||
xdecor.box = {
|
||||
slab_y = function(height, shift)
|
||||
return {
|
||||
-0.5,
|
||||
-0.5 + (shift or 0),
|
||||
-0.5,
|
||||
0.5,
|
||||
-0.5 + height + (shift or 0),
|
||||
0.5
|
||||
}
|
||||
end,
|
||||
slab_z = function(depth)
|
||||
return {-0.5, -0.5, -0.5 + depth, 0.5, 0.5, 0.5}
|
||||
end,
|
||||
bar_y = function(radius)
|
||||
return {-radius, -0.5, -radius, radius, 0.5, radius}
|
||||
end,
|
||||
cuboid = function(radius_x, radius_y, radius_z)
|
||||
return {-radius_x, -radius_y, -radius_z, radius_x, radius_y, radius_z}
|
||||
end
|
||||
}
|
||||
|
||||
xdecor.nodebox = {
|
||||
regular = {type = "regular"},
|
||||
null = {
|
||||
type = "fixed", fixed = {0,0,0,0,0,0}
|
||||
}
|
||||
}
|
||||
|
||||
xdecor.pixelbox = function(size, boxes)
|
||||
local fixed = {}
|
||||
for _, box in ipairs(boxes) do
|
||||
-- `unpack` has been changed to `table.unpack` in newest Lua versions.
|
||||
local x, y, z, w, h, l = unpack(box)
|
||||
fixed[#fixed + 1] = {
|
||||
(x / size) - 0.5,
|
||||
(y / size) - 0.5,
|
||||
(z / size) - 0.5,
|
||||
((x + w) / size) - 0.5,
|
||||
((y + h) / size) - 0.5,
|
||||
((z + l) / size) - 0.5
|
||||
}
|
||||
end
|
||||
|
||||
return {type = "fixed", fixed = fixed}
|
||||
end
|
||||
|
||||
local mt = {}
|
||||
|
||||
mt.__index = function(table, key)
|
||||
local ref = xdecor.box[key]
|
||||
local ref_type = type(ref)
|
||||
|
||||
if ref_type == "function" then
|
||||
return function(...)
|
||||
return {type = "fixed", fixed = ref(...)}
|
||||
end
|
||||
elseif ref_type == "table" then
|
||||
return {type = "fixed", fixed = ref}
|
||||
elseif ref_type == "nil" then
|
||||
error(key .. "could not be found among nodebox presets and functions")
|
||||
end
|
||||
|
||||
error("unexpected datatype " .. tostring(type(ref)) .. " while looking for " .. key)
|
||||
end
|
||||
|
||||
setmetatable(xdecor.nodebox, mt)
|
183
mods/xdecor/handlers/registration.lua
Normal file
|
@ -0,0 +1,183 @@
|
|||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
xdecor.xbg = default.gui_bg .. default.gui_bg_img .. default.gui_slots
|
||||
local default_inventory_size = 32
|
||||
|
||||
local default_inventory_formspecs = {
|
||||
["8"] = [[ size[8,6]
|
||||
list[context;main;0,0;8,1;]
|
||||
list[current_player;main;0,2;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;main] ]] ..
|
||||
default.get_hotbar_bg(0,2),
|
||||
|
||||
["16"] = [[ size[8,7]
|
||||
list[context;main;0,0;8,2;]
|
||||
list[current_player;main;0,3;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;main] ]] ..
|
||||
default.get_hotbar_bg(0,3),
|
||||
|
||||
["24"] = [[ size[8,8]
|
||||
list[context;main;0,0;8,3;]
|
||||
list[current_player;main;0,4;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;main]" ]] ..
|
||||
default.get_hotbar_bg(0,4),
|
||||
|
||||
["32"] = [[ size[8,9]
|
||||
list[context;main;0,0.3;8,4;]
|
||||
list[current_player;main;0,4.85;8,1;]
|
||||
list[current_player;main;0,6.08;8,3;8]
|
||||
listring[current_player;main]
|
||||
listring[context;main] ]] ..
|
||||
default.get_hotbar_bg(0,4.85)
|
||||
}
|
||||
|
||||
local function get_formspec_by_size(size)
|
||||
local formspec = default_inventory_formspecs[tostring(size)]
|
||||
return formspec or default_inventory_formspecs
|
||||
end
|
||||
|
||||
local default_can_dig = function(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("main")
|
||||
end
|
||||
|
||||
local function xdecor_stairs_alternative(nodename, def)
|
||||
local mod, name = nodename:match("(.*):(.*)")
|
||||
|
||||
for groupname, value in pairs(def.groups) do
|
||||
if groupname ~= "cracky" and groupname ~= "choppy" and
|
||||
groupname ~= "flammable" and groupname ~= "crumbly" and
|
||||
groupname ~= "snappy" then
|
||||
def.groups.groupname = nil
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.get_modpath("moreblocks") then
|
||||
stairsplus:register_all(
|
||||
mod,
|
||||
name,
|
||||
nodename,
|
||||
{
|
||||
description = def.description,
|
||||
tiles = def.tiles,
|
||||
groups = def.groups,
|
||||
sounds = def.sounds,
|
||||
}
|
||||
)
|
||||
elseif minetest.get_modpath("stairs") then
|
||||
local custom_tiles = xdecor.glasscuts[nodename]
|
||||
if custom_tiles and (custom_tiles.slab or custom_tiles.stair) then
|
||||
if custom_tiles.stair then
|
||||
stairs.register_stair(name, nodename,
|
||||
def.groups, custom_tiles.stair, S("@1 Stair", def.description),
|
||||
def.sounds)
|
||||
stairs.register_stair_inner(name, nodename,
|
||||
def.groups, custom_tiles.stair_inner, "", def.sounds, nil, S("Inner @1 Stair", def.description))
|
||||
stairs.register_stair_outer(name, nodename,
|
||||
def.groups, custom_tiles.stair_outer, "", def.sounds, nil, S("Outer @1 Stair", def.description))
|
||||
end
|
||||
if custom_tiles.slab then
|
||||
stairs.register_slab(name, nodename,
|
||||
def.groups, custom_tiles.slab, S("@1 Slab", def.description),
|
||||
def.sounds)
|
||||
end
|
||||
else
|
||||
stairs.register_stair_and_slab(name,nodename,
|
||||
def.groups,
|
||||
def.tiles,
|
||||
S("@1 Stair", def.description),
|
||||
S("@1 Slab", def.description),
|
||||
def.sounds, nil,
|
||||
S("Inner @1 Stair", def.description),
|
||||
S("Outer @1 Stair", def.description)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function xdecor.register(name, def)
|
||||
def.drawtype = def.drawtype or (def.mesh and "mesh") or (def.node_box and "nodebox")
|
||||
def.sounds = def.sounds or default.node_sound_defaults()
|
||||
|
||||
if not (def.drawtype == "normal" or def.drawtype == "signlike" or
|
||||
def.drawtype == "plantlike" or def.drawtype == "glasslike_framed" or
|
||||
def.drawtype == "glasslike_framed_optional") then
|
||||
def.paramtype2 = def.paramtype2 or "facedir"
|
||||
end
|
||||
|
||||
if def.sunlight_propagates ~= false and
|
||||
(def.drawtype == "plantlike" or def.drawtype == "torchlike" or
|
||||
def.drawtype == "signlike" or def.drawtype == "fencelike") then
|
||||
def.sunlight_propagates = true
|
||||
end
|
||||
|
||||
if not def.paramtype and
|
||||
(def.light_source or def.sunlight_propagates or
|
||||
def.drawtype == "nodebox" or def.drawtype == "mesh") then
|
||||
def.paramtype = "light"
|
||||
end
|
||||
|
||||
local infotext = def.infotext
|
||||
local inventory = def.inventory
|
||||
def.inventory = nil
|
||||
|
||||
if inventory then
|
||||
def.on_construct = def.on_construct or function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if infotext then meta:set_string("infotext", infotext) end
|
||||
|
||||
local size = inventory.size or default_inventory_size
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
inv:set_size("main", size)
|
||||
meta:set_string("formspec",
|
||||
(inventory.formspec or get_formspec_by_size(size)) .. xdecor.xbg)
|
||||
end
|
||||
|
||||
def.can_dig = def.can_dig or default_can_dig
|
||||
|
||||
elseif infotext and not def.on_construct then
|
||||
def.on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", infotext)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_node("xdecor:" .. name, def)
|
||||
|
||||
local workbench = minetest.settings:get_bool("enable_xdecor_workbench")
|
||||
|
||||
if workbench == false and
|
||||
(minetest.get_modpath("moreblocks") or minetest.get_modpath("stairs")) then
|
||||
if xdecor.stairs_valid_def(def) then
|
||||
xdecor_stairs_alternative("xdecor:"..name, def)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Registers aliases for a node that had a name collision
|
||||
-- with a node from the moreblocks mod
|
||||
function xdecor.register_legacy_aliases(original_basename, new_basename)
|
||||
minetest.register_alias("xdecor:"..original_basename, "xdecor:"..new_basename)
|
||||
minetest.register_alias("xdecor:"..original_basename.."_panel", "xdecor:"..new_basename.."_panel")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_doublepanel", "xdecor:"..new_basename.."_doublepanel")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_micropanel", "xdecor:"..new_basename.."_micropanel")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_halfstair", "xdecor:"..new_basename.."_halfstair")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_thinstair", "xdecor:"..new_basename.."_thinstair")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_cube", "xdecor:"..new_basename.."_cube")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_microslab", "xdecor:"..new_basename.."_microslab")
|
||||
minetest.register_alias("xdecor:"..original_basename.."_nanoslab", "xdecor:"..new_basename.."_nanoslab")
|
||||
if not minetest.get_modpath("moreblocks") then
|
||||
minetest.register_alias("stairs:slab_"..original_basename, "stairs:slab_"..new_basename)
|
||||
minetest.register_alias("stairs:stair_"..original_basename, "stairs:stair_"..new_basename)
|
||||
minetest.register_alias("stairs:stair_outer_"..original_basename, "stairs:stair_outer_"..new_basename)
|
||||
minetest.register_alias("stairs:stair_inner_"..original_basename, "stairs:stair_inner"..new_basename)
|
||||
end
|
||||
if minetest.get_modpath("stairsplus") and minetest.global_exists("stairsplus") and stairsplus.api then
|
||||
stairsplus.api.register_alias_all("xdecor:"..original_basename, "xdecor:"..new_basename)
|
||||
end
|
||||
end
|
||||
|
44
mods/xdecor/init.lua
Normal file
|
@ -0,0 +1,44 @@
|
|||
--local t = os.clock()
|
||||
|
||||
xdecor = {}
|
||||
local modpath = minetest.get_modpath("xdecor")
|
||||
|
||||
dofile(modpath .. "/handlers/glasscut.lua")
|
||||
dofile(modpath .. "/handlers/animations.lua")
|
||||
dofile(modpath .. "/handlers/helpers.lua")
|
||||
dofile(modpath .. "/handlers/nodeboxes.lua")
|
||||
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",
|
||||
"enchanting",
|
||||
"hive",
|
||||
"itemframe",
|
||||
"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, true)
|
||||
if enable then
|
||||
dofile(modpath .. "/src/" .. name .. ".lua")
|
||||
end
|
||||
end
|
||||
|
||||
-- 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
|
217
mods/xdecor/locale/template.txt
Normal file
|
@ -0,0 +1,217 @@
|
|||
# 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!=
|
||||
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.=
|
||||
Chess Board=
|
||||
Someone else plays white pieces!=
|
||||
It's not your turn!=
|
||||
Someone else plays black pieces!=
|
||||
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=
|
||||
White Pawn=
|
||||
Black Pawn=
|
||||
White Rook=
|
||||
Black Rook=
|
||||
White Knight=
|
||||
Black Knight=
|
||||
White Bishop=
|
||||
Black Bishop=
|
||||
White Queen=
|
||||
Black Queen=
|
||||
White King=
|
||||
Black King=
|
||||
Light a fire below to heat it up=
|
||||
Use a bowl to eat the soup=
|
||||
Drop foods inside to make a soup=
|
||||
Cauldron (empty)=
|
||||
Cauldron (cold water)=
|
||||
Cauldron (cold river water)=
|
||||
Cauldron (cold soup)=
|
||||
Cauldron (boiling water)=
|
||||
Cauldron (boiling river water)=
|
||||
Cauldron (boiling soup)=
|
||||
No room in your inventory to add a bucket of water.=
|
||||
No room in your inventory to add a bowl of soup.=
|
||||
Cauldron=
|
||||
For storing water and cooking soup=
|
||||
Cauldron with Water (cold)=
|
||||
Cauldron with River Water (cold)=
|
||||
Cauldron with Soup (cold)=
|
||||
Cauldron with Water (boiling)=
|
||||
Cauldron with River Water (boiling)=
|
||||
Cauldron with Soup (boiling)=
|
||||
Bowl=
|
||||
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@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=
|
||||
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=
|
||||
Lever=
|
||||
Opens doors when pulled=
|
||||
Bamboo Frame=
|
||||
Chainlink=
|
||||
Rusty Iron Bars=
|
||||
Wood Frame=
|
||||
Barricade=
|
||||
Barrel=
|
||||
Wooden Cabinet=
|
||||
24 inventory slots=
|
||||
Half Wooden Cabinet=
|
||||
8 inventory slots=
|
||||
Plain Shelf=
|
||||
Multi Shelf=
|
||||
Candle=
|
||||
Chair=
|
||||
Cobweb=
|
||||
Red Curtain=
|
||||
Cushion=
|
||||
Cushion Block=
|
||||
Japanese Door=
|
||||
Prison Door=
|
||||
Rusty Prison Door=
|
||||
Screen Door=
|
||||
Paper Door=
|
||||
Woodglass Door=
|
||||
Ender Chest=
|
||||
Interdimensional inventory=
|
||||
Ivy=
|
||||
Weathercock=
|
||||
Lantern=
|
||||
Hanging Lantern=
|
||||
Steel Lattice Light Box=
|
||||
Wooden Cross Light Box=
|
||||
Wooden Rhombus Light Box=
|
||||
Potted White Dandelion=
|
||||
Potted Yellow Dandelion=
|
||||
Potted Geranium=
|
||||
Potted Rose=
|
||||
Potted Tulip=
|
||||
Potted Viola=
|
||||
Painting=
|
||||
Garden Stone Path=
|
||||
Cactus Brick=
|
||||
Coal Stone Tile=
|
||||
Polished Desert Stone Block=
|
||||
Hardened Clay=
|
||||
Moon Brick=
|
||||
Runestone=
|
||||
Polished Stone Block=
|
||||
Packed Ice=
|
||||
Wooden Tile=
|
||||
Table=
|
||||
Tatami=
|
||||
Trampoline=
|
||||
Television=
|
||||
Wood Framed Glass=
|
||||
Radio=
|
||||
Speaker=
|
||||
Rope=
|
||||
Nanoslab=
|
||||
Micropanel=
|
||||
Microslab=
|
||||
Thin Stair=
|
||||
Cube=
|
||||
Panel=
|
||||
Slab=
|
||||
Double Panel=
|
||||
Half-Stair=
|
||||
Stair=
|
||||
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=
|
217
mods/xdecor/locale/xdecor.de.tr
Normal file
|
@ -0,0 +1,217 @@
|
|||
# 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!
|
||||
The game ended up in a dead position! It's a draw!=Das Partie endete in einer toten Stellung. Das ist ein Remis!
|
||||
No piece was captured and no pawn was moved for 75 consecutive moves of each player. It's a draw!=Für 75 Züge in Folge von je beiden Spielern wurde keine Figur geschlagen und kein Bauer gezogen. Es ist ein Remis!
|
||||
You have drawn the game by invoking the 50-move rule.=Sie haben die Partie remis enden lassen, indem Sie die 50-Züge-Regel angewandt haben.
|
||||
@1 has drawn the game by invoking the 50-move rule.=@1 hat die Partie mittels der 50-Züge Regel remis enden lassen.
|
||||
You have failed to make a game-drawing move. The game continues.=Sie haben keinen Zug gemacht, der die Partie remis enden lässt. Die Partie geht weiter.
|
||||
@1 made a draw claim using the 50-move rule but it was false. The game continues.=@1 hat ein Remis mittels der 50-Züge-Regel beansprucht aber lag falsch. Die Partie geht weiter.
|
||||
The exact same position has occured 5 times. It's a draw!=Die exakt gleiche Stellung ist 5 mal aufgetreten. Das ist ein Remis!
|
||||
You have drawn the game by invoking the threefold repetition rule.=Sie haben die Partie remis enden lassen, indem Sie die Stellungswiederholungsregel angewandt haben.
|
||||
@1 has drawn the game by invoking the threefold repetition rule.=@1 hat die Partie remis mittels der Stellungswiederholungsregel enden lassen.
|
||||
@1 made a draw claim using the threefold repetition rule but it was false. The game continues.=@1 hat ein Remis mittels der Stellungswiederholungsregel beansprucht aber lag falsch. Die Partie geht weiter.
|
||||
Chess Board=Schachbrett
|
||||
Someone else plays white pieces!=Jemand anderes spielt Weiß!
|
||||
It's not your turn!=Sie sind nicht am Zug!
|
||||
Someone else plays black pieces!=Jemand anderes spielt Schwarz!
|
||||
Black cannot move first!=Schwarz darf nicht zuerst ziehen!
|
||||
@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.=Sie können das Schachbrett nicht zurücksetzen, es wurde eine Partie gestartet. Versuchen Sie es erneut in @1.
|
||||
Resigning is not possible yet.=Aufgeben ist noch nicht möglich.
|
||||
You have resigned.=Sie haben aufgegeben.
|
||||
@1 has resigned. You win!=@1 hat aufgegeben. Sie haben gewonnen!
|
||||
You can't resign, you're not playing in this game.=Sie können nicht aufgeben, Sie spielen nicht in dieser Partie.
|
||||
You can't claim a draw, it's not your turn!=Sie können kein Remis beanspruchen, Sie sind nicht am Zug!
|
||||
You're only a spectator in this game of Chess.=Sie sind nur Zuschauer bei dieser Schachpartie.
|
||||
This isn't the time for promotion.=Jetzt ist nicht die Zeit für eine Umwandlung.
|
||||
It's not your turn! This promotion is meant for the other player.=Sie sind nicht am Zug! Diese Umwandlung ist für den anderen Spieler.
|
||||
You can't dig the chessboard, a game has been started. Reset it first or dig it again in @1.=Sie können das Schachbrett nicht abbauen, es wurde eine Partie gestartet. Setzen Sie es zuerst zurück oder bauen Sie es in @1 erneut ab.
|
||||
You can't dig the chessboard, a game has been started. Try it again in @1.=Sie können das Schachbrett nicht abbauen, es wurde eine Partie gestartet. Versuchen Sie es erneut in @1.
|
||||
Play a game of Chess against another player or the computer=Für Schachspiele gegen einen anderen Spieler oder den Computer
|
||||
White Pawn=Weißer Bauer
|
||||
Black Pawn=Schwarzer Bauer
|
||||
White Rook=Weißer Turm
|
||||
Black Rook=Schwarzer Turm
|
||||
White Knight=Weißer Springer
|
||||
Black Knight=Schwarzer Springer
|
||||
White Bishop=Weißer Läufer
|
||||
Black Bishop=Schwarzer Läufer
|
||||
White Queen=Weiße Dame
|
||||
Black Queen=Schwarze Dame
|
||||
White King=Weißer König
|
||||
Black King=Schwarzer König
|
||||
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
|
||||
Cauldron (empty)=Kessel (leer)
|
||||
Cauldron (cold water)=Kessel (kaltes Wasser)
|
||||
Cauldron (cold river water)=Kessel (kaltes Flusswasser)
|
||||
Cauldron (cold soup)=Kessel (kalte Suppe)
|
||||
Cauldron (boiling water)=Kessel (kochendes Wasser)
|
||||
Cauldron (boiling river water)=Kessel (kochendes Flusswasser)
|
||||
Cauldron (boiling soup)=Kessel (kochende Supppe)
|
||||
No room in your inventory to add a bucket of water.=Zu wenig Platz im Inventar für einen Eimer Wasser.
|
||||
No room in your inventory to add a bowl of soup.=Zu wenig Platz im Inventar für eine Schüssel voll Suppe.
|
||||
Cauldron=Kessel
|
||||
For storing water and cooking soup=Zur Lagerung von Wasser und zum Suppe kochen
|
||||
Cauldron with Water (cold)=Kessel mit Wasser (kalt)
|
||||
Cauldron with River Water (cold)=Kessel mit Flusssasser (kalt)
|
||||
Cauldron with Soup (cold)=Kessel mit Suppe (kalt)
|
||||
Cauldron with Water (boiling)=Kessel mit Wasser (kochend)
|
||||
Cauldron with River Water (boiling)=Kessel mit Flusswasser (kochend)
|
||||
Cauldron with Soup (boiling)=Kessel mit Suppe (kochend)
|
||||
Bowl=Schüssel
|
||||
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@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=× @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
|
||||
Lever=Schalthebel
|
||||
Opens doors when pulled=Öffnet Türen beim Betätigen
|
||||
Bamboo Frame=Bambusgerüst
|
||||
Chainlink=Maschendraht
|
||||
Rusty Iron Bars=Rostige Eisenstäbe
|
||||
Wood Frame=Holzrahmen
|
||||
Barricade=Barrikade
|
||||
Barrel=Fass
|
||||
Wooden Cabinet=Holzschrank
|
||||
24 inventory slots=24 Inventarplätze
|
||||
Half Wooden Cabinet=Halber Holzschrank
|
||||
8 inventory slots=8 Inventarplätze
|
||||
Plain Shelf=Schlichtes Regal
|
||||
Multi Shelf=Mehrzweckregal
|
||||
Candle=Kerze
|
||||
Chair=Stuhl
|
||||
Cobweb=Spinnenwebe
|
||||
Red Curtain=Roter Vorhang
|
||||
Cushion=Sitzkissen
|
||||
Cushion Block=Sitzkissenblock
|
||||
Japanese Door=Japanische Tür
|
||||
Prison Door=Kerkertür
|
||||
Rusty Prison Door=Rostige Kerkertür
|
||||
Screen Door=Fliegengittertür
|
||||
Paper Door=Papiertür
|
||||
Woodglass Door=Tür mit Lichtausschnitt
|
||||
Ender Chest=Endertruhe
|
||||
Interdimensional inventory=Interdimensionales Inventar
|
||||
Ivy=Efeu
|
||||
Weathercock=Wetterhahn
|
||||
Lantern=Laterne
|
||||
Hanging Lantern=Hängende Laterne
|
||||
Steel Lattice Light Box=Stahlgitterlichtbox
|
||||
Wooden Cross Light Box=Holzkreuzlichtbox
|
||||
Wooden Rhombus Light Box=Holzrautenlichtbox
|
||||
Potted White Dandelion=Weißer Löwenzahn im Topf
|
||||
Potted Yellow Dandelion=Gelber Löwenzahn im Topf
|
||||
Potted Geranium=Geranie im Topf
|
||||
Potted Rose=Rose im Topf
|
||||
Potted Tulip=Tulpe im Topf
|
||||
Potted Viola=Veilchen im Topf
|
||||
Painting=Gemälde
|
||||
Garden Stone Path=Steingartenweg
|
||||
Cactus Brick=Kaktusziegel
|
||||
Coal Stone Tile=Kohlesteinkachel
|
||||
Polished Desert Stone Block=Hochglanzwüstensteinblock
|
||||
Hardened Clay=Gehärteter Ton
|
||||
Moon Brick=Mondziegel
|
||||
Runestone=Runenstein
|
||||
Polished Stone Block=Hochglanzsteinblock
|
||||
Packed Ice=Packeis
|
||||
Wooden Tile=Holzkachel
|
||||
Table=Tisch
|
||||
Tatami=Tatamimatte
|
||||
Trampoline=Trampolin
|
||||
Television=Fernseher
|
||||
Wood Framed Glass=Holzrahmenglas
|
||||
Radio=Radio
|
||||
Speaker=Lautsprecher
|
||||
Rope=Seil
|
||||
Nanoslab=nanoplatte
|
||||
Micropanel=mikropaneel
|
||||
Microslab=mikroplatte
|
||||
Thin Stair=flachtreppe
|
||||
Cube=würfel
|
||||
Panel=paneel
|
||||
Slab=platte
|
||||
Double Panel=doppelpaneel
|
||||
Half-Stair=halbtreppe
|
||||
Stair=Treppe
|
||||
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
|
236
mods/xdecor/locale/xdecor.fr.tr
Normal file
|
@ -0,0 +1,236 @@
|
|||
# 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!=
|
||||
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.=
|
||||
Chess Board=Echiquier
|
||||
Someone else plays white pieces!=Quelqu’un d’autre joue les pièces blanches !
|
||||
It's not your turn!=
|
||||
Someone else plays black pieces!=Quelqu’un d’autre joue les pièces noires !
|
||||
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=
|
||||
White Pawn=Pion blanc
|
||||
Black Pawn=Pion noir
|
||||
White Rook=Tour blanche
|
||||
Black Rook=Tour noire
|
||||
White Knight=Cavalier blanc
|
||||
Black Knight=Cavalier noir
|
||||
White Bishop=Fou blanc
|
||||
Black Bishop=Fou noir
|
||||
White Queen=Reine blanche
|
||||
Black Queen=Reine noire
|
||||
White King=Roi blanc
|
||||
Black King=Roi noir
|
||||
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 à l’intérieur pour faire une soupe
|
||||
Cauldron (empty)=Chaudron (vide)
|
||||
Cauldron (cold water)=
|
||||
Cauldron (cold river water)=
|
||||
Cauldron (cold soup)=
|
||||
Cauldron (boiling water)=
|
||||
Cauldron (boiling river water)=
|
||||
Cauldron (boiling soup)=
|
||||
No room in your inventory to add a bucket of water.=Pas de place dans votre inventaire pour ajouter un seau d’eau.
|
||||
No room in your inventory to add a bowl of soup.=Pas de place dans votre inventaire pour ajouter un bol de soupe.
|
||||
Cauldron=Chaudron
|
||||
For storing water and cooking soup=
|
||||
Cauldron with Water (cold)=
|
||||
Cauldron with River Water (cold)=
|
||||
Cauldron with Soup (cold)=
|
||||
Cauldron with Water (boiling)=
|
||||
Cauldron with River Water (boiling)=
|
||||
Cauldron with Soup (boiling)=
|
||||
Bowl=Bol
|
||||
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 d’enchantements
|
||||
Enchant your tools with mese crystals=
|
||||
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=
|
||||
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
|
||||
Lever=Levier
|
||||
Opens doors when pulled=
|
||||
Bamboo Frame=Cadre en bambou
|
||||
Chainlink=Maillon de chaîne
|
||||
Rusty Iron Bars=Barreaux en fer rouillé
|
||||
Wood Frame=Cadre en bois
|
||||
Barricade=Barricade
|
||||
Barrel=Tonneau
|
||||
Wooden Cabinet=Meuble en bois
|
||||
24 inventory slots=
|
||||
Half Wooden Cabinet=Demi meuble en bois
|
||||
8 inventory slots=
|
||||
Plain Shelf=
|
||||
Multi Shelf=Étagères multiple
|
||||
Candle=Bougie
|
||||
Chair=Chaise
|
||||
Cobweb=Toile d’araignée
|
||||
Red Curtain=Rideaux rouge
|
||||
Cushion=Coussin
|
||||
Cushion Block=Bloc de coussin
|
||||
Japanese Door=Porte japonaise
|
||||
Prison Door=Porte de prison
|
||||
Rusty Prison Door=Barreaux de prison rouillés
|
||||
Screen Door=Porte avec moustiquaire
|
||||
Paper Door=
|
||||
Woodglass Door=Porte vitrée
|
||||
Ender Chest=Coffre de l’End
|
||||
Interdimensional inventory=
|
||||
Ivy=Lierre
|
||||
Weathercock=
|
||||
Lantern=Lanterne
|
||||
Hanging Lantern=
|
||||
Steel Lattice Light Box=
|
||||
Wooden Cross Light Box=
|
||||
Wooden Rhombus Light Box=
|
||||
Potted White Dandelion=Pissenlit blanc en pot
|
||||
Potted Yellow Dandelion=Pissenlit jaune en pot
|
||||
Potted Geranium=Géranium en pot
|
||||
Potted Rose=Rose en pot
|
||||
Potted Tulip=Tulipe en pot
|
||||
Potted Viola=Violette en pot
|
||||
Painting=Tableau
|
||||
Garden Stone Path=Chemin de pierres de jardin
|
||||
Cactus Brick=Brique en cactus
|
||||
Coal Stone Tile=Carreau en charbon et pierre
|
||||
Polished Desert Stone Block=
|
||||
Hardened Clay=Argile durcie
|
||||
Moon Brick=Brique lunaire
|
||||
Runestone=Pierre runique
|
||||
Polished Stone Block=
|
||||
Packed Ice=Glace compactée
|
||||
Wooden Tile=Carreau en bois
|
||||
Table=Table
|
||||
Tatami=Tatami
|
||||
Trampoline=Trampoline
|
||||
Television=Télévision
|
||||
Wood Framed Glass=Verre encadré par du bois
|
||||
Radio=
|
||||
Speaker=
|
||||
Rope=Corde
|
||||
Nanoslab=
|
||||
Micropanel=
|
||||
Microslab=
|
||||
Thin Stair=
|
||||
Cube=
|
||||
Panel=
|
||||
Slab=
|
||||
Double Panel=
|
||||
Half-Stair=
|
||||
Stair=
|
||||
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 #####
|
||||
|
||||
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 n’est 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 c’est votre tour de jouer, ou réessayez dans @1
|
||||
Cauldron (idle)=Chaudron (inactif)
|
||||
Cauldron (active) - Drop foods inside to make a soup=Chaudron (actif) - Placez des ingrédients à l’intérieur pour faire une soupe
|
||||
Cauldron (active) - Use a bowl to eat the soup=Chaudron (actif) - Utilisez un bol pour boire la soupe
|
||||
Cauldron (active)=Chaudron (actif)
|
||||
Bees are busy making honey…=Les abeilles sont occupées à fabriquer du miel…
|
||||
Desert Stone Tile=Carreau en pierre du désert
|
||||
Empty Shelf=Étagère vide
|
||||
Iron Light Box=Boite lumineuse en fer
|
||||
Slide Door=Porte coulissante
|
||||
Stone Tile=Carreau en pierre
|
||||
Wooden Light Box=Boite lumineuse en bois
|
236
mods/xdecor/locale/xdecor.it.tr
Normal file
|
@ -0,0 +1,236 @@
|
|||
# textdomain: xdecor
|
||||
# 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=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=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`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
|
||||
Black Rook=Torre nera
|
||||
White Knight=Cavallo bianco
|
||||
Black Knight=Cavallo nero
|
||||
White Bishop=Alfiere bianco
|
||||
Black Bishop=Alfiere nero
|
||||
White Queen=Regina bianca
|
||||
Black Queen=Regina nera
|
||||
White King=Re bianco
|
||||
Black King=Re nero
|
||||
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
|
||||
Cauldron (empty)=Calderone (vuoto)
|
||||
Cauldron (cold water)=
|
||||
Cauldron (cold river water)=
|
||||
Cauldron (cold soup)=
|
||||
Cauldron (boiling water)=
|
||||
Cauldron (boiling river water)=
|
||||
Cauldron (boiling soup)=
|
||||
No room in your inventory to add a bucket of water.=Non c'è spazio nell'inventario per aggiungere un secchio di acqua.
|
||||
No room in your inventory to add a bowl of soup.=Non c'è spazio nell'inventario per aggiungere una ciotola di zuppa.
|
||||
Cauldron=Calderone
|
||||
For storing water and cooking soup=
|
||||
Cauldron with Water (cold)=
|
||||
Cauldron with River Water (cold)=
|
||||
Cauldron with Soup (cold)=
|
||||
Cauldron with Water (boiling)=
|
||||
Cauldron with River Water (boiling)=
|
||||
Cauldron with Soup (boiling)=
|
||||
Bowl=Ciotola
|
||||
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@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=
|
||||
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
|
||||
Lever=Leva
|
||||
Opens doors when pulled=
|
||||
Bamboo Frame=Cornice di bambù
|
||||
Chainlink=Cotta di maglia
|
||||
Rusty Iron Bars=Sbarre di prigione arrugginite
|
||||
Wood Frame=Cornice in legno
|
||||
Barricade=Barricata
|
||||
Barrel=Barile
|
||||
Wooden Cabinet=Stipo di legno
|
||||
24 inventory slots=
|
||||
Half Wooden Cabinet=Stipo di legno a metà
|
||||
8 inventory slots=
|
||||
Plain Shelf=
|
||||
Multi Shelf=Mensole
|
||||
Candle=Candela
|
||||
Chair=Sedia
|
||||
Cobweb=Ragnatela
|
||||
Red Curtain=Tenda rossa
|
||||
Cushion=Cuscino
|
||||
Cushion Block=Blocco di cuscini
|
||||
Japanese Door=Porta giapponese
|
||||
Prison Door=Porta di prigione
|
||||
Rusty Prison Door=Porta di prigione arrugginita
|
||||
Screen Door=Porta a schermo
|
||||
Paper Door=
|
||||
Woodglass Door=Porta di vetro
|
||||
Ender Chest=Baule ender
|
||||
Interdimensional inventory=
|
||||
Ivy=Edera
|
||||
Weathercock=
|
||||
Lantern=Lanterna
|
||||
Hanging Lantern=
|
||||
Steel Lattice Light Box=
|
||||
Wooden Cross Light Box=
|
||||
Wooden Rhombus Light Box=
|
||||
Potted White Dandelion=Soffione bianco in vaso
|
||||
Potted Yellow Dandelion=Soffione giallo in vaso
|
||||
Potted Geranium=Geranio in vaso
|
||||
Potted Rose=Rosa in vaso
|
||||
Potted Tulip=Tulipano in vaso
|
||||
Potted Viola=Violetta in vaso
|
||||
Painting=Dipinto
|
||||
Garden Stone Path=Sentiero da giardino in pietra
|
||||
Cactus Brick=Mattone di cactus
|
||||
Coal Stone Tile=Mattonella di pietra di carbone
|
||||
Polished Desert Stone Block=
|
||||
Hardened Clay=Argilla indurita
|
||||
Moon Brick=Mattone lunare
|
||||
Runestone=Pietra runica
|
||||
Polished Stone Block=
|
||||
Packed Ice=Ghiaccio compatto
|
||||
Wooden Tile=Mattonella di legno
|
||||
Table=Tavolo
|
||||
Tatami=Tatami
|
||||
Trampoline=Trampolino
|
||||
Television=Televisione
|
||||
Wood Framed Glass=Cornice in legno con vetro
|
||||
Radio=
|
||||
Speaker=
|
||||
Rope=Corda
|
||||
Nanoslab=
|
||||
Micropanel=
|
||||
Microslab=
|
||||
Thin Stair=
|
||||
Cube=
|
||||
Panel=
|
||||
Slab=
|
||||
Double Panel=
|
||||
Half-Stair=
|
||||
Stair=
|
||||
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 #####
|
||||
|
||||
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
|
||||
Cauldron (active)=Calderone (attivo)
|
||||
Bees are busy making honey…=Le api sono occupate a fare il miele…
|
||||
Desert Stone Tile=Mattonella di pietra del deserto
|
||||
Empty Shelf=Mensola vuota
|
||||
Iron Light Box=Scatola luminosa di ferro
|
||||
Slide Door=Porta scorrevole
|
||||
Stone Tile=Mattonella di pietra
|
||||
Wooden Light Box=Mattonella luminosa di legno
|
8
mods/xdecor/mod.conf
Normal file
|
@ -0,0 +1,8 @@
|
|||
name = xdecor
|
||||
title = X-Decor-libre
|
||||
description = A libre decoration mod meant to be simple and well-featured.
|
||||
depends = default, bucket, doors, farming, stairs, xpanes
|
||||
optional_depends = player_api, fire, moreblocks, mesecons, unified_inventory, tt, toolranks
|
||||
min_minetest_version = 5.9
|
||||
release = 29354
|
||||
author = Wuzzy
|
BIN
mods/xdecor/screenshot.png
Normal file
After Width: | Height: | Size: 76 KiB |
31
mods/xdecor/settingtypes.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
# For enabling components of X-Decor-libre.
|
||||
|
||||
|
||||
|
||||
# This adds a chessboard on which you can play Chess against other players or the computer.
|
||||
enable_xdecor_chess (Enable Chess) bool true
|
||||
|
||||
# This enables the cauldron which you can use to store water and cook soup.
|
||||
enable_xdecor_cooking (Enable Cooking) bool true
|
||||
|
||||
# This adds the enchanting table which you can use to upgrade your tools with mese crystals.
|
||||
enable_xdecor_enchanting (Enable Enchanting) bool true
|
||||
|
||||
# This adds the artificial beehive which produces honey.
|
||||
enable_xdecor_hive (Enable Hive) bool true
|
||||
|
||||
# This adds itemframes which are used to show off items on a wall.
|
||||
enable_xdecor_itemframe (Enable Itemframe) bool true
|
||||
|
||||
# This enables the mailbox which allows players to receive gifts from other players.
|
||||
enable_xdecor_mailbox (Enable Mailbox) bool true
|
||||
|
||||
# This adds mechanisms like the lever and pressure plate which are used to trigger doors.
|
||||
enable_xdecor_mechanisms (Enable Mechanisms) bool true
|
||||
|
||||
# This adds ropes which can be used for climbing.
|
||||
enable_xdecor_rope (Enable Rope) bool true
|
||||
|
||||
# This adds the workbench which allows you to craft, store items, cut blocks and repair tools.
|
||||
# Due to block cutting, many new block shapes become available.
|
||||
enable_xdecor_workbench (Enable Workbench) bool true
|
BIN
mods/xdecor/sounds/xdecor_boiling_water.ogg
Normal file
BIN
mods/xdecor/sounds/xdecor_bouncy.ogg
Normal file
BIN
mods/xdecor/sounds/xdecor_enchanting.ogg
Normal file
3385
mods/xdecor/src/chess.lua
Normal file
200
mods/xdecor/src/chessbot.lua
Normal file
|
@ -0,0 +1,200 @@
|
|||
local chessbot = {}
|
||||
|
||||
local realchess = xdecor.chess
|
||||
|
||||
-- Delay in seconds for a bot moving a piece (excluding choosing a promotion)
|
||||
local BOT_DELAY_MOVE = 1.0
|
||||
-- Delay in seconds for a bot promoting a piece
|
||||
local BOT_DELAY_PROMOTE = 1.0
|
||||
|
||||
local function best_move(moves)
|
||||
local value, choices = 0, {}
|
||||
|
||||
for from, _ in pairs(moves) do
|
||||
for to, val in pairs(_) do
|
||||
if val > value then
|
||||
value = val
|
||||
choices = {{
|
||||
from = from,
|
||||
to = to
|
||||
}}
|
||||
elseif val == value then
|
||||
choices[#choices + 1] = {
|
||||
from = from,
|
||||
to = to
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #choices == 0 then
|
||||
return nil
|
||||
end
|
||||
local random = math.random(1, #choices)
|
||||
local choice_from, choice_to = choices[random].from, choices[random].to
|
||||
|
||||
return tonumber(choice_from), choice_to
|
||||
end
|
||||
|
||||
function chessbot.choose_move(board_t, meta_t)
|
||||
local lastMove = meta_t["lastMove"]
|
||||
local gameResult = meta_t["gameResult"]
|
||||
local botColor = meta_t["botColor"]
|
||||
local prevDoublePawnStepTo = meta_t["prevDoublePawnStepTo"]
|
||||
local castlingRights = {
|
||||
castlingWhiteR = meta_t["castlingWhiteR"],
|
||||
castlingWhiteL = meta_t["castlingWhiteL"],
|
||||
castlingBlackR = meta_t["castlingBlackR"],
|
||||
castlingBlackL = meta_t["castlingBlackL"],
|
||||
}
|
||||
|
||||
if botColor == "" then
|
||||
return
|
||||
end
|
||||
local currentBotColor, opponentColor
|
||||
if botColor == "black" then
|
||||
currentBotColor = "black"
|
||||
opponentColor = "white"
|
||||
elseif botColor == "white" then
|
||||
currentBotColor = "white"
|
||||
opponentColor = "black"
|
||||
elseif botColor == "both" then
|
||||
opponentColor = lastMove
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentBotColor = "white"
|
||||
else
|
||||
currentBotColor = "black"
|
||||
end
|
||||
end
|
||||
if (lastMove == opponentColor or ((botColor == "white" or botColor == "both") and lastMove == "")) and gameResult == "" then
|
||||
|
||||
local moves = realchess.get_theoretical_moves_for(board_t, currentBotColor, prevDoublePawnStepTo, castlingRights)
|
||||
local safe_moves, safe_moves_count = realchess.get_king_safe_moves(moves, board_t, currentBotColor)
|
||||
if safe_moves_count == 0 then
|
||||
-- No safe move: stalemate or checkmate
|
||||
end
|
||||
local choice_from, choice_to = best_move(safe_moves)
|
||||
if choice_from == nil then
|
||||
-- No best move: stalemate or checkmate
|
||||
return
|
||||
end
|
||||
|
||||
return choice_from, choice_to
|
||||
else
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.choose_move was apparently called in an invalid game state!")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
chessbot.perform_move = function(choice_from, choice_to, meta)
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local botColor = meta:get_string("botColor")
|
||||
local currentBotColor, opponentColor
|
||||
local botName
|
||||
if botColor == "black" then
|
||||
currentBotColor = "black"
|
||||
opponentColor = "white"
|
||||
elseif botColor == "white" then
|
||||
currentBotColor = "white"
|
||||
opponentColor = "black"
|
||||
elseif botColor == "both" then
|
||||
opponentColor = lastMove
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
currentBotColor = "white"
|
||||
else
|
||||
currentBotColor = "black"
|
||||
end
|
||||
end
|
||||
|
||||
-- Bot resigns if no move chosen
|
||||
if not choice_from or not choice_to then
|
||||
realchess.resign(meta, currentBotColor)
|
||||
return
|
||||
end
|
||||
|
||||
if currentBotColor == "white" then
|
||||
botName = meta:get_string("playerWhite")
|
||||
else
|
||||
botName = meta:get_string("playerBlack")
|
||||
end
|
||||
|
||||
local gameResult = meta:get_string("gameResult")
|
||||
if gameResult ~= "" then
|
||||
return
|
||||
end
|
||||
local botColor = meta:get_string("botColor")
|
||||
if botColor == "" then
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.perform_move: botColor in meta string was empty!")
|
||||
return
|
||||
end
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local lastMoveTime = meta:get_int("lastMoveTime")
|
||||
if lastMoveTime > 0 or lastMove == "" then
|
||||
-- Set the bot name if not set already
|
||||
if currentBotColor == "black" and meta:get_string("playerBlack") == "" then
|
||||
meta:set_string("playerBlack", botName)
|
||||
elseif currentBotColor == "white" and meta:get_string("playerWhite") == "" then
|
||||
meta:set_string("playerWhite", botName)
|
||||
end
|
||||
|
||||
-- Make a move
|
||||
local moveOK = realchess.move(meta, "board", choice_from, "board", choice_to, botName)
|
||||
if not moveOK then
|
||||
minetest.log("error", "[xdecor] Chess: Bot tried to make an invalid move from "..
|
||||
realchess.index_to_notation(choice_from).." to "..realchess.index_to_notation(choice_to))
|
||||
end
|
||||
-- Bot resigns if it tried to make an invalid move
|
||||
if not moveOK then
|
||||
realchess.resign(meta, currentBotColor)
|
||||
end
|
||||
else
|
||||
minetest.log("error", "[xdecor] Chess: chessbot.perform_move: No last move!")
|
||||
end
|
||||
end
|
||||
|
||||
function chessbot.choose_promote(board_t, pawnIndex)
|
||||
-- Bot always promotes to queen
|
||||
return "queen"
|
||||
end
|
||||
|
||||
function chessbot.perform_promote(meta, promoteTo)
|
||||
minetest.after(BOT_DELAY_PROMOTE, function()
|
||||
local lastMove = meta:get_string("lastMove")
|
||||
local color
|
||||
if lastMove == "black" or lastMove == "" then
|
||||
color = "white"
|
||||
else
|
||||
color = "black"
|
||||
end
|
||||
realchess.promote_pawn(meta, color, promoteTo)
|
||||
end)
|
||||
end
|
||||
|
||||
function chessbot.move(inv, meta)
|
||||
local board_t = realchess.board_to_table(inv)
|
||||
local meta_t = {
|
||||
lastMove = meta:get_string("lastMove"),
|
||||
gameResult = meta:get_string("gameResult"),
|
||||
botColor = meta:get_string("botColor"),
|
||||
prevDoublePawnStepTo = meta:get_int("prevDoublePawnStepTo"),
|
||||
castlingWhiteL = meta:get_int("castlingWhiteL"),
|
||||
castlingWhiteR = meta:get_int("castlingWhiteR"),
|
||||
castlingBlackL = meta:get_int("castlingBlackL"),
|
||||
castlingBlackR = meta:get_int("castlingBlackR"),
|
||||
}
|
||||
local choice_from, choice_to = chessbot.choose_move(board_t, meta_t)
|
||||
minetest.after(BOT_DELAY_MOVE, function()
|
||||
chessbot.perform_move(choice_from, choice_to, meta)
|
||||
end)
|
||||
end
|
||||
|
||||
function chessbot.promote(inv, meta, pawnIndex)
|
||||
local board_t = realchess.board_to_table(inv)
|
||||
local promoteTo = chessbot.choose_promote(board_t, pawnIndex)
|
||||
if not promoteTo then
|
||||
promoteTo = "queen"
|
||||
end
|
||||
chessbot.perform_promote(meta, promoteTo)
|
||||
end
|
||||
|
||||
return chessbot
|
517
mods/xdecor/src/cooking.lua
Normal file
|
@ -0,0 +1,517 @@
|
|||
local cauldron, sounds = {}, {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Set to true to print soup ingredients and fire nodes to console
|
||||
local DEBUG_RECOGNIZED_ITEMS = false
|
||||
|
||||
--~ cauldron hint
|
||||
local hint_fire = S("Light a fire below to heat it up")
|
||||
--~ cauldron hint
|
||||
local hint_eat = S("Use a bowl to eat the soup")
|
||||
--~ cauldron hint
|
||||
local hint_recipe = S("Drop foods inside to make a soup")
|
||||
|
||||
local infotexts = {
|
||||
["xdecor:cauldron_empty"] = S("Cauldron (empty)"),
|
||||
["xdecor:cauldron_idle"] = S("Cauldron (cold water)").."\n"..hint_fire,
|
||||
["xdecor:cauldron_idle_river_water"] = S("Cauldron (cold river water)").."\n"..hint_fire,
|
||||
["xdecor:cauldron_idle_soup"] = S("Cauldron (cold soup)").."\n"..hint_eat,
|
||||
["xdecor:cauldron_boiling"] = S("Cauldron (boiling water)").."\n"..hint_recipe,
|
||||
["xdecor:cauldron_boiling_river_water"] = S("Cauldron (boiling river water)").."\n"..hint_recipe,
|
||||
["xdecor:cauldron_soup"] = S("Cauldron (boiling soup)").."\n"..hint_eat,
|
||||
}
|
||||
|
||||
local function set_infotext(meta, node)
|
||||
if infotexts[node.name] then
|
||||
meta:set_string("infotext", infotexts[node.name])
|
||||
end
|
||||
end
|
||||
|
||||
-- HACKY list of soup ingredients.
|
||||
-- The cauldron will check if any of these strings are contained in the itemname
|
||||
-- after the ":".
|
||||
local ingredients_list = {
|
||||
"apple", "mushroom", "honey", "pumpkin", "egg", "bread", "meat",
|
||||
"chicken", "carrot", "potato", "melon", "rhubarb", "cucumber",
|
||||
"corn", "beans", "berries", "grapes", "tomato", "wheat"
|
||||
}
|
||||
|
||||
-- List of items that can never be soup ingredients. Overwrites anything else.
|
||||
local non_ingredients = {
|
||||
-- xdecor
|
||||
"xdecor:bowl_soup",
|
||||
-- Minetest Game: default
|
||||
"default:apple_mark", "default:blueberry_bush_leaves_with_berries",
|
||||
-- Minetest Game: farming
|
||||
"farming:seed_wheat",
|
||||
"farming:wheat_1", "farming:wheat_2", "farming:wheat_3", "farming:wheat_4",
|
||||
"farming:wheat_5", "farming:wheat_6", "farming:wheat_7", "farming:wheat_8",
|
||||
}
|
||||
local non_ingredients_keyed = table.key_value_swap(non_ingredients)
|
||||
|
||||
cauldron.cbox = {
|
||||
{0, 0, 0, 16, 16, 0},
|
||||
{0, 0, 16, 16, 16, 0},
|
||||
{0, 0, 0, 0, 16, 16},
|
||||
{16, 0, 0, 0, 16, 16},
|
||||
{0, 0, 0, 16, 8, 16}
|
||||
}
|
||||
|
||||
-- Returns true is given item is a fire
|
||||
local function is_fire(itemstring)
|
||||
return minetest.get_item_group(itemstring, "fire") ~= 0
|
||||
end
|
||||
|
||||
-- Returns true if the node at pos is above fire
|
||||
local function is_heated(pos)
|
||||
local below_node = {x = pos.x, y = pos.y - 1, z = pos.z}
|
||||
local nn = minetest.get_node(below_node).name
|
||||
-- Check fire group
|
||||
if is_fire(nn) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.stop_sound(pos)
|
||||
local spos = minetest.hash_node_position(pos)
|
||||
if sounds[spos] then
|
||||
minetest.sound_stop(sounds[spos])
|
||||
sounds[spos] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.start_sound(pos)
|
||||
local spos = minetest.hash_node_position(pos)
|
||||
-- Stop sound if one already exists.
|
||||
-- Only 1 sound per position at maximum allowed.
|
||||
if sounds[spos] then
|
||||
cauldron.stop_sound(pos)
|
||||
end
|
||||
sounds[spos] = minetest.sound_play("xdecor_boiling_water", {
|
||||
pos = pos,
|
||||
max_hear_distance = 5,
|
||||
gain = 0.8,
|
||||
loop = true
|
||||
})
|
||||
end
|
||||
|
||||
function cauldron.idle_construct(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
set_infotext(meta, node)
|
||||
timer:start(10.0)
|
||||
cauldron.stop_sound(pos)
|
||||
end
|
||||
|
||||
function cauldron.boiling_construct(pos)
|
||||
cauldron.start_sound(pos)
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(5.0)
|
||||
end
|
||||
|
||||
|
||||
function cauldron.filling(pos, node, clicker, itemstack)
|
||||
local inv = clicker:get_inventory()
|
||||
local wield_item = clicker:get_wielded_item():get_name()
|
||||
|
||||
do
|
||||
if wield_item == "bucket:bucket_empty" and node.name:sub(-6) ~= "_empty" then
|
||||
local bucket_item
|
||||
if node.name:sub(-11) == "river_water" then
|
||||
bucket_item = "bucket:bucket_river_water 1"
|
||||
else
|
||||
bucket_item = "bucket:bucket_water 1"
|
||||
end
|
||||
if itemstack:get_count() > 1 then
|
||||
if inv:room_for_item("main", bucket_item) then
|
||||
itemstack:take_item()
|
||||
inv:add_item("main", bucket_item)
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(),
|
||||
S("No room in your inventory to add a bucket of water."))
|
||||
return itemstack
|
||||
end
|
||||
else
|
||||
itemstack:replace(bucket_item)
|
||||
end
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2})
|
||||
|
||||
elseif minetest.get_item_group(wield_item, "water_bucket") == 1 and node.name:sub(-6) == "_empty" then
|
||||
local newnode
|
||||
if wield_item == "bucket:bucket_river_water" then
|
||||
newnode = "xdecor:cauldron_idle_river_water"
|
||||
else
|
||||
newnode = "xdecor:cauldron_idle"
|
||||
end
|
||||
minetest.set_node(pos, {name = newnode, param2 = node.param2})
|
||||
itemstack:replace("bucket:bucket_empty")
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
function cauldron.idle_timer(pos)
|
||||
if not is_heated(pos) then
|
||||
return true
|
||||
end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
if node.name:sub(-4) == "soup" then
|
||||
node.name = "xdecor:cauldron_soup"
|
||||
elseif node.name:sub(-11) == "river_water" then
|
||||
node.name = "xdecor:cauldron_boiling_river_water"
|
||||
else
|
||||
node.name = "xdecor:cauldron_boiling"
|
||||
end
|
||||
minetest.set_node(pos, node)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Ugly hack to determine if an item has the function `minetest.item_eat` in its definition.
|
||||
local function eatable(itemstring)
|
||||
local item = itemstring:match("[%w_:]+")
|
||||
local on_use_def = minetest.registered_items[item].on_use
|
||||
if not on_use_def then return end
|
||||
|
||||
return string.format("%q", string.dump(on_use_def)):find("item_eat")
|
||||
end
|
||||
|
||||
-- Checks if the given item can be used as ingredient for the soup
|
||||
local function is_ingredient(itemstring)
|
||||
if non_ingredients_keyed[itemstring] then
|
||||
return false
|
||||
end
|
||||
local basename = itemstring:match(":([%w_]+)")
|
||||
if not basename then
|
||||
return false
|
||||
end
|
||||
for _, ingredient in ipairs(ingredients_list) do
|
||||
if eatable(itemstring) or basename:find(ingredient) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function cauldron.boiling_timer(pos)
|
||||
-- Cool down cauldron if there is no fire
|
||||
local node = minetest.get_node(pos)
|
||||
if not is_heated(pos) then
|
||||
local newnode
|
||||
if node.name:sub(-4) == "soup" then
|
||||
newnode = "xdecor:cauldron_idle_soup"
|
||||
elseif node.name:sub(-11) == "river_water" then
|
||||
newnode = "xdecor:cauldron_idle_river_water"
|
||||
else
|
||||
newnode = "xdecor:cauldron_idle"
|
||||
end
|
||||
minetest.set_node(pos, {name = newnode, param2 = node.param2})
|
||||
return true
|
||||
end
|
||||
|
||||
if node.name:sub(-4) == "soup" then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Cooking:
|
||||
|
||||
-- Count the ingredients in the cauldron
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
if not next(objs) then
|
||||
return true
|
||||
end
|
||||
|
||||
local ingredients = {}
|
||||
for _, obj in pairs(objs) do
|
||||
if obj and not obj:is_player() and obj:get_luaentity().itemstring then
|
||||
local itemstring = obj:get_luaentity().itemstring
|
||||
local item = ItemStack(itemstring)
|
||||
local itemname = item:get_name()
|
||||
|
||||
if is_ingredient(itemname) then
|
||||
local basename = itemstring:match(":([%w_]+)")
|
||||
table.insert(ingredients, basename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove ingredients and turn liquid into soup
|
||||
if #ingredients >= 2 then
|
||||
for _, obj in pairs(objs) do
|
||||
obj:remove()
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_soup", param2 = node.param2})
|
||||
end
|
||||
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function cauldron.take_soup(pos, node, clicker, itemstack)
|
||||
local inv = clicker:get_inventory()
|
||||
local wield_item = clicker:get_wielded_item()
|
||||
local item_name = wield_item:get_name()
|
||||
|
||||
if item_name == "xdecor:bowl" or item_name == "farming:bowl" then
|
||||
if wield_item:get_count() > 1 then
|
||||
if inv:room_for_item("main", "xdecor:bowl_soup 1") then
|
||||
itemstack:take_item()
|
||||
inv:add_item("main", "xdecor:bowl_soup 1")
|
||||
else
|
||||
minetest.chat_send_player(clicker:get_player_name(),
|
||||
S("No room in your inventory to add a bowl of soup."))
|
||||
return itemstack
|
||||
end
|
||||
else
|
||||
itemstack:replace("xdecor:bowl_soup 1")
|
||||
end
|
||||
|
||||
minetest.set_node(pos, {name = "xdecor:cauldron_empty", param2 = node.param2})
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
xdecor.register("cauldron_empty", {
|
||||
description = S("Cauldron"),
|
||||
_tt_help = S("For storing water and cooking soup"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1,cauldron=1},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_empty.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle", {
|
||||
description = S("Cauldron with Water (cold)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_idle.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:cauldron_empty",
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.idle_construct,
|
||||
on_timer = cauldron.idle_timer,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle_river_water", {
|
||||
description = S("Cauldron with River Water (cold)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {"xdecor_cauldron_top_idle_river_water.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:cauldron_empty",
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.idle_construct,
|
||||
on_timer = cauldron.idle_timer,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_idle_soup", {
|
||||
description = S("Cauldron with Soup (cold)"),
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1,cauldron=2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
tiles = {"xdecor_cauldron_top_idle_soup.png", "xdecor_cauldron_bottom.png", "xdecor_cauldron_sides.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(10.0)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
on_timer = cauldron.idle_timer,
|
||||
on_rightclick = cauldron.take_soup,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_boiling", {
|
||||
description = S("Cauldron with Water (boiling)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_boiling_water.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.boiling_construct,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
xdecor.register("cauldron_boiling_river_water", {
|
||||
description = S("Cauldron with River Water (boiling)"),
|
||||
groups = {cracky=2, oddly_breakable_by_hand=1, not_in_creative_inventory=1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_boiling_river_water.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_rightclick = cauldron.filling,
|
||||
on_construct = cauldron.boiling_construct,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
|
||||
xdecor.register("cauldron_soup", {
|
||||
description = S("Cauldron with Soup (boiling)"),
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1, not_in_creative_inventory = 1,cauldron=3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
drop = "xdecor:cauldron_empty",
|
||||
damage_per_second = 2,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_cauldron_top_anim_soup.png",
|
||||
animation = {type = "vertical_frames", length = 3.0}
|
||||
},
|
||||
"xdecor_cauldron_bottom.png",
|
||||
"xdecor_cauldron_sides.png"
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
collision_box = xdecor.pixelbox(16, cauldron.cbox),
|
||||
on_construct = function(pos)
|
||||
cauldron.start_sound(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
set_infotext(meta, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(5.0)
|
||||
end,
|
||||
on_timer = cauldron.boiling_timer,
|
||||
on_rightclick = cauldron.take_soup,
|
||||
on_destruct = function(pos)
|
||||
cauldron.stop_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Craft items
|
||||
|
||||
minetest.register_craftitem("xdecor:bowl", {
|
||||
description = S("Bowl"),
|
||||
inventory_image = "xdecor_bowl.png",
|
||||
wield_image = "xdecor_bowl.png",
|
||||
groups = {food_bowl = 1, flammable = 2},
|
||||
})
|
||||
|
||||
minetest.register_craftitem("xdecor:bowl_soup", {
|
||||
description = S("Bowl of soup"),
|
||||
inventory_image = "xdecor_bowl_soup.png",
|
||||
wield_image = "xdecor_bowl_soup.png",
|
||||
groups = {},
|
||||
stack_max = 1,
|
||||
on_use = minetest.item_eat(30, "xdecor:bowl")
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:bowl 3",
|
||||
recipe = {
|
||||
{"group:wood", "", "group:wood"},
|
||||
{"", "group:wood", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cauldron_empty",
|
||||
recipe = {
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Restart boiling cauldron sounds",
|
||||
name = "xdecor:restart_boiling_cauldron_sounds",
|
||||
nodenames = {"xdecor:cauldron_boiling", "xdecor:cauldron_boiling_river_water", "xdecor:cauldron_soup"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
cauldron.start_sound(pos)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update cauldron infotexts",
|
||||
name = "xdecor:update_cauldron_infotexts",
|
||||
nodenames = {"group:cauldron"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
set_infotext(meta, node)
|
||||
end,
|
||||
})
|
||||
|
||||
if DEBUG_RECOGNIZED_ITEMS then
|
||||
-- Print all soup ingredients and fire nodes
|
||||
-- in console
|
||||
minetest.register_on_mods_loaded(function()
|
||||
local ingredients = {}
|
||||
local fires = {}
|
||||
for k,v in pairs(minetest.registered_items) do
|
||||
if is_ingredient(k) then
|
||||
table.insert(ingredients, k)
|
||||
end
|
||||
if is_fire(k) then
|
||||
table.insert(fires, k)
|
||||
end
|
||||
end
|
||||
table.sort(ingredients)
|
||||
table.sort(fires)
|
||||
local str_i = table.concat(ingredients, ", ")
|
||||
local str_f = table.concat(fires, ", ")
|
||||
print("[xdecor] List of ingredients for soup: "..str_i)
|
||||
print("[xdecor] List of nodes that can heat cauldron: "..str_f)
|
||||
end)
|
||||
end
|
115
mods/xdecor/src/enchanted_tools.lua
Normal file
|
@ -0,0 +1,115 @@
|
|||
-- Register enchanted tools.
|
||||
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Number of uses for the (normal) steel hoe from Minetest Game (as of 01/12/20224)
|
||||
-- This is technically redundant because we cannot access that number
|
||||
-- directly, but it's unlikely to change in future because Minetest Game is
|
||||
-- unlikely to change.
|
||||
local STEEL_HOE_USES = 500
|
||||
|
||||
-- Modifier of the steel hoe uses for the enchanted steel hoe
|
||||
local STEEL_HOE_USES_MODIFIER = 2.2
|
||||
|
||||
-- Modifier of the bug net uses for the enchanted bug net
|
||||
local BUG_NET_USES_MODIFIER = 4
|
||||
|
||||
-- Multiplies by much faster the fast hammer repairs
|
||||
local HAMMER_FAST_MODIFIER = 1.3
|
||||
|
||||
-- Reduces the wear taken by the hammer for a single repair step
|
||||
-- (absolute value)
|
||||
local HAMMER_DURABLE_MODIFIER = 100
|
||||
|
||||
-- Register enchantments for default tools from Minetest Game
|
||||
local materials = {"steel", "bronze", "mese", "diamond"}
|
||||
local tooltypes = {
|
||||
{ "axe", { "durable", "fast" }, "choppy" },
|
||||
{ "pick", { "durable", "fast" }, "cracky" },
|
||||
{ "shovel", { "durable", "fast" }, "crumbly" },
|
||||
{ "sword", { "sharp" }, nil },
|
||||
}
|
||||
for t=1, #tooltypes do
|
||||
for m=1, #materials do
|
||||
local tooltype = tooltypes[t][1]
|
||||
local enchants = tooltypes[t][2]
|
||||
local dig_group = tooltypes[t][3]
|
||||
local material = materials[m]
|
||||
xdecor.register_enchantable_tool("default:"..tooltype.."_"..material, {
|
||||
enchants = enchants,
|
||||
dig_group = dig_group,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
-- Register enchantment for bug net
|
||||
xdecor.register_enchantable_tool("fireflies:bug_net", {
|
||||
enchants = { "durable" },
|
||||
dig_group = "catchable",
|
||||
bonuses = {
|
||||
uses = BUG_NET_USES_MODIFIER,
|
||||
}
|
||||
})
|
||||
|
||||
-- Register enchanted steel hoe (more durability)
|
||||
if farming.register_hoe then
|
||||
local percent = math.round((STEEL_HOE_USES_MODIFIER - 1) * 100)
|
||||
local hitem = ItemStack("farming:hoe_steel")
|
||||
local hdesc = hitem:get_short_description() or "farming:hoe_steel"
|
||||
local ehdesc, ehsdesc = xdecor.enchant_description(hdesc, "durable", percent)
|
||||
farming.register_hoe(":farming:enchanted_hoe_steel_durable", {
|
||||
description = ehdesc,
|
||||
short_description = ehsdesc,
|
||||
inventory_image = xdecor.enchant_texture("farming_tool_steelhoe.png"),
|
||||
max_uses = STEEL_HOE_USES * STEEL_HOE_USES_MODIFIER,
|
||||
groups = {hoe = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
xdecor.register_custom_enchantable_tool("farming:hoe_steel", {
|
||||
durable = "farming:enchanted_hoe_steel_durable",
|
||||
})
|
||||
end
|
||||
|
||||
-- Register enchanted hammer (more durbility and efficiency)
|
||||
local hammerdef = minetest.registered_items["xdecor:hammer"]
|
||||
if hammerdef then
|
||||
local hitem = ItemStack("xdecor:hammer")
|
||||
local hdesc = hitem:get_short_description() or "xdecor:hammer"
|
||||
local repair = hammerdef._xdecor_hammer_repair
|
||||
local repair_cost = hammerdef._xdecor_hammer_repair_cost
|
||||
|
||||
-- Durable hammer (reduces wear taken by each repair step)
|
||||
local d_repair_cost_modified = repair_cost - HAMMER_DURABLE_MODIFIER
|
||||
local d_percent = math.round(100 - d_repair_cost_modified/repair_cost * 100)
|
||||
local d_ehdesc, d_ehsdesc = xdecor.enchant_description(hdesc, "durable", d_percent)
|
||||
|
||||
xdecor.register_hammer("xdecor:enchanted_hammer_durable", {
|
||||
description = d_ehdesc,
|
||||
short_description = d_ehsdesc,
|
||||
image = xdecor.enchant_texture("xdecor_hammer.png"),
|
||||
repair_cost = d_repair_cost_modified,
|
||||
groups = {repair_hammer = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
-- Fast hammer (increases both repair amount and repair cost per
|
||||
-- repair step by an equal amount)
|
||||
local f_repair_modified = math.round(repair * HAMMER_FAST_MODIFIER)
|
||||
local repair_diff = f_repair_modified - repair
|
||||
local f_repair_cost_modified = repair_cost + repair_diff
|
||||
local f_percent = math.round(HAMMER_FAST_MODIFIER * 100 - 100)
|
||||
local f_ehdesc, f_ehsdesc = xdecor.enchant_description(hdesc, "fast", f_percent)
|
||||
|
||||
xdecor.register_hammer("xdecor:enchanted_hammer_fast", {
|
||||
description = f_ehdesc,
|
||||
short_description = f_ehsdesc,
|
||||
image = xdecor.enchant_texture("xdecor_hammer.png"),
|
||||
repair = f_repair_modified,
|
||||
repair_cost = f_repair_cost_modified,
|
||||
groups = {repair_hammer = 1, not_in_creative_inventory = 1}
|
||||
})
|
||||
|
||||
xdecor.register_custom_enchantable_tool("xdecor:hammer", {
|
||||
durable = "xdecor:enchanted_hammer_durable",
|
||||
fast = "xdecor:enchanted_hammer_fast",
|
||||
})
|
||||
end
|
506
mods/xdecor/src/enchanting.lua
Normal file
|
@ -0,0 +1,506 @@
|
|||
local enchanting = {}
|
||||
|
||||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local NS = function(s) return s end
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
local ceil, abs, random = math.ceil, math.abs, math.random
|
||||
local reg_tools = minetest.registered_tools
|
||||
local reg_enchantable_tools = {}
|
||||
local available_tool_enchants = {}
|
||||
|
||||
-- Cost in Mese crystal(s) for enchanting.
|
||||
local MESE_COST = 1
|
||||
|
||||
-- Default strenth of the enchantments
|
||||
local DEFAULT_ENCHANTING_USES = 1.2 -- Durability
|
||||
local DEFAULT_ENCHANTING_TIMES = 0.1 -- Efficiency
|
||||
local DEFAULT_ENCHANTING_DAMAGES = 1 -- Sharpness
|
||||
|
||||
local function to_percent(orig_value, final_value)
|
||||
return abs(ceil(((final_value - orig_value) / orig_value) * 100))
|
||||
end
|
||||
|
||||
function enchanting:get_tooltip_raw(enchant, percent)
|
||||
local specs = {
|
||||
durable = "#00baff",
|
||||
fast = "#74ff49",
|
||||
sharp = "#ffff00",
|
||||
}
|
||||
local enchant_loc = {
|
||||
--~ Enchantment
|
||||
fast = S("Efficiency"),
|
||||
--~ Enchantment
|
||||
durable = S("Durability"),
|
||||
--~ Enchantment
|
||||
sharp = S("Sharpness"),
|
||||
}
|
||||
|
||||
if minetest.colorize then
|
||||
--~ Tooltip in format "<enchantment name> (+<bonus>%)", e.g. "Efficiency (+5%)"
|
||||
return minetest.colorize(specs[enchant], S("@1 (+@2%)", enchant_loc[enchant], percent))
|
||||
else
|
||||
return S("@1 (+@2%)", enchant_loc[enchant], percent)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function enchanting:get_tooltip(enchant, orig_caps, fleshy, bonus_defs)
|
||||
local bonus = {durable = 0, efficiency = 0, damages = 0}
|
||||
|
||||
if orig_caps then
|
||||
bonus.durable = to_percent(orig_caps.uses, orig_caps.uses * bonus_defs.uses)
|
||||
local sum_caps_times = 0
|
||||
for i=1, #orig_caps.times do
|
||||
sum_caps_times = sum_caps_times + orig_caps.times[i]
|
||||
end
|
||||
local average_caps_time = sum_caps_times / #orig_caps.times
|
||||
bonus.efficiency = to_percent(average_caps_time, average_caps_time -
|
||||
bonus_defs.times)
|
||||
end
|
||||
|
||||
if fleshy then
|
||||
bonus.damages = to_percent(fleshy, fleshy + bonus_defs.damages)
|
||||
end
|
||||
|
||||
local specs = {
|
||||
durable = bonus.durable,
|
||||
fast = bonus.efficiency,
|
||||
sharp = bonus.damages,
|
||||
}
|
||||
local percent = specs[enchant]
|
||||
return enchanting:get_tooltip_raw(enchant, percent)
|
||||
end
|
||||
|
||||
local enchant_buttons = {
|
||||
fast = "image_button[3.6,0.67;4.75,0.85;bg_btn.png;fast;"..FS("Efficiency").."]",
|
||||
durable = "image_button[3.6,1.65;4.75,1.05;bg_btn.png;durable;"..FS("Durability").."]",
|
||||
sharp = "image_button[3.6,2.8;4.75,0.85;bg_btn.png;sharp;"..FS("Sharpness").."]",
|
||||
}
|
||||
|
||||
function enchanting.formspec(pos, enchants)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local formspec = [[
|
||||
size[9,8.6;]
|
||||
no_prepend[]
|
||||
bgcolor[#080808BB;true]
|
||||
listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]
|
||||
background9[0,0;9,9;ench_ui.png;6]
|
||||
list[context;tool;0.9,2.9;1,1;]
|
||||
list[context;mese;2,2.9;1,1;]
|
||||
list[current_player;main;0.55,4.5;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;tool]
|
||||
listring[current_player;main]
|
||||
listring[context;mese]
|
||||
image[2,2.9;1,1;mese_layout.png]
|
||||
]]
|
||||
--~ Sharpness enchantment
|
||||
.."tooltip[sharp;"..FS("Your weapon inflicts more damage").."]"
|
||||
--~ Durability enchantment
|
||||
.."tooltip[durable;"..FS("Your tool lasts longer").."]"
|
||||
--~ Efficiency enchantment
|
||||
.."tooltip[fast;"..FS("Your tool digs faster").."]"
|
||||
..default.gui_slots .. default.get_hotbar_bg(0.55, 4.5)
|
||||
|
||||
if enchants then
|
||||
for e=1, #enchants do
|
||||
formspec = formspec .. enchant_buttons[enchants[e]]
|
||||
end
|
||||
end
|
||||
meta:set_string("formspec", formspec)
|
||||
end
|
||||
|
||||
function enchanting.on_put(pos, listname, _, stack)
|
||||
if listname == "tool" then
|
||||
local stackname = stack:get_name()
|
||||
local enchants = available_tool_enchants[stackname]
|
||||
if enchants then
|
||||
enchanting.formspec(pos, enchants)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.fields(pos, _, fields, sender)
|
||||
if not next(fields) or fields.quit then return end
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local tool = inv:get_stack("tool", 1)
|
||||
local mese = inv:get_stack("mese", 1)
|
||||
local orig_wear = tool:get_wear()
|
||||
local mod, name = tool:get_name():match("(.*):(.*)")
|
||||
local enchanted_tool = (mod or "") .. ":enchanted_" .. (name or "") .. "_" .. next(fields)
|
||||
|
||||
if mese:get_count() >= MESE_COST and reg_tools[enchanted_tool] then
|
||||
minetest.sound_play("xdecor_enchanting", {
|
||||
to_player = sender:get_player_name(),
|
||||
gain = 0.8
|
||||
})
|
||||
|
||||
tool:replace(enchanted_tool)
|
||||
tool:add_wear(orig_wear)
|
||||
mese:take_item(MESE_COST)
|
||||
inv:set_stack("mese", 1, mese)
|
||||
inv:set_stack("tool", 1, tool)
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.dig(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("tool") and inv:is_empty("mese")
|
||||
end
|
||||
|
||||
function enchanting.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"tool", "mese"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
local function allowed(tool)
|
||||
if not tool then
|
||||
return false
|
||||
end
|
||||
if reg_enchantable_tools[tool] then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.put(_, listname, _, stack)
|
||||
local stackname = stack:get_name()
|
||||
if listname == "mese" and (stackname == "default:mese_crystal" or
|
||||
stackname == "imese:industrial_mese_crystal") then
|
||||
return stack:get_count()
|
||||
elseif listname == "tool" and allowed(stackname) then
|
||||
return 1
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function enchanting.on_take(pos, listname)
|
||||
if listname == "tool" then
|
||||
enchanting.formspec(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", S("Enchantment Table"))
|
||||
enchanting.formspec(pos)
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("tool", 1)
|
||||
inv:set_size("mese", 1)
|
||||
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open")
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(0.5)
|
||||
end
|
||||
|
||||
function enchanting.destruct(pos)
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 0.9)) do
|
||||
if obj and obj:get_luaentity() and
|
||||
obj:get_luaentity().name == "xdecor:book_open" then
|
||||
obj:remove()
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting.timer(pos)
|
||||
local minp = {x = pos.x - 2, y = pos.y, z = pos.z - 2}
|
||||
local maxp = {x = pos.x + 2, y = pos.y + 1, z = pos.z + 2}
|
||||
|
||||
local bookshelves = minetest.find_nodes_in_area(minp, maxp, "default:bookshelf")
|
||||
if #bookshelves == 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
local bookshelf_pos = bookshelves[random(1, #bookshelves)]
|
||||
local x = pos.x - bookshelf_pos.x
|
||||
local y = bookshelf_pos.y - pos.y
|
||||
local z = pos.z - bookshelf_pos.z
|
||||
|
||||
if tostring(x .. z):find(2) then
|
||||
minetest.add_particle({
|
||||
pos = bookshelf_pos,
|
||||
velocity = {x = x, y = 2 - y, z = z},
|
||||
acceleration = {x = 0, y = -2.2, z = 0},
|
||||
expirationtime = 1,
|
||||
size = 1.5,
|
||||
glow = 5,
|
||||
texture = "xdecor_glyph" .. random(1,18) .. ".png"
|
||||
})
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
xdecor.register("enchantment_table", {
|
||||
description = S("Enchantment Table"),
|
||||
_tt_help = S("Enchant your tools with mese crystals"),
|
||||
tiles = {
|
||||
"xdecor_enchantment_top.png", "xdecor_enchantment_bottom.png",
|
||||
"xdecor_enchantment_side.png", "xdecor_enchantment_side.png",
|
||||
"xdecor_enchantment_side.png", "xdecor_enchantment_side.png"
|
||||
},
|
||||
groups = {cracky = 1, level = 1},
|
||||
is_ground_content = false,
|
||||
light_source = 6,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = enchanting.dig,
|
||||
on_blast = enchanting.blast,
|
||||
on_timer = enchanting.timer,
|
||||
on_construct = enchanting.construct,
|
||||
on_destruct = enchanting.destruct,
|
||||
on_receive_fields = enchanting.fields,
|
||||
on_metadata_inventory_put = enchanting.on_put,
|
||||
on_metadata_inventory_take = enchanting.on_take,
|
||||
allow_metadata_inventory_put = enchanting.put,
|
||||
allow_metadata_inventory_move = function()
|
||||
return 0
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_entity("xdecor:book_open", {
|
||||
initial_properties = {
|
||||
visual = "sprite",
|
||||
visual_size = {x=0.75, y=0.75},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
pointable = false,
|
||||
physical = false,
|
||||
textures = {"xdecor_book_open.png"},
|
||||
static_save = false,
|
||||
},
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "recreate book entity",
|
||||
name = "xdecor:create_book_entity",
|
||||
nodenames = {"xdecor:enchantment_table"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.9)
|
||||
|
||||
for _, obj in ipairs(objs) do
|
||||
local e = obj:get_luaentity()
|
||||
if e and e.name == "xdecor:book_open" then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
minetest.add_entity({x = pos.x, y = pos.y + 0.85, z = pos.z}, "xdecor:book_open")
|
||||
end,
|
||||
})
|
||||
|
||||
function enchanting:enchant_texture(img)
|
||||
if img == nil or img == "" or type(img) ~= "string" then
|
||||
return "no_texture.png"
|
||||
else
|
||||
return "("..img.. ")^[colorize:violet:50"
|
||||
end
|
||||
end
|
||||
|
||||
function enchanting:register_tool(original_tool_name, def)
|
||||
local original_tool = reg_tools[original_tool_name]
|
||||
if not original_tool then
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool for non-existing tool: "..original_tool_name)
|
||||
return
|
||||
end
|
||||
local original_toolcaps = original_tool.tool_capabilities
|
||||
if not original_toolcaps then
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool for tool without tool_capabilities: "..original_tool_name)
|
||||
return
|
||||
end
|
||||
local original_damage_groups = original_toolcaps.damage_groups
|
||||
local original_groupcaps = original_toolcaps.groupcaps
|
||||
local original_basename = original_tool_name:match(".*:(.*)")
|
||||
local toolitem = ItemStack(original_tool_name)
|
||||
local original_desc = toolitem:get_short_description() or original_tool_name
|
||||
local groups
|
||||
if def.groups then
|
||||
groups = table.copy(def.groups)
|
||||
elseif original_tool.groups then
|
||||
groups = table.copy(original_tool.groups)
|
||||
else
|
||||
groups = {}
|
||||
end
|
||||
groups.not_in_creative_inventory = 1
|
||||
for _, enchant in ipairs(def.enchants) do
|
||||
local groupcaps = table.copy(original_groupcaps)
|
||||
local full_punch_interval = original_toolcaps.full_punch_interval
|
||||
local max_drop_level = original_toolcaps.max_drop_level
|
||||
local dig_group = def.dig_group
|
||||
local fleshy
|
||||
|
||||
if not def.bonuses then
|
||||
def.bonuses = {}
|
||||
end
|
||||
local bonus_defs = {
|
||||
uses = def.bonuses.uses or DEFAULT_ENCHANTING_USES,
|
||||
times = def.bonuses.times or DEFAULT_ENCHANTING_TIMES,
|
||||
damages = def.bonuses.damages or DEFAULT_ENCHANTING_DAMAGES,
|
||||
}
|
||||
|
||||
if enchant == "durable" then
|
||||
groupcaps[dig_group].uses = ceil(original_groupcaps[dig_group].uses *
|
||||
bonus_defs.uses)
|
||||
elseif enchant == "fast" then
|
||||
for i, time in pairs(original_groupcaps[dig_group].times) do
|
||||
groupcaps[dig_group].times[i] = time - bonus_defs.times
|
||||
end
|
||||
elseif enchant == "sharp" then
|
||||
fleshy = original_damage_groups.fleshy
|
||||
fleshy = fleshy + bonus_defs.damages
|
||||
else
|
||||
minetest.log("error", "[xdecor] Called enchanting:register_tool with unsupported enchant: "..tostring(enchant))
|
||||
return
|
||||
end
|
||||
|
||||
local arg1 = original_desc
|
||||
local arg2 = self:get_tooltip(enchant, original_groupcaps[dig_group], fleshy, bonus_defs)
|
||||
local enchantedTool = original_tool.mod_origin .. ":enchanted_" .. original_basename .. "_" .. enchant
|
||||
|
||||
local invimg = original_tool.inventory_image
|
||||
invimg = enchanting:enchant_texture(invimg)
|
||||
local wieldimg = original_tool.wield_image
|
||||
if wieldimg == nil or wieldimg == "" then
|
||||
wieldimg = invimg
|
||||
end
|
||||
minetest.register_tool(":" .. enchantedTool, {
|
||||
--~ Enchanted tool description, e.g. "Enchanted Diamond Sword". @1 is the original tool name, @2 is the enchantment text, e.g. "Durability (+20%)"
|
||||
description = S("Enchanted @1\n@2", arg1, arg2),
|
||||
--~ Enchanted tool description, e.g. "Enchanted Diamond Sword"
|
||||
short_description = S("Enchanted @1", arg1),
|
||||
inventory_image = invimg,
|
||||
wield_image = wieldimg,
|
||||
groups = groups,
|
||||
tool_capabilities = {
|
||||
groupcaps = groupcaps, damage_groups = {fleshy = fleshy},
|
||||
full_punch_interval = full_punch_interval,
|
||||
max_drop_level = max_drop_level
|
||||
},
|
||||
pointabilities = original_tool.pointabilities,
|
||||
})
|
||||
if minetest.get_modpath("toolranks") then
|
||||
toolranks.add_tool(enchantedTool)
|
||||
end
|
||||
end
|
||||
available_tool_enchants[original_tool_name] = table.copy(def.enchants)
|
||||
reg_enchantable_tools[original_tool_name] = true
|
||||
end
|
||||
|
||||
function enchanting:register_custom_tool(original_tool_name, enchanted_tools)
|
||||
if not available_tool_enchants[original_tool_name] then
|
||||
available_tool_enchants[original_tool_name] = {}
|
||||
end
|
||||
for enchant, v in pairs(enchanted_tools) do
|
||||
table.insert(available_tool_enchants[original_tool_name], enchant)
|
||||
end
|
||||
reg_enchantable_tools[original_tool_name] = true
|
||||
end
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:enchantment_table",
|
||||
recipe = {
|
||||
{"", "default:book", ""},
|
||||
{"default:diamond", "default:obsidian", "default:diamond"},
|
||||
{"default:obsidian", "default:obsidian", "default:obsidian"}
|
||||
}
|
||||
})
|
||||
|
||||
--[[ API FUNCTIONS ]]
|
||||
|
||||
--[[
|
||||
Register one or more enchantments for an already defined tool.
|
||||
This will register a new tool for each enchantment. The new tools will
|
||||
have the following changes over the original:
|
||||
* New description and short_description
|
||||
* Apply a purple glow on wield_image and inventory_image using
|
||||
"(<original_texture_string>)^[colorize:purple"
|
||||
* Change tool_capabilities and damage_groups, depending on
|
||||
enchantments.
|
||||
* Have groups set to { not_in_creative_inventory = 1 }
|
||||
|
||||
The new tools will follow this naming scheme:
|
||||
|
||||
<original_mod>:enchanted_<original_basename>_<enchantment>
|
||||
|
||||
e.g. example:sword_diamond with the enchantment "sharp" will
|
||||
have "example:enchanted_sword_diamond_sharp" added.
|
||||
|
||||
You must make sure this name is available before calling this
|
||||
function.
|
||||
|
||||
Arguments:
|
||||
* toolname: Itemstring of original tool to enchant
|
||||
* def: Definition table with the following fields:
|
||||
* enchants: a list of strings, one for each enchantment to add.
|
||||
there must be at least one enchantment.
|
||||
Available enchantments:
|
||||
* "durable": Durability (tool lasts longer)
|
||||
* "fast": Efficiency (tool digs faster)
|
||||
* "sharp": Sharpness (more damage using the damage group "fleshy")
|
||||
* dig_group: Must be specified if Durability or Efficiency is used.
|
||||
This defines the tool's digging group that enchantment will improve.
|
||||
* bonuses: optional table to customize the enchantment "strengths":
|
||||
* uses: multiplies number of uses (Durability) (default: 1.2)
|
||||
* times: subtracts from digging time; higher = faster (Efficiency) (default: 0.1)
|
||||
* damages: adds to damage (Sharpness) (default: 1)
|
||||
* groups: optional table specifying all item groups. If specified,
|
||||
this should at least contain `not_in_creative_inventory=1`.
|
||||
If unspecified (recommended), the enchanted tools will inherit all
|
||||
groups from the original tool, plus they receive `not_in_creative_inventory=1`
|
||||
]]
|
||||
xdecor.register_enchantable_tool = function(toolname, def)
|
||||
enchanting:register_tool(toolname, def)
|
||||
end
|
||||
|
||||
--[[ Registers a custom tool enchantment.
|
||||
Here, you are fully free to design the tool yourself.
|
||||
|
||||
The enchanted tools should follow these guidelines:
|
||||
|
||||
1) Use xdecor.enchant_description to generate the description and short_description
|
||||
2) Use xdecor.enchant_texture to generate the inventory_image and wield_image
|
||||
3) Set groups to { not_in_creative_inventory = 1 }
|
||||
|
||||
Arguments:
|
||||
* toolname: Itemstring of original tool to enchant
|
||||
* enchanted_tools: Table of enchanted tools.
|
||||
* The keys are enchantment names from "enchants" in xdecor.register_enchantable_tool
|
||||
* The values are the itemstrings of the enchanted tools for those
|
||||
enchantments
|
||||
]]
|
||||
xdecor.register_custom_enchantable_tool = function(toolname, enchanted_tools)
|
||||
enchanting:register_custom_tool(toolname, enchanted_tools)
|
||||
end
|
||||
|
||||
-- Takes a texture (string) and applies an "enchanting" modifier on it.
|
||||
-- Useful when you want to register custom tool enchantments.
|
||||
xdecor.enchant_texture = function(texture)
|
||||
return enchanting:enchant_texture(texture)
|
||||
end
|
||||
|
||||
--[[
|
||||
Takes a description of a normal tool and modifies it for the enchanted tool variant.
|
||||
Arguments:
|
||||
* description: Original description to modify
|
||||
* enchant: Enchantment type. One of the enchantment names from "enchants" in xdecor.register_enchantable_tool
|
||||
* percent: Percentage to display
|
||||
|
||||
Returns: <description>, <short_description>
|
||||
|
||||
-- Useful when you want to register custom tool enchantments.
|
||||
]]
|
||||
xdecor.enchant_description = function(description, enchant, percent)
|
||||
local append = enchanting:get_tooltip_raw(enchant, percent)
|
||||
local desc = S("Enchanted @1\n@2", description, append)
|
||||
local short_desc S("Enchanted @1", description)
|
||||
return desc, short_desc
|
||||
end
|
||||
|
204
mods/xdecor/src/hive.lua
Normal file
|
@ -0,0 +1,204 @@
|
|||
local hive = {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
local HONEY_MAX = 16
|
||||
local NEEDED_FLOWERS = 3
|
||||
local TIMER_MIN = 64
|
||||
local TIMER_MAX = 128
|
||||
|
||||
local text_busy = FS("The bees are busy making honey.")
|
||||
local text_noflowers = FS("The bees are looking for flowers.")
|
||||
local text_fewflowers = FS("The bees want to pollinate more flowers.")
|
||||
local text_idle = FS("The bees are idle.")
|
||||
local text_sleep = FS("The bees are resting.")
|
||||
|
||||
function hive.set_formspec(meta, status)
|
||||
local statustext
|
||||
if status == "busy" then
|
||||
statustext = text_busy
|
||||
elseif status == "noflowers" then
|
||||
statustext = text_noflowers
|
||||
elseif status == "fewflowers" then
|
||||
statustext = text_fewflowers
|
||||
elseif status == "idle" then
|
||||
statustext = text_idle
|
||||
elseif status == "sleep" then
|
||||
statustext = text_sleep
|
||||
end
|
||||
|
||||
local formspec = "size[8,6;]"
|
||||
.."label[0.5,0;"..statustext.."]"
|
||||
..[[ image[6,1;1,1;hive_bee.png]
|
||||
image[5,1;1,1;hive_layout.png]
|
||||
list[context;honey;5,1;1,1;]
|
||||
list[current_player;main;0,2.35;8,4;]
|
||||
listring[current_player;main]
|
||||
listring[context;honey] ]] ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0,2.35)
|
||||
meta:set_string("formspec", formspec)
|
||||
end
|
||||
|
||||
local function count_flowers(pos)
|
||||
local radius = 4
|
||||
local minp = vector.add(pos, -radius)
|
||||
local maxp = vector.add(pos, radius)
|
||||
local flowers = minetest.find_nodes_in_area_under_air(minp, maxp, "group:flower")
|
||||
return #flowers
|
||||
end
|
||||
|
||||
local function is_sleeptime()
|
||||
local time = (minetest.get_timeofday() or 0) * 24000
|
||||
if time < 5500 or time > 18500 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function hive.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
local status = "idle"
|
||||
local flowers = count_flowers(pos)
|
||||
if is_sleeptime() then
|
||||
status = "sleep"
|
||||
elseif flowers >= NEEDED_FLOWERS then
|
||||
status = "busy"
|
||||
elseif flowers > 0 then
|
||||
status = "fewflowers"
|
||||
else
|
||||
status = "noflowers"
|
||||
end
|
||||
hive.set_formspec(meta, status)
|
||||
meta:set_string("infotext", S("Artificial Hive"))
|
||||
inv:set_size("honey", 1)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(math.random(TIMER_MIN, TIMER_MAX))
|
||||
end
|
||||
|
||||
function hive.timer(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
if is_sleeptime() then
|
||||
hive.set_formspec(meta, "sleep")
|
||||
return true
|
||||
end
|
||||
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local honeystack = inv:get_stack("honey", 1)
|
||||
local honey = honeystack:get_count()
|
||||
|
||||
local flowers = count_flowers(pos)
|
||||
|
||||
if flowers >= NEEDED_FLOWERS and honey < HONEY_MAX then
|
||||
if honey == HONEY_MAX - 1 then
|
||||
hive.set_formspec(meta, "idle")
|
||||
else
|
||||
hive.set_formspec(meta, "busy")
|
||||
end
|
||||
inv:add_item("honey", "xdecor:honey")
|
||||
elseif honey == HONEY_MAX then
|
||||
hive.set_formspec(meta, "idle")
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
return true
|
||||
end
|
||||
if flowers == 0 then
|
||||
hive.set_formspec(meta, "noflowers")
|
||||
elseif flowers < NEEDED_FLOWERS then
|
||||
hive.set_formspec(meta, "fewflowers")
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function hive.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"honey"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
xdecor.register("hive", {
|
||||
description = S("Artificial Hive"),
|
||||
--~ Tooltip of artificial hive
|
||||
_tt_help = S("Bees live here and produce honey"),
|
||||
tiles = {"xdecor_hive_top.png", "xdecor_hive_top.png",
|
||||
"xdecor_hive_side.png", "xdecor_hive_side.png",
|
||||
"xdecor_hive_side.png", "xdecor_hive_front.png"},
|
||||
groups = {choppy=3, oddly_breakable_by_hand=2, flammable=1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_construct = hive.construct,
|
||||
on_timer = hive.timer,
|
||||
on_blast = hive.blast,
|
||||
|
||||
can_dig = function(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("honey")
|
||||
end,
|
||||
|
||||
on_punch = function(_, _, puncher)
|
||||
puncher:set_hp(puncher:get_hp() - 2)
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_put = function()
|
||||
return 0
|
||||
end,
|
||||
|
||||
on_metadata_inventory_take = function(pos, list, index, stack)
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
local remainstack = inv:get_stack(list, index)
|
||||
-- Trigger if taking anything from full honey slot
|
||||
if remainstack:get_count() + stack:get_count() >= HONEY_MAX then
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(math.random(TIMER_MIN, TIMER_MAX))
|
||||
if not is_sleeptime() and count_flowers(pos) >= NEEDED_FLOWERS then
|
||||
local meta = minetest.get_meta(pos)
|
||||
hive.set_formspec(meta, "busy")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Craft items
|
||||
|
||||
minetest.register_craftitem("xdecor:honey", {
|
||||
description = S("Honey"),
|
||||
inventory_image = "xdecor_honey.png",
|
||||
wield_image = "xdecor_honey.png",
|
||||
on_use = minetest.item_eat(2),
|
||||
groups = {
|
||||
food_honey = 1,
|
||||
food_sugar = 1,
|
||||
flammable = 2,
|
||||
},
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hive",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"default:paper", "default:paper", "default:paper"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
if minetest.get_modpath("unified_inventory") then
|
||||
unified_inventory.register_craft_type("xdecor:hive", {
|
||||
description = S("Made by bees"),
|
||||
icon = "hive_bee.png",
|
||||
width = 1,
|
||||
height = 1,
|
||||
uses_crafting_grid = false
|
||||
})
|
||||
|
||||
unified_inventory.register_craft({
|
||||
output = "xdecor:honey",
|
||||
type = "xdecor:hive",
|
||||
items = {"xdecor:hive"},
|
||||
width = 1
|
||||
})
|
||||
end
|
249
mods/xdecor/src/itemframe.lua
Normal file
|
@ -0,0 +1,249 @@
|
|||
-- Item frames.
|
||||
|
||||
-- Hint:
|
||||
-- If your item appears behind or too far in front of the item frame, add
|
||||
-- _xdecor_itemframe_offset = <number>
|
||||
-- to your item definition to fix it.
|
||||
|
||||
local itemframe, tmp = {}, {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
screwdriver = screwdriver or {}
|
||||
|
||||
local function remove_item(pos, node)
|
||||
local objs = minetest.get_objects_inside_radius(pos, 0.5)
|
||||
if not objs then return end
|
||||
|
||||
for _, obj in pairs(objs) do
|
||||
local ent = obj:get_luaentity()
|
||||
if obj and ent and ent.name == "xdecor:f_item" then
|
||||
obj:remove() break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local facedir = {
|
||||
[0] = {x = 0, y = 0, z = 1},
|
||||
{x = 1, y = 0, z = 0},
|
||||
{x = 0, y = 0, z = -1},
|
||||
{x = -1, y = 0, z = 0}
|
||||
}
|
||||
|
||||
local function update_item(pos, node)
|
||||
remove_item(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local itemstring = meta:get_string("item")
|
||||
local posad = facedir[node.param2]
|
||||
if not posad or itemstring == "" then return end
|
||||
|
||||
local itemdef = ItemStack(itemstring):get_definition()
|
||||
local offset_plus = 0
|
||||
if itemdef and itemdef._xdecor_itemframe_offset then
|
||||
offset_plus = itemdef._xdecor_itemframe_offset
|
||||
offset_plus = math.min(6, math.max(-6, offset_plus))
|
||||
end
|
||||
local offset = (6.5+offset_plus)/16
|
||||
|
||||
pos = vector.add(pos, vector.multiply(posad, offset))
|
||||
tmp.nodename = node.name
|
||||
tmp.texture = ItemStack(itemstring):get_name()
|
||||
|
||||
local entity = minetest.add_entity(pos, "xdecor:f_item")
|
||||
local yaw = (math.pi * 2) - node.param2 * (math.pi / 2)
|
||||
entity:set_yaw(yaw)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(15.0)
|
||||
end
|
||||
|
||||
local function drop_item(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local item = meta:get_string("item")
|
||||
if item == "" then return end
|
||||
|
||||
minetest.add_item(pos, item)
|
||||
meta:set_string("item", "")
|
||||
remove_item(pos, node)
|
||||
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:stop()
|
||||
end
|
||||
|
||||
function itemframe.set_infotext(meta)
|
||||
local itemstring = meta:get_string("item")
|
||||
local owner = meta:get_string("owner")
|
||||
if itemstring == "" then
|
||||
if owner ~= "" then
|
||||
--~ Item frame infotext. @1 = item frame name, @2 = owner name (player)
|
||||
meta:set_string("infotext", S("@1 (owned by @2)",
|
||||
S("Item Frame"), owner))
|
||||
else
|
||||
meta:set_string("infotext", S("Item Frame"))
|
||||
end
|
||||
else
|
||||
local itemstack = ItemStack(itemstring)
|
||||
local tooltip = itemstack:get_short_description()
|
||||
if tooltip == "" then
|
||||
tooltip = itemstack:get_name()
|
||||
end
|
||||
if itemstring == "" then
|
||||
tooltip = S("Item Frame")
|
||||
end
|
||||
if owner ~= "" then
|
||||
meta:set_string("infotext", S("@1 (owned by @2)", tooltip, owner))
|
||||
else
|
||||
meta:set_string("infotext", tooltip)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function itemframe.after_place(pos, placer, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local name = placer:get_player_name()
|
||||
meta:set_string("owner", name)
|
||||
itemframe.set_infotext(meta)
|
||||
end
|
||||
|
||||
function itemframe.timer(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local num = #minetest.get_objects_inside_radius(pos, 0.5)
|
||||
|
||||
if num == 0 and meta:get_string("item") ~= "" then
|
||||
update_item(pos, node)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function itemframe.rightclick(pos, node, clicker, itemstack)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = clicker:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
if not admin and (player_name ~= owner or not itemstack) then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
drop_item(pos, node)
|
||||
local itemstring = itemstack:take_item():to_string()
|
||||
meta:set_string("item", itemstring)
|
||||
itemframe.set_infotext(meta)
|
||||
update_item(pos, node)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function itemframe.punch(pos, node, puncher)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = puncher:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
if admin and player_name == owner then
|
||||
drop_item(pos, node)
|
||||
end
|
||||
end
|
||||
|
||||
function itemframe.dig(pos, player)
|
||||
if not player then return end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = player and player:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
local admin = minetest.check_player_privs(player_name, "protection_bypass")
|
||||
|
||||
return admin or player_name == owner
|
||||
end
|
||||
|
||||
function itemframe.blast(pos)
|
||||
return
|
||||
end
|
||||
|
||||
xdecor.register("itemframe", {
|
||||
description = S("Item Frame"),
|
||||
--~ Item frame tooltip
|
||||
_tt_help = S("For presenting a single item"),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
on_rotate = screwdriver.disallow,
|
||||
sunlight_propagates = true,
|
||||
inventory_image = "xdecor_itemframe.png",
|
||||
node_box = xdecor.nodebox.slab_z(0.9375),
|
||||
tiles = {
|
||||
"xdecor_wood.png", "xdecor_wood.png", "xdecor_wood.png",
|
||||
"xdecor_wood.png", "xdecor_wood.png", "xdecor_itemframe.png"
|
||||
},
|
||||
after_place_node = itemframe.after_place,
|
||||
on_timer = itemframe.timer,
|
||||
on_rightclick = itemframe.rightclick,
|
||||
on_punch = itemframe.punch,
|
||||
can_dig = itemframe.dig,
|
||||
on_blast = itemframe.blast,
|
||||
after_destruct = remove_item,
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
})
|
||||
|
||||
minetest.register_entity("xdecor:f_item", {
|
||||
initial_properties = {
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 0.33, y = 0.33},
|
||||
collisionbox = {0,0,0,0,0,0},
|
||||
pointable = false,
|
||||
physical = false,
|
||||
textures = {"air"},
|
||||
},
|
||||
on_activate = function(self, staticdata)
|
||||
local pos = self.object:get_pos()
|
||||
if minetest.get_node(pos).name ~= "xdecor:itemframe" then
|
||||
self.object:remove()
|
||||
end
|
||||
|
||||
if tmp.nodename and tmp.texture then
|
||||
self.nodename = tmp.nodename
|
||||
tmp.nodename = nil
|
||||
self.texture = tmp.texture
|
||||
tmp.texture = nil
|
||||
elseif staticdata and staticdata ~= "" then
|
||||
local data = staticdata:split(";")
|
||||
if data and data[1] and data[2] then
|
||||
self.nodename = data[1]
|
||||
self.texture = data[2]
|
||||
end
|
||||
end
|
||||
if self.texture then
|
||||
self.object:set_properties({
|
||||
textures = {self.texture}
|
||||
})
|
||||
end
|
||||
end,
|
||||
get_staticdata = function(self)
|
||||
if self.nodename and self.texture then
|
||||
return self.nodename .. ";" .. self.texture
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:itemframe",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "default:paper", "group:stick"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update itemframe infotexts",
|
||||
name = "xdecor:update_itemframe_infotexts",
|
||||
nodenames = {"xdecor:itemframe"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
itemframe.set_infotext(meta)
|
||||
end,
|
||||
})
|
||||
|
211
mods/xdecor/src/mailbox.lua
Normal file
|
@ -0,0 +1,211 @@
|
|||
local mailbox = {}
|
||||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
|
||||
-- Max. length of the list of givers in mailbox formspec
|
||||
local GIVER_LIST_LENGTH = 7
|
||||
|
||||
local function get_img(img)
|
||||
if not img then return end
|
||||
local img_name = img:match("(.*)%.png")
|
||||
|
||||
if img_name then
|
||||
return img_name .. ".png"
|
||||
end
|
||||
end
|
||||
|
||||
local function img_col(stack)
|
||||
local def = minetest.registered_items[stack]
|
||||
if not def then
|
||||
return ""
|
||||
end
|
||||
|
||||
if def.inventory_image ~= "" then
|
||||
local img = get_img(def.inventory_image)
|
||||
if img then
|
||||
return img
|
||||
end
|
||||
end
|
||||
|
||||
if def.tiles then
|
||||
local tile, img = def.tiles[1]
|
||||
if type(tile) == "table" then
|
||||
img = get_img(tile.name)
|
||||
elseif type(tile) == "string" then
|
||||
img = get_img(tile)
|
||||
end
|
||||
|
||||
if img then
|
||||
return img
|
||||
end
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
function mailbox:formspec(pos, owner, is_owner)
|
||||
local spos = pos.x .. "," .. pos.y .. "," .. pos.z
|
||||
local meta = minetest.get_meta(pos)
|
||||
local giver, img = "", ""
|
||||
|
||||
if is_owner then
|
||||
for i = 1, GIVER_LIST_LENGTH do
|
||||
local giving = meta:get_string("giver" .. i)
|
||||
if giving ~= "" then
|
||||
local stack = meta:get_string("stack" .. i)
|
||||
local giver_name = giving:sub(1,12)
|
||||
local stack_name = stack:match("[%w_:]+")
|
||||
local stack_count = stack:match("%s(%d+)") or 1
|
||||
|
||||
-- List of donors. A line looks like this:
|
||||
-- <donor name> <item icon> × <item count>
|
||||
giver = giver .. "#FFFF00," .. giver_name .. "," .. i ..
|
||||
--~ Used in the mailbox donor list. Will be displayed as item icon followed by this string. @1 = item count
|
||||
",#FFFFFF," .. FS("× @1", stack_count) .. ","
|
||||
|
||||
img = img .. i .. "=" ..
|
||||
img_col(stack_name) .. "^\\[resize:16x16,"
|
||||
end
|
||||
end
|
||||
|
||||
return "size[9.5,9]"
|
||||
.."label[0,0;"..FS("Mailbox").."]"
|
||||
.."label[6,0;"..FS("Last donators").."]"
|
||||
..[[ box[6,0.72;3.3,3.9;#555555]
|
||||
listring[current_player;main]
|
||||
list[current_player;main;0.75,5.25;8,4;]
|
||||
tableoptions[background=#00000000;highlight=#00000000;border=false] ]] ..
|
||||
"tablecolumns[color;text;image," .. img .. "0;color;text]" ..
|
||||
"table[6,0.75;3.3,4;givers;" .. giver .. "]" ..
|
||||
"list[nodemeta:" .. spos .. ";mailbox;0,0.75;6,4;]" ..
|
||||
"listring[nodemeta:" .. spos .. ";mailbox]" ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0.75, 5.25)
|
||||
end
|
||||
|
||||
return "size[8,5]" ..
|
||||
"list[current_player;main;0,1.25;8,4;]" ..
|
||||
"label[0,0;"..FS("Send your goods to\n@1",
|
||||
(minetest.colorize and
|
||||
minetest.colorize("#FFFF00", owner) or owner)) .. "]" ..
|
||||
"list[nodemeta:" .. spos .. ";drop;3.5,0;1,1;]" ..
|
||||
"listring[]" ..
|
||||
xdecor.xbg .. default.get_hotbar_bg(0, 1.25)
|
||||
end
|
||||
|
||||
function mailbox.dig(pos, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local owner = meta:get_string("owner")
|
||||
local player_name = player and player:get_player_name()
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
return inv:is_empty("mailbox") and player_name == owner
|
||||
end
|
||||
|
||||
function mailbox.blast(pos)
|
||||
return
|
||||
end
|
||||
|
||||
function mailbox.after_place_node(pos, placer)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player_name = placer:get_player_name()
|
||||
|
||||
meta:set_string("owner", player_name)
|
||||
meta:set_string("infotext", S("@1's Mailbox", player_name))
|
||||
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("mailbox", 6 * 4)
|
||||
inv:set_size("drop", 1)
|
||||
end
|
||||
|
||||
function mailbox.rightclick(pos, node, clicker, itemstack, pointed_thing)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local player = clicker:get_player_name()
|
||||
local owner = meta:get_string("owner")
|
||||
|
||||
minetest.show_formspec(player, "xdecor:mailbox",
|
||||
mailbox:formspec(pos, owner, (player == owner)))
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function mailbox.put(pos, listname, _, stack, player)
|
||||
if listname == "drop" then
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
if inv:room_for_item("mailbox", stack) then
|
||||
return -1
|
||||
else
|
||||
minetest.chat_send_player(player:get_player_name(),
|
||||
S("The mailbox is full."))
|
||||
end
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function mailbox.on_put(pos, listname, _, stack, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
if listname == "drop" and inv:room_for_item("mailbox", stack) then
|
||||
inv:set_list("drop", {})
|
||||
inv:add_item("mailbox", stack)
|
||||
|
||||
for i = GIVER_LIST_LENGTH, 2, -1 do
|
||||
meta:set_string("giver" .. i, meta:get_string("giver" .. (i - 1)))
|
||||
meta:set_string("stack" .. i, meta:get_string("stack" .. (i - 1)))
|
||||
end
|
||||
|
||||
meta:set_string("giver1", player:get_player_name())
|
||||
meta:set_string("stack1", stack:to_string())
|
||||
end
|
||||
end
|
||||
|
||||
function mailbox.allow_take(pos, listname, index, stack, player)
|
||||
if listname == "drop" then
|
||||
return 0
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
|
||||
if player:get_player_name() ~= meta:get_string("owner") then
|
||||
return 0
|
||||
end
|
||||
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
function mailbox.allow_move(pos)
|
||||
return 0
|
||||
end
|
||||
|
||||
xdecor.register("mailbox", {
|
||||
description = S("Mailbox"),
|
||||
--~ Mailbox tooltip
|
||||
_tt_help = S("Lets other players give you things"),
|
||||
tiles = {"xdecor_mailbox_top.png", "xdecor_mailbox_bottom.png",
|
||||
"xdecor_mailbox_side.png", "xdecor_mailbox_side.png",
|
||||
"xdecor_mailbox.png", "xdecor_mailbox.png"},
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = mailbox.dig,
|
||||
on_blast = mailbox.blast,
|
||||
on_rightclick = mailbox.rightclick,
|
||||
allow_metadata_inventory_take = mailbox.allow_take,
|
||||
allow_metadata_inventory_move = mailbox.allow_move,
|
||||
on_metadata_inventory_put = mailbox.on_put,
|
||||
allow_metadata_inventory_put = mailbox.put,
|
||||
after_place_node = mailbox.after_place_node
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:mailbox",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"dye:red", "default:paper", "dye:red"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
325
mods/xdecor/src/mechanisms.lua
Normal file
|
@ -0,0 +1,325 @@
|
|||
-- Thanks to sofar for helping with that code.
|
||||
|
||||
local plate = {}
|
||||
screwdriver = screwdriver or {}
|
||||
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local ALPHA_OPAQUE = minetest.features.use_texture_alpha_string_modes and "opaque" or false
|
||||
|
||||
-- Number of seconds an actuator (pressure plate, lever) stays active.
|
||||
-- After this time, it will return to the disabled state again.
|
||||
local DISABLE_ACTUATOR_AFTER = 2.0
|
||||
|
||||
-- Effect area of pressure plates and levers. Doors within this area
|
||||
-- can be affected.
|
||||
local PRESSURE_PLATE_AREA_MIN = {x = -2, y = 0, z = -2}
|
||||
local PRESSURE_PLATE_AREA_MAX = {x = 2, y = 0, z = 2}
|
||||
local LEVER_AREA_MIN = {x = -2, y = -1, z = -2}
|
||||
local LEVER_AREA_MAX = {x = 2, y = 1, z = 2}
|
||||
|
||||
-- Pressure plates check for players within this radius
|
||||
local PRESSURE_PLATE_PLAYER_RADIUS = 0.8
|
||||
-- Interval in seconds that pressure plates check for players
|
||||
local PRESSURE_PLATE_CHECK_TIMER = 0.1
|
||||
|
||||
local function door_open(pos_door, player)
|
||||
local door = doors.get(pos_door)
|
||||
if not door then
|
||||
return
|
||||
end
|
||||
door:open(player)
|
||||
end
|
||||
|
||||
local function door_close(pos_door, player)
|
||||
local door = doors.get(pos_door)
|
||||
if not door then
|
||||
return
|
||||
end
|
||||
door:close(player)
|
||||
end
|
||||
|
||||
-- Returns true if the door node at pos is currently next to any
|
||||
-- active actuator node (lever, pressure plate)
|
||||
local function door_is_actuatored(pos_door)
|
||||
local minp = vector.add(LEVER_AREA_MIN, pos_door)
|
||||
local maxp = vector.add(LEVER_AREA_MAX, pos_door)
|
||||
local levers = minetest.find_nodes_in_area(minp, maxp, "group:lever")
|
||||
for l=1, #levers do
|
||||
local lnode = minetest.get_node(levers[l])
|
||||
if minetest.get_item_group(lnode.name, "xdecor_actuator") == 2 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
minp = vector.add(PRESSURE_PLATE_AREA_MIN, pos_door)
|
||||
maxp = vector.add(PRESSURE_PLATE_AREA_MAX, pos_door)
|
||||
local pressure_plates = minetest.find_nodes_in_area(minp, maxp, "group:pressure_plate")
|
||||
for p=1, #pressure_plates do
|
||||
local pnode = minetest.get_node(pressure_plates[p])
|
||||
if minetest.get_item_group(pnode.name, "xdecor_actuator") == 2 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function actuator_timeout(pos_actuator, actuator_area_min, actuator_area_max)
|
||||
local actuator = minetest.get_node(pos_actuator)
|
||||
|
||||
-- Get name of last player that triggered the actuator
|
||||
local meta = minetest.get_meta(pos_actuator)
|
||||
local last_triggerer_str = meta:get_string("last_triggerer")
|
||||
local last_triggerer_obj = minetest.get_player_by_name(last_triggerer_str)
|
||||
|
||||
-- Turn off actuator
|
||||
if minetest.get_item_group(actuator.name, "xdecor_actuator") == 2 then
|
||||
local def = minetest.registered_nodes[actuator.name]
|
||||
if def._xdecor_actuator_off then
|
||||
minetest.set_node(pos_actuator, { name = def._xdecor_actuator_off, param2 = actuator.param2 })
|
||||
end
|
||||
end
|
||||
|
||||
-- Close neighboring doors that are no longer next to any active actuator
|
||||
local minp = vector.add(actuator_area_min, pos_actuator)
|
||||
local maxp = vector.add(actuator_area_max, pos_actuator)
|
||||
local doors = minetest.find_nodes_in_area(minp, maxp, "group:door")
|
||||
for d=1, #doors do
|
||||
if not door_is_actuatored(doors[d]) then
|
||||
local dnode = minetest.get_node(doors[d])
|
||||
local ddef = minetest.registered_nodes[dnode.name]
|
||||
if (ddef.protected and last_triggerer_obj) or (not ddef.protected) then
|
||||
door_close(doors[d], last_triggerer_obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function actuator_activate(pos_actuator, actuator_area_min, actuator_area_max, player)
|
||||
local player_name = player:get_player_name()
|
||||
local actuator = minetest.get_node(pos_actuator)
|
||||
local ga = minetest.get_item_group(actuator.name, "xdecor_actuator")
|
||||
if ga == 2 then
|
||||
-- No-op if actuator is already active
|
||||
return
|
||||
elseif ga == 1 then
|
||||
local def = minetest.registered_nodes[actuator.name]
|
||||
-- Turn actuator on
|
||||
if def._xdecor_actuator_on then
|
||||
minetest.set_node(pos_actuator, { name = def._xdecor_actuator_on, param2 = actuator.param2 })
|
||||
|
||||
-- Store name of last player that triggered the actuator
|
||||
local meta = minetest.get_meta(pos_actuator)
|
||||
meta:set_string("last_triggerer", player_name)
|
||||
end
|
||||
end
|
||||
|
||||
-- Turn on neighboring doors
|
||||
local minp = vector.add(actuator_area_min, pos_actuator)
|
||||
local maxp = vector.add(actuator_area_max, pos_actuator)
|
||||
local doors = minetest.find_nodes_in_area(minp, maxp, "group:door")
|
||||
for i = 1, #doors do
|
||||
door_open(doors[i], player)
|
||||
end
|
||||
end
|
||||
|
||||
function plate.construct(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(PRESSURE_PLATE_CHECK_TIMER)
|
||||
end
|
||||
|
||||
function plate.has_player_standing_on(pos)
|
||||
local objs = minetest.get_objects_inside_radius(pos, PRESSURE_PLATE_PLAYER_RADIUS)
|
||||
for _, player in pairs(objs) do
|
||||
if player:is_player() then
|
||||
return true, player
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function plate.timer(pos)
|
||||
if not doors.get then
|
||||
return true
|
||||
end
|
||||
local ok, player = plate.has_player_standing_on(pos)
|
||||
if ok then
|
||||
actuator_activate(pos, PRESSURE_PLATE_AREA_MIN, PRESSURE_PLATE_AREA_MAX, player)
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function plate.construct_on(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end
|
||||
|
||||
function plate.timer_on(pos)
|
||||
if plate.has_player_standing_on(pos) then
|
||||
-- If player is still standing on active pressure plate, restart timer
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
return
|
||||
end
|
||||
|
||||
actuator_timeout(pos, PRESSURE_PLATE_AREA_MIN, PRESSURE_PLATE_AREA_MAX)
|
||||
end
|
||||
|
||||
function plate.register(material, desc, def)
|
||||
local groups
|
||||
if def.groups then
|
||||
groups = table.copy(def.groups)
|
||||
else
|
||||
groups = {}
|
||||
end
|
||||
groups.pressure_plate = 1
|
||||
groups.xdecor_actuator = 1
|
||||
xdecor.register("pressure_" .. material .. "_off", {
|
||||
description = def.description or (desc .. " Pressure Plate"),
|
||||
--~ Pressure plate tooltip
|
||||
_tt_help = S("Opens doors when stepped on"),
|
||||
tiles = {"xdecor_pressure_" .. material .. ".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 1, 14}}),
|
||||
groups = groups,
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds,
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = plate.construct,
|
||||
on_timer = plate.timer,
|
||||
_xdecor_actuator_off = "xdecor:pressure_"..material.."_off",
|
||||
_xdecor_actuator_on = "xdecor:pressure_"..material.."_on",
|
||||
})
|
||||
local groups_on = table.copy(groups)
|
||||
groups_on.xdecor_actuator = 2
|
||||
groups_on.pressure_plate = 2
|
||||
xdecor.register("pressure_" .. material .. "_on", {
|
||||
tiles = {"xdecor_pressure_" .. material .. ".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{1, 0, 1, 14, 0.4, 14}}),
|
||||
groups = groups_on,
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds,
|
||||
drop = "xdecor:pressure_" .. material .. "_off",
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = plate.construct_on,
|
||||
on_timer = plate.timer_on,
|
||||
_xdecor_actuator_off = "xdecor:pressure_"..material.."_off",
|
||||
_xdecor_actuator_on = "xdecor:pressure_"..material.."_on",
|
||||
})
|
||||
end
|
||||
|
||||
plate.register("wood", "Wooden", {
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2},
|
||||
description = S("Wooden Pressure Plate"),
|
||||
})
|
||||
|
||||
plate.register("stone", "Stone", {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2},
|
||||
description = S("Stone Pressure Plate"),
|
||||
})
|
||||
|
||||
xdecor.register("lever_off", {
|
||||
description = S("Lever"),
|
||||
--~ Lever tooltip
|
||||
_tt_help = S("Opens doors when pulled"),
|
||||
tiles = {"xdecor_lever_off.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, lever = 1, xdecor_actuator = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
if not doors.get then
|
||||
return itemstack
|
||||
end
|
||||
actuator_activate(pos, LEVER_AREA_MIN, LEVER_AREA_MAX, clicker)
|
||||
return itemstack
|
||||
end,
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
_xdecor_actuator_off = "xdecor:lever_off",
|
||||
_xdecor_actuator_on = "xdecor:lever_on",
|
||||
})
|
||||
|
||||
xdecor.register("lever_on", {
|
||||
tiles = {"xdecor_lever_on.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
drawtype = "nodebox",
|
||||
node_box = xdecor.pixelbox(16, {{2, 1, 15, 12, 14, 1}}),
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, lever = 2, xdecor_actuator = 2, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_rightclick = function(pos, node, clicker, itemstack)
|
||||
-- Prevent placing nodes on activated lever with the place key
|
||||
-- for consistent behavior with the lever in "off" state.
|
||||
-- The player may still place nodes using [Sneak].
|
||||
return itemstack
|
||||
end,
|
||||
on_construct = function(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end,
|
||||
on_timer = function(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
actuator_timeout(pos, LEVER_AREA_MIN, LEVER_AREA_MAX)
|
||||
end,
|
||||
drop = "xdecor:lever_off",
|
||||
_xdecor_itemframe_offset = -3.5,
|
||||
_xdecor_actuator_off = "xdecor:lever_off",
|
||||
_xdecor_actuator_on = "xdecor:lever_on",
|
||||
})
|
||||
|
||||
-- Make sure the node timers of active actuators are still
|
||||
-- active when these nodes load again. If not, start them
|
||||
-- again to trigger their timer action, which is expected
|
||||
-- to turn off the actuator soon.
|
||||
minetest.register_lbm({
|
||||
label = "Restart actuator timers (X-Decor-libre)",
|
||||
name = "xdecor:restart_actuator_timers",
|
||||
nodenames = { "group:xdecor_actuator" },
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local g = minetest.get_item_group(node.name, "xdecor_actuator")
|
||||
if g ~= 2 then
|
||||
return
|
||||
end
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
if not timer:is_started() then
|
||||
timer:start(DISABLE_ACTUATOR_AFTER)
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:pressure_stone_off",
|
||||
type = "shapeless",
|
||||
recipe = {"group:stone", "group:stone"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:pressure_wood_off",
|
||||
type = "shapeless",
|
||||
recipe = {"group:wood", "group:wood"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:lever_off",
|
||||
recipe = {
|
||||
{"group:stick"},
|
||||
{"group:stone"}
|
||||
}
|
||||
})
|
962
mods/xdecor/src/nodes.lua
Normal file
|
@ -0,0 +1,962 @@
|
|||
screwdriver = screwdriver or {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local ALPHA_CLIP = minetest.features.use_texture_alpha_string_modes and "clip" or true
|
||||
local ALPHA_OPAQUE = minetest.features.use_texture_alpha_string_modes and "opaque" or false
|
||||
|
||||
local function register_pane(name, desc, def)
|
||||
xpanes.register_pane(name, {
|
||||
description = desc,
|
||||
tiles = {"xdecor_" .. name .. ".png"},
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
textures = def.textures or {"xdecor_" .. name .. ".png", "" ,"xdecor_" .. name .. ".png"},
|
||||
inventory_image = "xdecor_" .. name .. ".png",
|
||||
wield_image = "xdecor_" .. name .. ".png",
|
||||
groups = def.groups,
|
||||
sounds = def.sounds or default.node_sound_defaults(),
|
||||
recipe = def.recipe
|
||||
})
|
||||
end
|
||||
|
||||
register_pane("bamboo_frame", S("Bamboo Frame"), {
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, pane = 1, flammable = 2},
|
||||
recipe = {
|
||||
{"default:papyrus", "default:papyrus", "default:papyrus"},
|
||||
{"default:papyrus", "farming:cotton", "default:papyrus"},
|
||||
{"default:papyrus", "default:papyrus", "default:papyrus"}
|
||||
},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
register_pane("chainlink", S("Chainlink"), {
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2, pane = 1},
|
||||
recipe = {
|
||||
{"default:steel_ingot", "", "default:steel_ingot"},
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"default:steel_ingot", "", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
register_pane("rusty_bar", S("Rusty Iron Bars"), {
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
textures = {"xdecor_rusty_bar.png", "", "xdecor_rusty_bar_top.png"},
|
||||
groups = {cracky = 2, pane = 1},
|
||||
recipe = {
|
||||
{"", "default:dirt", ""},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"},
|
||||
{"default:iron_lump", "default:iron_lump", "default:iron_lump"},
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
register_pane("wood_frame", S("Wood Frame"), {
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
textures = {"xdecor_wood_frame.png", "", "xdecor_wood_frame_top.png"},
|
||||
groups = {choppy = 2, pane = 1, flammable = 2},
|
||||
recipe = {
|
||||
{"group:wood", "group:stick", "group:wood"},
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:wood", "group:stick", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
xdecor.register("baricade", {
|
||||
description = S("Barricade"),
|
||||
drawtype = "plantlike",
|
||||
paramtype2 = "facedir",
|
||||
inventory_image = "xdecor_baricade.png",
|
||||
tiles = {"xdecor_baricade.png"},
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
damage_per_second = 4,
|
||||
selection_box = xdecor.nodebox.slab_y(0.3),
|
||||
collision_box = xdecor.pixelbox(2, {{0, 0, 1, 2, 2, 0}})
|
||||
})
|
||||
|
||||
xdecor.register("barrel", {
|
||||
description = S("Barrel"),
|
||||
tiles = {"xdecor_barrel_top.png", "xdecor_barrel_top.png", "xdecor_barrel_sides.png"},
|
||||
on_place = minetest.rotate_node,
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults()
|
||||
})
|
||||
|
||||
local function blast_storage(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"main"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
local function register_storage(name, desc, def)
|
||||
xdecor.register(name, {
|
||||
description = desc,
|
||||
_tt_help = def._tt_help,
|
||||
inventory = {size = def.inv_size or 24},
|
||||
infotext = desc,
|
||||
tiles = def.tiles,
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
node_box = def.node_box,
|
||||
on_rotate = def.on_rotate,
|
||||
on_place = def.on_place,
|
||||
on_blast = blast_storage,
|
||||
groups = def.groups or {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
register_storage("cabinet", S("Wooden Cabinet"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_front.png"
|
||||
}
|
||||
})
|
||||
|
||||
register_storage("cabinet_half", S("Half Wooden Cabinet"), {
|
||||
inv_size = 8,
|
||||
_tt_help = S("8 inventory slots"),
|
||||
node_box = xdecor.nodebox.slab_y(0.5, 0.5),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_cabinet_sides.png", "xdecor_cabinet_sides.png",
|
||||
"xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_sides.png",
|
||||
"xdecor_half_cabinet_sides.png", "xdecor_half_cabinet_front.png"
|
||||
}
|
||||
})
|
||||
|
||||
if minetest.get_modpath("moreblocks") then
|
||||
minetest.register_alias("xdecor:empty_shelf", "moreblocks:empty_shelf")
|
||||
else
|
||||
-- Node renamed from "Empty Shelf" because it was misleading.
|
||||
-- (you can still put things in it, making it non-empty)
|
||||
register_storage("empty_shelf", S("Plain Shelf"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"default_wood.png", "default_wood.png", "default_wood.png",
|
||||
"default_wood.png", "default_wood.png^xdecor_empty_shelf.png"
|
||||
},
|
||||
})
|
||||
|
||||
-- Update infotext of old empty_shelf nodes to "Plain Shelf"
|
||||
minetest.register_lbm({
|
||||
label = "Update plain shelf infotext",
|
||||
name = "xdecor:empty_shelf_to_plain_shelf",
|
||||
nodenames = {"xdecor:empty_shelf"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", S("Plain Shelf"))
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
register_storage("multishelf", S("Multi Shelf"), {
|
||||
_tt_help = S("24 inventory slots"),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"default_wood.png", "default_wood.png", "default_wood.png",
|
||||
"default_wood.png", "default_wood.png^xdecor_multishelf.png"
|
||||
},
|
||||
})
|
||||
|
||||
xdecor.register("candle", {
|
||||
description = S("Candle"),
|
||||
light_source = 12,
|
||||
drawtype = "torchlike",
|
||||
inventory_image = "xdecor_candle_inv.png",
|
||||
wield_image = "xdecor_candle_wield.png",
|
||||
paramtype2 = "wallmounted",
|
||||
walkable = false,
|
||||
groups = {dig_immediate = 3, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_candle_floor.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
},
|
||||
{
|
||||
name = "xdecor_candle_hanging.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
},
|
||||
{
|
||||
name = "xdecor_candle_wall.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.25, -0.3, -0.25, 0.25, 0.5, 0.25},
|
||||
wall_bottom = {-0.25, -0.5, -0.25, 0.25, 0.1, 0.25},
|
||||
wall_side = {-0.5, -0.35, -0.15, -0.15, 0.4, 0.15}
|
||||
}
|
||||
})
|
||||
|
||||
xdecor.register("chair", {
|
||||
description = S("Chair"),
|
||||
tiles = {"xdecor_wood.png"},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2, sittable = 1},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{3, 0, 11, 2, 16, 2},
|
||||
{11, 0, 11, 2, 16, 2},
|
||||
{5, 9, 11.5, 6, 6, 1},
|
||||
{3, 0, 3, 2, 6, 2},
|
||||
{11, 0, 3, 2, 6, 2},
|
||||
{3, 6, 3, 10, 2, 8}
|
||||
}),
|
||||
can_dig = xdecor.sit_dig,
|
||||
after_destruct = xdecor.sit_destruct,
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
xdecor.sit(pos, node, clicker, pointed_thing)
|
||||
return itemstack
|
||||
end,
|
||||
_xdecor_itemframe_offset = -1.5,
|
||||
})
|
||||
|
||||
xdecor.register("cobweb", {
|
||||
description = S("Cobweb"),
|
||||
drawtype = "plantlike",
|
||||
tiles = {"xdecor_cobweb.png"},
|
||||
inventory_image = "xdecor_cobweb.png",
|
||||
move_resistance = 8,
|
||||
walkable = false,
|
||||
selection_box = {type = "regular"},
|
||||
groups = {snappy = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_leaves_defaults()
|
||||
})
|
||||
|
||||
local curtain_colors = {
|
||||
red = { S("Red Curtain"), "wool_red.png", "wool:red" },
|
||||
}
|
||||
|
||||
local CURTAIN_OFFSET = 1/16
|
||||
|
||||
-- For preserve_metadata for curtains.
|
||||
-- Erases metadata from the drops
|
||||
-- because the item metadata should be empty
|
||||
-- to allow proper item stacking.
|
||||
local cleanup_curtain_meta = function(_,_,_,drops)
|
||||
for d=1, #drops do
|
||||
local meta = drops[d]:get_meta()
|
||||
meta:set_string("palette_index", "")
|
||||
end
|
||||
end
|
||||
|
||||
for c, info in pairs(curtain_colors) do
|
||||
local desc = info[1]
|
||||
local base_texture = info[2]
|
||||
local craft_item = info[3]
|
||||
xdecor.register("curtain_" .. c, {
|
||||
description = desc,
|
||||
walkable = false,
|
||||
tiles = {base_texture, "("..base_texture..")^[transformFY", base_texture},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
inventory_image = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126",
|
||||
wield_image = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126",
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "wallmounted",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -0.5+CURTAIN_OFFSET, 0.5, 0.5 },
|
||||
wall_top = { -0.5, 0.5-CURTAIN_OFFSET, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, -0.5+CURTAIN_OFFSET, 0.5 },
|
||||
},
|
||||
groups = {dig_immediate = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
on_rightclick = function(pos, node, _, itemstack)
|
||||
minetest.set_node(pos, {name = "xdecor:curtain_open_" .. c, param2 = node.param2})
|
||||
return itemstack
|
||||
end,
|
||||
preserve_metadata = cleanup_curtain_meta,
|
||||
})
|
||||
|
||||
local open_tile = base_texture.."^xdecor_curtain_open_overlay.png^[makealpha:255,126,126"
|
||||
xdecor.register("curtain_open_" .. c, {
|
||||
tiles = {
|
||||
open_tile,
|
||||
"("..open_tile..")^[transformFY",
|
||||
base_texture,
|
||||
base_texture,
|
||||
base_texture.."^xdecor_curtain_open_overlay_top.png^[makealpha:255,126,126",
|
||||
base_texture.."^xdecor_curtain_open_overlay_bottom.png^[makealpha:255,126,126",
|
||||
},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
drawtype = "nodebox",
|
||||
paramtype2 = "wallmounted",
|
||||
node_box = {
|
||||
type = "wallmounted",
|
||||
wall_side = { -0.5, -0.5, -0.5, -0.5+CURTAIN_OFFSET, 0.5, 0.5 },
|
||||
wall_top = { -0.5, 0.5-CURTAIN_OFFSET, -0.5, 0.5, 0.5, 0.5 },
|
||||
wall_bottom = { -0.5, -0.5, -0.5, 0.5, -0.5+CURTAIN_OFFSET, 0.5 },
|
||||
},
|
||||
walkable = false,
|
||||
groups = {dig_immediate = 3, flammable = 3, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
drop = "xdecor:curtain_" .. c,
|
||||
on_rightclick = function(pos, node, _, itemstack)
|
||||
minetest.set_node(pos, {name="xdecor:curtain_" .. c, param2 = node.param2})
|
||||
return itemstack
|
||||
end,
|
||||
preserve_metadata = cleanup_curtain_meta,
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:curtain_" .. c .. " 4",
|
||||
recipe = {
|
||||
{"", craft_item, ""},
|
||||
{"", craft_item, ""}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("cushion", {
|
||||
description = S("Cushion"),
|
||||
tiles = {"xdecor_cushion.png"},
|
||||
groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -50, sittable = 1},
|
||||
is_ground_content = false,
|
||||
on_place = minetest.rotate_node,
|
||||
node_box = xdecor.nodebox.slab_y(0.5),
|
||||
can_dig = xdecor.sit_dig,
|
||||
after_destruct = xdecor.sit_destruct,
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
xdecor.sit(pos, node, clicker, pointed_thing)
|
||||
return itemstack
|
||||
end
|
||||
})
|
||||
|
||||
xdecor.register("cushion_block", {
|
||||
description = S("Cushion Block"),
|
||||
tiles = {"xdecor_cushion.png"},
|
||||
groups = {snappy = 3, flammable = 3, fall_damage_add_percent = -75},
|
||||
is_ground_content = false,
|
||||
})
|
||||
|
||||
local function door_access(name)
|
||||
return name:find("prison")
|
||||
end
|
||||
|
||||
local xdecor_doors = {
|
||||
japanese = {
|
||||
recipe = {
|
||||
{"group:wood", "default:paper"},
|
||||
{"default:paper", "group:wood"},
|
||||
{"group:wood", "default:paper"}
|
||||
},
|
||||
desc = S("Japanese Door"),
|
||||
},
|
||||
prison = {
|
||||
recipe = {
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat",},
|
||||
{"xpanes:bar_flat", "default:steel_ingot",},
|
||||
{"xpanes:bar_flat", "xpanes:bar_flat"}
|
||||
},
|
||||
desc = S("Prison Door"),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sound_open = "xpanes_steel_bar_door_open",
|
||||
sound_close = "xpanes_steel_bar_door_close",
|
||||
gain_open = 0.18,
|
||||
gain_close = 0.16,
|
||||
},
|
||||
rusty_prison = {
|
||||
recipe = {
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",},
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat",},
|
||||
{"xpanes:rusty_bar_flat", "xpanes:rusty_bar_flat"}
|
||||
},
|
||||
desc = S("Rusty Prison Door"),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sound_open = "xpanes_steel_bar_door_open",
|
||||
sound_close = "xpanes_steel_bar_door_close",
|
||||
gain_open = 0.21,
|
||||
gain_close = 0.19,
|
||||
},
|
||||
screen = {
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"xpanes:chainlink_flat", "xpanes:chainlink_flat"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Screen Door"),
|
||||
},
|
||||
slide = {
|
||||
recipe = {
|
||||
{"default:paper", "default:paper"},
|
||||
{"default:paper", "default:paper"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Paper Door"),
|
||||
},
|
||||
woodglass = {
|
||||
recipe = {
|
||||
{"default:glass", "default:glass"},
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"}
|
||||
},
|
||||
desc = S("Woodglass Door"),
|
||||
},
|
||||
}
|
||||
|
||||
local mesecons_register
|
||||
|
||||
if minetest.global_exists("mesecon") then
|
||||
mesecons_register = { effector = {
|
||||
action_on = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:open()
|
||||
end
|
||||
end,
|
||||
action_off = function(pos, node)
|
||||
local door = doors.get(pos)
|
||||
if door then
|
||||
door:close()
|
||||
end
|
||||
end,
|
||||
rules = mesecon.rules.pplate
|
||||
}}
|
||||
end
|
||||
|
||||
for name, def in pairs(xdecor_doors) do
|
||||
if not doors.register then break end
|
||||
doors.register(name .. "_door", {
|
||||
tiles = {
|
||||
{name = "xdecor_" .. name .. "_door.png", backface_culling = true}
|
||||
},
|
||||
description = def.desc,
|
||||
inventory_image = "xdecor_" .. name .. "_door_inv.png",
|
||||
sounds = def.sounds,
|
||||
sound_open = def.sound_open,
|
||||
sound_close = def.sound_close,
|
||||
gain_open = def.gain_open,
|
||||
gain_close = def.gain_close,
|
||||
protected = door_access(name),
|
||||
groups = {choppy = 2, cracky = 2, oddly_breakable_by_hand = 1, door = 1, node = 1},
|
||||
recipe = def.recipe,
|
||||
mesecons = mesecons_register,
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("enderchest", {
|
||||
description = S("Ender Chest"),
|
||||
_tt_help = S("Interdimensional inventory"),
|
||||
tiles = {
|
||||
"xdecor_enderchest_top.png", "xdecor_enderchest_top.png",
|
||||
"xdecor_enderchest_side.png", "xdecor_enderchest_side.png",
|
||||
"xdecor_enderchest_side.png", "xdecor_enderchest_front.png"
|
||||
},
|
||||
groups = {cracky = 1, choppy = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("formspec", [[ size[8,9]
|
||||
list[current_player;enderchest;0,0;8,4;]
|
||||
list[current_player;main;0,5;8,4;]
|
||||
listring[current_player;enderchest]
|
||||
listring[current_player;main] ]]
|
||||
.. xdecor.xbg .. default.get_hotbar_bg(0,5))
|
||||
|
||||
meta:set_string("infotext", S("Ender Chest"))
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local inv = player:get_inventory()
|
||||
inv:set_size("enderchest", 8*4)
|
||||
end)
|
||||
|
||||
xdecor.register("ivy", {
|
||||
description = S("Ivy"),
|
||||
drawtype = "signlike",
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
groups = {snappy = 3, attached_node = 1, plant = 1, flammable = 3},
|
||||
paramtype2 = "wallmounted",
|
||||
selection_box = {type="wallmounted"},
|
||||
tiles = {"xdecor_ivy.png"},
|
||||
inventory_image = "xdecor_ivy.png",
|
||||
wield_image = "xdecor_ivy.png",
|
||||
sounds = default.node_sound_leaves_defaults()
|
||||
})
|
||||
|
||||
xdecor.register("rooster", {
|
||||
description = S("Weathercock"),
|
||||
drawtype = "torchlike",
|
||||
inventory_image = "xdecor_rooster.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_rooster.png"},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
-- Lantern which attaches to the floor.
|
||||
-- Has a hanging variant
|
||||
xdecor.register("lantern", {
|
||||
description = S("Lantern"),
|
||||
light_source = 13,
|
||||
drawtype = "plantlike",
|
||||
inventory_image = "xdecor_lantern_inv.png",
|
||||
wield_image = "xdecor_lantern_inv.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 3},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_lantern.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = xdecor.pixelbox(16, {{4, 0, 4, 8, 16, 8}}),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
-- Check protection
|
||||
if minetest.is_protected(pointed_thing.above, placer:get_player_name()) and
|
||||
not minetest.check_player_privs(placer, "protection_bypass") then
|
||||
minetest.record_protection_violation(pointed_thing.above, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Decide whether the lantern attaches the the floor
|
||||
-- (default) or the ceiling.
|
||||
local leftover, place_pos, nodename
|
||||
local up = vector.new(pointed_thing.above.x, pointed_thing.above.y+1, pointed_thing.above.z)
|
||||
local upnode = minetest.get_node(up)
|
||||
local updef = minetest.registered_nodes[upnode.name]
|
||||
local down = vector.new(pointed_thing.above.x, pointed_thing.above.y-1, pointed_thing.above.z)
|
||||
local downnode = minetest.get_node(down)
|
||||
local downdef = minetest.registered_nodes[downnode.name]
|
||||
local sound_play = false
|
||||
if pointed_thing.under.y > pointed_thing.above.y then
|
||||
nodename = "xdecor:lantern_hanging"
|
||||
if downdef and not downdef.walkable then
|
||||
sound_play = true
|
||||
end
|
||||
elseif downdef and not downdef.walkable and updef and updef.walkable then
|
||||
nodename = "xdecor:lantern_hanging"
|
||||
sound_play = true
|
||||
else
|
||||
nodename = "xdecor:lantern"
|
||||
end
|
||||
leftover, place_pos = minetest.item_place_node(ItemStack(nodename), placer, pointed_thing)
|
||||
if place_pos == nil then
|
||||
return
|
||||
end
|
||||
if leftover:get_count() == 0 and
|
||||
not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
if sound_play then
|
||||
minetest.sound_play(default.node_sound_metal_defaults().place, {pos=place_pos}, true)
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
-- Same as lantern, but attaches to ceiling
|
||||
xdecor.register("lantern_hanging", {
|
||||
description = S("Hanging Lantern"),
|
||||
light_source = 13,
|
||||
drawtype = "plantlike",
|
||||
inventory_image = "xdecor_lantern_inv.png^xdecor_lantern_hanging_overlay_inv.png",
|
||||
wield_image = "xdecor_lantern_inv.png",
|
||||
walkable = false,
|
||||
groups = {snappy = 3, attached_node = 4, not_in_creative_inventory = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {
|
||||
{
|
||||
name = "xdecor_lantern.png",
|
||||
animation = {type="vertical_frames", length = 1.5}
|
||||
}
|
||||
},
|
||||
selection_box = xdecor.pixelbox(16, {{4, 0, 4, 8, 16, 8}}),
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
drop = "xdecor:lantern",
|
||||
})
|
||||
|
||||
-- Update legacy lantern (back when they were wallmounted)
|
||||
-- that are hanging to the proper node.
|
||||
minetest.register_lbm({
|
||||
label = "Update hanging lanterns",
|
||||
name = "xdecor:update_hanging_lanterns",
|
||||
nodenames = {"xdecor:lantern"},
|
||||
run_at_every_load = false,
|
||||
action = function(pos, node)
|
||||
if node.param2 == 0 then -- wallmounted 0 value means attached to the ceiling
|
||||
-- Only convert the node if it needs to hang
|
||||
-- (walkable node above, non-walkable node below)
|
||||
local up = vector.new(pos.x, pos.y+1, pos.z)
|
||||
local upnode = minetest.get_node(up)
|
||||
local updef = minetest.registered_nodes[upnode.name]
|
||||
local down = vector.new(pos.x, pos.y-1, pos.z)
|
||||
local downnode = minetest.get_node(down)
|
||||
local downdef = minetest.registered_nodes[downnode.name]
|
||||
if updef and updef.walkable and downdef and not downdef.walkable then
|
||||
minetest.swap_node(pos, {name="xdecor:lantern_hanging"})
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
local xdecor_lightbox = {
|
||||
iron = S("Steel Lattice Light Box"),
|
||||
wooden = S("Wooden Cross Light Box"),
|
||||
wooden2 = S("Wooden Rhombus Light Box"),
|
||||
}
|
||||
|
||||
for l, desc in pairs(xdecor_lightbox) do
|
||||
xdecor.register(l .. "_lightbox", {
|
||||
description = desc,
|
||||
tiles = {"xdecor_" .. l .. "_lightbox.png"},
|
||||
groups = {cracky = 3, choppy = 3, oddly_breakable_by_hand = 2},
|
||||
is_ground_content = false,
|
||||
light_source = 13,
|
||||
sounds = default.node_sound_glass_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
local xdecor_potted = {
|
||||
dandelion_white = S("Potted White Dandelion"),
|
||||
dandelion_yellow = S("Potted Yellow Dandelion"),
|
||||
geranium = S("Potted Geranium"),
|
||||
rose = S("Potted Rose"),
|
||||
tulip = S("Potted Tulip"),
|
||||
viola = S("Potted Viola"),
|
||||
}
|
||||
|
||||
for f, desc in pairs(xdecor_potted) do
|
||||
xdecor.register("potted_" .. f, {
|
||||
description = desc,
|
||||
walkable = false,
|
||||
groups = {snappy = 3, flammable = 3, plant = 1, flower = 1},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_" .. f .. "_pot.png"},
|
||||
inventory_image = "xdecor_" .. f .. "_pot.png",
|
||||
drawtype = "plantlike",
|
||||
sounds = default.node_sound_leaves_defaults({
|
||||
place = default.node_sound_stone_defaults().place,
|
||||
dug = default.node_sound_stone_defaults().dug,
|
||||
}),
|
||||
selection_box = xdecor.nodebox.slab_y(0.3)
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:potted_" .. f,
|
||||
recipe = {
|
||||
{"default:clay_brick", "flowers:" .. f, "default:clay_brick"},
|
||||
{"", "default:clay_brick", ""}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
local painting_box = {
|
||||
type = "wallmounted",
|
||||
wall_top = {-0.4375, 0.4375, -0.3125, 0.4375, 0.5, 0.3125},
|
||||
wall_bottom = {-0.4375, -0.5, -0.3125, 0.4375, -0.4375, 0.3125},
|
||||
wall_side = {-0.5, -0.3125, -0.4375, -0.4375, 0.3125, 0.4375}
|
||||
}
|
||||
|
||||
xdecor.register("painting_1", {
|
||||
description = S("Painting"),
|
||||
tiles = {"xdecor_painting_1.png","xdecor_painting_1.png^[transformR180","xdecor_painting_1.png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
inventory_image = "xdecor_painting_empty.png",
|
||||
wield_image = "xdecor_painting_empty.png",
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
sunlight_propagates = true,
|
||||
groups = {choppy = 3, oddly_breakable_by_hand = 2, flammable = 2, attached_node = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = painting_box,
|
||||
node_placement_prediction = "",
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if pointed_thing.type ~= "node" then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
-- Check protection
|
||||
if minetest.is_protected(pointed_thing.above, placer:get_player_name()) and
|
||||
not minetest.check_player_privs(placer, "protection_bypass") then
|
||||
minetest.record_protection_violation(pointed_thing.above, placer:get_player_name())
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local num = math.random(4)
|
||||
local leftover, place_pos = minetest.item_place_node(
|
||||
ItemStack("xdecor:painting_" .. num), placer, pointed_thing)
|
||||
|
||||
if not place_pos then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
if leftover:get_count() == 0 and
|
||||
not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||
itemstack:take_item()
|
||||
end
|
||||
|
||||
-- Play 'place' sound manually
|
||||
minetest.sound_play(default.node_sound_wood_defaults().place, {pos=place_pos}, true)
|
||||
|
||||
return itemstack
|
||||
end,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
})
|
||||
|
||||
for i = 2, 4 do
|
||||
xdecor.register("painting_" .. i, {
|
||||
tiles = {"xdecor_painting_"..i..".png","xdecor_painting_"..i..".png^[transformR180","xdecor_painting_"..i..".png"},
|
||||
use_texture_alpha = ALPHA_OPAQUE,
|
||||
paramtype2 = "wallmounted",
|
||||
wallmounted_rotate_vertical = true,
|
||||
drop = "xdecor:painting_1",
|
||||
sunlight_propagates = true,
|
||||
groups = {
|
||||
choppy = 3,
|
||||
oddly_breakable_by_hand = 2,
|
||||
flammable = 2,
|
||||
attached_node = 1,
|
||||
not_in_creative_inventory = 1
|
||||
},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = painting_box
|
||||
})
|
||||
end
|
||||
|
||||
xdecor.register("stonepath", {
|
||||
description = S("Garden Stone Path"),
|
||||
tiles = {"default_stone.png"},
|
||||
groups = {snappy = 3},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
sounds = default.node_sound_stone_defaults(),
|
||||
sunlight_propagates = true,
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{8, 0, 8, 6, .5, 6}, {1, 0, 1, 6, .5, 6},
|
||||
{1, 0, 10, 5, .5, 5}, {10, 0, 2, 4, .5, 4}
|
||||
}),
|
||||
selection_box = xdecor.nodebox.slab_y(0.05)
|
||||
})
|
||||
|
||||
local function register_hard_node(name, desc, def)
|
||||
def = def or {}
|
||||
xdecor.register(name, {
|
||||
description = desc,
|
||||
tiles = def.tiles or {"xdecor_" .. name .. ".png"},
|
||||
groups = def.groups or {cracky = 1},
|
||||
is_ground_content = false,
|
||||
sounds = def.sounds or default.node_sound_stone_defaults()
|
||||
})
|
||||
end
|
||||
|
||||
register_hard_node("cactusbrick", S("Cactus Brick"))
|
||||
register_hard_node("coalstone_tile", S("Coal Stone Tile"))
|
||||
register_hard_node("desertstone_tile", S("Polished Desert Stone Block"))
|
||||
register_hard_node("hard_clay", S("Hardened Clay"))
|
||||
register_hard_node("moonbrick", S("Moon Brick"))
|
||||
register_hard_node("stone_rune", S("Runestone"))
|
||||
|
||||
-- renamed from stone_tile to fix naming collision with moreblocks
|
||||
-- mod for the registrations under the 'stairs:' namespace
|
||||
register_hard_node("stone_tile_x", S("Polished Stone Block"), {
|
||||
tiles = {"xdecor_stone_tile.png"},
|
||||
})
|
||||
xdecor.register_legacy_aliases("stone_tile", "stone_tile_x")
|
||||
|
||||
register_hard_node("packed_ice", S("Packed Ice"), {
|
||||
groups = {cracky = 1, cools_lava = 1, slippery = 3},
|
||||
sounds = default.node_sound_glass_defaults()
|
||||
})
|
||||
|
||||
-- renamed from wood_tile to fix naming collision with moreblocks
|
||||
-- mod for the registrations under the 'stairs:' namespace
|
||||
register_hard_node("wood_tile_x", S("Wooden Tile"), {
|
||||
groups = {choppy = 1, wood = 1, flammable = 2},
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
tiles = {"xdecor_wood_tile.png"},
|
||||
})
|
||||
xdecor.register_legacy_aliases("wood_tile", "wood_tile_x")
|
||||
|
||||
xdecor.register("table", {
|
||||
description = S("Table"),
|
||||
tiles = {"xdecor_wood.png"},
|
||||
groups = {choppy = 2, oddly_breakable_by_hand = 1, flammable = 2},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
node_box = xdecor.pixelbox(16, {
|
||||
{0, 14, 0, 16, 2, 16}, {5.5, 0, 5.5, 5, 14, 6}
|
||||
})
|
||||
})
|
||||
|
||||
xdecor.register("tatami", {
|
||||
description = S("Tatami"),
|
||||
tiles = {"xdecor_tatami.png"},
|
||||
wield_image = "xdecor_tatami.png",
|
||||
groups = {snappy = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
sunlight_propagates = true,
|
||||
node_box = xdecor.nodebox.slab_y(0.0625)
|
||||
})
|
||||
|
||||
xdecor.register("trampoline", {
|
||||
description = S("Trampoline"),
|
||||
tiles = {"xdecor_trampoline.png", "xdecor_trampoline_bottom.png", "xdecor_trampoline_sides.png"},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 1, fall_damage_add_percent = -80, bouncy = 90},
|
||||
is_ground_content = false,
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{ -0.5, -1/16, -0.5, 0.5, 0, 0.5 }, -- bouncy top
|
||||
{ -0.5, -0.5, -0.5, -3/16, 0, -3/16 }, -- leg 1
|
||||
{ 3/16, -0.5, -0.5, 0.5, 0, -3/16 }, -- leg 2
|
||||
{ -0.5, -0.5, 3/16, -3/16, 0, 0.5 }, -- leg 3
|
||||
{ 3/16, -0.5, 3/16, 0.5, 0, 0.5 }, -- leg 4
|
||||
{ -3/16, -5/16, -0.5, 3/16, -1/16, -7/16 }, -- connector 1
|
||||
{ -0.5, -5/16, -3/16, -7/16, -1/16, 3/16 }, -- connector 2
|
||||
{ -3/16, -5/16, 7/16, 3/16, -1/16, 0.5 }, -- connector 3
|
||||
{ 7/16, -5/16, -3/16, 0.5, -1/16, 3/16 }, -- connector 4
|
||||
},
|
||||
},
|
||||
selection_box = xdecor.nodebox.slab_y(0.5),
|
||||
collision_box = xdecor.nodebox.slab_y(0.5),
|
||||
sounds = default.node_sound_defaults({
|
||||
footstep = {
|
||||
name = "xdecor_bouncy",
|
||||
gain = 0.8
|
||||
},
|
||||
dig = default.node_sound_wood_defaults().dig,
|
||||
}),
|
||||
})
|
||||
|
||||
xdecor.register("tv", {
|
||||
description = S("Television"),
|
||||
light_source = 11,
|
||||
groups = {cracky = 3, oddly_breakable_by_hand = 2},
|
||||
is_ground_content = false,
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_television_left.png^[transformR270",
|
||||
"xdecor_television_left.png^[transformR90",
|
||||
"xdecor_television_left.png^[transformFX",
|
||||
"xdecor_television_left.png", "xdecor_television_back.png",
|
||||
{
|
||||
name = "xdecor_television_front_animated.png",
|
||||
animation = {type = "vertical_frames", length = 80.0}
|
||||
}
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
})
|
||||
|
||||
xdecor.register("woodframed_glass", {
|
||||
description = S("Wood Framed Glass"),
|
||||
drawtype = "glasslike_framed",
|
||||
sunlight_propagates = true,
|
||||
tiles = {"xdecor_woodframed_glass.png", "xdecor_woodframed_glass_detail.png"},
|
||||
use_texture_alpha = ALPHA_CLIP,
|
||||
groups = {cracky = 2, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_glass_defaults(),
|
||||
_xdecor_custom_noncube_tiles = {
|
||||
stair = {
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
stair_inner = {
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR270",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
},
|
||||
stair_outer = {
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR90",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_outer_stairside.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png^[transformR90",
|
||||
"xdecor_woodframed_glass_outer_stairside.png",
|
||||
},
|
||||
halfstair = {
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_stairside_flip.png",
|
||||
"xdecor_woodframed_glass_stairside.png",
|
||||
"xdecor_woodframed_glass_split.png^[transformR90",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
},
|
||||
slab = {
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
cube = { "xdecor_woodframed_glass_cube.png" },
|
||||
thinstair = { "xdecor_woodframed_glass_split.png" },
|
||||
micropanel = { "xdecor_woodframed_glass_split.png" },
|
||||
panel = {
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass_cube.png",
|
||||
"xdecor_woodframed_glass_split.png",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
local devices = {
|
||||
{ "radio", S("Radio"), default.node_sound_metal_defaults() },
|
||||
--~ as in "loudspeaker"
|
||||
{ "speaker", S("Speaker"), default.node_sound_metal_defaults() },
|
||||
}
|
||||
for _, v in pairs(devices) do
|
||||
xdecor.register(v[1], {
|
||||
description = v[2],
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
tiles = {
|
||||
"xdecor_" .. v[1] .. "_top.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_side.png",
|
||||
"xdecor_" .. v[1] .. "_back.png",
|
||||
"xdecor_" .. v[1] .. "_front.png",
|
||||
},
|
||||
groups = {cracky = 2, not_cuttable = 1},
|
||||
is_ground_content = false,
|
||||
sounds = v[3],
|
||||
})
|
||||
end
|
405
mods/xdecor/src/recipes.lua
Normal file
|
@ -0,0 +1,405 @@
|
|||
minetest.register_craft({
|
||||
output = "xdecor:baricade",
|
||||
recipe = {
|
||||
{"group:stick", "", "group:stick"},
|
||||
{"", "default:steel_ingot", ""},
|
||||
{"group:stick", "", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:barrel",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"default:iron_lump", "", "default:iron_lump"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:candle",
|
||||
recipe = {
|
||||
{"default:torch"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cabinet",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"doors:trapdoor", "", "doors:trapdoor"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cabinet_half 2",
|
||||
recipe = {
|
||||
{"xdecor:cabinet"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cactusbrick",
|
||||
recipe = {
|
||||
{"default:brick", "default:cactus"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:chair",
|
||||
recipe = {
|
||||
{"group:stick", "", ""},
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:coalstone_tile 4",
|
||||
recipe = {
|
||||
{"default:coalblock", "default:stone"},
|
||||
{"default:stone", "default:coalblock"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cobweb",
|
||||
recipe = {
|
||||
{"farming:string", "", "farming:string"},
|
||||
{"", "farming:string", ""},
|
||||
{"farming:string", "", "farming:string"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cushion 3",
|
||||
recipe = {
|
||||
{"wool:red", "wool:red", "wool:red"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:cushion_block",
|
||||
recipe = {
|
||||
{"xdecor:cushion"},
|
||||
{"xdecor:cushion"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:desertstone_tile 4",
|
||||
recipe = {
|
||||
{"default:desert_stone_block", "default:desert_stone_block"},
|
||||
{"default:desert_stone_block", "default:desert_stone_block"},
|
||||
}
|
||||
})
|
||||
|
||||
if not minetest.get_modpath("moreblocks") then
|
||||
minetest.register_craft({
|
||||
output = "xdecor:empty_shelf",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"", "", ""},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:enderchest",
|
||||
recipe = {
|
||||
{"", "default:obsidian", ""},
|
||||
{"default:obsidian", "default:chest", "default:obsidian"},
|
||||
{"", "default:obsidian", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hard_clay",
|
||||
recipe = {
|
||||
{"default:clay", "default:clay"},
|
||||
{"default:clay", "default:clay"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:iron_lightbox",
|
||||
recipe = {
|
||||
{"xpanes:bar_flat", "default:torch", "xpanes:bar_flat"},
|
||||
{"xpanes:bar_flat", "default:glass", "xpanes:bar_flat"},
|
||||
{"xpanes:bar_flat", "default:torch", "xpanes:bar_flat"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:ivy 4",
|
||||
recipe = {
|
||||
{"group:leaves"},
|
||||
{"group:leaves"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:lantern",
|
||||
recipe = {
|
||||
{"default:iron_lump"},
|
||||
{"default:torch"},
|
||||
{"default:iron_lump"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:moonbrick",
|
||||
recipe = {
|
||||
{"default:brick", "default:stone"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:multishelf",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood", "group:wood"},
|
||||
{"group:vessel", "group:book", "group:vessel"},
|
||||
{"group:wood", "group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:packed_ice",
|
||||
recipe = {
|
||||
{"", "default:ice", ""},
|
||||
{"default:ice", "", "default:ice"},
|
||||
{"", "default:ice", ""},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:painting_1",
|
||||
recipe = {
|
||||
{"default:sign_wall_wood", "group:dye"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:radio",
|
||||
type = "shapeless",
|
||||
recipe = {"xdecor:speaker", "xdecor:speaker"}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:rooster",
|
||||
recipe = {
|
||||
{"default:gold_ingot", "", "default:gold_ingot"},
|
||||
{"", "default:gold_ingot", ""},
|
||||
{"default:gold_ingot", "", "default:gold_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:speaker",
|
||||
recipe = {
|
||||
{"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"},
|
||||
{"default:copper_ingot", "", "default:copper_ingot"},
|
||||
{"default:gold_ingot", "default:copper_ingot", "default:gold_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stone_tile_x 4",
|
||||
recipe = {
|
||||
{"default:stone_block", "default:stone_block"},
|
||||
{"default:stone_block", "default:stone_block"},
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stone_rune 4",
|
||||
recipe = {
|
||||
{"default:stone_block", "default:stone_block", "default:stone_block"},
|
||||
{"default:stone_block", "", "default:stone_block"},
|
||||
{"default:stone_block", "default:stone_block", "default:stone_block"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:stonepath 16",
|
||||
recipe = {
|
||||
{"stairs:slab_cobble", "", "stairs:slab_cobble"},
|
||||
{"", "stairs:slab_cobble", ""},
|
||||
{"stairs:slab_cobble", "", "stairs:slab_cobble"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:table",
|
||||
recipe = {
|
||||
{"stairs:slab_wood", "stairs:slab_wood", "stairs:slab_wood"},
|
||||
{"", "group:stick", ""},
|
||||
{"", "group:stick", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:tatami",
|
||||
recipe = {
|
||||
{"farming:wheat", "farming:wheat", "farming:wheat"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:trampoline",
|
||||
recipe = {
|
||||
{"farming:string", "farming:string", "farming:string"},
|
||||
{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:tv",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:glass", "default:steel_ingot"},
|
||||
{"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:woodframed_glass",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"group:stick", "default:glass", "group:stick"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wood_tile_x 2",
|
||||
recipe = {
|
||||
{"", "group:wood", ""},
|
||||
{"group:wood", "", "group:wood"},
|
||||
{"", "group:wood", ""}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wooden_lightbox",
|
||||
recipe = {
|
||||
{"group:stick", "default:torch", "group:stick"},
|
||||
{"group:stick", "default:glass", "group:stick"},
|
||||
{"group:stick", "default:torch", "group:stick"}
|
||||
}
|
||||
})
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:wooden2_lightbox",
|
||||
recipe = {
|
||||
{"group:stick", "group:stick", "group:stick"},
|
||||
{"default:torch", "default:glass", "default:torch"},
|
||||
{"group:stick", "group:stick", "group:stick"}
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:empty_shelf",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:multishelf",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:cabinet",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:barrel",
|
||||
burntime = 30,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:cabinet_half",
|
||||
burntime = 15,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:workbench",
|
||||
burntime = 15,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:table",
|
||||
burntime = 12,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:woodglass_door",
|
||||
burntime = 13,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:screen_door",
|
||||
burntime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:slide_door",
|
||||
burntime = 8,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xpanes:wood_frame_flat",
|
||||
burntime = 5,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xpanes:bamboo_frame_flat",
|
||||
burntime = 3,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "doors:japanese_door",
|
||||
burntime = 8,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:chair",
|
||||
burntime = 6,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:baricade",
|
||||
burntime = 6,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:wood_tile_x",
|
||||
burntime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "realchess:chessboard",
|
||||
burntime = 4,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:painting_1",
|
||||
burntime = 3,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:tatami",
|
||||
burntime = 1,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "fuel",
|
||||
recipe = "xdecor:ivy",
|
||||
burntime = 1,
|
||||
})
|
||||
|
132
mods/xdecor/src/rope.lua
Normal file
|
@ -0,0 +1,132 @@
|
|||
local rope = {}
|
||||
local S = minetest.get_translator("xdecor")
|
||||
|
||||
-- Maximum length a rope can extend to
|
||||
local MAX_ROPES = 30
|
||||
|
||||
local ropesounds = default.node_sound_leaves_defaults()
|
||||
|
||||
-- Code by Mirko K. (modified by Temperest, Wulfsdad, kilbith and Wuzzy) (License: GPL).
|
||||
function rope.place(itemstack, placer, pointed_thing)
|
||||
local creative = minetest.is_creative_enabled(placer:get_player_name())
|
||||
local protection_bypass = minetest.check_player_privs(placer, "protection_bypass")
|
||||
local pname = placer:get_player_name()
|
||||
if pointed_thing.type == "node" then
|
||||
-- Use pointed node's on_rightclick function first, if present
|
||||
if placer and not placer:get_player_control().sneak then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
local pos = pointed_thing.above
|
||||
-- Check protection
|
||||
if minetest.is_protected(pos, pname) and not protection_bypass then
|
||||
minetest.record_protection_violation(pos, pname)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local oldnode = minetest.get_node(pos)
|
||||
local stackname = itemstack:get_name()
|
||||
-- Limit rope length to max. stack size or MAX_ROPES (whatever is smaller).
|
||||
-- Prevents the rope to extend infinitely in Creative Mode.
|
||||
local max_ropes = math.min(itemstack:get_stack_max(), MAX_ROPES)
|
||||
|
||||
-- Start placing ropes and extend it downwards until we hit an obstacle,
|
||||
-- run out of ropes or hit the maximum rope length.
|
||||
local start_pos = table.copy(pos)
|
||||
local ropes_to_place = 0
|
||||
local new_rope_nodes = {}
|
||||
while oldnode.name == "air" and (creative or (ropes_to_place < itemstack:get_count())) and ropes_to_place < max_ropes do
|
||||
-- Stop extending rope into protected area
|
||||
if minetest.is_protected(pos, pname) and not protection_bypass then
|
||||
break
|
||||
end
|
||||
|
||||
table.insert(new_rope_nodes, table.copy(pos))
|
||||
pos.y = pos.y - 1
|
||||
oldnode = minetest.get_node(pos)
|
||||
ropes_to_place = ropes_to_place + 1
|
||||
end
|
||||
local newnode = {name = stackname}
|
||||
if ropes_to_place == 1 then
|
||||
minetest.set_node(new_rope_nodes[1], newnode)
|
||||
else
|
||||
minetest.bulk_set_node(new_rope_nodes, newnode)
|
||||
end
|
||||
if not creative then
|
||||
itemstack:take_item(ropes_to_place)
|
||||
end
|
||||
|
||||
-- Play placement sound manually
|
||||
if ropes_to_place > 0 then
|
||||
minetest.sound_play(ropesounds.place, {pos=start_pos}, true)
|
||||
end
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function rope.remove(pos, oldnode, digger, rope_name)
|
||||
local num = 0
|
||||
local below = {x = pos.x, y = pos.y, z = pos.z}
|
||||
local digger_inv = digger:get_inventory()
|
||||
|
||||
while minetest.get_node(below).name == rope_name do
|
||||
minetest.remove_node(below)
|
||||
below.y = below.y - 1
|
||||
num = num + 1
|
||||
end
|
||||
|
||||
if num == 0 then return end
|
||||
|
||||
-- Play dig sound manually
|
||||
minetest.sound_play(ropesounds.dug, {pos=pos}, true)
|
||||
|
||||
-- Give/drop rope items
|
||||
local creative = minetest.is_creative_enabled(digger:get_player_name())
|
||||
if not creative or not digger_inv:contains_item("main", rope_name) then
|
||||
if creative then
|
||||
num = 1
|
||||
end
|
||||
local item = rope_name.." "..num
|
||||
local leftover = digger_inv:add_item("main", rope_name.." "..num)
|
||||
if not leftover:is_empty() then
|
||||
minetest.add_item(pos, leftover)
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
xdecor.register("rope", {
|
||||
description = S("Rope"),
|
||||
drawtype = "plantlike",
|
||||
walkable = false,
|
||||
climbable = true,
|
||||
groups = {dig_immediate = 3, flammable = 3},
|
||||
is_ground_content = false,
|
||||
tiles = {"xdecor_rope.png"},
|
||||
inventory_image = "xdecor_rope_inv.png",
|
||||
wield_image = "xdecor_rope_inv.png",
|
||||
selection_box = xdecor.pixelbox(8, {{3, 0, 3, 2, 8, 2}}),
|
||||
node_placement_prediction = "",
|
||||
on_place = rope.place,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
pos = vector.new(pos.x, pos.y-1, pos.z)
|
||||
rope.remove(pos, oldnode, digger, "xdecor:rope")
|
||||
end,
|
||||
sounds = ropesounds,
|
||||
})
|
||||
|
||||
-- Recipes
|
||||
|
||||
minetest.register_craft({
|
||||
output = "xdecor:rope",
|
||||
recipe = {
|
||||
{"farming:string"},
|
||||
{"farming:string"},
|
||||
{"farming:string"}
|
||||
}
|
||||
})
|
602
mods/xdecor/src/workbench.lua
Normal file
|
@ -0,0 +1,602 @@
|
|||
local workbench = {}
|
||||
local registered_cuttable_nodes = {}
|
||||
local special_cuts = {}
|
||||
|
||||
screwdriver = screwdriver or {}
|
||||
local min, ceil = math.min, math.ceil
|
||||
local S = minetest.get_translator("xdecor")
|
||||
local FS = function(...) return minetest.formspec_escape(S(...)) end
|
||||
|
||||
local DEFAULT_HAMMER_REPAIR = 500
|
||||
local DEFAULT_HAMMER_REPAIR_COST = 700
|
||||
|
||||
|
||||
-- Nodeboxes definitions
|
||||
workbench.defs = {
|
||||
-- Name Yield Nodeboxes (X Y Z W H L) Description
|
||||
{"nanoslab", 16, {{ 0, 0, 0, 8, 1, 8 }}, S("Nanoslab")},
|
||||
{"micropanel", 16, {{ 0, 0, 0, 16, 1, 8 }}, S("Micropanel")},
|
||||
{"microslab", 8, {{ 0, 0, 0, 16, 1, 16 }}, S("Microslab")},
|
||||
{"thinstair", 8, {{ 0, 7, 0, 16, 1, 8 },
|
||||
{ 0, 15, 8, 16, 1, 8 }}, S("Thin Stair")},
|
||||
{"cube", 4, {{ 0, 0, 0, 8, 8, 8 }}, S("Cube")},
|
||||
{"panel", 4, {{ 0, 0, 0, 16, 8, 8 }}, S("Panel")},
|
||||
{"slab", 2, nil, S("Slab") },
|
||||
{"doublepanel", 2, {{ 0, 0, 0, 16, 8, 8 },
|
||||
{ 0, 8, 8, 16, 8, 8 }}, S("Double Panel")},
|
||||
{"halfstair", 2, {{ 0, 0, 0, 8, 8, 16 },
|
||||
{ 0, 8, 8, 8, 8, 8 }}, S("Half-Stair")},
|
||||
{"stair_outer", 1, nil, nil},
|
||||
{"stair", 1, nil, S("Stair")},
|
||||
{"stair_inner", 1, nil, nil},
|
||||
}
|
||||
|
||||
local custom_repairable = {}
|
||||
function xdecor:register_repairable(item)
|
||||
custom_repairable[item] = true
|
||||
end
|
||||
|
||||
-- Tools allowed to be repaired
|
||||
function workbench:repairable(stack)
|
||||
-- Explicitly registered as repairable: Overrides everything else
|
||||
if custom_repairable[stack] then
|
||||
return true
|
||||
end
|
||||
-- no repair if non-tool
|
||||
if not minetest.registered_tools[stack] then
|
||||
return false
|
||||
end
|
||||
-- no repair if disable_repair group
|
||||
if minetest.get_item_group(stack, "disable_repair") == 1 then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Returns true if item can be cut into basic stairs and slabs
|
||||
function workbench:cuttable(itemname)
|
||||
local split = string.split(itemname, ":")
|
||||
if split and split[1] and split[2] then
|
||||
if minetest.registered_nodes["stairs:stair_"..split[2]] ~= nil or
|
||||
minetest.registered_nodes["stairs:slab_"..split[2]] ~= nil then
|
||||
return true
|
||||
end
|
||||
end
|
||||
if registered_cuttable_nodes[itemname] == true then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- Returns true if item can be cut into xdecor extended shapes (thinslab, panel, cube, etc.)
|
||||
function workbench:cuttable_extended(itemname)
|
||||
return registered_cuttable_nodes[itemname] == true
|
||||
end
|
||||
|
||||
-- method to allow other mods to check if an item is repairable
|
||||
function xdecor:is_repairable(stack)
|
||||
return workbench:repairable(stack)
|
||||
end
|
||||
|
||||
function workbench:get_output(inv, input, name)
|
||||
local output = {}
|
||||
local extended = workbench:cuttable_extended(input:get_name())
|
||||
for i = 1, #self.defs do
|
||||
local nbox = self.defs[i]
|
||||
local cuttype = nbox[1]
|
||||
local count = nbox[2] * input:get_count()
|
||||
local max_count = input:get_stack_max()
|
||||
if count > max_count then
|
||||
-- Limit count to maximum multiple to avoid waste
|
||||
count = nbox[2] * math.floor(max_count / nbox[2])
|
||||
end
|
||||
local was_cut = false
|
||||
if extended or nbox[3] == nil then
|
||||
local item = name .. "_" .. cuttype
|
||||
|
||||
item = nbox[3] and item or "stairs:" .. cuttype .. "_" .. name:match(":(.*)")
|
||||
if minetest.registered_items[item] then
|
||||
output[i] = item .. " " .. count
|
||||
was_cut = true
|
||||
end
|
||||
end
|
||||
if not was_cut and special_cuts[input:get_name()] ~= nil then
|
||||
local cut = special_cuts[input:get_name()][cuttype]
|
||||
if cut then
|
||||
output[i] = cut .. " " .. count
|
||||
was_cut = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
inv:set_list("forms", output)
|
||||
end
|
||||
|
||||
local main_fs = ""..
|
||||
--~ Verb shown in workbench form where you can cut a node
|
||||
"label[0.9,1.23;"..FS("Cut").."]"
|
||||
--~ Verb shown in workbench form where you can repair an item
|
||||
.."label[0.9,2.23;"..FS("Repair").."]"
|
||||
..[[ box[-0.05,1;2.05,0.9;#555555]
|
||||
box[-0.05,2;2.05,0.9;#555555] ]]
|
||||
--~ Button in workbench form
|
||||
.."button[0,0;2,1;craft;"..FS("Crafting").."]"
|
||||
--~ Button in workbench form
|
||||
.."button[2,0;2,1;storage;"..FS("Storage").."]"
|
||||
..[[ image[3,1;1,1;gui_arrow.png]
|
||||
image[0,1;1,1;worktable_saw.png]
|
||||
image[0,2;1,1;worktable_anvil.png]
|
||||
image[3,2;1,1;hammer_layout.png]
|
||||
list[context;input;2,1;1,1;]
|
||||
list[context;tool;2,2;1,1;]
|
||||
list[context;hammer;3,2;1,1;]
|
||||
list[context;forms;4,0;4,3;]
|
||||
listring[current_player;main]
|
||||
listring[context;tool]
|
||||
listring[current_player;main]
|
||||
listring[context;hammer]
|
||||
listring[current_player;main]
|
||||
listring[context;forms]
|
||||
listring[current_player;main]
|
||||
listring[context;input]
|
||||
]]
|
||||
|
||||
local crafting_fs = "image[5,1;1,1;gui_furnace_arrow_bg.png^[transformR270]"
|
||||
.."button[0,0;1.5,1;back;< "..FS("Back").."]"
|
||||
..[[ list[current_player;craft;2,0;3,3;]
|
||||
list[current_player;craftpreview;6,1;1,1;]
|
||||
listring[current_player;main]
|
||||
listring[current_player;craft]
|
||||
]]
|
||||
|
||||
local storage_fs = "list[context;storage;0,1;8,2;]"
|
||||
.."button[0,0;1.5,1;back;< "..FS("Back").."]"
|
||||
..[[listring[context;storage]
|
||||
listring[current_player;main]
|
||||
]]
|
||||
|
||||
local formspecs = {
|
||||
-- Main formspec
|
||||
main_fs,
|
||||
|
||||
-- Crafting formspec
|
||||
crafting_fs,
|
||||
|
||||
-- Storage formspec
|
||||
storage_fs,
|
||||
}
|
||||
|
||||
function workbench:set_formspec(meta, id)
|
||||
meta:set_string("formspec",
|
||||
"size[8,7;]list[current_player;main;0,3.25;8,4;]" ..
|
||||
formspecs[id] .. xdecor.xbg .. default.get_hotbar_bg(0,3.25))
|
||||
end
|
||||
|
||||
function workbench.construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
|
||||
inv:set_size("tool", 1)
|
||||
inv:set_size("input", 1)
|
||||
inv:set_size("hammer", 1)
|
||||
inv:set_size("forms", 4*3)
|
||||
inv:set_size("storage", 8*2)
|
||||
|
||||
meta:set_string("infotext", S("Work Bench"))
|
||||
workbench:set_formspec(meta, 1)
|
||||
end
|
||||
|
||||
function workbench.fields(pos, _, fields)
|
||||
if fields.quit then return end
|
||||
|
||||
local meta = minetest.get_meta(pos)
|
||||
local id = fields.back and 1 or fields.craft and 2 or fields.storage and 3
|
||||
if not id then return end
|
||||
|
||||
workbench:set_formspec(meta, id)
|
||||
end
|
||||
|
||||
function workbench.dig(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
return inv:is_empty("input") and inv:is_empty("hammer") and
|
||||
inv:is_empty("tool") and inv:is_empty("storage")
|
||||
end
|
||||
|
||||
function workbench.blast(pos)
|
||||
local drops = xdecor.get_inventory_drops(pos, {"input", "hammer", "tool", "storage"})
|
||||
minetest.remove_node(pos)
|
||||
return drops
|
||||
end
|
||||
|
||||
function workbench.timer(pos)
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local tool = inv:get_stack("tool", 1)
|
||||
local hammer = inv:get_stack("hammer", 1)
|
||||
|
||||
if tool:is_empty() or hammer:is_empty() or tool:get_wear() == 0 then
|
||||
timer:stop()
|
||||
return
|
||||
end
|
||||
|
||||
local hammerdef = hammer:get_definition()
|
||||
|
||||
-- Tool's wearing range: 0-65535; 0 = new condition
|
||||
tool:add_wear(-hammerdef._xdecor_hammer_repair or DEFAULT_HAMMER_REPAIR)
|
||||
hammer:add_wear(hammerdef._xdecor_hammer_repair_cost or DEFAULT_HAMMER_REPAIR_COST)
|
||||
|
||||
inv:set_stack("tool", 1, tool)
|
||||
inv:set_stack("hammer", 1, hammer)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function workbench.allow_put(pos, listname, index, stack, player)
|
||||
local stackname = stack:get_name()
|
||||
if (listname == "tool" and workbench:repairable(stackname)) or
|
||||
(listname == "input" and workbench:cuttable(stackname)) or
|
||||
(listname == "hammer" and minetest.get_item_group(stackname, "repair_hammer") == 1) or
|
||||
listname == "storage" then
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
return 0
|
||||
end
|
||||
|
||||
function workbench.on_put(pos, listname, index, stack, player)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
if listname == "input" then
|
||||
local input = inv:get_stack("input", 1)
|
||||
workbench:get_output(inv, input, stack:get_name())
|
||||
elseif listname == "tool" or listname == "hammer" then
|
||||
local timer = minetest.get_node_timer(pos)
|
||||
timer:start(3.0)
|
||||
end
|
||||
end
|
||||
|
||||
function workbench.allow_move(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
if (to_list == "storage" and from_list ~= "forms") then
|
||||
return count
|
||||
elseif (to_list == "hammer" and from_list == "tool") or (to_list == "tool" and from_list == "hammer") then
|
||||
local inv = minetest.get_inventory({type="node", pos=pos})
|
||||
local stack = inv:get_stack(from_list, from_index)
|
||||
if minetest.get_item_group(stack:get_name(), "repair_hammer") == 1 then
|
||||
return count
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function workbench.on_move(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local from_stack = inv:get_stack(from_list, from_index)
|
||||
local to_stack = inv:get_stack(to_list, to_index)
|
||||
|
||||
workbench.on_take(pos, from_list, from_index, from_stack, player)
|
||||
workbench.on_put(pos, to_list, to_index, to_stack, player)
|
||||
end
|
||||
|
||||
function workbench.allow_take(pos, listname, index, stack, player)
|
||||
return stack:get_count()
|
||||
end
|
||||
|
||||
function workbench.on_take(pos, listname, index, stack, player)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
local input = inv:get_stack("input", 1)
|
||||
local inputname = input:get_name()
|
||||
local stackname = stack:get_name()
|
||||
|
||||
if listname == "input" then
|
||||
if stackname == inputname and workbench:cuttable(inputname) then
|
||||
workbench:get_output(inv, input, stackname)
|
||||
else
|
||||
inv:set_list("forms", {})
|
||||
end
|
||||
elseif listname == "forms" then
|
||||
local fromstack = inv:get_stack(listname, index)
|
||||
if not fromstack:is_empty() and fromstack:get_name() ~= stackname then
|
||||
local player_inv = player:get_inventory()
|
||||
if player_inv:room_for_item("main", fromstack) then
|
||||
player_inv:add_item("main", fromstack)
|
||||
end
|
||||
end
|
||||
|
||||
input:take_item(ceil(stack:get_count() / workbench.defs[index][2]))
|
||||
inv:set_stack("input", 1, input)
|
||||
workbench:get_output(inv, input, inputname)
|
||||
end
|
||||
end
|
||||
|
||||
xdecor.register("workbench", {
|
||||
description = S("Work Bench"),
|
||||
_tt_help = S("For cutting blocks, repairing tools with a hammer, crafting and storing items"),
|
||||
groups = {cracky = 2, choppy = 2, oddly_breakable_by_hand = 1},
|
||||
is_ground_content = false,
|
||||
sounds = default.node_sound_wood_defaults(),
|
||||
tiles = {
|
||||
"xdecor_workbench_top.png","xdecor_workbench_bottom.png",
|
||||
"xdecor_workbench_sides.png", "xdecor_workbench_sides.png",
|
||||
"xdecor_workbench_front.png", "xdecor_workbench_front.png"
|
||||
},
|
||||
on_rotate = screwdriver.rotate_simple,
|
||||
can_dig = workbench.dig,
|
||||
on_blast = workbench.blast,
|
||||
on_timer = workbench.timer,
|
||||
on_construct = workbench.construct,
|
||||
on_receive_fields = workbench.fields,
|
||||
on_metadata_inventory_put = workbench.on_put,
|
||||
on_metadata_inventory_take = workbench.on_take,
|
||||
on_metadata_inventory_move = workbench.on_move,
|
||||
allow_metadata_inventory_put = workbench.allow_put,
|
||||
allow_metadata_inventory_take = workbench.allow_take,
|
||||
allow_metadata_inventory_move = workbench.allow_move
|
||||
})
|
||||
|
||||
local function register_cut_raw(node, workbench_def)
|
||||
local mod_name, item_name = node:match("^(.-):(.*)")
|
||||
local def = minetest.registered_nodes[node]
|
||||
|
||||
if item_name and workbench_def[3] then
|
||||
local groups = {}
|
||||
local tiles
|
||||
groups.not_in_creative_inventory = 1
|
||||
|
||||
for k, v in pairs(def.groups) do
|
||||
if k ~= "wood" and k ~= "stone" and k ~= "level" then
|
||||
groups[k] = v
|
||||
end
|
||||
end
|
||||
|
||||
if def.tiles then
|
||||
if #def.tiles > 1 and (def.drawtype:sub(1,5) ~= "glass") then
|
||||
tiles = def.tiles
|
||||
else
|
||||
tiles = {def.tiles[1]}
|
||||
end
|
||||
else
|
||||
tiles = {def.tile_images[1]}
|
||||
end
|
||||
|
||||
-- Erase `tileable_vertical=false` from tiles because it
|
||||
-- lead to buggy textures (e.g. with default:permafrost_with_moss)
|
||||
for t=1, #tiles do
|
||||
if type(tiles[t]) == "table" and tiles[t].tileable_vertical == false then
|
||||
tiles[t].tileable_vertical = nil
|
||||
end
|
||||
end
|
||||
|
||||
local custom_tiles = xdecor.glasscuts[node]
|
||||
if custom_tiles then
|
||||
if not custom_tiles.nanoslab then
|
||||
custom_tiles.nanoslab = custom_tiles.cube
|
||||
end
|
||||
if not custom_tiles.micropanel then
|
||||
custom_tiles.micropanel = custom_tiles.micropanel
|
||||
end
|
||||
if not custom_tiles.doublepanel then
|
||||
custom_tiles.doublepanel = custom_tiles.panel
|
||||
end
|
||||
end
|
||||
|
||||
if not minetest.registered_nodes["stairs:slab_" .. item_name] then
|
||||
if custom_tiles and (custom_tiles.slab or custom_tiles.stair) then
|
||||
if custom_tiles.stair then
|
||||
stairs.register_stair(item_name, node,
|
||||
groups, custom_tiles.stair, S("@1 Stair", def.description),
|
||||
def.sounds)
|
||||
stairs.register_stair_inner(item_name, node,
|
||||
groups, custom_tiles.stair_inner, "", def.sounds, nil, S("Inner @1 Stair", def.description))
|
||||
stairs.register_stair_outer(item_name, node,
|
||||
groups, custom_tiles.stair_outer, "", def.sounds, nil, S("Outer @1 Stair", def.description))
|
||||
end
|
||||
if custom_tiles.slab then
|
||||
stairs.register_slab(item_name, node,
|
||||
groups, custom_tiles.slab, S("@1 Slab", def.description),
|
||||
def.sounds)
|
||||
end
|
||||
else
|
||||
stairs.register_stair_and_slab(item_name, node,
|
||||
groups, tiles,
|
||||
S("@1 Stair", def.description),
|
||||
S("@1 Slab", def.description),
|
||||
def.sounds, nil,
|
||||
S("Inner @1 Stair", def.description),
|
||||
S("Outer @1 Stair", def.description))
|
||||
end
|
||||
end
|
||||
|
||||
local cutname = workbench_def[1]
|
||||
local tiles_special_cut
|
||||
if custom_tiles and custom_tiles[cutname] then
|
||||
tiles_special_cut = custom_tiles[cutname]
|
||||
else
|
||||
tiles_special_cut = tiles
|
||||
end
|
||||
|
||||
local cutnodename = node .. "_" .. cutname
|
||||
if minetest.registered_nodes[cutnodename] then
|
||||
minetest.log("error", "[xdecor] register_cut_raw: Refusing to register node "..cutnodename.." becaut it was already registered!")
|
||||
return false
|
||||
end
|
||||
minetest.register_node(":" .. cutnodename, {
|
||||
--~ Format of the description of a cut node. @1: Base node description (e.g. "Stone"); @2: modifier (e.g. "Nanoslab")
|
||||
description = S("@1 @2", def.description, workbench_def[4]),
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
drawtype = "nodebox",
|
||||
sounds = def.sounds,
|
||||
tiles = tiles_special_cut,
|
||||
use_texture_alpha = def.use_texture_alpha,
|
||||
groups = groups,
|
||||
is_ground_content = def.is_ground_content,
|
||||
node_box = xdecor.pixelbox(16, workbench_def[3]),
|
||||
sunlight_propagates = true,
|
||||
on_place = minetest.rotate_node
|
||||
})
|
||||
|
||||
elseif item_name and mod_name then
|
||||
minetest.register_alias_force(
|
||||
("%s:%s_innerstair"):format(mod_name, item_name),
|
||||
("stairs:stair_inner_%s"):format(item_name)
|
||||
)
|
||||
minetest.register_alias_force(
|
||||
("%s:%s_outerstair"):format(mod_name, item_name),
|
||||
("stairs:stair_outer_%s"):format(item_name)
|
||||
)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function workbench:register_cut(nodename, cutlist)
|
||||
if registered_cuttable_nodes[nodename] then
|
||||
minetest.log("error", "[xdecor] Workbench: Tried to register cut for node "..nodename..", but it was already registered!")
|
||||
return false
|
||||
end
|
||||
local ok = true
|
||||
for _, d in ipairs(workbench.defs) do
|
||||
local ok = register_cut_raw(nodename, d)
|
||||
if not ok then
|
||||
ok = false
|
||||
end
|
||||
end
|
||||
registered_cuttable_nodes[nodename] = true
|
||||
return ok
|
||||
end
|
||||
|
||||
function workbench:register_special_cut(nodename, cutlist)
|
||||
if registered_cuttable_nodes[nodename] or special_cuts[nodename] then
|
||||
minetest.log("error", "[xdecor] Workbench: Tried to register special cut for node "..nodename..", but it was already registered!")
|
||||
return false
|
||||
end
|
||||
registered_cuttable_nodes[nodename] = true
|
||||
special_cuts[nodename] = cutlist
|
||||
end
|
||||
|
||||
-- Workbench craft
|
||||
minetest.register_craft({
|
||||
output = "xdecor:workbench",
|
||||
recipe = {
|
||||
{"group:wood", "group:wood"},
|
||||
{"group:wood", "group:wood"}
|
||||
}
|
||||
})
|
||||
|
||||
-- Register default cuttable blocks
|
||||
do
|
||||
local cuttable_nodes = {}
|
||||
|
||||
-- Nodes allowed to be cut:
|
||||
-- Only the regular, solid blocks without metas or explosivity
|
||||
-- from the xdecor or default mods.
|
||||
for nodename, def in pairs(minetest.registered_nodes) do
|
||||
local nodenamesplit = string.split(nodename, ":")
|
||||
local modname = nodenamesplit[1]
|
||||
if (modname == "xdecor" or modname == "default") and xdecor.stairs_valid_def(def) then
|
||||
cuttable_nodes[#cuttable_nodes + 1] = nodename
|
||||
end
|
||||
end
|
||||
|
||||
for i = 1, #cuttable_nodes do
|
||||
local node = cuttable_nodes[i]
|
||||
workbench:register_cut(node)
|
||||
end
|
||||
end
|
||||
|
||||
-- Special cuts for cushion block and cabinet
|
||||
workbench:register_special_cut("xdecor:cushion_block", { slab = "xdecor:cushion" })
|
||||
workbench:register_special_cut("xdecor:cabinet", { slab = "xdecor:cabinet_half" })
|
||||
|
||||
--[[ API FUNCTIONS ]]
|
||||
|
||||
--[[ Register a custom hammer (for repairing).
|
||||
A hammer repair items at the work bench. The workbench repeatedly
|
||||
checks if a hammer and a repairable tool are in the slots. The hammer
|
||||
will repair the tool in regular intervals. This is called a "step".
|
||||
In each step, the hammer reduces the wear of the repairable
|
||||
tool but increases its own wear, each by a fixed amount.
|
||||
|
||||
This function allows you to register a custom hammer with custom
|
||||
name, item image and wear stats.
|
||||
|
||||
Arguments:
|
||||
* name: Internal itemname
|
||||
* def: Definition table:
|
||||
* description: Item `description`
|
||||
* image: Inventory image and wield image
|
||||
* groups: Item groups (MUST contain at least `repair_hammer = 1`)
|
||||
* repair: How much item wear the hammer repairs per step
|
||||
* repair_cost: How much item wear the hammer takes itself per step
|
||||
|
||||
Note: Mind the implication of repair_cost! If repair_cost is lower than
|
||||
repair, this means practically infinite durability if you have two
|
||||
hammers that repair each other. If repair_cost is higher than repair,
|
||||
then hammers will break eventually.
|
||||
]]
|
||||
function xdecor.register_hammer(name, def)
|
||||
minetest.register_tool(name, {
|
||||
description = def.description,
|
||||
_tt_help = S("Repairs tools at the work bench"),
|
||||
inventory_image = def.image,
|
||||
wield_image = def.image,
|
||||
on_use = function() do
|
||||
return end
|
||||
end,
|
||||
groups = def.groups,
|
||||
_xdecor_hammer_repair = def.repair or DEFAULT_HAMMER_REPAIR,
|
||||
_xdecor_hammer_repair_cost = def.repair_cost or DEFAULT_HAMMER_REPAIR_COST,
|
||||
})
|
||||
end
|
||||
|
||||
--[[ EXPERIMENTAL FUNCTION:
|
||||
Registers various 'cut' node variants for the node with the given nodename,
|
||||
which will be available in the workbench.
|
||||
This must only be called once per node. Calling it again is an error.
|
||||
|
||||
The following nodes will be registered:
|
||||
|
||||
* <nodename>_nanoslab
|
||||
* <nodename>_micropanel
|
||||
* <nodename>_microslab
|
||||
* <nodename>_thinstair
|
||||
* <nodename>_cube
|
||||
* <nodename>_panel
|
||||
* <nodename>_doublepanel
|
||||
* <nodename>_halfstair
|
||||
|
||||
You MUST make sure these names are not already taken before
|
||||
calling this function. Failing to do so is an error.
|
||||
|
||||
Additionally, a slab, stair, inner stair and outer stair
|
||||
will be registered by using the `stairs` mod if the slab
|
||||
node does not exist yet. Refer to the `stairs` mod documentation
|
||||
for details.
|
||||
|
||||
Returns true if all nodes were registered successfully,
|
||||
returns false (and writes to error log) if any error occurred.
|
||||
]]
|
||||
xdecor.register_cut = function(nodename)
|
||||
return workbench:register_cut(nodename)
|
||||
end
|
||||
|
||||
|
||||
--[[ END OF API FUNCTIONS ]]
|
||||
|
||||
|
||||
-- Register xdecor's built-in hammer
|
||||
xdecor.register_hammer("xdecor:hammer", {
|
||||
description = S("Hammer"),
|
||||
image = "xdecor_hammer.png",
|
||||
groups = { repair_hammer = 1 },
|
||||
repair = DEFAULT_HAMMER_REPAIR,
|
||||
repair_cost = DEFAULT_HAMMER_REPAIR_COST,
|
||||
})
|
||||
|
||||
-- Hammer recipes
|
||||
minetest.register_craft({
|
||||
output = "xdecor:hammer",
|
||||
recipe = {
|
||||
{"default:steel_ingot", "group:stick", "default:steel_ingot"},
|
||||
{"", "group:stick", ""}
|
||||
}
|
||||
})
|
BIN
mods/xdecor/textures/bg_btn.png
Normal file
After Width: | Height: | Size: 82 B |
BIN
mods/xdecor/textures/bishop_black.png
Normal file
After Width: | Height: | Size: 171 B |
BIN
mods/xdecor/textures/bishop_white.png
Normal file
After Width: | Height: | Size: 176 B |
BIN
mods/xdecor/textures/chess_bg.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
mods/xdecor/textures/chess_draw_50move.png
Normal file
After Width: | Height: | Size: 472 B |
BIN
mods/xdecor/textures/chess_draw_50move_next.png
Normal file
After Width: | Height: | Size: 466 B |
BIN
mods/xdecor/textures/chess_draw_repeat3.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
mods/xdecor/textures/chess_draw_repeat3_next.png
Normal file
After Width: | Height: | Size: 441 B |
BIN
mods/xdecor/textures/chess_figurine_bishop_black.png
Normal file
After Width: | Height: | Size: 200 B |
BIN
mods/xdecor/textures/chess_figurine_bishop_white.png
Normal file
After Width: | Height: | Size: 180 B |
BIN
mods/xdecor/textures/chess_figurine_king_black.png
Normal file
After Width: | Height: | Size: 210 B |
BIN
mods/xdecor/textures/chess_figurine_king_white.png
Normal file
After Width: | Height: | Size: 192 B |
BIN
mods/xdecor/textures/chess_figurine_knight_black.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
mods/xdecor/textures/chess_figurine_knight_white.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
mods/xdecor/textures/chess_figurine_pawn_black.png
Normal file
After Width: | Height: | Size: 161 B |
BIN
mods/xdecor/textures/chess_figurine_pawn_white.png
Normal file
After Width: | Height: | Size: 162 B |
BIN
mods/xdecor/textures/chess_figurine_queen_black.png
Normal file
After Width: | Height: | Size: 213 B |
BIN
mods/xdecor/textures/chess_figurine_queen_white.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
mods/xdecor/textures/chess_figurine_rook_black.png
Normal file
After Width: | Height: | Size: 167 B |
BIN
mods/xdecor/textures/chess_figurine_rook_white.png
Normal file
After Width: | Height: | Size: 164 B |
BIN
mods/xdecor/textures/chess_resign.png
Normal file
After Width: | Height: | Size: 380 B |
BIN
mods/xdecor/textures/chess_turn_black.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
mods/xdecor/textures/chess_turn_white.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
mods/xdecor/textures/chessboard_sides.png
Normal file
After Width: | Height: | Size: 115 B |
BIN
mods/xdecor/textures/chessboard_top.png
Normal file
After Width: | Height: | Size: 208 B |
BIN
mods/xdecor/textures/ench_ui.png
Normal file
After Width: | Height: | Size: 2 KiB |
BIN
mods/xdecor/textures/gui_arrow.png
Normal file
After Width: | Height: | Size: 469 B |
BIN
mods/xdecor/textures/hammer_layout.png
Normal file
After Width: | Height: | Size: 116 B |
BIN
mods/xdecor/textures/hive_bee.png
Normal file
After Width: | Height: | Size: 625 B |
BIN
mods/xdecor/textures/hive_layout.png
Normal file
After Width: | Height: | Size: 237 B |
BIN
mods/xdecor/textures/king_black.png
Normal file
After Width: | Height: | Size: 190 B |
BIN
mods/xdecor/textures/king_white.png
Normal file
After Width: | Height: | Size: 196 B |
BIN
mods/xdecor/textures/knight_black.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
mods/xdecor/textures/knight_white.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
mods/xdecor/textures/mailbox_blank16.png
Normal file
After Width: | Height: | Size: 82 B |
BIN
mods/xdecor/textures/mese_layout.png
Normal file
After Width: | Height: | Size: 139 B |
BIN
mods/xdecor/textures/pawn_black.png
Normal file
After Width: | Height: | Size: 167 B |
BIN
mods/xdecor/textures/pawn_black_promo_anim.png
Normal file
After Width: | Height: | Size: 889 B |
BIN
mods/xdecor/textures/pawn_white.png
Normal file
After Width: | Height: | Size: 167 B |
BIN
mods/xdecor/textures/pawn_white_promo_anim.png
Normal file
After Width: | Height: | Size: 947 B |
BIN
mods/xdecor/textures/queen_black.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
mods/xdecor/textures/queen_white.png
Normal file
After Width: | Height: | Size: 189 B |
BIN
mods/xdecor/textures/rook_black.png
Normal file
After Width: | Height: | Size: 173 B |
BIN
mods/xdecor/textures/rook_white.png
Normal file
After Width: | Height: | Size: 179 B |
BIN
mods/xdecor/textures/stairs_glass_cube.png
Normal file
After Width: | Height: | Size: 268 B |
BIN
mods/xdecor/textures/stairs_obsidian_glass_cube.png
Normal file
After Width: | Height: | Size: 148 B |
BIN
mods/xdecor/textures/worktable_anvil.png
Normal file
After Width: | Height: | Size: 158 B |
BIN
mods/xdecor/textures/worktable_saw.png
Normal file
After Width: | Height: | Size: 194 B |
BIN
mods/xdecor/textures/xdecor_bamboo_frame.png
Normal file
After Width: | Height: | Size: 283 B |
BIN
mods/xdecor/textures/xdecor_baricade.png
Normal file
After Width: | Height: | Size: 258 B |
BIN
mods/xdecor/textures/xdecor_barrel_sides.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
mods/xdecor/textures/xdecor_barrel_top.png
Normal file
After Width: | Height: | Size: 296 B |
BIN
mods/xdecor/textures/xdecor_book_open.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
mods/xdecor/textures/xdecor_bowl.png
Normal file
After Width: | Height: | Size: 193 B |
BIN
mods/xdecor/textures/xdecor_bowl_soup.png
Normal file
After Width: | Height: | Size: 215 B |
BIN
mods/xdecor/textures/xdecor_cabinet_front.png
Normal file
After Width: | Height: | Size: 247 B |
BIN
mods/xdecor/textures/xdecor_cabinet_sides.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
mods/xdecor/textures/xdecor_cactusbrick.png
Normal file
After Width: | Height: | Size: 465 B |
BIN
mods/xdecor/textures/xdecor_candle_floor.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
mods/xdecor/textures/xdecor_candle_hanging.png
Normal file
After Width: | Height: | Size: 219 B |
BIN
mods/xdecor/textures/xdecor_candle_inv.png
Normal file
After Width: | Height: | Size: 177 B |
BIN
mods/xdecor/textures/xdecor_candle_wall.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
mods/xdecor/textures/xdecor_candle_wield.png
Normal file
After Width: | Height: | Size: 174 B |
BIN
mods/xdecor/textures/xdecor_cauldron_bottom.png
Normal file
After Width: | Height: | Size: 153 B |