mirror of
https://github.com/minetest-mods/global_exchange.git
synced 2025-06-29 14:21:59 +02:00
Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
868213081f | |||
969571f559 | |||
15bba05412 | |||
10b438c2b7 | |||
3517409a1a | |||
8430e9fab5 | |||
6989f6a00e | |||
9c8f62320e | |||
b22b72f5c2 | |||
ce33c159fd | |||
c1a527eeea | |||
57deb8582e | |||
81517a5b3d | |||
0de7a34fcf | |||
d49a7fdc12 | |||
73407cd6fa | |||
b52e813d45 | |||
5cfb580545 | |||
141de27c97 | |||
808b3cbf04 | |||
2a5a726cc0 |
127
README.md
127
README.md
@ -15,87 +15,86 @@ Nodes
|
||||
|
||||
Using the Exchange
|
||||
==================
|
||||
Main Screen
|
||||
Overview
|
||||
-----------
|
||||
The first screen you see is where you can search and post new buy/sell orders.
|
||||
Here is an overview of each element:
|
||||
- Market Summary - Pressing this will take you to the market summary screen.
|
||||
- Your Orders - This will take you to a screen where you can view and cancel
|
||||
your existing orders.
|
||||
- Item - This field is for entering the item name (e.g. default:cobble) of the
|
||||
item you want to search or post an order for.
|
||||
- Amount - This field is for entering how many of the item you want to buy/sell
|
||||
when posting an order. It has no purpose in searches.
|
||||
- Select Item - This button takes you to a screen for choosing your item
|
||||
graphically, instead of manually typing an item name.
|
||||
- Rate - This field is for entering the desired price per item when posting an
|
||||
order. For buy orders, this is the maximum price - your order will also accept
|
||||
items that are cheaper. For sell orders, this is the minimum price - your
|
||||
order will also accept buyers that are willing to pay more. The Rate field has
|
||||
no effect on searches
|
||||
- Search - This button searches existing orders for the selected item. If you
|
||||
have the "Sell" box checked, it will only display buy orders, and will display
|
||||
them in descending rate. If you have the box unchecked, it will show sell
|
||||
orders in order of ascending rate.
|
||||
- Post Order - This posts a new order for the item with the given amount and
|
||||
rate. If the "Sell" box is checked, this is a sell order, so the exchange will
|
||||
remove the items from your inventory. If it's unchecked, you are making a buy
|
||||
order, so it will deduct credits from your account. If there are already
|
||||
matching orders, it will immediately fill your order up to the amount possible,
|
||||
and the remainder will stay as a new order.
|
||||
- Sell - This checkbox determines what kind of orders to search for, and also
|
||||
what kind of order you are posting.
|
||||
- Search Results - This will display the results of your search. Clicking on an
|
||||
element here will automatically fill the "Amount" and "Rate" fields, so that if
|
||||
you click "Post Order", it will match the order you clicked.
|
||||
At the top of the exchange form there are four tabs: Market Summary, Buy, Sell,
|
||||
and Your Orders. Pressing each tab will take you to the indicated screen as
|
||||
described below.
|
||||
|
||||
Market Summary
|
||||
--------------
|
||||
This summarizes the various items available on the exchange. From left to right,
|
||||
the columns display the item name, the description (what is shown in inventory),
|
||||
the amount requested by buyers, the maximum rate offered by buyers, the amount
|
||||
offered by sellers, and the minimum rate offered by sellers. It is updated
|
||||
periodically.
|
||||
the tool wear if applicable, the amount requested by buyers, the maximum rate
|
||||
offered by buyers, the amount offered by sellers, and the minimum rate offered
|
||||
by sellers. It is updated periodically.
|
||||
|
||||
Buy
|
||||
-----------
|
||||
The upper-left corner shows the open order book for the selected item,
|
||||
consisting of the three best sell offers (lowest asking price and least tool
|
||||
wear) followed by the three best buy offers (highest offer price and highest
|
||||
acceptable tool wear). To the right is an image of the selected item, entry
|
||||
fields for the quantity and offer price, and a drop-down field for the desired
|
||||
tool wear: "New" (no wear), "Good" (up to 10% wear), "Worn" (up to 50% wear),
|
||||
and "Junk" (any amount of wear). To qualify, a seller must offer an item with
|
||||
wear equal to or less than the indicated amount (e.g. if you select "Good" you
|
||||
may receive an item with only 5% wear, but not one 15% worn). Similarly, the
|
||||
offer price is the highest price you are willing to pay; in practice you may
|
||||
pay less depending on the open sell orders. Orders are always fulfilled at the
|
||||
price listed in the open order book.
|
||||
|
||||
At the bottom of the form is a grid similar to the creative inventory. You can
|
||||
page through the available items using the "<<" and ">>" buttons and select the
|
||||
item you wish to buy simply by clicking on it.
|
||||
|
||||
To finalize the order, press the "Place Bid" button. Note that it is permitted
|
||||
to enter an order which exceeds your available funds at the time the order is
|
||||
placed. As matching sell orders are located, the order will be fulfulled until
|
||||
there are insufficient funds to cover the next item, at which point the
|
||||
remainder of the order will be cancelled.
|
||||
|
||||
Sell
|
||||
-----------
|
||||
As with the Buy screen, the upper-left corner shows the open order book for
|
||||
the selected item. Instead of a static image, the selected item appears as a
|
||||
1x1 inventory. At the bottom of the screen is the standard 8x4 player
|
||||
inventory. To choose the type and quantity of items to sell, move the items
|
||||
from your player inventory to the exchange inventory. Below the exchange
|
||||
inventory is an entry field for the desired asking price. To finalize the
|
||||
order, press the "Sell" button. As with buy orders, the asking price is the
|
||||
lowest price you are willing to accept, and you may receive a higher price
|
||||
depending on the open buy orders.
|
||||
|
||||
Unsold items in the exchange inventory are returned to the player inventory
|
||||
when the form is closed, or to the player's Inbox if the inventory is full.
|
||||
(However, items in the exchange inventory at the time of a server crash, or
|
||||
other abnormal condition, may be lost.)
|
||||
|
||||
Your Orders
|
||||
-----------
|
||||
This screen lets you see and cancel your orders. To cancel an order, click the
|
||||
order and press the "Cancel" button.
|
||||
|
||||
Select Item
|
||||
-----------
|
||||
This displays a creative-style inventory menu for selecting an item for searches
|
||||
or posting orders. To select an item, drag it from the inventory to the box near
|
||||
the bottom of the form
|
||||
order and press the "Cancel" button. If the order was sell order, the items
|
||||
held in "escrow" are returned to your player inventory. If any of the items do
|
||||
not fit in the inventory they are placed in your Inbox instead to be claimed
|
||||
later.
|
||||
|
||||
Buying/Selling
|
||||
==============
|
||||
Once you have opened the exchange, you have a few options. If you don't already
|
||||
know what you want to buy or sell, you can look at the Market Summary to get a
|
||||
glance at what people are offering. After you have decided on what you are
|
||||
going to do, return to the exchange page.
|
||||
going to do, return to the Buy or Sell page.
|
||||
|
||||
If you are selling an item, you should check the "Sell" checkbox. Otherwise,
|
||||
leave it unchecked. Next, you need to select the item you want to deal in. There
|
||||
are two ways: typing the item name (e.g. default:cobble) in manually to the item
|
||||
field, or using the "Select Item" menu. If you haven't already decided on a price,
|
||||
or you want to make sure your order is filled quickly, you can conduct a search.
|
||||
To do this, click the "Search" button. This will give you a list of results. If
|
||||
you checked the "Sell" box, then these will be buy orders, and will show the
|
||||
maximum price per item each buyer is willing to accept. Otherwise, these will be
|
||||
sell orders, displaying the minimum price each seller will accept. If you click
|
||||
on a search result, it will automatically fill your Amount and Rate fields to
|
||||
match.
|
||||
|
||||
The Amount and Rate fields are used to decide how much and how expensively you
|
||||
want to make your order. When selling, the Rate field is the minimum price you
|
||||
will accept. When buying, it is the maximum. Once everything is filled out how
|
||||
you want it, press the "Post Order" button. If there are matching offers (when
|
||||
you post a buy/sell offer, there are one or more sell/buy offers with a price
|
||||
at least as good), then that part of your offer will immediately be filled. For
|
||||
example, if you post a buy order for 10 cobblestone at 5 credits each, and there
|
||||
is a sell offer for 5 cobblestone 3 credits each, it will give you 5 cobble
|
||||
immediately, and leave an order on the exchange for 5 more cobblestone.
|
||||
When selling, the Ask field is the minimum price you will accept for each
|
||||
item. When buying, the Bid field determines the maximum amount you are willing
|
||||
to pay. If there are matching offers (i.e. there are one or more offers with a
|
||||
price at least as good and a compatible tool wear level), then that part of
|
||||
your offer will immediately be filled. For example, if you post a buy order
|
||||
for 10 cobblestone at 5 credits each, and there is a sell offer for 5
|
||||
cobblestone at 3 credits each, it will give you 5 cobble immediately at a
|
||||
total cost of 15 credits (the order-book price), and leave an order on the
|
||||
exchange for 5 more cobblestone at 5 credits each.
|
||||
|
||||
Once your offer is on the exchange, you can view or cancel it from the "Your
|
||||
Orders" menu.
|
||||
|
325
atm.lua
325
atm.lua
@ -1,152 +1,197 @@
|
||||
-- A telling machine. Call this file with the exchange argument.
|
||||
local exchange = ...
|
||||
local exchange, formlib = ...
|
||||
local S = minetest.get_translator("global_exchange")
|
||||
|
||||
local atm_form = "global_exchange:atm_form"
|
||||
local atm_pos = {}
|
||||
|
||||
local main_menu =[[
|
||||
size[6,2]
|
||||
button[2,0;2,1;info;Account Info]
|
||||
button[4,0;2,1;wire;Wire Monies]
|
||||
button[1,1;4,1;transaction_log;Transaction Log]
|
||||
]]
|
||||
|
||||
|
||||
local function logout(x,y)
|
||||
return "button[" .. x .. "," .. y .. ";2,1;logout;Log Out]"
|
||||
end
|
||||
|
||||
|
||||
local function label(x,y,text)
|
||||
return "label[" .. x .. "," .. y .. ";"
|
||||
.. minetest.formspec_escape(text) .. "]"
|
||||
end
|
||||
|
||||
local function field(x,y, w,h, name, label, default)
|
||||
return "field[" .. x .. "," .. y .. ";" .. w .. "," .. h .. ";"
|
||||
.. name .. ";" .. minetest.formspec_escape(label) .. ";"
|
||||
.. minetest.formspec_escape(default) .. "]"
|
||||
end
|
||||
|
||||
local unique_num = 1
|
||||
|
||||
local function unique()
|
||||
local ret = unique_num
|
||||
local unique = (function(unique_num)
|
||||
return function()
|
||||
unique_num = unique_num + 1
|
||||
return unique_num
|
||||
end
|
||||
end)(0)
|
||||
|
||||
return ret
|
||||
end
|
||||
local coins = {
|
||||
[1] = "bitchange:minecoinblock", [2] = "bitchange:minecoin", [3] = "bitchange:mineninth",
|
||||
[4] = "maptools:gold_coin", [5] = "maptools:silver_coin", [6] = "maptools:copper_coin"
|
||||
}
|
||||
|
||||
local coins_convert = {
|
||||
[coins[6]]=1, [coins[5]]=9, [coins[4]]=81, [coins[3]]=729, [coins[2]]=6561, [coins[1]]=59049,
|
||||
["minercantile:copper_coin"]=1, ["minercantile:silver_coin"]=9, ["minercantile:gold_coin"]=81
|
||||
}
|
||||
|
||||
local function info_fs(p_name)
|
||||
local balance = exchange:get_balance(p_name)
|
||||
local function withdraw_fs(fs, p_name, amount)
|
||||
local spos = atm_pos[p_name].x..","..atm_pos[p_name].y..","..atm_pos[p_name].z
|
||||
local inv = minetest.get_inventory({ type = "node", pos={x=atm_pos[p_name].x, y=atm_pos[p_name].y, z=atm_pos[p_name].z} })
|
||||
|
||||
local fs
|
||||
if not balance then
|
||||
fs = label(0.5,0.5, "You don't have an account.")
|
||||
local msg = ""
|
||||
local w_amount = tonumber(amount)
|
||||
if w_amount and math.floor(w_amount) == w_amount and w_amount > 0 then
|
||||
local succ, err = exchange:give_credits(p_name, 0 - w_amount, S("Cash withdrawal: (-@1)", w_amount))
|
||||
if succ then
|
||||
local index = 1
|
||||
repeat
|
||||
local m = math.floor(w_amount / coins_convert[coins[index]])
|
||||
if m > 0 then
|
||||
inv:add_item( "main", ItemStack({ name = coins[index], count = m }) )
|
||||
end
|
||||
w_amount = w_amount - (coins_convert[coins[index]] * m)
|
||||
index = index + 1
|
||||
until ( w_amount == 0)
|
||||
else
|
||||
fs = label(0.5,0.5, "Balance: " .. balance)
|
||||
msg = err
|
||||
end
|
||||
elseif w_amount then
|
||||
msg = S("Invalid number ! Must be an Integer > 0")
|
||||
end
|
||||
|
||||
return "size[4,3]" .. fs .. logout(0.5,2)
|
||||
end
|
||||
|
||||
|
||||
local function wire_fs(p_name)
|
||||
local balance = exchange:get_balance(p_name)
|
||||
|
||||
local fs = "size[4,5]" .. logout(0,4)
|
||||
fs:size(8,10)
|
||||
|
||||
if not balance then
|
||||
return fs .. label(0.5,0.5, "You don't have an account.")
|
||||
fs:label(0.5, 0.5, S("You don't have an account."))
|
||||
else
|
||||
fs:label(3,8.9, S("Balance: @1", balance))
|
||||
fs:field(0.75, 1.25, 3.25, 1, "w_amount", S("Desired amount:"))
|
||||
fs:button(4, 1, 3.25, 1, "withdraw", S("Get !"))
|
||||
fs:label(1, 2.25, S("Or deposit your coins to credit your account:"))
|
||||
fs:list(1,3,6,1, "nodemeta:"..spos, "main")
|
||||
fs:list(0,4.25, 8,4, "current_player", "main")
|
||||
fs("listring[current_player;main]"..
|
||||
"listring[nodemeta:"..spos..";main]"
|
||||
)
|
||||
fs:label(0,9.75, msg)
|
||||
end
|
||||
fs:button(0,8.75, 2,1, "logout", S("Log Out"))
|
||||
end
|
||||
|
||||
local function info_fs(fs, p_name)
|
||||
local balance = exchange:get_balance(p_name)
|
||||
|
||||
fs:size(4,3)
|
||||
|
||||
if balance then
|
||||
fs:label(0.5,0.5, S("Balance: @1", balance))
|
||||
else
|
||||
fs:label(0.5,0.5, S("You don't have an account."))
|
||||
end
|
||||
|
||||
-- To prevent duplicates
|
||||
return fs .. field(-100, -100, 0,0, "trans_id", "", unique()) ..
|
||||
label(0.5,0.5, "Balance: " .. balance) ..
|
||||
field(0.5,1.5, 2,1, "recipient", "Send to:", "") ..
|
||||
field(0.5,2.5, 2,1, "amount", "Amount", "") ..
|
||||
"button[2,4;2,1;send;Send]"
|
||||
fs:button(1,2, 2,1, "logout", S("Log Out"))
|
||||
end
|
||||
|
||||
|
||||
local function send_fs(p_name, receiver, amt_str)
|
||||
local fs = "size[7,3]"
|
||||
local function wire_fs(fs, p_name)
|
||||
local balance = exchange:get_balance(p_name)
|
||||
|
||||
fs:size(4,5)
|
||||
|
||||
if balance then
|
||||
-- To detect duplicate/stale form submission
|
||||
fs:field(-100, -100, 0,0, "trans_id", "", unique())
|
||||
|
||||
fs:label(0.50,0.325, S("Balance: @1", balance))
|
||||
fs:field(0.75,1.750, 3,1, "recipient", S("Send to:"), "")
|
||||
fs:field(0.75,3.000, 3,1, "amount", S("Amount"), "")
|
||||
|
||||
fs:button(0,4.25, 2,1, "logout", S("Log Out"))
|
||||
fs:button(2,4.25, 2,1, "send", S("Send"))
|
||||
else
|
||||
fs:button(0,4, 2,1, "logout", S("Back"))
|
||||
fs:label(0.5,0.5, S("You don't have an account."))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function send_fs(fs, p_name, receiver, amt_str)
|
||||
fs:size(10,3)
|
||||
|
||||
fs:button(4,2, 2,1, "wire", S("Back"))
|
||||
|
||||
local amt = tonumber(amt_str)
|
||||
local msg = nil
|
||||
|
||||
if not amt or amt <= 0 then
|
||||
return fs .. label(0.5,0.5, "Invalid transfer amount.") ..
|
||||
"button[0.5,2;2,1;wire;Back]"
|
||||
end
|
||||
|
||||
msg = S("Invalid transfer amount.")
|
||||
else
|
||||
local succ, err = exchange:transfer_credits(p_name, receiver, amt)
|
||||
|
||||
if not succ then
|
||||
return fs .. label(0.5,0.5, "Error: " .. err) ..
|
||||
"button[0.5,2;2,1;wire;Back]"
|
||||
msg = "Error: " .. err
|
||||
else
|
||||
msg = "Successfully sent " .. amt ..
|
||||
" credits to " .. receiver .. "."
|
||||
end
|
||||
return fs.. label(0.5,0.5, "Successfully sent " ..
|
||||
amt .. " credits to " .. receiver) ..
|
||||
"button[0.5,2;2,1;wire;Back]"
|
||||
end
|
||||
|
||||
fs:label(0.5,0.5, msg)
|
||||
end
|
||||
|
||||
|
||||
local function log_fs(p_name)
|
||||
local res = {
|
||||
"size[8,8]label[0,0;Transaction Log]button[0,7;2,1;logout;Log Out]",
|
||||
"tablecolumns[text;text]",
|
||||
"table[0,1;8,6;log_table;Time,Message",
|
||||
}
|
||||
local function log_fs(fs, p_name)
|
||||
fs:size(14,8)
|
||||
|
||||
for i, entry in ipairs(exchange:player_log(p_name)) do
|
||||
i = i*4
|
||||
res[i] = ","
|
||||
res[i+1] = tostring(entry.Time)
|
||||
res[i+2] = ","
|
||||
res[i+3] = entry.Message
|
||||
fs:label(0,0, S("Transaction Log"))
|
||||
|
||||
fs:element("tablecolumns", "text", "text")
|
||||
|
||||
fs("table[0,0.75;13.75,6.75;log_table;Time,Message")
|
||||
for _, entry in ipairs(exchange:player_log(p_name)) do
|
||||
fs(","):escape_list(entry.Time, entry.Message)
|
||||
end
|
||||
res[#res+1] ="]"
|
||||
fs("]")
|
||||
|
||||
return table.concat(res)
|
||||
fs:button(6,7.5, 2,1, "logout", S("Log Out"))
|
||||
end
|
||||
|
||||
|
||||
local function main_menu_fs(fs, p_name)
|
||||
fs:size(8,2)
|
||||
fs:button(0,0.125, 4,1, "withdraw", S("Cash deposit and withdrawal"))
|
||||
fs:button(4,0.125, 2,1, "info", S("Account Info"))
|
||||
fs:button(6,0.125, 2,1, "wire", S("Wire Monies"))
|
||||
fs:button(0.50, 1.125, 7, 1, "transaction_log", S("Transaction Log"))
|
||||
end
|
||||
|
||||
|
||||
local function show_atm_form(fs_fn, p_name, ...)
|
||||
local fs = formlib.Builder()
|
||||
fs_fn(fs, p_name, ...)
|
||||
minetest.show_formspec(p_name, atm_form, tostring(fs))
|
||||
end
|
||||
|
||||
|
||||
local trans_ids = {}
|
||||
|
||||
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname ~= atm_form then return end
|
||||
if fields.quit then return true end
|
||||
|
||||
local p_name = player:get_player_name()
|
||||
|
||||
local this_id = fields.trans_id
|
||||
local this_id = tonumber(fields.trans_id)
|
||||
|
||||
if this_id and this_id == trans_ids[p_name] then
|
||||
if this_id and trans_ids[p_name] and this_id <= trans_ids[p_name] then
|
||||
-- Ignore duplicate/stale form submittal
|
||||
return true
|
||||
end
|
||||
|
||||
trans_ids[p_name] = this_id
|
||||
|
||||
if fields.logout then
|
||||
minetest.show_formspec(p_name, atm_form, main_menu)
|
||||
end
|
||||
|
||||
if fields.info then
|
||||
minetest.show_formspec(p_name, atm_form, info_fs(p_name))
|
||||
end
|
||||
|
||||
if fields.wire then
|
||||
minetest.show_formspec(p_name, atm_form, wire_fs(p_name))
|
||||
end
|
||||
|
||||
if fields.send then
|
||||
minetest.show_formspec(p_name, atm_form,
|
||||
send_fs(p_name, fields.recipient, fields.amount))
|
||||
end
|
||||
|
||||
if fields.transaction_log then
|
||||
minetest.show_formspec(p_name, atm_form, log_fs(p_name))
|
||||
show_atm_form(main_menu_fs, p_name)
|
||||
elseif fields.info then
|
||||
show_atm_form(info_fs, p_name)
|
||||
elseif fields.wire then
|
||||
show_atm_form(wire_fs, p_name)
|
||||
elseif fields.withdraw then
|
||||
show_atm_form(withdraw_fs, p_name, fields and fields.w_amount)
|
||||
elseif fields.send then
|
||||
show_atm_form(send_fs, p_name, fields.recipient, fields.amount)
|
||||
elseif fields.transaction_log then
|
||||
show_atm_form(log_fs, p_name)
|
||||
end
|
||||
|
||||
return true
|
||||
@ -180,18 +225,19 @@ minetest.register_node("global_exchange:atm_bottom", {
|
||||
selection_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
{-0.5, 0.5, -0.5, -0.375, 1.125, -0.25},
|
||||
{0.375, 0.5, -0.5, 0.5, 1.125, -0.25},
|
||||
{-0.5, 0.5, -0.25, 0.5, 1.5, 0.5},
|
||||
{-0.5, 1.125, -0.4375, -0.375, 1.25, -0.25},
|
||||
{0.375, 1.125, -0.4375, 0.5, 1.25, -0.25},
|
||||
{-0.5, 1.25, -0.375, -0.375, 1.375, -0.25},
|
||||
{0.375, 1.25, -0.375, 0.5, 1.375, -0.25},
|
||||
{-0.5, 1.375, -0.3125, -0.375, 1.5, -0.25},
|
||||
{0.375, 1.375, -0.3125, 0.5, 1.5, -0.25},
|
||||
{-0.500, -0.500, -0.5000, 0.500, 0.500, 0.50},
|
||||
{-0.500, 0.500, -0.5000, -0.375, 1.125, -0.25},
|
||||
{ 0.375, 0.500, -0.5000, 0.500, 1.125, -0.25},
|
||||
{-0.500, 0.500, -0.2500, 0.500, 1.500, 0.50},
|
||||
{-0.500, 1.125, -0.4375, -0.375, 1.250, -0.25},
|
||||
{ 0.375, 1.125, -0.4375, 0.500, 1.250, -0.25},
|
||||
{-0.500, 1.250, -0.3750, -0.375, 1.375, -0.25},
|
||||
{ 0.375, 1.250, -0.3750, 0.500, 1.375, -0.25},
|
||||
{-0.500, 1.375, -0.3125, -0.375, 1.500, -0.25},
|
||||
{ 0.375, 1.375, -0.3125, 0.500, 1.500, -0.25},
|
||||
},
|
||||
},
|
||||
groups = {cracky=2, atm = 1},
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local under = pointed_thing.under
|
||||
local pos
|
||||
@ -223,6 +269,11 @@ minetest.register_node("global_exchange:atm_bottom", {
|
||||
return itemstack
|
||||
end
|
||||
end,
|
||||
can_dig = function(pos,player)
|
||||
local meta = minetest.get_meta(pos);
|
||||
local inv = meta:get_inventory()
|
||||
return inv:is_empty("main")
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
local pos2 = {x = pos.x, y = pos.y + 1, z = pos.z}
|
||||
local n2 = minetest.get_node(pos2)
|
||||
@ -230,10 +281,49 @@ minetest.register_node("global_exchange:atm_bottom", {
|
||||
minetest.remove_node(pos2)
|
||||
end
|
||||
end,
|
||||
groups = {cracky=2, atm = 1},
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
meta:set_string("infotext", "ATM")
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("main", 6)
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local itname = stack:get_name()
|
||||
if coins_convert[itname] ~= nil then
|
||||
return stack:get_count()
|
||||
end
|
||||
return 0
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local itname = stack:get_name()
|
||||
if coins_convert[itname] ~= nil then
|
||||
local p_name = player:get_player_name()
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local nb = stack:get_count()
|
||||
local amount = coins_convert[itname] * nb
|
||||
local succ, msg = exchange:give_credits(p_name, amount, S("Cash deposit (+@1)", amount))
|
||||
if succ then
|
||||
inv:set_stack(listname, index, nil)
|
||||
minetest.log("action", p_name.." put "..nb.." "..stack:get_name() .. " to ATM at " .. minetest.pos_to_string(pos))
|
||||
show_atm_form(withdraw_fs, p_name)
|
||||
--minetest.show_formspec(p_name, atm_form, deposit_fs(p_name))
|
||||
else
|
||||
minetest.log("error", p_name.." want to put "..nb.." "..stack:get_name().." to ATM at ".. minetest.pos_to_string(pos).." but: "..msg)
|
||||
end
|
||||
end
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
minetest.log("action", player:get_player_name().." take "..stack:get_count().." "..stack:get_name().." from ATM at "..minetest.pos_to_string(pos))
|
||||
end,
|
||||
on_rightclick = function(pos, _, clicker)
|
||||
local p_name = clicker:get_player_name()
|
||||
atm_pos[p_name] = pos
|
||||
minetest.sound_play("atm_beep", {pos = pos, gain = 0.3, max_hear_distance = 5})
|
||||
minetest.show_formspec(clicker:get_player_name(), atm_form, main_menu)
|
||||
show_atm_form(main_menu_fs, clicker:get_player_name())
|
||||
end,
|
||||
})
|
||||
|
||||
@ -254,15 +344,15 @@ minetest.register_node("global_exchange:atm_top", {
|
||||
node_box = {
|
||||
type = "fixed",
|
||||
fixed = {
|
||||
{-0.5, -0.5, -0.5, -0.375, 0.125, -0.25},
|
||||
{0.375, -0.5, -0.5, 0.5, 0.125, -0.25},
|
||||
{-0.5, -0.5, -0.25, 0.5, 0.5, 0.5},
|
||||
{-0.5, 0.125, -0.4375, -0.375, 0.25, -0.25},
|
||||
{0.375, 0.125, -0.4375, 0.5, 0.25, -0.25},
|
||||
{-0.5, 0.25, -0.375, -0.375, 0.375, -0.25},
|
||||
{0.375, 0.25, -0.375, 0.5, 0.375, -0.25},
|
||||
{-0.5, 0.375, -0.3125, -0.375, 0.5, -0.25},
|
||||
{0.375, 0.375, -0.3125, 0.5, 0.5, -0.25},
|
||||
{-0.500, -0.500, -0.5000, -0.375, 0.125, -0.25},
|
||||
{ 0.375, -0.500, -0.5000, 0.500, 0.125, -0.25},
|
||||
{-0.500, -0.500, -0.2500, 0.500, 0.500, 0.50},
|
||||
{-0.500, 0.125, -0.4375, -0.375, 0.250, -0.25},
|
||||
{ 0.375, 0.125, -0.4375, 0.500, 0.250, -0.25},
|
||||
{-0.500, 0.250, -0.3750, -0.375, 0.375, -0.25},
|
||||
{ 0.375, 0.250, -0.3750, 0.500, 0.375, -0.25},
|
||||
{-0.500, 0.375, -0.3125, -0.375, 0.500, -0.25},
|
||||
{ 0.375, 0.375, -0.3125, 0.500, 0.500, -0.25},
|
||||
}
|
||||
},
|
||||
selection_box = {
|
||||
@ -285,3 +375,4 @@ minetest.register_craft( {
|
||||
})
|
||||
|
||||
minetest.register_alias("global_exchange:atm", "global_exchange:atm_bottom")
|
||||
-- vim:set ts=4 sw=4 noet:
|
||||
|
@ -1 +0,0 @@
|
||||
default?
|
@ -1 +0,0 @@
|
||||
Adds a server-wide commodities (item) exchange.
|
@ -1,60 +1,61 @@
|
||||
|
||||
local exchange = ...
|
||||
local exchange, formlib = ...
|
||||
|
||||
local mailbox_form = "global_exchange:digital_mailbox"
|
||||
|
||||
local mailbox_contents = {}
|
||||
local selected_index = {}
|
||||
-- Map from player names to their most recent search result
|
||||
|
||||
-- Map from player names to their most recent search result
|
||||
local function get_mail(p_name)
|
||||
local mail_maybe = mailbox_contents[p_name]
|
||||
if mail_maybe then
|
||||
|
||||
if not mail_maybe then
|
||||
local _,res = exchange:view_inbox(p_name)
|
||||
mail_maybe = res or {}
|
||||
mailbox_contents[p_name] = mail_maybe
|
||||
selected_index[p_name] = math.min(selected_index[p_name] or 0, #mail_maybe)
|
||||
end
|
||||
|
||||
return mail_maybe
|
||||
else
|
||||
mailbox_contents[p_name] = {}
|
||||
return mailbox_contents[p_name]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function mk_inbox_list(results, x, y, w, h)
|
||||
local res = {
|
||||
"textlist[",
|
||||
tostring(x),
|
||||
",",
|
||||
tostring(y),
|
||||
";",
|
||||
tostring(w),
|
||||
",",
|
||||
tostring(h),
|
||||
";result_list;"
|
||||
}
|
||||
local function wear_string(wear)
|
||||
return "-" .. math.ceil(100 * wear / 65535) .. "%"
|
||||
end
|
||||
|
||||
|
||||
local function mk_inbox_list(fs, results, x, y, w, h)
|
||||
fs:textlist(x,y, w,h, "result_list", function(add_row)
|
||||
for i, row in ipairs(results) do
|
||||
res[i*2+8] = row.Amount .. " " .. row.Item
|
||||
res[i*2+9] = ","
|
||||
local wear_suffix = nil
|
||||
if row.Wear > 0 then
|
||||
wear_suffix = " (" .. wear_string(row.Wear) .. ")"
|
||||
end
|
||||
res[#res+1] = "]"
|
||||
|
||||
return table.concat(res)
|
||||
add_row(row.Amount, " ", row.Item, wear_suffix)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
local function mk_mail_fs(p_name, results, err_str)
|
||||
fs = "size[6,8]" ..
|
||||
"label[0,0;Inbox]"
|
||||
local function mk_mail_fs(fs, p_name, results, err_str)
|
||||
fs:size(8,8)
|
||||
fs:label(0,0, "Inbox")
|
||||
|
||||
if err_str then
|
||||
fs = fs .. "label[3,0;Error: " .. err_str .. "]"
|
||||
fs:label(3,0, "Error: " .. err_str)
|
||||
end
|
||||
|
||||
return fs .. mk_inbox_list(results, 0, 1, 6, 6) ..
|
||||
"button[0,7;2,1;claim;Claim]"
|
||||
mk_inbox_list(fs, results, 0, 1, 7.75, 6.25)
|
||||
|
||||
fs:button(3,7.35, 2,1, "claim", "Claim")
|
||||
end
|
||||
|
||||
|
||||
local function show_mail(p_name, results, err_str)
|
||||
minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, results, err_str))
|
||||
local function show_mail(p_name, err_str)
|
||||
local fs = formlib.Builder()
|
||||
mk_mail_fs(fs, p_name, get_mail(p_name), err_str)
|
||||
minetest.show_formspec(p_name, mailbox_form, tostring(fs))
|
||||
end
|
||||
|
||||
|
||||
@ -63,35 +64,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if fields.quit then return true end
|
||||
|
||||
local p_name = player:get_player_name()
|
||||
local idx = selected_index[p_name]
|
||||
|
||||
if fields.claim
|
||||
and idx then
|
||||
local row = get_mail(p_name)[idx]
|
||||
|
||||
if row then
|
||||
local stack = ItemStack(row.Item)
|
||||
stack:set_count(row.Amount)
|
||||
|
||||
local p_inv = player:get_inventory()
|
||||
if not p_inv:room_for_item("main", stack) then
|
||||
show_mail(p_name, get_mail(p_name), "Not enough room.")
|
||||
return true
|
||||
end
|
||||
|
||||
local succ, res = exchange:take_inbox(row.Id, row.Amount)
|
||||
if not succ then
|
||||
show_mail(p_name, get_mail(p_name), res)
|
||||
end
|
||||
|
||||
stack:set_count(res)
|
||||
|
||||
p_inv:add_item("main", stack)
|
||||
|
||||
table.remove(get_mail(p_name), idx)
|
||||
show_mail(p_name, get_mail(p_name))
|
||||
end
|
||||
end
|
||||
|
||||
if fields.result_list then
|
||||
local event = minetest.explode_textlist_event(fields.result_list)
|
||||
@ -101,22 +73,48 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
end
|
||||
|
||||
if fields.claim then
|
||||
local idx = selected_index[p_name]
|
||||
local row = get_mail(p_name)[idx]
|
||||
|
||||
if row then
|
||||
local stack = ItemStack(row.Item)
|
||||
stack:set_count(row.Amount)
|
||||
stack:set_wear(row.Wear)
|
||||
|
||||
local p_inv = player:get_inventory()
|
||||
local leftover = p_inv:add_item("main", stack)
|
||||
local took_amount = row.Amount - leftover:get_count()
|
||||
|
||||
mailbox_contents[p_name] = nil
|
||||
|
||||
local succ, res = exchange:take_inbox(row.Id, took_amount)
|
||||
if succ then
|
||||
show_mail(p_name)
|
||||
else
|
||||
show_mail(p_name, res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end)
|
||||
|
||||
|
||||
minetest.register_node("global_exchange:mailbox", {
|
||||
description = "Digital Mailbox",
|
||||
tiles = {"global_exchange_box.png",
|
||||
tiles = {
|
||||
"global_exchange_box.png",
|
||||
"global_exchange_box.png",
|
||||
"global_exchange_box.png^global_exchange_mailbox_side.png",
|
||||
},
|
||||
is_ground_content = false,
|
||||
stack_max = 1,
|
||||
groups = {cracky=2},
|
||||
on_rightclick = function(pos, node, clicker)
|
||||
local p_name = clicker:get_player_name()
|
||||
local _,res = exchange:view_inbox(p_name)
|
||||
mailbox_contents[p_name] = res
|
||||
minetest.show_formspec(p_name, mailbox_form, mk_mail_fs(p_name, res))
|
||||
mailbox_contents[p_name] = nil
|
||||
show_mail(p_name)
|
||||
end,
|
||||
})
|
||||
|
||||
@ -129,3 +127,4 @@ minetest.register_craft( {
|
||||
{ "default:stone", "default:stone", "default:stone" },
|
||||
}
|
||||
})
|
||||
-- vim:set ts=4 sw=4 noet:
|
||||
|
891
exchange.lua
891
exchange.lua
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
172
formlib.lua
Normal file
172
formlib.lua
Normal file
@ -0,0 +1,172 @@
|
||||
local formlib = {}
|
||||
local builder_methods = {}
|
||||
|
||||
function formlib.escape(x)
|
||||
if x == nil then return "" end
|
||||
return minetest.formspec_escape(tostring(x))
|
||||
end
|
||||
|
||||
function formlib.bool(x)
|
||||
-- nil and false are returned as-is, everything else maps to true
|
||||
return x and true
|
||||
end
|
||||
|
||||
function builder_methods.append(fs, ...)
|
||||
for i=1,select("#", ...) do
|
||||
local x = select(i, ...)
|
||||
if x ~= nil then table.insert(fs, tostring(x)) end
|
||||
end
|
||||
return fs
|
||||
end
|
||||
|
||||
function builder_methods.escape(fs, ...)
|
||||
for i=1,select("#", ...) do
|
||||
local x = select(i, ...)
|
||||
if x ~= nil then table.insert(fs, formlib.escape(x)) end
|
||||
end
|
||||
return fs
|
||||
end
|
||||
|
||||
function builder_methods.escape_list(fs, ...)
|
||||
for i=1,select("#", ...) do
|
||||
local x = select(i, ...)
|
||||
if i > 1 then fs(",") end
|
||||
fs:escape(x)
|
||||
end
|
||||
return fs
|
||||
end
|
||||
|
||||
function builder_methods.escape_groups(fs, ...)
|
||||
for i=1,select("#", ...) do
|
||||
local group = select(i, ...)
|
||||
if i > 1 then fs(";") end
|
||||
if type(group) == "table" then
|
||||
fs:escape_list(unpack(group))
|
||||
else
|
||||
fs:escape(group)
|
||||
end
|
||||
end
|
||||
return fs
|
||||
end
|
||||
|
||||
function builder_methods.element(fs, name, ...)
|
||||
return fs(name, "["):escape_groups(...):append("]")
|
||||
end
|
||||
|
||||
function builder_methods.size(fs, w,h, fixed)
|
||||
if fixed == nil then
|
||||
return fs:element("size", {w,h})
|
||||
else
|
||||
return fs:element("size", {w,h, formlib.bool(fixed)})
|
||||
end
|
||||
end
|
||||
|
||||
function builder_methods.bgcolor(fs, color, fullscreen)
|
||||
if fullscreen == nil then
|
||||
return fs:element("bgcolor", {color})
|
||||
else
|
||||
return fs:element("bgcolor", {color}, {formlib.bool(fullscreen)})
|
||||
end
|
||||
end
|
||||
|
||||
function builder_methods.list(fs, x,y, w,h, inv_loc, inv_list, start_idx)
|
||||
return fs:element("list", {inv_loc}, {inv_list}, {x,y}, {w,h}, {start_idx})
|
||||
end
|
||||
|
||||
function builder_methods.button(fs, x,y, w,h, name, text)
|
||||
return fs:element("button", {x,y}, {w,h}, {name}, {text})
|
||||
end
|
||||
|
||||
function builder_methods.item_image_button(fs, x,y, w,h, name, item, text)
|
||||
return fs:element("item_image_button", {x,y}, {w,h}, {item}, {name}, {text})
|
||||
end
|
||||
|
||||
function builder_methods.label(fs, x,y, text)
|
||||
return fs:element("label", {x,y}, {text})
|
||||
end
|
||||
|
||||
function builder_methods.field(fs, x,y, w,h, name, label, default, close_on_enter)
|
||||
fs:element("field", {x,y}, {w,h}, {name}, {label}, {default})
|
||||
if close_on_enter ~= nil then
|
||||
fs:element("field_close_on_enter", {name}, {formlib.bool(close_on_enter)})
|
||||
end
|
||||
return fs
|
||||
end
|
||||
|
||||
function builder_methods.box(fs, x,y, w,h, color)
|
||||
return fs:element("box", {x,y}, {w,h}, {color})
|
||||
end
|
||||
|
||||
function builder_methods.dropdown(fs, x,y, w, name, body_fn, selected_idx)
|
||||
fs("dropdown["):escape_groups({x,y}, {w}, {name}):append(";")
|
||||
local first = true
|
||||
local results = { body_fn(function(...)
|
||||
if first then first = false else fs(",") end
|
||||
fs:escape(...)
|
||||
end) }
|
||||
if selected_idx ~= nil then fs(";"):escape(selected_idx) end
|
||||
return fs("]"), unpack(results)
|
||||
end
|
||||
|
||||
function builder_methods.tabheader(fs, x,y, name, body_fn, current_tab, transparent, draw_border)
|
||||
fs("tabheader["):escape_groups({x,y}, {name}):append(";")
|
||||
local first = true
|
||||
local results = { body_fn(function(...)
|
||||
if first then first = false else fs(",") end
|
||||
fs:escape(...)
|
||||
end) }
|
||||
fs(";"):escape_groups({current_tab}, {formlib.bool(transparent)}, {formlib.bool(draw_border)})
|
||||
return fs("]"), unpack(results)
|
||||
end
|
||||
|
||||
function builder_methods.textlist(fs, x,y, w,h, name, body_fn, selected_idx, transparent)
|
||||
fs("textlist["):escape_groups({x,y}, {w,h}, {name}):append(";")
|
||||
local first = true
|
||||
local results = { body_fn(function(...)
|
||||
if first then first = false else fs(",") end
|
||||
fs:escape(...)
|
||||
end) }
|
||||
fs(";"):escape_groups({selected_idx}, {formlib.bool(transparent)})
|
||||
return fs("]"), unpack(results)
|
||||
end
|
||||
|
||||
function builder_methods.tableoptions(fs, ...)
|
||||
return fs:element("tableoptions", ...)
|
||||
end
|
||||
|
||||
function builder_methods.tablecolumns(fs, ...)
|
||||
return fs:element("tablecolumns", ...)
|
||||
end
|
||||
|
||||
function builder_methods.table(fs, x,y, w,h, name, body_fn, selected_idx)
|
||||
fs("table["):escape_groups({x,y}, {w,h}, {name}):append(";")
|
||||
local first = true
|
||||
local results = { body_fn(function(...)
|
||||
if first then first = false else fs(",") end
|
||||
fs:escape_list(...)
|
||||
end) }
|
||||
if selected_idx ~= nil then fs(";"):escape(selected_idx) end
|
||||
return fs("]"), unpack(results)
|
||||
end
|
||||
|
||||
function builder_methods.container(fs, x,y, sub_fn, ...)
|
||||
fs:element("container", {x,y})
|
||||
local results = { sub_fn(fs, ...) }
|
||||
return fs("container_end[]"), unpack(results)
|
||||
end
|
||||
|
||||
local builder_meta = {
|
||||
__metatable = "protected",
|
||||
__index = builder_methods,
|
||||
__call = builder_methods.append,
|
||||
__tostring = table.concat,
|
||||
}
|
||||
|
||||
function formlib.Builder()
|
||||
local fs = {}
|
||||
setmetatable(fs, builder_meta)
|
||||
return fs
|
||||
end
|
||||
|
||||
return formlib
|
||||
-- vim:set ts=4 sw=4 noet:
|
68
init.lua
68
init.lua
@ -1,53 +1,47 @@
|
||||
|
||||
local insecure_env = minetest.request_insecure_environment()
|
||||
assert(insecure_env,
|
||||
"global_exchange needs to be trusted to run under mod security.")
|
||||
assert(insecure_env, "global_exchange needs to be trusted to run under mod security.")
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname()) .. "/"
|
||||
|
||||
local income = tonumber(minetest.setting_get("citizens_income")) or 10
|
||||
local income_interval = 1200
|
||||
local income_msg = "You receive your citizen's income (+" .. income .. ")"
|
||||
local S = minetest.get_translator("global_exchange")
|
||||
|
||||
local next_payout = os.time() + income_interval
|
||||
|
||||
local exchange =
|
||||
assert(loadfile(modpath .. "exchange.lua"))(insecure_env).open_exchange(
|
||||
minetest.get_worldpath() .. "/global_exchange.db"
|
||||
)
|
||||
local exchange = assert(loadfile(modpath .. "exchange.lua"))(insecure_env).
|
||||
open_exchange(minetest.get_worldpath() .. "/global_exchange.db")
|
||||
|
||||
local formlib = assert(loadfile(modpath .. "formlib.lua"))()
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
exchange:close()
|
||||
end)
|
||||
|
||||
|
||||
local function check_giving()
|
||||
local now = os.time()
|
||||
if now < next_payout then
|
||||
return
|
||||
end
|
||||
|
||||
next_payout = now + income_interval
|
||||
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
local p_name = player:get_player_name()
|
||||
|
||||
local succ = exchange:give_credits(p_name, income,
|
||||
"Citizen's Income (+" .. income .. ")")
|
||||
|
||||
if succ then
|
||||
minetest.chat_send_player(p_name, income_msg)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.after(5, check_giving)
|
||||
local function handle_setbalance_command(caller, name, newbalance)
|
||||
return exchange:set_balance(name, newbalance)
|
||||
end
|
||||
|
||||
minetest.after(5, check_giving)
|
||||
minetest.register_privilege("balance", {
|
||||
description = S("Can use /setbalance"),
|
||||
give_to_singleplayer = false
|
||||
})
|
||||
|
||||
minetest.register_chatcommand("setbalance", {
|
||||
params = S("[<name>] <balance>"),
|
||||
description = S("set a player's trading balance"),
|
||||
privs = {balance=true},
|
||||
func = function(caller, param)
|
||||
local name, balancestr = string.match(param, "([^ ]+) ([0-9]+)")
|
||||
if not name or not balancestr then
|
||||
name = caller
|
||||
balancestr = string.match(param, "([0-9]+)")
|
||||
if not balancestr then
|
||||
return false, S("Invalid parameters (see /help setbalance)")
|
||||
end
|
||||
end
|
||||
return handle_setbalance_command(caller, name, tonumber(balancestr))
|
||||
end,
|
||||
})
|
||||
|
||||
assert(loadfile(modpath .. "atm.lua"))(exchange, formlib)
|
||||
assert(loadfile(modpath .. "exchange_machine.lua"))(exchange, formlib)
|
||||
assert(loadfile(modpath .. "digital_mailbox.lua"))(exchange, formlib)
|
||||
|
||||
assert(loadfile(modpath .. "atm.lua"))(exchange)
|
||||
assert(loadfile(modpath .. "exchange_machine.lua"))(exchange)
|
||||
assert(loadfile(modpath .. "digital_mailbox.lua"))(exchange)
|
||||
minetest.log("action", "[global_exchange] loaded.")
|
||||
|
82
locale/global_exchange.fr.tr
Normal file
82
locale/global_exchange.fr.tr
Normal file
@ -0,0 +1,82 @@
|
||||
# textdomain:global_exchange
|
||||
|
||||
### exchange.lua ###
|
||||
Database Busy.=BDD occupée.
|
||||
Programmer error.=Erreur du programmeur.
|
||||
Failed to log message.=Echec journalisation message.
|
||||
Account already exists.=Compte déjà existant.
|
||||
@1 does not have an account.=@1 n'a pas de compte.
|
||||
Non-integer credit delta=Delta de crédit non entier
|
||||
@1 does not have enough money.=@1 n'a pas assez d'argent.
|
||||
Non-integer credit amount=Montant de crédit non entier
|
||||
Failed to log sender message=Echec journalisation message de l'émetteur
|
||||
Failed to log receiver message=Echec journalisation message du récepteur
|
||||
Noninteger quantity=Quantité non entière
|
||||
Nonpositive quantity=Quantité non positive
|
||||
Noninteger rate=Taux non entier
|
||||
Nonpositive rate=Taux non positif
|
||||
Noninteger wear=Usure non entière
|
||||
Invalid wear=Usure invalide
|
||||
No such order.=Pas un tel ordre.
|
||||
Order does not exist.=L'ordre n'existe pas.
|
||||
|
||||
### init.lua ###
|
||||
Can use /setbalance=Peut utiliser /setbalance
|
||||
set a player's trading balance=définir le solde commercial d'un joueur
|
||||
Invalid parameters (see /help setbalance)=Paramètres invalides (voir /help setbalance)
|
||||
|
||||
### atm.lua ###
|
||||
Cash withdrawal: (-@1)=Retrait d'espèces : (-@1)
|
||||
Invalid number ! Must be an Integer > 0=Nombre invalide ! Doit être un Entier > 0
|
||||
You don't have an account.=Vous n'avez pas de compte.
|
||||
Balance: @1=Balance : @1
|
||||
Desired amount:=Montant désiré :
|
||||
Get !=Obtenir !
|
||||
Or deposit your coins to credit your account:=Ou deposez vos pièces pour créditer votre compte :
|
||||
Log Out=Sortir
|
||||
Balance: @1=Balance : @1
|
||||
Send to:=Envoyer à :
|
||||
Amount=Montant
|
||||
Send=Envoie
|
||||
Back=Retour
|
||||
Invalid transfer amount.=Montant de transfert invalide.
|
||||
Cash deposit and withdrawal=Dépot et retrait d'espèces
|
||||
Account Info=Infos du compte
|
||||
Wire Monies=Virement bancaire
|
||||
Transaction Log=Journaux transactions
|
||||
ATM=Distributeur Automatique d'argent
|
||||
Cash deposit (+@1)=Dépot d'espèces (+@1)
|
||||
|
||||
### exchange_machine.lua ###
|
||||
Wear=Usure
|
||||
Buy Vol=Qté achat
|
||||
Buy Max=Achat Max
|
||||
Sell Vol=Qté vente
|
||||
Sell Min=Vente Min
|
||||
Unknown Item=Item inconnue
|
||||
No description=Pas de description
|
||||
New (-0%)=Neuf (-0%)
|
||||
Good (-10%)=Bon (-10%)
|
||||
Worn (-50%)=Usé (-50%)
|
||||
Junk (-100%)=Indésirable (-100%)
|
||||
Poster=Émetteur
|
||||
Rate=Taux
|
||||
Quantity=Quantité
|
||||
Bid (ea.)=Offre
|
||||
Place Bid=Faire Offre
|
||||
Ask (ea.)=Demande
|
||||
Sell=Vendre
|
||||
Cancel Order=Annuler Ordre
|
||||
Market=Marché
|
||||
Buy=Acheter
|
||||
My Orders=Mes Ordres
|
||||
You must input an item=Vous devez saisir un élément
|
||||
That item does not exist.=Cet élément n'existe pas.
|
||||
Invalid wear.=Usure invalide.
|
||||
Invalid amount.=Montant invalide.
|
||||
Invalid rate.=Taux invalide.
|
||||
Cannot sell an item with metadata.=Ne peut vendre un item avec des métadonnées.
|
||||
Qty=Qté
|
||||
Filter=Filtre
|
||||
Search=Chercher
|
||||
Reset=Reset
|
Reference in New Issue
Block a user