From eb10b9c9b7e00e82cd2baff15cb55d2e57e5ca92 Mon Sep 17 00:00:00 2001 From: FaceDeer Date: Sat, 27 Jul 2019 15:12:52 -0600 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .gitignore | 41 ++ LICENSE | 21 + default_markets.lua | 229 ++++++++++ depends.txt | 1 + formspecs.lua | 460 +++++++++++++++++++ init.lua | 18 + license.txt | 21 + market.lua | 552 +++++++++++++++++++++++ mod.conf | 1 + readme.md | 67 +++ screenshot.png | Bin 0 -> 97308 bytes settingtypes.txt | 5 + textures/commoditymarket_caravan.png | Bin 0 -> 1042 bytes textures/commoditymarket_crown.png | Bin 0 -> 721 bytes textures/commoditymarket_empty_shelf.png | Bin 0 -> 206 bytes textures/commoditymarket_goblin.png | Bin 0 -> 438 bytes textures/commoditymarket_gold_coins.png | Bin 0 -> 1364 bytes textures/commoditymarket_moon.png | Bin 0 -> 457 bytes textures/commoditymarket_search.png | Bin 0 -> 1290 bytes textures/commoditymarket_trade.png | Bin 0 -> 207 bytes textures/commoditymarket_under.png | Bin 0 -> 1001 bytes textures/commoditymarket_under_top.png | Bin 0 -> 759 bytes textures/license.txt | 8 + 24 files changed, 1426 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 default_markets.lua create mode 100644 depends.txt create mode 100644 formspecs.lua create mode 100644 init.lua create mode 100644 license.txt create mode 100644 market.lua create mode 100644 mod.conf create mode 100644 readme.md create mode 100644 screenshot.png create mode 100644 settingtypes.txt create mode 100644 textures/commoditymarket_caravan.png create mode 100644 textures/commoditymarket_crown.png create mode 100644 textures/commoditymarket_empty_shelf.png create mode 100644 textures/commoditymarket_goblin.png create mode 100644 textures/commoditymarket_gold_coins.png create mode 100644 textures/commoditymarket_moon.png create mode 100644 textures/commoditymarket_search.png create mode 100644 textures/commoditymarket_trade.png create mode 100644 textures/commoditymarket_under.png create mode 100644 textures/commoditymarket_under_top.png create mode 100644 textures/license.txt diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6fd0a37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# Compiled Lua sources +luac.out + +# luarocks build files +*.src.rock +*.zip +*.tar.gz + +# Object files +*.o +*.os +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo +*.def +*.exp + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..33bee86 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 FaceDeer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/default_markets.lua b/default_markets.lua new file mode 100644 index 0000000..8d559b9 --- /dev/null +++ b/default_markets.lua @@ -0,0 +1,229 @@ +local default_modpath = minetest.get_modpath("default") +if not default_modpath then return end + +local gold_coins_required = false + +local default_items = {"default:axe_bronze","default:axe_diamond","default:axe_mese","default:axe_steel","default:axe_steel","default:axe_stone","default:axe_wood","default:pick_bronze","default:pick_diamond","default:pick_mese","default:pick_steel","default:pick_stone","default:pick_wood","default:shovel_bronze","default:shovel_diamond","default:shovel_mese","default:shovel_steel","default:shovel_stone","default:shovel_wood","default:sword_bronze","default:sword_diamond","default:sword_mese","default:sword_steel","default:sword_stone","default:sword_wood", "default:blueberries", "default:book", "default:bronze_ingot", "default:clay_brick", "default:clay_lump", "default:coal_lump", "default:copper_ingot", "default:copper_lump", "default:diamond", "default:flint", "default:gold_ingot", "default:gold_lump", "default:iron_lump", "default:mese_crystal", "default:mese_crystal_fragment", "default:obsidian_shard", "default:paper", "default:steel_ingot", "default:stick", "default:tin_ingot", "default:tin_lump", "default:acacia_tree", "default:acacia_wood", "default:apple", "default:aspen_tree", "default:aspen_wood", "default:blueberry_bush_sapling", "default:bookshelf", "default:brick", "default:bronzeblock", "default:bush_sapling", "default:cactus", "default:clay", "default:coalblock", "default:cobble", "default:copperblock", "default:desert_cobble", "default:desert_sand", "default:desert_sandstone", "default:desert_sandstone_block", "default:desert_sandstone_brick", "default:desert_stone", "default:desert_stone_block", "default:desert_stonebrick", "default:diamondblock", "default:dirt", "default:glass", "default:goldblock", "default:gravel", "default:ice", "default:junglegrass", "default:junglesapling", "default:jungletree", "default:junglewood", "default:ladder_steel", "default:ladder_wood", "default:large_cactus_seedling", "default:mese", "default:mese_post_light", "default:meselamp", "default:mossycobble", "default:obsidian", "default:obsidian_block", "default:obsidian_glass", "default:obsidianbrick", "default:papyrus", "default:pine_sapling", "default:pine_tree", "default:pine_wood", "default:sand", "default:sandstone", "default:sandstone_block", "default:sandstonebrick", "default:sapling", "default:silver_sand", "default:silver_sandstone", "default:silver_sandstone_block", "default:silver_sandstone_brick", "default:snow", "default:snowblock", "default:steelblock", "default:stone", "default:stone_block", "default:stonebrick", "default:tinblock", "default:tree", "default:wood",} + +------------------------------------------------------------------------------ +if minetest.settings:get_bool("commoditymarket_enable_kings_market") then +local kings_def = { + description = "King's Market", + long_description = "The largest and most accessible market for the common man, the King's Market uses gold coins as its medium of exchange (or the equivalent in gold ingots - 1000 coins to the ingot). However, as a respectable institution of the surface world, the King's Market operates only during the hours of daylight. The purchase and sale of swords and explosives is prohibited in the King's Market.", + currency = { + ["default:gold_ingot"] = 1000, + ["commoditymarket:gold_coins"] = 1 + }, + currency_symbol = "Au", + allow_item = function(item) + if item:sub(1,13) == "default:sword" or item:sub(1,4) == "tnt:" then + return false + end + return true + end, + inventory_limit = 100000, + initial_items = default_items, +} + +gold_coins_required = true + +commoditymarket.register_market("kings", kings_def) + +minetest.register_node("commoditymarket:kings_market", { + description = "King's Market", + _doc_items_longdesc = "", + tiles = {"default_chest_top.png","default_chest_top.png", + "default_chest_side.png","default_chest_side.png", + "commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_crown.png",}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {choppy = 2, oddly_breakable_by_hand = 1,}, + sounds = default.node_sound_wood_defaults(), + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local timeofday = minetest.get_timeofday() + if timeofday > 0.2 and timeofday < 0.8 then + commoditymarket.show_market("kings", clicker:get_player_name()) + else + minetest.chat_send_player(clicker:get_player_name(), "At this time of day the King's Market is closed.") + end + end, + can_dig = function(pos, player) + if player and minetest.check_player_privs(player, "server") then + return true + end + return false + end, +}) +end +------------------------------------------------------------------------------- + +if minetest.settings:get_bool("commoditymarket_enable_night_market") then +local night_def = { + description = "Night Market", + long_description = "When the sun sets and the stalls of the King's Market close, other vendors are just waking up to share their wares. The Night Market is not as voluminous as the King's Market but accepts a wider range of wares. It accepts the same gold coinage of the realm.", + currency = { + ["default:gold_ingot"] = 1000, + ["commoditymarket:gold_coins"] = 1 + }, + currency_symbol = "Au", + inventory_limit = 10000, + initial_items = default_items, +} + +gold_coins_required = true + +commoditymarket.register_market("night", night_def) + +minetest.register_node("commoditymarket:night_market", { + description = night_def.description, + _doc_items_longdesc = night_def.long_description, + tiles = {"default_chest_top.png","default_chest_top.png", + "default_chest_side.png","default_chest_side.png", + "commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_moon.png",}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {choppy = 2, oddly_breakable_by_hand = 1,}, + sounds = default.node_sound_wood_defaults(), + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + local timeofday = minetest.get_timeofday() + if timeofday < 0.2 or timeofday > 0.8 then + commoditymarket.show_market("night", clicker:get_player_name()) + else + minetest.chat_send_player(clicker:get_player_name(), "At this time of day the Night Market is closed.") + end + end, + can_dig = function(pos, player) + if player and minetest.check_player_privs(player, "server") then + return true + end + return false + end, +}) +end +------------------------------------------------------------------------------- +if minetest.settings:get_bool("commoditymarket_enable_caravan_market", true) then +-- "Trader's Caravan" - small-capacity market that players can build + +local caravan_def = { + description = "Trader's Caravan", + long_description = "Unlike most markets that have well-known fixed locations that travelers congregate to, the network of Trader's Caravans is fluid and dynamic in their locations. A Trader's Caravan can show up anywhere, make modest trades, and then be gone the next time you visit them. These caravans accept gold and gold coins as a currency.", + currency = { + ["default:gold_ingot"] = 1000, + ["commoditymarket:gold_coins"] = 1 + }, + currency_symbol = "Au", + inventory_limit = 1000, + initial_items = default_items, +} + +gold_coins_required = true + +minetest.register_craft({ + output = "commoditymarket:caravan_market", + recipe = { + {'', "default:gold_ingot", ''}, + {'group:wood', "default:chest_locked", 'group:wood'}, + {'group:wood', 'group:wood', 'group:wood'}, + } +}) + +commoditymarket.register_market("caravan", caravan_def) + +minetest.register_node("commoditymarket:caravan_market", { + description = "Trader's Caravan", + _doc_items_longdesc = caravan_def.long_description, + tiles = {"default_chest_top.png","default_chest_top.png", + "default_chest_side.png^commoditymarket_caravan.png","default_chest_side.png^commoditymarket_caravan.png", + "commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_trade.png",}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {choppy = 2, oddly_breakable_by_hand = 1,}, + sounds = default.node_sound_wood_defaults(), + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + commoditymarket.show_market("caravan", clicker:get_player_name()) + end, +}) +end +------------------------------------------------------------------------------- +-- "Goblin Exchange" +if minetest.settings:get_bool("commoditymarket_enable_goblin_market") then + +local goblin_def = { + description = "Goblin Exchange", + long_description = "One does not usually associate Goblins with the sort of sophistication that running a market requires. Usually one just associates Goblins with savagery and violence. But they understand the principle of tit-for-tat exchange, and if approached correctly they actually respect the concepts of ownership and debt. However, for some peculiar reason they understand this concept in the context of coal lumps. Goblins deal in the standard coal lump as their form of currency, conceptually divided into 100 coal centilumps (though Goblin brokers prefer to \"keep the change\" when giving back actual coal lumps).", + currency = { + ["default:coal_lump"] = 100 + }, + currency_symbol = "cC", + inventory_limit = 1000, +} + +commoditymarket.register_market("goblin", goblin_def) + +minetest.register_node("commoditymarket:goblin_market", { + description = goblin_def.description, + _doc_items_longdesc = goblin_def.long_description, + tiles = {"default_chest_top.png","default_chest_top.png", + "default_chest_side.png","default_chest_side.png", + "commoditymarket_empty_shelf.png","default_chest_side.png^commoditymarket_goblin.png",}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {choppy = 2, oddly_breakable_by_hand = 1,}, + sounds = default.node_sound_wood_defaults(), + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + commoditymarket.show_market("goblin", clicker:get_player_name()) + end, + can_dig = function(pos, player) + if player and minetest.check_player_privs(player, "server") then + return true + end + return false + end, +}) +end +-------------------------------------------------------------------------------- + +if minetest.settings:get_bool("commoditymarket_enable_under_market") then +local undermarket_def = { + description = "Undermarket", + long_description = "Deep in the bowels of the world, below even the goblin-infested warrens and ancient delvings of the dwarves, dark and mysterious beings once dwelled. A few still linger to this day, and facilitate barter for those brave souls willing to travel in their lost realms. The Undermarket uses Mese chips as a currency - twenty chips to the Mese fragment. Though traders are loathe to physically break Mese crystals up into units that small, as it renders it useless for other purposes.", + currency = { + ["default:mese"] = 9*9*20, + ["default:mese_crystal"] = 9*20, + ["default:mese_crystal_fragment"] = 20 + }, + currency_symbol = "\u{20A5}", + inventory_limit = 10000, +} + +commoditymarket.register_market("under", undermarket_def) + +minetest.register_node("commoditymarket:under_market", { + description = undermarket_def.description, + _doc_items_longdesc = undermarket_def.long_description, + tiles = {"commoditymarket_under_top.png","commoditymarket_under_top.png", + "commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png","commoditymarket_under.png"}, + paramtype2 = "facedir", + is_ground_content = false, + groups = {choppy = 2, oddly_breakable_by_hand = 1,}, + sounds = default.node_sound_stone_defaults(), + on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) + commoditymarket.show_market("under", clicker:get_player_name()) + end, + can_dig = function(pos, player) + if player and minetest.check_player_privs(player, "server") then + return true + end + return false + end, +}) +end +------------------------------------------------------------------ + +if gold_coins_required then +minetest.register_craftitem("commoditymarket:gold_coins", { + description = "Gold Coins", + inventory_image = "commoditymarket_gold_coins.png", + stack_max = 1000, +}) +end \ No newline at end of file diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..21c2521 --- /dev/null +++ b/depends.txt @@ -0,0 +1 @@ +default? \ No newline at end of file diff --git a/formspecs.lua b/formspecs.lua new file mode 100644 index 0000000..fcc575c --- /dev/null +++ b/formspecs.lua @@ -0,0 +1,460 @@ +-- Inventory formspec +------------------------------------------------------------------------------------- + +local inventory_comp = function(invitem1, invitem2) return invitem1.item < invitem2.item end + +local get_account_formspec = function(market, account) + local formspec = { + "size[10,10]", + "tabheader[0,0;tabs;"..market.def.description..",Your Inventory,Market Orders;2;false;true]", + "tablecolumns[text;text,align=center;text;text,align=center]", + "table[0,0;9.9,4;inventory;", + "Item,Quantity,Item,Quantity" + } + + local inventory = {} + local inventory_count = 0 + for item, quantity in pairs(account.inventory) do + table.insert(inventory, {item=item, quantity=quantity}) + inventory_count = inventory_count + quantity + end + table.sort(inventory, inventory_comp) + local i = 1 + while i <= #inventory do + local n = #formspec+1 + formspec[n] = "," .. inventory[i].item + formspec[n+1] = "," .. inventory[i].quantity + i = i + 1 + if inventory[i] then + formspec[n+2] = "," .. inventory[i].item + formspec[n+3] = "," .. inventory[i].quantity + end + i = i + 1 + end + + formspec[#formspec+1] = "]container[1.1,4.5]list[detached:commoditymarket:"..market.name..";add;0,0;1,1;]" + .."label[1,0;Drop items here to\nadd to your account]" + .."listring[current_player;main]listring[detached:commoditymarket:"..market.name..";add]" + + if market.def.inventory_limit then + formspec[#formspec+1] = "label[3,0;Inventory limit:\n"..inventory_count.."/"..market.def.inventory_limit.."]" + end + formspec[#formspec+1] = "label[4.9,0;Balance:\n"..market.def.currency_symbol .. account.balance .."]" + .."field[6.1,0.25;1,1;withdrawamount;;]" + .."field_close_on_enter[withdrawamount;false]" + .."button[6.7,0;1.2,1;withdraw;Withdraw]" + .."container_end[]" + + formspec[#formspec+1] = "container[1.1,5.75]list[current_player;main;0,0;8,1;]".. + "list[current_player;main;0,1.25;8,3;8]container_end[]" + + return table.concat(formspec) +end + +-- Market formspec +-------------------------------------------------------------------------------------------------------- + +local compare_market_item = function(mkt1, mkt2) return mkt1.item < mkt2.item end +local compare_market_desc = function(mkt1, mkt2) + local def1 = minetest.registered_items[mkt1.item] or {} + local def2 = minetest.registered_items[mkt2.item] or {} + return (def1.description or "Unknown Item") < (def2.description or "Unknown Item") +end +local compare_buy_volume = function(mkt1, mkt2) return mkt1.buy_volume > mkt2.buy_volume end +local compare_buy_max = function(mkt1, mkt2) + return ((mkt1.buy_orders[#mkt1.buy_orders] or {}).price or -2^30) > ((mkt2.buy_orders[#mkt2.buy_orders] or {}).price or -2^30) +end +local compare_sell_volume = function(mkt1, mkt2) return mkt1.sell_volume > mkt2.sell_volume end +local compare_sell_min = function(mkt1, mkt2) + return ((mkt1.sell_orders[#mkt1.sell_orders] or {}).price or 2^31) < ((mkt2.sell_orders[#mkt2.sell_orders] or {}).price or 2^31) +end +local compare_last_price = function(mkt1, mkt2) return (mkt1.last_price or 2^31) < (mkt2.last_price or 2^31) end + +local sort_marketlist = function(item_list, account) + local sort_by = account.sort_markets_by_column or 1 + -- "Item,Description,#00FF00,Buy Vol,Buy Max,#FF0000,Sell Vol,Sell Min,Last Price" + if sort_by == 1 then + table.sort(item_list, compare_market_item) + elseif sort_by == 2 then + table.sort(item_list, compare_market_desc) + elseif sort_by == 4 then + table.sort(item_list, compare_buy_volume) + elseif sort_by == 5 then + table.sort(item_list, compare_buy_max) + elseif sort_by == 7 then + table.sort(item_list, compare_sell_volume) + elseif sort_by == 8 then + table.sort(item_list, compare_sell_min) + elseif sort_by == 9 then + table.sort(item_list, compare_last_price) + end +end + +local make_marketlist = function(market, account) + local market_list = {} + local search_filter = account.search or "" + for item, row in pairs(market.orders_for_items) do + if (search_filter == "" or string.find(item, search_filter)) then + if account.filter_participating == "true" then + local found = false + for _, order in ipairs(row.buy_orders) do + if account == order.account then + found = true + break + end + end + if not found then + for _, order in ipairs(row.sell_orders) do + if account == order.account then + found = true + break + end + end + end + if found then + table.insert(market_list, row) + end + else + table.insert(market_list, row) + end + end + end + sort_marketlist(market_list, account) + return market_list +end + +local get_market_formspec = function(market, account) + local selected = account.selected + local formspec = { + "size[10,10]", + "tabheader[0,0;tabs;"..market.def.description..",Your Inventory,Market Orders;3;false;true]", + "tablecolumns[text;" + .."text;" + .."color,span=2;" + .."text,align=right,tooltip=Number of items there's demand for in the market;" + .."text,align=right,tooltip=Maximum price being offered to buy one of these;" + .."color,span=2;" + .."text,align=right,tooltip=Number of items available for sale in the market;" + .."text,align=right,tooltip=Minimum price being demanded to sell one of these;" + .."text,align=right,tooltip=Price paid for one of these the last time one was sold]", + "table[0,0;9.9,5;summary;", + "Item,Description,#00FF00,Buy Vol,Buy Max,#FF0000,Sell Vol,Sell Min,Last Price" + } + + local selected_idx + local selected_row + + local market_list = make_marketlist(market, account) + + -- Show list of item market summaries + for i, row in ipairs(market_list) do + local item_display = row.item + if item_display:len() > 20 then + item_display = item_display:sub(1,18).."..." + end + local n = #formspec+1 + formspec[n] = "," .. item_display + local def = minetest.registered_items[row.item] or {} + local desc_display = def.description or "Unknown Item" + if desc_display:len() > 20 then + desc_display = desc_display:sub(1,18).."..." + end + formspec[n+1] = "," .. desc_display + formspec[n+2] = ",#00FF00" + formspec[n+3] = "," .. row.buy_volume + formspec[n+4] = "," .. ((row.buy_orders[#row.buy_orders] or {}).price or "-") + formspec[n+5] = ",#FF0000" + formspec[n+6] = "," .. row.sell_volume + formspec[n+7] = "," .. ((row.sell_orders[#row.sell_orders] or {}).price or "-") + formspec[n+8] = "," .. (row.last_price or "-") + + -- we happen to be processing the row that matches the item this player has selected. Record that. + if selected == row.item then + selected_row = row + selected_idx = i + 1 + end + + end + -- a row that's visible is marked as the selected item, so make it selected in the formspec + if selected_row then + formspec[#formspec+1] = ";"..selected_idx + end + formspec[#formspec+1] = "]" + + -- search field + formspec[#formspec+1] = "container[2.5,5]field_close_on_enter[search_filter;false]" + .."field[0,0.85;2.5,1;search_filter;;"..minetest.formspec_escape(account.search or "").."]" + .."image_button[2.25,0.6;0.8,0.8;commoditymarket_search.png;apply_search;]" + .."checkbox[1.77,0;filter_participating;My orders;".. account.filter_participating .."]" + .."tooltip[search_filter;Enter substring to search item identifiers for]" + .."tooltip[apply_search;Apply search to outputs]" + .."container_end[]" + + -- if a visible item market is selected, show the orders for it in detail + if selected_row then + local current_time = minetest.get_gametime() + -- player inventory for this item and for currency + formspec[#formspec+1] = "label[0.1,5.1;"..selected.."\nIn inventory: " + .. tostring(account.inventory[selected] or 0) .."\nBalance: "..market.def.currency_symbol..account.balance .."]" + + -- buy/sell controls + formspec[#formspec+1] = "container[6,5]" + formspec[#formspec+1] = "button[0,0.5;1,1;buy;Buy]field[1.3,0.85;1,1;quantity;Quantity;]field[2.3,0.85;1,1;price;Price;]button[3,0.5;1,1;sell;Sell]" + .."field_close_on_enter[quantity;false]field_close_on_enter[price;false]" + formspec[#formspec+1] = "container_end[]" + + -- table of buy and sell orders + formspec[#formspec+1] = "tablecolumns[color;text;" + .."text,align=right,tooltip=The price per item in this order;" + .."text,align=right,tooltip=The total amount of items in this particular order;" + .."text,align=right,tooltip=The total amount of items available at this price accounting for the other orders also currently being offered;" + .."text,tooltip=The name of the player who placed this order;" + .."text,align=right,tooltip=How many days ago this order was placed]" + formspec[#formspec+1] = "table[0,6.5;9.9,3.5;orders;#FFFFFF,Order,Price,Quantity,Total Volume,Player,Days Old" + local sell_volume = selected_row.sell_volume + for i, sell in ipairs(selected_row.sell_orders) do + formspec[#formspec+1] = ",#FF0000,Sell,"..sell.price..","..sell.quantity..","..sell_volume + ..","..sell.account.name..","..math.floor((current_time-sell.timestamp)/86400) + sell_volume = sell_volume - sell.quantity + end + local buy_volume = 0 + local buy_orders = selected_row.buy_orders + local buy_count = #buy_orders + -- Show buy orders in reverse order + for i = buy_count, 1, -1 do + buy = buy_orders[i] + buy_volume = buy_volume + buy.quantity + formspec[#formspec+1] = ",#00FF00,Buy,"..buy.price..","..buy.quantity..","..buy_volume + ..","..buy.account.name..","..math.floor((current_time-buy.timestamp)/86400) + end + formspec[#formspec+1] = "]" + else + formspec[#formspec+1] = "label[0.1,5.1;Select an item to view or place orders]" + end + return table.concat(formspec) +end + +------------------------------------------------------------------------------------- +-- Information formspec + +--{item=item, quantity=quantity, price=price, purchaser=purchaser, seller=seller, timestamp = minetest.get_gametime()} +local log_to_string = function(market, log_entry) + local purchaser_name + if log_entry.purchaser == log_entry.seller then + purchaser_name = "themself" + else + purchaser_name = log_entry.purchaser.name + end + return "On day " .. math.ceil(log_entry.timestamp/86400) .. " " .. log_entry.seller.name .. " sold " .. log_entry.quantity .. " " + .. log_entry.item .. " to " .. purchaser_name .. " at " .. market.def.currency_symbol .. log_entry.price +end + + +local get_info_formspec = function(market, account) + local formspec = { + "size[10,10]", + "tabheader[0,0;tabs;"..market.def.description..",Your Inventory,Market Orders;1;false;true]", + "textarea[0.5,0.5;9.5,1.5;;Description:;"..market.def.long_description.."]", + -- TODO: logging temporarily disabled, it was causing minetest.serialize to generate invalid output for some reason + --"textarea[0.5,2.5;9.5,6;;Your Recent Purchases and Sales:;", + } +-- if next(account.log) then +-- for _, log_entry in ipairs(account.log) do +-- formspec[#formspec+1] = log_to_string(market, log_entry) .. "\n" +-- end +-- else +-- formspec[#formspec+1] = "No logged activites in this market yet" +-- end +-- formspec[#formspec+1] = "]" + + return table.concat(formspec) +end + +--------------------------------------------------------------------------------------- + +commoditymarket.get_formspec = function(market, account) + local tab = account.tab + if tab == 1 then + return get_info_formspec(market, account) + elseif tab == 2 then + return get_account_formspec(market, account) + else + return get_market_formspec(market, account) + end +end + +------------------------------------------------------------------------------------ +-- Handling recieve_fields + + +local add_to_player_inventory = function(name, item, amount) + local playerinv = minetest.get_inventory({type="player", name=name}) + local not_full = true + while amount > 0 and not_full do + local stack = ItemStack(item .. " " .. amount) + amount = amount - stack:get_count() + local leftover = playerinv:add_item("main", stack) + if leftover:get_count() > 0 then + amount = amount + leftover:get_count() + return amount + end + end + return amount +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local formname_split = formname:split(":") + + if formname_split[1] ~= "commoditymarket" then + return false + end + + local market = commoditymarket.registered_markets[formname_split[2]] + if not market then + return false + end + + local name = formname_split[3] + if name ~= player:get_player_name() then + return false + end + + local account = market:get_account(name) + local something_changed = false + + if fields.tabs then + account.tab = tonumber(fields.tabs) + something_changed = true + end + + -- player clicked on an item in the market summary table + if fields.summary then + local summaryevent = minetest.explode_table_event(fields.summary) + if summaryevent.type == "DCL" or summaryevent.type == "CHG" then + if summaryevent.row == 1 then + -- header clicked, sort by column + account.sort_markets_by_column = summaryevent.column + else + -- item clicked, recreate the list to find out which one + local marketlist = make_marketlist(market, account) + local selected = marketlist[summaryevent.row-1] + if selected then + account.selected = selected.item + end + end + elseif summaryevent.type == "INV" then + account.selected = nil + end + something_changed = true + end + + if fields.orders then + local ordersevent = minetest.explode_table_event(fields.orders) + if ordersevent.type == "DCL" then + local selected_idx = ordersevent.row - 1 -- account for header + local selected_row = market.orders_for_items[account.selected] -- sell orders come first + local sell_orders = selected_row.sell_orders + local sell_order_count = #sell_orders + local selected_order + if selected_idx <= sell_order_count then -- if the index is within the range of sell orders, + selected_order = sell_orders[selected_idx] + if selected_order.account == account then -- and the order belongs to the current player, + market:cancel_sell(account.selected, selected_order) -- cancel it + something_changed = true + end + else + -- otherwise we're in the buy group, shift the index up by sell_order_count and reverse index order + local buy_orders = selected_row.buy_orders + local buy_orders_count = #buy_orders + selected_order = buy_orders[buy_orders_count - (selected_idx - sell_order_count - 1)] + if selected_order.account == account then + market:cancel_buy(account.selected, selected_order) + something_changed = true + end + end + end + end + + if fields.buy then + local quantity = tonumber(fields.quantity) + local price = tonumber(fields.price) + if price ~= nil and quantity ~= nil then + market:buy(name, account.selected, quantity, price) + something_changed = true + end + end + if fields.sell then + local quantity = tonumber(fields.quantity) + local price = tonumber(fields.price) + if price ~= nil and quantity ~= nil then + market:sell(name, account.selected, quantity, price) + something_changed = true + end + end + + -- player clicked in their inventory table, may need to give him his stuff back + if fields.inventory then + local invevent = minetest.explode_table_event(fields.inventory) + if invevent.type == "DCL" then + local index = invevent.row*2 + math.ceil(invevent.column/2) - 4 + local account = market:get_account(name) + local inventory = {} + for item, quantity in pairs(account.inventory) do + table.insert(inventory, {item=item, quantity=quantity}) + end + table.sort(inventory, inventory_comp) + if inventory[index] then + local item = inventory[index].item + local amount = account.inventory[item] + local remaining = add_to_player_inventory(name, item, amount) + if remaining == 0 then + account.inventory[item] = nil + else + account.inventory[item] = remaining + end + if remaining ~= amount then + something_changed = true + end + end + end + end + + if fields.withdraw or fields.key_enter_field == "withdrawamount" then + local withdrawvalue = tonumber(fields.withdrawamount) + if withdrawvalue then + local account = market:get_account(name) + withdrawvalue = math.min(withdrawvalue, account.balance) + for _, currency in ipairs(market.def.currency_ordered) do + this_unit_amount = math.floor(withdrawvalue/currency.amount) + if this_unit_amount > 0 then + local remaining = add_to_player_inventory(name, currency.item, this_unit_amount) + local value_given = (this_unit_amount - remaining) * currency.amount + account.balance = account.balance - value_given + withdrawvalue = withdrawvalue - value_given + something_changed = true + end + end + end + end + + if fields.search_filter then + local value = string.lower(fields.search_filter) + if account.search ~= value then + account.search = value + end + end + + if (fields.filter_participating == "true" and account.filter_participating == "false") or + (fields.filter_participating == "false" and account.filter_participating == "true") then + account.filter_participating = fields.filter_participating + something_changed = true + end + + if fields.apply_search or fields.key_enter_field == "search_filter" then + something_changed = true + end + + if something_changed then + minetest.show_formspec(name, formname, market:get_formspec(account)) + end +end) diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..ec1b5c0 --- /dev/null +++ b/init.lua @@ -0,0 +1,18 @@ +commoditymarket = {} + +local MP = minetest.get_modpath(minetest.get_current_modname()) +dofile(MP.."/formspecs.lua") +dofile(MP.."/market.lua") +dofile(MP.."/default_markets.lua") + +minetest.register_chatcommand("market.show", { + params = "marketname", + privs = {server=true}, + decription = "show market formspec", + func = function(name, param) + local market = commoditymarket.registered_markets[param] + if market == nil then return end + local formspec = market:get_formspec(market:get_account(name)) + minetest.show_formspec(name, "commoditymarket:"..param..":"..name, formspec) + end, +}) diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..ab4f465 --- /dev/null +++ b/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 FaceDeer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/market.lua b/market.lua new file mode 100644 index 0000000..fa85ae1 --- /dev/null +++ b/market.lua @@ -0,0 +1,552 @@ +commoditymarket.registered_markets = {} +local log_length_limit = 30 + +-- from http://lua-users.org/wiki/BinaryInsert +--[[ + table.bininsert( table, value [, comp] ) + + Inserts a given value through BinaryInsert into the table sorted by [, comp]. + + If 'comp' is given, then it must be a function that receives + two table elements, and returns true when the first is less + than the second, e.g. comp = function(a, b) return a > b end, + will give a sorted table, with the biggest value on position 1. + [, comp] behaves as in table.sort(table, value [, comp]) + returns the index where 'value' was inserted +]]-- +local comp_default = function(a, b) return a < b end +function table.bininsert(t, value, comp) + -- Initialise compare function + local comp = comp or comp_default + -- Initialise numbers + local iStart, iEnd, iMid, iState = 1, #t, 1, 0 + -- Get insert position + while iStart <= iEnd do + -- calculate middle + iMid = math.floor( (iStart+iEnd)/2 ) + -- compare + if comp(value, t[iMid]) then + iEnd, iState = iMid - 1, 0 + else + iStart, iState = iMid + 1, 1 + end + end + local target = iMid+iState + table.insert(t, target, value) + return target +end + +-- lowest price first +local buy_comp = function(order1, order2) + local price1 = order1.price + local price2 = order2.price + if price1 < price2 then + return true + elseif price1 == price2 and order1.timestamp < order2.timestamp then + return true + end + return false +end +-- highest price first +local sell_comp = function(order1, order2) + local price1 = order1.price + local price2 = order2.price + if price1 > price2 then + return true + elseif price1 == price2 and order1.timestamp < order2.timestamp then + return true + end + return false +end + +--------------------------------- + +local get_account = function(market, player_name) + local account = market.player_accounts[player_name] + if account then + return account + end + account = {} + account.search = "" + account.name = player_name + account.balance = 0 -- currency + account.inventory = {} -- items stored in the market inventory that aren't part of sell orders yet. stored as "[item] = count" + account.filter_participating = "false" + account.log = {} -- might want to use a more sophisticated queue, but this isn't going to be a big list so that's more trouble than it's worth right now. + market.player_accounts[player_name] = account + return account +end + +local log_sale = function(item, quantity, price, purchaser, seller) +-- TODO: disabled temporarily, the log code should work in theory but in practice minetest.serialize was generating invalid output for some reason. +-- local log_entry = {item=item, quantity=quantity, price=price, purchaser=purchaser, seller=seller, timestamp = minetest.get_gametime()} +-- local purchaser_log = purchaser.log +-- local seller_log = seller.log +-- table.insert(purchaser_log, log_entry) +-- if #purchaser_log > log_length_limit then +-- table.remove(purchaser_log, 1) +-- end +-- if (purchaser ~= seller) then +-- table.insert(seller_log, log_entry) +-- if #seller_log > log_length_limit then +-- table.remove(seller_log, 1) +-- end +-- end +end + +local remove_orders_by_account = function(orders, account) + if not orders then return end + local i = 1 + while i < #orders do + local order = orders[i] + if order.account == account then + table.remove(orders, i) + else + i = i + 1 + end + end +end + +local remove_account = function(player_name) + local account = player_accounts[player_name] + if account == nil then + return + end + + player_accounts[player_name] = nil + for item, lists in pairs(market) do + remove_orders_by_account(lists.buy_orders, account) + remove_orders_by_account(lists.sell_orders, account) + end +end + +------------------------------------------------------------------------------------------ + +local add_inventory_to_account = function(market, account, item, quantity) + if quantity < 1 or minetest.registered_items[item] == nil then + return false + end + + if market.def.currency[item] then + account.balance = account.balance + market.def.currency[item] * quantity + else + account.inventory[item] = (account.inventory[item] or 0) + quantity + end + return true +end + +local remove_inventory_from_account = function(account, item, quantity) + if quantity < 1 then + return false + end + + local inventory = account.inventory + local current_quantity = inventory[item] or 0 + if current_quantity < quantity then + return false + end + + local new_quantity = current_quantity - quantity + if new_quantity == 0 then + inventory[item] = nil + else + inventory[item] = new_quantity + end + return true +end + +local remove_order = function(order, array) + for i, market_order in ipairs(array) do + if order == market_order then + table.remove(array, i) + return true + end + end + return false +end + +----------------------------------------------------------------------------------------------------------- + +local add_sell = function(market, account, item, price, quantity) + price = tonumber(price) + quantity = tonumber(quantity) + -- validate that this sell order is possible + if price < 0 or not remove_inventory_from_account(account, item, quantity) then + return false + end + + local buy_market = market.orders_for_items[item].buy_orders + local buy_order = buy_market[#buy_market] + local current_buy_volume = market.orders_for_items[item].buy_volume + + -- go through existing buy orders that are more expensive than or equal to the price + -- we're demanding, selling them at the order's price until we run out of + -- buy orders or run out of demand + while quantity > 0 and buy_order and buy_order.price >= price do + local quantity_to_sell = math.min(buy_order.quantity, quantity) + quantity = quantity - quantity_to_sell + local earned = quantity_to_sell*buy_order.price + account.balance = account.balance + earned + add_inventory_to_account(market, buy_order.account, item, quantity_to_sell) + buy_order.quantity = buy_order.quantity - quantity_to_sell + current_buy_volume = current_buy_volume - quantity_to_sell + + if buy_order.account ~= account then + -- don't update the last price if a player is just buying and selling from themselves + market.orders_for_items[item].last_price = buy_order.price + end + + log_sale(item, quantity_to_sell, buy_order.price, buy_order.account, account) + + if buy_order.quantity == 0 then + table.remove(buy_market, #buy_market) + end + buy_order = buy_market[#buy_market] + end + market.orders_for_items[item].buy_volume = current_buy_volume + + if quantity > 0 then + local sell_market = market.orders_for_items[item].sell_orders + + -- create the order and insert it into order arrays + local order = {account=account, price=price, quantity=quantity, timestamp=minetest.get_gametime()} + table.bininsert(sell_market, order, sell_comp) + market.orders_for_items[item].sell_volume = market.orders_for_items[item].sell_volume + quantity + end +end + +local cancel_sell = function(market, item, order) + local account = order.account + local quantity = order.quantity + + local sell_market = market.orders_for_items[item].sell_orders + + remove_order(order, sell_market) + market.orders_for_items[item].sell_volume = market.orders_for_items[item].sell_volume - quantity + add_inventory_to_account(market, account, item, quantity) +end + +----------------------------------------------------------------------------------------------------------- + +local test_buy = function(market, balance, item, price, quantity) + if price < 0 or quantity < 1 then return false end + + local sell_market = market.orders_for_items[item].sell_orders + local test_quantity = quantity + local test_balance = balance + local i = 0 + local sell_order = sell_market[#sell_market] + while test_quantity > 0 and sell_order and sell_order.price <= price do + local quantity_to_buy = math.min(sell_order.quantity, test_quantity) + test_quantity = test_quantity - quantity_to_buy + test_balance = test_balance - quantity_to_buy*sell_order.price + i = i + 1 + sell_order = sell_market[#sell_market-i] + end + local spent = balance - test_balance + test_balance = test_balance - test_quantity*price + if test_balance < 0 then + return false, spent, test_quantity + end + + return true, spent, test_quantity +end + +local add_buy = function(market, account, item, price, quantity) + price = tonumber(price) + quantity = tonumber(quantity) + if not test_buy(market, account.balance, item, price, quantity) then return false end + + local sell_market = market.orders_for_items[item].sell_orders + local sell_order = sell_market[#sell_market] + local current_sell_volume = market.orders_for_items[item].sell_volume + + -- go through existing sell orders that are cheaper than or equal to the price + -- we're wanting to offer, buying them up at the offered price until we run out of + -- sell orders or run out of supply + while quantity > 0 and sell_order and sell_order.price <= price do + local quantity_to_buy = math.min(sell_order.quantity, quantity) + quantity = quantity - quantity_to_buy + local spent = quantity_to_buy*sell_order.price + account.balance = account.balance - spent + sell_order.account.balance = sell_order.account.balance + spent + sell_order.quantity = sell_order.quantity - quantity_to_buy + current_sell_volume = current_sell_volume - quantity_to_buy + add_inventory_to_account(market, account, item, quantity_to_buy) + + if sell_order.account ~= account then + -- don't update the last price if a player is just buying and selling from themselves + market.orders_for_items[item].last_price = sell_order.price + end + + log_sale(item, quantity_to_buy, sell_order.price, account, sell_order.account) + + -- Sell order completely used up, remove it + if sell_order.quantity == 0 then + table.remove(sell_market, #sell_market) + end + + -- get the next sell order + sell_order = sell_market[#sell_market] + end + market.orders_for_items[item].sell_volume = current_sell_volume + + if quantity > 0 then + local buy_market = market.orders_for_items[item].buy_orders + -- create the order for the remainder and insert it into order arrays + local order = {account=account, price=price, quantity=quantity, timestamp=minetest.get_gametime()} + account.balance = account.balance - quantity*price -- buy orders are pre-paid + table.bininsert(buy_market, order, buy_comp) + market.orders_for_items[item].buy_volume = market.orders_for_items[item].buy_volume + quantity + end + + return true +end + +local cancel_buy = function(market, item, order) + local account = order.account + local quantity = order.quantity + local price = order.price + + local buy_market = market.orders_for_items[item].buy_orders + market.orders_for_items[item].buy_volume = market.orders_for_items[item].buy_volume - quantity + + remove_order(order, buy_market) + + account.balance = account.balance + price*quantity +end + +----------------------------------------------------------------------------------------------------------- + +local remove_market_item = function(market, item) + local marketitem = market.orders_for_items[item] + if marketitem then + local buy_orders = marketitem.buy_orders + while #buy_orders > 0 do + market:cancel_buy(item, buy_orders[#buy_orders]) + end + local sell_orders = marketitem.sell_orders + while #sell_orders > 0 do + market:cancel_sell(item, sell_orders[#sell_orders]) + end + market.orders_for_items[item] = nil + end +end + +minetest.register_chatcommand("market.removeitem", { + params = "marketname item", + privs = {server=true}, + decription = "remove item from market. All existing buys and sells will be cancelled.", + func = function(name, param) + local params = param:split(" ") + if #params ~= 2 then + return + end + local market = commoditymarket.registered_markets[params[1]] + if market == nil then + return + end + remove_market_item(market, params[2]) + end, +}) + +----------------------------------------------------------------------------------------------------------- + +local initialize_market_item = function(orders_for_items, item) + if orders_for_items[item] == nil then + local lists = {} + lists.buy_orders = {} + lists.sell_orders = {} + lists.buy_volume = 0 + lists.sell_volume = 0 + lists.item = item + -- leave last_price nil to indicate it's never been sold before + orders_for_items[item] = lists + end +end + +-- API exposed to the outside world +local add_inventory = function(self, player_name, item, quantity) + return add_inventory_to_account(self, get_account(self, player_name), item, quantity) +end +local remove_inventory = function(self, player_name, item, quantity) + return remove_inventory_from_account(get_account(self, player_name), item, quantity) +end +local sell = function(self, player_name, item, quantity, price) + return add_sell(self, get_account(self, player_name), item, price, quantity) +end +local buy = function(self, player_name, item, quantity, price) + return add_buy(self, get_account(self, player_name), item, price, quantity) +end + +local load_market_data = function(marketname) + local path = minetest.get_worldpath() + local filename = path .. "\\market_"..marketname..".lua" + local file = loadfile(filename) -- returns nil if the file doesn't exist + if file then + return file() + else + return nil + end +end + +local save_market_data = function(market) + local path = minetest.get_worldpath() + local filename = path .. "\\market_"..market.name..".lua" + local file, err = io.open(filename, "w") + if err ~= nil then + minetest.log("error", "[commoditymarket] Could not save market to \"" .. filename .. "\"") + return false + end + local data = {} + data.player_accounts = market.player_accounts + data.orders_for_items = market.orders_for_items + file:write(minetest.serialize(data)) + return true +end + +commoditymarket.register_market = function(market_name, market_def) + assert(not commoditymarket.registered_markets[market_name]) + + market_def.currency_symbol = market_def.currency_symbol or "\u{00A4}" -- defaults to the generic currency symbol ("scarab") + market_def.description = market_def.description or "Market" + market_def.long_description = market_def.long_description or "A market where orders to buy or sell items can be placed and fulfilled." + + -- Reprocess currency table into a form easier for the withdraw code to work with + market_def.currency_ordered = {} + for item, amount in pairs(market_def.currency) do + table.insert(market_def.currency_ordered, {item=item, amount=amount}) + end + table.sort(market_def.currency_ordered, function(currency1, currency2) return currency1.amount > currency2.amount end) + + local new_market = {} + new_market.def = market_def + commoditymarket.registered_markets[market_name] = new_market + + local loaded_data = load_market_data(market_name) + if loaded_data then + new_market.player_accounts = loaded_data.player_accounts + new_market.orders_for_items = loaded_data.orders_for_items + else + new_market.player_accounts = {} + new_market.orders_for_items = {} + end + + -- If there's a list of initial items in the market def, initialize them. allow_item can trump this. + local initial_items = market_def.initial_items + if initial_items then + -- defer until after to ensure that all initial items have been registered, so we can guard against invalid items + minetest.after(0, + function() + for _, item in ipairs(initial_items) do + if minetest.registered_items[item] and + ((not market_def.allow_item) or market_def.allow_item(item)) and + not market_def.currency[item] then + initialize_market_item(new_market.orders_for_items, item) + end + end + end) + end + market_def.initial_items = nil -- don't need this any more + + new_market.name = market_name + + new_market.add_inventory = add_inventory + new_market.remove_inventory = remove_inventory + new_market.sell = sell + new_market.buy = buy + new_market.cancel_sell = cancel_sell + new_market.cancel_buy = cancel_buy + new_market.get_formspec = commoditymarket.get_formspec + new_market.get_account = get_account + new_market.save = save_market_data + + -- save markets on shutdown + minetest.register_on_shutdown(function() new_market:save() end) + + -- and also every ten minutes, to be on the safe side in case Minetest crashes + -- TODO: a more sophisticated approach that checks whether the market data is "dirty" before actually saving + local until_next_save = 600 + minetest.register_globalstep(function(dtime) + until_next_save = until_next_save - dtime + if until_next_save < 0 then + new_market:save() + until_next_save = 600 + end + end) + + ---------------------------------------------------------------------- + -- Detached inventory for adding items into the market + + local inv = minetest.create_detached_inventory("commoditymarket:"..market_name, { + allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) + return 0 + end, + allow_put = function(inv, listname, index, stack, player) + -- Currency items are always allowed + local item = stack:get_name() + if new_market.def.currency[item] then + return stack:get_count() + end + + -- only new tools, no used tools + if stack:get_wear() ~= 0 then + return 0 + end + + --nothing with metadata permitted + local meta = stack:get_meta():to_table() + local fields = meta.fields + local inventory = meta.inventory + if (fields and next(fields)) or (inventory and next(inventory)) then + return 0 + end + + -- If there's no allow_item function defined, allow everything. Otherwise check if the item is allowed + if (not market_def.allow_item) or market_def.allow_item(item) then + local allowed_count = stack:get_count() + + if market_def.inventory_limit then + -- limit additions to the inventory_limit, if there is one + local current_count = 0 + for _, inventory_quantity in pairs(new_market:get_account(player:get_player_name()).inventory) do + current_count = current_count + inventory_quantity + end + allowed_count = math.min(allowed_count, allowed_count + market_def.inventory_limit - (current_count+allowed_count)) + if allowed_count <= 0 then return 0 end + end + + --ensures the item is in the market listing if it wasn't before + initialize_market_item(new_market.orders_for_items, item) + return allowed_count + end + return 0 + end, + allow_take = function(inv, listname, index, stack, player) + return 0 + end, + on_move = function(inv, from_list, from_index, to_list, to_index, count, player) + end, + on_take = function(inv, listname, index, stack, player) + end, + on_put = function(inv, listname, index, stack, player) + if listname == "add" then + local item = stack:get_name() + local count = stack:get_count() + new_market:add_inventory(player:get_player_name(), item, count) + inv:set_list("add", {}) + local name = player:get_player_name() + local formspec = new_market:get_formspec(new_market:get_account(name)) + minetest.show_formspec(name, "commoditymarket:"..market_name..":"..name, formspec) + end + end + }) + inv:set_size("add", 1) +end + +commoditymarket.show_market = function(market_name, player_name) + local market = commoditymarket.registered_markets[market_name] + if market == nil then return end + local formspec = market:get_formspec(market:get_account(player_name)) + minetest.show_formspec(player_name, "commoditymarket:"..market_name..":"..player_name, formspec) +end \ No newline at end of file diff --git a/mod.conf b/mod.conf new file mode 100644 index 0000000..9f6561f --- /dev/null +++ b/mod.conf @@ -0,0 +1 @@ +name = commoditymarket \ No newline at end of file diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..f32acca --- /dev/null +++ b/readme.md @@ -0,0 +1,67 @@ +This mod implements marketplaces where players can post buy and sell offers for various items, allowing for organic market forces to determine the relative values of the resources in a world. + +The basic market interface is the same across all markets and market types, but this mod allows for a variety of different ways that markets can be configured to support different playstyles. Markets can have restrictions on what they will allow to be bought and sold, different types of "currency", and can share a common inventory across multiple locations or can be localized to just one spot at the discretion of the server owner. + +## Currency + +Each market has one or more "currency" items defined that are treated differently from the other items that can be bought and sold there. Currency items are translated into a player's currency balance rather than being bought and sold directly. + +For example, the default market offered by this mod has this currency definition: + + { + ["default:gold_ingot"] = 1000, + ["commoditymarket:gold_coin"] = 1 + } + +When a gold ingot is added to the player's market account it turns into 1000 units of currency. When a gold coin is added it turns into 1 unit of currency. You can't buy and sell gold directly in this market, it is instead the "standard" by which the value of other items is measured. + +There's no reason that all markets in a given world have to use the same currency. Having variety in currency types adds flavour to the world and also introduces opportunities for enterprising traders to make a profit by moneychanging between different marketplaces. + +## Account Inventory + +In addition to tracking a player's currency balance, each player's account has an inventory that serves as a holding area for items that are destined to be sold or that have been bought by the player but not yet retrieved. This inventory is a bit different from the standard Minetest inventory in that it doesn't hold individual item "stacks", allowing for larger quantities of items to be accumulated than would otherwise be practical. If a player needs to buy 20,000 stone bricks for a major construction project then their account's inventory will hold that. + +To prevent abuse of the market inventory as a free storage space, or just to add some unique flavor to a particular market, a limit on the inventory's size can be added. This limit only affects transfers from a player's personal inventory into the market inventory; the limit can be exceeded by incoming items being sold to the player. + +Note that tools cannot be added to the market inventory if they have any wear on them, nor can the market handle items with attached metadata (such as books that have had text added to them). + +## Placing a "Buy" Order + +A buy order is an offer to give a certain amount of currency in exchange for a particular type of item. To place a buy order go to the "Market Orders" tab of the market's interface and select the item from the list of items on the market. If the item isn't listed it may be that the market is simply "unaware" of the item's existence; try placing an example of the item into your personal inventory and if the item is permitted on the market a new entry will be added to Market Orders. + +Enter the quanitity and price you desire and then click the "buy" button to place a buy order. + +If there are already "sell" orders for the item when you place a buy order, some or all of your buy order might be immediately fulfilled provided you are offering a sufficient price. Your purchases will be made at the price that the sell orders have been set to - if you were willing to pay 15 units of currency per item but someone was already offering to sell for 2 units of currency per item, you only pay 2 units for each of that offer's items. + +If there aren't enough compatible sell orders to fulfil your buy order, the remainder will be placed into the market and made available for future sellers to see and fulfil if they agree to your price. Your buy order will immediately deduct the currency required for it from your account's balance, but if you cancel your order you will get that currency back - it's not gone until the order is actually fulfilled. + +Double-click on your order in the orders list to cancel it. + +## Placing a "Sell" Order + +Sell orders are an offer of a certain amount of an item and a price you're willing to accept in exchange for them. They're placed in a similar manner to buy orders, except by clicking the "sell" button instead of the "buy" button. + +If there are already buyers with buy orders that meet or exceed your price, some or all of your sell order may be immediately fulfilled. You'll be paid the price that the buyers are offering rather than the amount you're demanding. + +If any of your sell offer is left unfulfilled, the sell order will be added to the market for future buyers to see. The items for this offer will be immediately taken from your market inventory but if you cancel your order you will get those items back. + +Double-click on your order in the orders list to cancel it. + +## Commands + +This mod has several commands that a server administrator can use: + +* market.removeitem marketname item -- cancels all existing buy and sell orders for an item and removes its entry from the market tab. This is useful if you've changed what items are permitted in a particular market and need to clear out items that are no longer allowed. +* market.show marketname -- opens the market's formspec + +## Registering a market + +The file "default_markets.lua" contains a number of pre-defined markets that provide examples of what's possible with this mod. They can be enabled as-is with game settings and include: + +* King's Market - a basic sort of "commoner's marketplace", only open during the day +* Night Market - the shadier side of commerce, only open during the night +* Trader's Caravan - a type of market that players can build and place themselves, with a small inventory capacity. +* Goblin Exchange - a strange marketplace that uses coal as a currency +* Undermarket - where dark powers make their trades, using Mese as a currency + +All of these except for the Trader's Caravan are intended to be placed in specific locations by server administrators, they have on_dig methods that prevent them from being removed and don't have crafting recipes. \ No newline at end of file diff --git a/screenshot.png b/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..4fa29720e435955b3df4cdba51cc0056a1fce83d GIT binary patch literal 97308 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 z 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 M07*qoM6N<$g82vCJ^%m! literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_crown.png b/textures/commoditymarket_crown.png new file mode 100644 index 0000000000000000000000000000000000000000..2df11488d0f04062d7cf12c329600c50764c2117 GIT binary patch literal 721 zcmV;?0xtcDP)1Mvi)1X5LH(TbnuZ$fP5$DTX)ek@oamREsew@CYa>5Xsj^6A~L!}JlGH*Yi8N@aauWOH(hgXu#64)^b~HlC37`x0~uE8=P9 zGpuf8V|!N}P9rw1@6lURqLvxr8& zzWf(N7~St7)hVV?;udq3mjR!j5XKdn;HZm&U^I>MlvzgOJfLWd;H&`PT|<>!;A@W< zLtW$$92OgsJQ$&vlMDvbRgb9e&^}}9*V{+{t=|!?Uqy$QD4hWr^23PbtNw zpAoVKo8%N{8f^?Fo*@YNXG8Gk5QIfm;Oi38`3K0cA`MC#S{oChb_d()5Vcp(NgHk3 zhy;9HA+E%g1Vg_`v+6BJD1jpMXgm zjdQp{0Rc#E7&+<<;oBiAL(AZhM`1zPj~wYF8hn__82!mLpz6UYnC5Qu;-sj zJ{PYPfKmz+C}mLU2&FWFAQC_XkvAZGbrj3m^Z)Y&m`f}@Wkw;U00000NkvXXu0mjf D7ArXG literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_empty_shelf.png b/textures/commoditymarket_empty_shelf.png new file mode 100644 index 0000000000000000000000000000000000000000..404fc8bef29f4dbdafa62abe8de3ab73ee9f8bdc GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!R)9~4tGt|)wUJVgy>fAsiGij} zyoW}Fvr0#%b#91$ZK7FTh;~VYZbpEXma0^Aj{IYwu6R!u$B>F!spl-28WaQ$9C)L8 z`r-fm+Fr_5uCD^lMn%49+Y~4@yK$qZR6*A&pUteScVb=UX-y4|lM*~0ec`l7ruVl0 z#}g*A%)wKgKXa>iE9-DOb!%0dOeb}F zWf?_Dbx#9_RC~uzyRh)k$oR07ti+VUwEWWS^2)Nxu8Nx0hUPgPz5P9+vV61W&a^0x zi~{~h3_5a)cY-{db<1>+E z{~<18L0wlF{+2k4t7jG_-Zb6&Cgci(!UL&Ot3QA2*;;(%fuKRDSHbz4GP9Q5&(-9) zq4~7hSus1+`>l16;*s~eZZF)n#P8Di$al;-dAsdvzFuUtf2yKswEE)f7oJO=*cx&D bf55#yiKqV=bL2&!ix@mz{an^LB{Ts5S{jKA literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_gold_coins.png b/textures/commoditymarket_gold_coins.png new file mode 100644 index 0000000000000000000000000000000000000000..73f4e83324086be77ea1ae5ceaa272deab59cca4 GIT binary patch literal 1364 zcmZvcX;70_6o!MGkbGYVf(o*WqPA#sU`lHn?cf3hGy(!5meRqo?qX$%E85l;wV)z~ zge3^5sHKXCf?6p^NJt1lR`|MxVqX;!~B%i-3~^J^|S{+B5} zx`Ar&d->xc*fZ4h&*lLMe5STjVhQVOb87=8skcR(!% zQ9f13!L{kf)wH&LF0wz*=3QYzIXRAdSz<*Vf6nbvA(MevFQY zR0yE|1`Un5sieTq!s@edG{|VkqKP?JPZM-E!PH9_83Q!wEw2aZZP3Vp=!ha_!YpV> zt92|>P6{C)0}~ni(1@p21+P(%tN{ippgkXJD+Ns_G_bMuQV_85`fMDT<_;_2c?%3_ zKyU>!TgV~~j*L#`yI~WLoP}(fegIz7!=w&0UC=EC{uOHdWvoXGCOsLA%$AheP2boi zE2K`NkLBeQ9TA15nPN89$i{`)m?WPn;!-R40N0MrnOaH-22qm zafM)3ntV1zo)#XqM95$XB0h2zM$FktBH4_D2d|4g{_Rd5@5+>^!{s(M4&H}8W4Oov zx&K|X{#X9F+@&jBSmg3UF}|g1)&vGlC(vF9;{%-iRnvhrRid8O1MDL60oraB`J%l4 zNpjJ{G?_93^9wOt?3-76!F+Peaw#!unY1UU((kwU*npk;%=n}3b^CsJz`Hi}I3V!% zwBm`tZ5uX!69*M<6Ykaqhip1>t-RxDBtMff`|kyR1)bS`#_2+2$(KLL`-AFS_l9KT z9`W2{-r=vW-&yI` zw0KbK|4B+p=fU#0vgHq}Hnr~EgSHuCd#jT>Uoa$X{Fyo1ZC88P-Yri*ey(`e?Yee` z(+-GllbRP9w33um#e)}A65_T{t6++AJM8-okno^$)$3PMEbYWMsk_asto agUzA@w-$}zaq;`VD?B73xMF?MFaH3|=8~!a literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_moon.png b/textures/commoditymarket_moon.png new file mode 100644 index 0000000000000000000000000000000000000000..73410507e4a8b313bf089410033125627b9fd854 GIT binary patch literal 457 zcmV;)0XF`LP)$P@(Y4N1 z+qjtIF9Wu{>k9&G(Ys;DRp@EgUHFL*C-hG$q=?&kAAaMJ89Cp#G0LW7-fVZx~L}SAl@cXB9av6j(d?*5h?cfGRzQtw9`Zt z7EEE|M;Zna)LcYB-#VwC?VKFT00000NkvXXu0mjfyy&;* literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_search.png b/textures/commoditymarket_search.png new file mode 100644 index 0000000000000000000000000000000000000000..2ba479eedf11b40a6b942e71d5c62c8503dc4dc0 GIT binary patch literal 1290 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD~={fl(*GC&U%V-M)SMjT<-qj{-s= zU>NdfHZZ)BOM?7@85kKE**Libgha(8l+@HUwRH83Oss93+}s1gBa%|mvhs>5sv5ic zCrq3&b^6SC3l=X~wqoU~)oa&n*tB`e*6llX?mlqv$k7uQE?>WK^VaP<_a8id^8Cfi zH*ep)|M2ni*Ka?5{`os6$mA{q1GAQ=i(^Pd+}oL%;kN<=+9IPTY+4bKdn8JWQ72@Z zP?=O&Q|fB&B;Jmn|Nk$PH?rL5&b$5jos@ldzH1vluia5@RKEG|@)=0rPWAEh&hD6n z6Lx#dk$t~&ZR!0^mCawzCG3jGHCuhO>3|f{mD;@0Ras)!R>r-TgKxZu6h= z;z?_Ars_N`^VRzI>5u34%Ba3uTPFqRa4n6h-cs}L^q!i8uKKTD<~ye!;W^)GqqqF> zQ_jK~w<+&RTUM{)WZ9j1x873cL*ntz4DK`Zd8S)A&itiQQC!TrWmZVizUhMdB2qU6 zIeeCR>*eEhOGp3L%LlIw50=y~yxKTr$)CU9xBS|l>H0R`_2%NW(j1ekLw+~LU)cBm zHCwvK3Db33>l7}$>FnJ2?Z349v5D@yxje@>yI%Ke9R9O?NAAWL?pF?CFW364l)O@J zzsuI*R(pQpv_;pNW^MTAd+FQTi{HMmTsx+=woIg*DA3oLaP+~GXGC)|9jlP zZJL1eAwE_A^yy+Ro&M|pI3ZNS8X>+*(8^c9E8vl*aRuk830~GE>8V?HcO_n$vSG!y zTubld?fc@}h0a)b1j|Tj9R6j;+Az6~%iz(;;vW-dUAA1vP+%9pcuS^|?|N7<+j9|y zBP+QAxFS zv&wR|sTIR7kp<$4ztTJIbzF!x{FT(QPbN9v<< z4`x`w9?<{%)Z$6}39$hU4GfRF+|&>3TvFxNQ0%*WbyrcKrybju^;su5U&Mz=3q+K} z=KDDOKiCu#y2{^-BiZ3k#@FB1uO4eS@F#uu`}v>Qk`qoIPCd|Yplf-wa?>i){_Dq* z6ZU=JlweF$-4vO?vPS45r^LbS-%qf_=dPG)(Z6r=L%{}nDaId*ft1=oagGBD4Ihsy tGt`?feQ<|TDnMTCkCZ3pk3hf|aRF}Gr)Sf0W&$%QgQu&X%Q~loCIDQ;3w{6q literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_trade.png b/textures/commoditymarket_trade.png new file mode 100644 index 0000000000000000000000000000000000000000..b6401b03cbd021c180c3d4184143ab2a9196c01d GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbL!S%6Q7E0B&1@Qe2KN)8M3b~6d` zw)b+g2>0=d3h>Q{4o?aV4DhfE_HvEz^N0v=iw^dP3HFK$^V{s(wiKw7yCldjn4x3& z`SbT4z54LyZ^8eCtAN6`o-U3d6>-TD4hOi@EG;A#)|lnh*)clG#ii}w5;Hh??r6(t z4mUr(6@dl^&YV`(IB@*@S+=Lfg&UQ7lz12lE;AZy23)=bG>E~|)z4*}Q$iB}sB}TY literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_under.png b/textures/commoditymarket_under.png new file mode 100644 index 0000000000000000000000000000000000000000..007be317a4cfa1108745d52b09b12f52244f64d0 GIT binary patch literal 1001 zcmV zaB^>EX>4U6ba`-PAZ2)IW&i+q+I>*bt-~+~{AY?c0tSp>9H&X8ZqV^d0;$qUuSh<_ zVRL80_I%voZx8AQ(ub+5VuZLj%}5M0=7A06z$)-eK6rRHC@7AdvotM!3!dUU6@RNa zGx&ZPGamJqiTz_kX=8pKq}lJ!!`>Nc)VSn(??7wjNBNV~QnfkHTj zdgMkZLtNI~=>0~%-|I`>|E}RYO2|YTH^#(t$;geJXY3=8LJ=7crbTry=@v{qEJW`0 zw}e0AKlgC84=;42ZAvY7nwkIr010qNS#tmYE+YT{E+YYWr9XB6000McNliru;|CiL z3>!qS4&ML(02y>eSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00MPML_t(2 z&jkQkZ`?%qo9`QY#>d*;&4#2TDR-qp#qq=gNQietk$B_x_Bm1xsM-Re(2za4Y_e;6 z#-8It;^|M{*41>k@0C`|#q!dlC;*r2WyOT!HrG`#>1oIZW!u$lb892 zpL|RSlBAQ<)1oNqNg2FLBuplmN{~4uX)2EznpZV|u%q*kD1G?k$>T&~mcrTTN$2|Q zdZiQLt+KWRh_Y;^gS7)+M{rvp$<;AZzx9dk=eE#(}Uw!oc!{zP2L1t$k zob_Exzx@0?gxKx}AHCggU!PyyU0*3<%Y^=3tS^82L#qT)D4Ff=&GFG3H=EURwS4{8 zpZj(&d)K~sQ+l32Xat{O%-in8s~Z=2v0mkcA{u2o7D2>=lbRWYX;(fZLQsT+LoRX5 zn;)P4u=#IMmqpvR+gBUIG>j|&`o5L-_p3z8 z?a&!xhdh literal 0 HcmV?d00001 diff --git a/textures/commoditymarket_under_top.png b/textures/commoditymarket_under_top.png new file mode 100644 index 0000000000000000000000000000000000000000..22a1bb109cb2f5253975fd652dd8a46e10e9b997 GIT binary patch literal 759 zcmV-fb`Sz%GAk7Xh_P(!hb$|!*3LPEF^W*v50Dob zq44^8jN^E-dBb_(gJ8ekD>dKWua%k!5Mx~sqL-JKX1j$5P?p5^%axer^?WvVjsTq3 z7>C2y6?xHiy*6eT$0T7-KmG)}-EOscP_t@pZ4kMx)ygOz26hjY0OveS z7`sg?SxgB~3{aFMOS8lAAfz0pAx>$A((~zrBf@!Zt+s)W2>}#Y zGXXI0&hMIr=4qL5mc|i^nr(C3AK$%wUzVkq#DBX6C`M^&r}3;6c;_)8r_-sf?+C`T zl=rK((-JU(h;Sjvnw6ri6Z{JY&fph$>m96Agz^7i@fZ`PQi pD9Wm;8J9wW4$sZyAm`ib<$oYsa9u~c8z%q&002ovPDHLkV1nYxQVRe8 literal 0 HcmV?d00001 diff --git a/textures/license.txt b/textures/license.txt new file mode 100644 index 0000000..7cfdb40 --- /dev/null +++ b/textures/license.txt @@ -0,0 +1,8 @@ +commoditymarket_gold_coins.png - from https://commons.wikimedia.org/wiki/File:Farm-Fresh_coins.png, by FatCow under the CC-BY 3.0 license +commoditymarket_crown.png - from https://commons.wikimedia.org/wiki/File:Farm-Fresh_crown_gold.png by FatCow under the CC-BY 3.0 Unported license +commoditymarket_moon.png - from https://commons.wikimedia.org/wiki/File:Luneta08.svg by Arturo D. Castillo —Zoram.hakaan— under the CC-BY 3.0 Unported license +commoditymarket_goblin.png - cropped from the "goblins" mod, Copyright 2015 by Francisco "FreeLikeGNU" Athens Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) +commoditymarket_empty_shelf.png - from the moreblocks mod's "moreblocks_empty_shelf", under the zlib license by Hugo Locurcio and contributors +commoditymarket_search.png - Copyright © Diego Martínez (kaeza): CC BY-SA 3.0 + +commoditymarket_trade.png, commoditymarket_under.png, and commoditymarket_under_top were created by FaceDeer and released under the CC0 public domain license \ No newline at end of file