From 2e6c271f4016b792cee046f214ec9161a02dcc3d Mon Sep 17 00:00:00 2001 From: Freeman Date: Mon, 27 May 2024 19:58:18 +0200 Subject: [PATCH] emeraldbank mod now focuses only on the bank and the economy API The shops will be separated in another mod --- LICENSE.txt | 14 - README.md | 176 +--- bank.lua | 2 +- commands.lua | 18 +- fancyshop.lua | 1781 -------------------------------- functions.lua | 108 +- income.lua | 2 +- init.lua | 2 - mod.conf | 6 +- settingtypes.txt | 20 - shop.lua | 327 ------ textures/admin_depo.png | Bin 303 -> 0 bytes textures/admin_vend.png | Bin 257 -> 0 bytes textures/copier.png | Bin 227 -> 0 bytes textures/inactive.png | Bin 890 -> 0 bytes textures/player_depo.png | Bin 565 -> 0 bytes textures/player_vend.png | Bin 552 -> 0 bytes textures/player_vend_front.png | Bin 526 -> 0 bytes textures/upgrade_front.png | Bin 556 -> 0 bytes 19 files changed, 12 insertions(+), 2444 deletions(-) delete mode 100644 fancyshop.lua delete mode 100644 shop.lua delete mode 100644 textures/admin_depo.png delete mode 100644 textures/admin_vend.png delete mode 100644 textures/copier.png delete mode 100644 textures/inactive.png delete mode 100644 textures/player_depo.png delete mode 100644 textures/player_vend.png delete mode 100644 textures/player_vend_front.png delete mode 100644 textures/upgrade_front.png diff --git a/LICENSE.txt b/LICENSE.txt index 57e29f8..99f72d4 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -15,20 +15,6 @@ You should have received a copy of the GNU Affero General Public License along with Emeraldbank. If not, see . -Textures License: - -admin_depo.png -admin_vend.png -copier.png -inactive.png -player_depo.png -player_vend_front.png -player_vend.png -upgrade_front.png - -Copyright (c) 2018 ChimneySwift, LadyK under MIT License - - Sounds License: - cash.ogg: diff --git a/README.md b/README.md index d1c7d27..b9f1e2e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -# Emerald Bank and Shops (MineClonia/MineClone2) + +# Emerald Bank and Shops (MineClonia) [![ContentDB](https://content.minetest.net/packages/NathanielFreeman/emeraldbank/shields/downloads/)](https://content.minetest.net/packages/NathanielFreeman/emeraldbank/) @@ -14,7 +15,7 @@ EmeraldBank Mod is [Libre/Free Software](https://www.gnu.org/philosophy/free-sw. Keep your Emeralds in a bank! -Why Emeralds? In MineClonia/MineClone2 the emerald is money to trade with villagers! +Why Emeralds? In MineClonia the emerald is money to trade with villagers! Multiplayer support! @@ -26,151 +27,7 @@ Rightclick on bank open the bank interface, where you can deposit or withdraw yo You can transfer money to other players in Bank interface. -## Shops (Like fancy_vend mod) - -The new shops are based in _fancy_vend_ mod shops - -[Learn more about shops here](https://github.com/ChimneySwift/fancy_vend/blob/master/README.md) - -There are many vendor mods for Minetest, but most have too few options, lack support for automation mods, or are too tedious to set up and maintain. Fancy vendors are entirely self-contained nodes which provide light, trade, display and store items. Fancy vendors are _pipeworks_, _digilines_ and _mcl_awards_ compatible, enabling a variety of automation-based features. - -### Basic configuration - -Each fancy vendor needs 2 nodes of room. If the area you wish to place the vendor doesn't have enough space, due to either a node or a protected area, the node will not be placed. If the vendor has sufficient room, it will place a vendor node in addition to a display node on top. The display node's only purpose is aesthetics, to "contain" the rotating display object. - -Configuring a vendor is as simple as picking up and placing the input and output items into their respective slots as if they were regular inventories (items in these inventories are "ghosts", so don't actually take anything from the player's inventory) and setting the quantities for each item, as shown below: - -![Setting up a vendor](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Setting%20up%20a%20vendor.PNG?raw=true "Setting up a vendor") - -Stocking a vendor is as simple as placing the output item into the vendor's inventory (perhaps using one of the handy inventory movement buttons) as demonstrated below: - -![Stocking a vendor](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Stocking%20a%20vendor.PNG?raw=true "Stocking a vendor") - -After stocking a vendor, you may wish to press the "sort" button, which will combine unfilled stacks and sort the stacks in alphabetical order. - -If the vendor is intended to be used to purchase items, you may wish to set the vendor to a depositor in the vendor settings, this will display the input item in the display case and change the vendor's appearance to make it clear to potential sellers the vendor's purpose. The previous example vendor set to a depositor can be seen below: - -![A player depositor](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/A%20player%20depositor.PNG?raw=true "A player depositor") - -### Buying items -Regular players who can't access a fancy vendor's inventory or configuration will be displayed a purchase screen when they access a vendor. This screen displays vendor information and status, as well as buying options. Unlike many vendor mods, fancy vendors give buyers to buy multiple "lots" at once. Doing this can save a lot of clicking, as the number of input and output items traded is multiplied by this number. - -There is also a button labeled "Fill lots to max" which will pre-load the lots field with the maximum number of lots that the player can purchase from the vendor (which will be either the maximum the player can afford, or the maximum the shop can sell, whichever is smaller). - -An example image of the buyer formspec can be seen below: - -![Buying from a fancy vendor](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Buying%20from%20a%20fancy%20vendor.PNG?raw=true "Buying from a fancy vendor") - -### Advanced settings -Fancy vendors have many additional options which enable sellers to greatly customize vendors. - -![Fancy Vendor settings](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Fancy%20Vendor%20settings.PNG?raw=true "Fancy Vendor settings") - -**Banned Buyers:** -This field is a list of players (separated by commas) who won't be able to purchase from the vendor. This setting might be useful if you wish to stop players buying out your vendor's stock and reselling it for a higher margin. - -**Co-Sellers:** -This field is a list of players (separated by commas) who will be able to access the vendor's inventory. **Please note: Anyone added to the list has full access to the vendor's inventory, however cannot modify the vendor settings nor dig the vendor.** - -**Buy/sell worn tools:** -These options allow for the seller to stop the vendor from purchasing or selling worn tools. A message will display on the buyer formspec if one of these options is disabled. - -**Inactive force:** -While the seller is reconfiguring a vendor, or in the process of creating a shop, the owner might wish for the vendor to be inactive so players cannot purchase from it, in which case they can enable this option. - -**Autosort:** -If this option is enabled, the vendor's inventory will automatically sort when the vendor formspec is closed by someone who can access the inventory. - -**Logs:** -The logs formspec displays the 40 most-recent transactions. While only people who can modify the vendor are allowed to access this formspec, these logs are kept in metadata which could be easily read client-side. - -**Geminio Wand:** -This tool can be used to easily copy vendor settings from one vendor to another. Simply right click a vendor with it to copy the settings to the tool, and left click any other vendor to set that vendor's settings. **The Geminio Wand will not copy input and output items nor quantities.** You must be able to modify the settings of the vendor to do this. You can craft one with the following recipe: - -![Crafting a Geminio Wand](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Crafting%20a%20Geminio%20Wand.PNG?raw=true "Crafting a Geminio Wand") - -### Automation -Fancy Vendors are digilines and pipeworks compatible, enabling the creation of highly automated shops. - -#### Pipeworks -Fancy vendors connect to pipeworks devices from the bottom, rear and sides. When the optional pipeworks dependancy is satisfied, a number of pipeworks-specific options will also appear in the settings menu: - -![Pipeworks Settings](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Pipeworks%20Settings.PNG?raw=true "Pipeworks Settings") - -**Split incoming stacks:** -This option enabled incoming stacks from pipeworks tubes to be split if only some of the stack can be accepted. - -**Eject incoming currency:** -When this option is enabled, the input items will be sent out of the **bottom** of the fancy vendor instead of being added to the vendor's internal inventory. - -**Accept output only:** -When this option is enabled, incoming items which aren't the output item will be rejected and not added to the vendor's inventory. - -#### Hoppers -Fancy vendors are MCL hopper compatible. Also they have been tested to work with [TenPlus1's hopper mod](https://github.com/tenplus1/hopper) however should work with all hopper mods and forks. Hoppers can filter into vendors from the sides, however cannot be drained from the bottom as hoppers are protected and Fancy Vendors are locked. However, the shop owner is given the `Eject incoming currency` option which operates on hoppers similarly to how it does on pipeworks, by manually adding incoming currency to the inventory of a hopper placed below the vendor (or into the vendor's inventory if the hopper is full). Due to API limitations, `Accept output only` is not hopper-compatible and `Split incoming stacks` is not necessary. - -#### Digilines -Fancy vendors are digilines compatible. When the digilines dependency is satisfied, an option to set the digiline channel will appear in settings. If this channel is set, every purchase will result in the following table being sent over that channel: - -```lua -local msg = { - buyer = player:get_player_name(), -- Purchaser's playername - lots = lots, -- Number of lots purchased - settings = settings, -- The settings table -} -``` - -The default settings table can be seen below: - -```lua -local settings_default = { - input_item = "", - output_item = "", - input_item_qty = 1, - output_item_qty = 1, - admin_vendor = false, - depositor = false, - currency_eject = false, - accept_output_only = false, - split_incoming_stacks = false, - inactive_force = false, - accept_worn_input = true, - accept_worn_output = true, - digiline_channel = "", - co_sellers = "", - banned_buyers = "", -} -``` - -Fancy Vendors and Fancy Vendor Display Nodes conduct digiline signals also. - -This feature could theoretically make rewards-based shops feasable. - -### Out Of Stock Mail -This mod integrates with [Athous Mail Mod](https://github.com/mt-mods/mail) to alert shop owners when their shops lose stock. -When a vendor empties, the mod sends mail telling them that their vendor is out of stock. In the event another mod empties, the previous message will be edited so as to avoid flooding their inbox if they have many vendors. - -### Upgrading vendors - -**NOTE:** If you wish to simply run this mod in parallel with existing vendor mods, simply load this mod (no configuration required) - -Many servers already have vendor mods in place. Fancy Vend makes it easier for servers to upgrade with it's unique upgrading system. Fancy Vend will replace vendors from the supported vendor mods (money, vendor, easyvend and currency) with upgrade nodes. Upgrade nodes allow for sellers to empty the old node's inventory (if applicable), dig the upgrade node (which will drop a regular vendor) and set up a new shop. if a user tried to place an upgrade node, the stack is turned into a stack of regular vendors. - -Since upgrade functionality can be achieved without the old mod loaded, the server owner must add the old vendor mod's name to `minetest.conf` as follows: - -`fancy_vend_old_vendor_mods = money` - -If there are multiple vendor mods the the owner wishes to enable this functionality on, they can add several mods to the list, separating each mod name with commas as follows: - -`fancy_vend_old_vendor_mods = emeraldbank,money,vendor,easyvend` - -If the owner wishes to keep the mod loaded, but still replace vendor nodes, the will need to add the mod to both `minetest.conf` and `mod.conf`. - -Vendor upgrade: - -![Vendor upgrade](https://github.com/ChimneySwift/fancy_vend/blob/master/screenshots/Vendor%20upgrade.PNG?raw=true "Vendor upgrade") - -## User Commands +## Commands User /pay command. Pay emeralds to another player: @@ -184,7 +41,6 @@ User /money command. Show you the emeralds in your bank account in the chat. /money ``` -## Administration EmeraldBank mod also include a variety of tools for server administrators. **Admin Emerald command** @@ -198,31 +54,9 @@ Add `` emeralds to `` account. If num is 0 return emeralds in player account. -**Temporarily disabling vendors:** -Any player with the disable_vendor privilege can run - -``` -/disable_all_vendors -``` - -to force all vendors into an inactive state. Please use this if you find a dangerous bug and are waiting for it to be fixed. - -**Admin vendors:** -Admin vendors perform the same role as their regular counterparts, however they do so with no stock or inventory requirements, simply creating and destroying items as players purchase. - -Since incorrectly configured admin vendors could be easily used to duplicate items, the `admin_vendor` privilege is required for the option to switch a vendor to one appears. If the user is ever revoked this privilege, all admin vendors they own will be forced into an inactive state until the privilege is re-granted or the vendor is set to a player vendor. - -**Modifying vendors:** -If a user has the `protection_bypass` privilege, they will be able to access the full extent of the vendor as if they were the owner, including inventory and settings. - -**Server and client load:** -Fancy vend uses only one infrequent abm to refresh vendor objects in the event of a clearobjects. No other vendor updating is done unless a player purchases from the vendor or adjusts settings. - -Note: Some clients using mobile and/or older devices, including PCs, may experience additional lag if many fancy vendors are used in a small space, however not to an extent greater than the majority of shops where players use itemframes or pedestals to achieve the same functionality as the fancy vendor's display. - ## More Info -This mod is for [MineClonia](https://content.minetest.net/packages/ryvnf/mineclonia/) or [MineClone2](https://content.minetest.net/packages/Wuzzy/mineclone2/) Games, dont work with MTG +This mod is for [MineClonia](https://content.minetest.net/packages/ryvnf/mineclonia/) or [VoxeLibre](https://content.minetest.net/packages/Wuzzy/mineclone2/) Games, dont work with MTG Feel free to contribute, send MR/PR or issues. diff --git a/bank.lua b/bank.lua index cef1041..570cc7e 100644 --- a/bank.lua +++ b/bank.lua @@ -1,6 +1,6 @@ --- Copyright (C) 2021, 2023 Ale +-- Copyright (C) 2021, 2024 Sandro del Toro -- This file is part of Emeraldbank Minetest Mod. diff --git a/commands.lua b/commands.lua index e70978d..5d87e8a 100644 --- a/commands.lua +++ b/commands.lua @@ -1,6 +1,6 @@ --- Copyright (C) 2021, 2023 Ale +-- Copyright (C) 2021, 2024 Sandro del Toro -- This file is part of Emeraldbank Minetest Mod. @@ -96,19 +96,3 @@ core.register_chatcommand("emeralds", { end end }) - --- experimental upgrade command -core.register_chatcommand("upgrade", { - description = S("Admin Command! Upgrade a shop"), - privs = {server=true}, - func = function(name, param) - local player = core.get_player_by_name(name) - local pos = player:get_pos() - local nodename = core.get_node(pos).name - if nodename == "emeraldbank:shop" or nodename == "emeraldbank:shop_empty" then - emeraldbank.upgrade_shop(pos) - return true - end - return false - end -}) diff --git a/fancyshop.lua b/fancyshop.lua deleted file mode 100644 index 449c934..0000000 --- a/fancyshop.lua +++ /dev/null @@ -1,1781 +0,0 @@ - - --- Copyright (C) 2021, 2024 Sandro del Toro - --- This file is part of Emeraldbank Minetest Mod. - --- Emeraldbank is free software: you can redistribute it and/or modify --- it under the terms of the GNU Affero General Public License as --- published by the Free Software Foundation, either version 3 of the --- License, or (at your option) any later version. - --- Emeraldbank is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU Affero General Public License for more details. - --- You should have received a copy of the GNU Affero General Public License --- along with Emeraldbank. If not, see . - - --- This code was forked from fancy_vend mod, adapted to MineClone2. - - -local S = core.get_translator(core.get_current_modname()) - -local settings = minetest.settings - -local shopcraft = core.settings:get_bool("emeraldbank.shop_craft") or true - -local formspec_prefix = "emeraldbank:shop_formspec" - -local shop_timer = emeraldbank.shop_timer - -local display_node = (settings:get("fancy_vend.display_node") or "mcl_core:glass") -local max_logs = (tonumber(settings:get("fancy_vend.log_max")) or 40) -local autorotate_speed = (tonumber(settings:get("fancy_vend.autorotate_speed")) or 1) -local no_alerts = settings:get_bool("fancy_vend.no_alerts") - -local drop_vendor = "fancy_vend:player_vendor" - --- Register a copy of the display node with no drops to make players separating the obsidian glass with something like a piston a non-issue. -local display_node_def = table.copy(minetest.registered_nodes[display_node]) -display_node_def.drop = "" -display_node_def.pointable = false -display_node_def.groups.not_in_creative_inventory = 1 -display_node_def.description = S("Fancy Vendor Display Node (you hacker you!)") -display_node_def.on_blast = function() return nil end -if pipeworks then - display_node_def.digiline = { - wire = { - rules = pipeworks.digilines_rules - } - } -end -minetest.register_node(":fancy_vend:display_node", display_node_def) - --- Craftitem to display when vendor is inactive (Use just image for this???) -minetest.register_craftitem(":fancy_vend:inactive",{inventory_image = "inactive.png",}) - -minetest.register_privilege("disable_vendor", S("Enables the user to set all vendors to inactive.")) - -local function bts(bool) - if bool == false then - return "false" - elseif bool == true then - return "true" - else - return bool - end -end - -local function stb(str) - if str == "false" then - return false - elseif str == "true" then - return true - else - return str - end -end - -local modstorage = minetest.get_mod_storage() - -if modstorage:get_string("all_inactive_force") == "" then - modstorage:set_string("all_inactive_force", "false") -end - -local all_inactive_force = stb(modstorage:get_string("all_inactive_force")) - -minetest.register_chatcommand("disable_all_vendors", { - description = S("Toggle vendor inactivity."), - privs = {disable_vendor=true}, - func = function(name, param) - if all_inactive_force then - all_inactive_force = false - modstorage:set_string("all_inactive_force", "false") - else - all_inactive_force = true - modstorage:set_string("all_inactive_force", "true") - end - end, -}) - -table.length = function(table) - local length - for i in pairs(table) do - length = length + 1 - end - return length -end - -local function send_message(pos, channel, msg) - if channel and channel ~= "" then - digilines.receptor_send(pos, digilines.rules.default, channel, msg) - end -end - --- Awards -if minetest.get_modpath("awards") then - awards.register_achievement("fancy_vend:getting_fancy",{ - title = S("Getting Fancy"), - description = S("Craft a fancy vendor."), - trigger = { - type = "craft", - item = drop_vendor, - target = 1, - }, - icon = "player_vend.png^mcl_core_emerald.png", - }) - - -- awards.register_achievement("fancy_vend:wizard",{ - -- title = "You're a Wizard", - -- description = S("Craft a copy tool."), - -- trigger = { - -- type = "craft", - -- item = "fancy_vend:copy_tool", - -- target = 1, - -- }, - -- icon = "copier.png", - -- }) - - awards.register_achievement("fancy_vend:trader",{ - title = "Trader", - description = "Configure a depositor.", - icon = "player_depo.png^mcl_core_emerald.png", - }) - awards.register_achievement("fancy_vend:seller",{ - title = "Seller", - description = "Configure a vendor.", - icon = "player_vend.png^mcl_core_emerald.png", - }) - awards.register_achievement("fancy_vend:shop_keeper",{ - title = "Shop Keeper", - description = "Configure 10 vendors or depositors.", - icon = "player_vend.png^mcl_core_emerald.png", - secret = true, - }) - awards.register_achievement("fancy_vend:merchant",{ - title = "Merchant", - description = "Configure 25 vendors or depositors.", - icon = "player_vend.png^mcl_core_emerald.png", - secret = true, - }) - awards.register_achievement("fancy_vend:super_merchant",{ - title = "Super Merchant", - description = "Configure 100 vendors or depositors. How do you even have this much stuff to sell?", - icon = "player_vend.png^mcl_core_emerald.png", - secret = true, - }) - awards.register_achievement("fancy_vend:god_merchant",{ - title = "God Merchant", - description = "Configure 9001 vendors or depositors. Ok wot.", - icon = "player_vend.png^mcl_core_emerald.png", - secret = true, -- Oi. Cheater. - }) -end - -local tmp = {} - -minetest.register_entity(":fancy_vend:display_item",{ - hp_max = 1, - visual = "wielditem", - visual_size = {x = 0.33, y = 0.33}, - collisionbox = {0, 0, 0, 0, 0, 0}, - physical = false, - textures = {"air"}, - on_activate = function(self, staticdata) - if tmp.nodename ~= nil and tmp.texture ~= nil then - self.nodename = tmp.nodename - tmp.nodename = nil - self.texture = tmp.texture - tmp.texture = nil - else - if staticdata ~= nil and staticdata ~= "" then - local data = staticdata:split(';') - if data and data[1] and data[2] then - self.nodename = data[1] - self.texture = data[2] - end - end - end - if self.texture ~= nil then - self.object:set_properties({textures = {self.texture}}) - end - self.object:set_properties({automatic_rotate = autorotate_speed}) - end, - get_staticdata = function(self) - if self.nodename ~= nil and self.texture ~= nil then - return self.nodename .. ';' .. self.texture - end - return "" - end, -}) - -local function remove_item(pos) - local objs = nil - objs = minetest.get_objects_inside_radius(pos, .5) - if objs then - for _, obj in ipairs(objs) do - if obj and obj:get_luaentity() and obj:get_luaentity().name == "fancy_vend:display_item" then - obj:remove() - end - end - end -end - -local function update_item(pos, node) - pos.y = pos.y + 1 - remove_item(pos) - if minetest.get_node(pos).name ~= "fancy_vend:display_node" then - -- minetest.log("warning", "[Emeraldbank]: Placing display item inside "..minetest.get_node(pos).name.." at "..minetest.pos_to_string(pos).." is not permitted, aborting") - -- return - minetest.set_node(pos, {name = "fancy_vend:display_node"}) - end - pos.y = pos.y - 1 - local meta = minetest.get_meta(pos) - if meta:get_string("item") ~= "" then - pos.y = pos.y + (12 / 16 + 0.11) - tmp.nodename = node.name - tmp.texture = ItemStack(meta:get_string("item")):get_name() - local e = minetest.add_entity(pos,"fancy_vend:display_item") - pos.y = pos.y - (12 / 16 + 0.11) - end -end - --- LBM to refresh entities after clearobjects -minetest.register_lbm({ - label = "Refresh vendor display", - name = ":fancy_vend:display_refresh", - nodenames = {"fancy_vend:display_node"}, - run_at_every_load = true, - action = function(pos, node) - if not next(minetest.get_objects_inside_radius(pos, 0.5)) then - pos.y = pos.y - 1 - update_item(pos, node) - end - end -}) - -local function set_vendor_settings(pos, SettingsDef) - local meta = minetest.get_meta(pos) - meta:set_string("settings", minetest.serialize(SettingsDef)) -end - -emeraldbank.set_vendor_settings = set_vendor_settings - -local function reset_vendor_settings(pos) - local settings_default = { - input_item = "mcl_core:emerald", -- Don't change this unless you plan on setting this up to add this item to the inventories - output_item = "", -- Don't change this unless you plan on setting this up to add this item to the inventories - input_item_qty = 1, - output_item_qty = 1, - admin_vendor = false, - depositor = false, - currency_eject = false, - accept_output_only = false, - split_incoming_stacks = false, - inactive_force = false, - accept_worn_input = true, - accept_worn_output = true, - digiline_channel = "", - co_sellers = "", - banned_buyers = "", - auto_sort = false, - } - set_vendor_settings(pos, settings_default) - return settings_default -end - -emeraldbank.reset_vendor_settings = reset_vendor_settings - -local function get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local settings = minetest.deserialize(meta:get_string("settings")) - if not settings then - return reset_vendor_settings(pos) - else - -- If settings added by newer versions of fancy_vend are nil then send defaults - if settings.auto_sort == nil then - settings.auto_sort = false - end - - -- Sanitatize number values (backwards compat) - settings.input_item_qty = (type(settings.input_item_qty) == "number" and math.abs(settings.input_item_qty) or 1) - settings.output_item_qty = (type(settings.output_item_qty) == "number" and math.abs(settings.output_item_qty) or 1) - return settings - end -end - -emeraldbank.get_vendor_settings = get_vendor_settings - -local function can_buy_from_vendor(pos, player) - local settings = get_vendor_settings(pos) - local banned_buyers = string.split((settings.banned_buyers or ""),",") - for i in pairs(banned_buyers) do - if banned_buyers[i] == player:get_player_name() then - return false - end - end - return true -end - -local function can_modify_vendor(pos, player) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local is_owner = false - if meta:get_string("owner") == player:get_player_name() or minetest.check_player_privs(player, {protection_bypass=true}) then - is_owner = true - end - return is_owner -end - -local function can_dig_vendor(pos, player) - local meta = minetest.get_meta(pos); - local inv = meta:get_inventory() - return inv:is_empty("main") and can_modify_vendor(pos, player) -end - -local function can_access_vendor_inv(player, pos) - local meta = minetest.get_meta(pos) - if minetest.check_player_privs(player, {protection_bypass=true}) or meta:get_string("owner") == player:get_player_name() then return true end - local settings = get_vendor_settings(pos) - local co_sellers = string.split(settings.co_sellers,",") - for i in pairs(co_sellers) do - if co_sellers[i] == player:get_player_name() then - return true - end - end - return false -end - --- Inventory helpers: - --- Function to sort inventory (Taken from technic_chests) -local function sort_inventory(inv) - local inlist = inv:get_list("main") - local typecnt = {} - local typekeys = {} - for _, st in ipairs(inlist) do - if not st:is_empty() then - local n = st:get_name() - local w = st:get_wear() - local m = st:get_metadata() - local k = string.format("%s %05d %s", n, w, m) - if not typecnt[k] then - typecnt[k] = { - name = n, - wear = w, - metadata = m, - stack_max = st:get_stack_max(), - count = 0, - } - table.insert(typekeys, k) - end - typecnt[k].count = typecnt[k].count + st:get_count() - end - end - table.sort(typekeys) - local outlist = {} - for _, k in ipairs(typekeys) do - local tc = typecnt[k] - while tc.count > 0 do - local c = math.min(tc.count, tc.stack_max) - table.insert(outlist, ItemStack({ - name = tc.name, - wear = tc.wear, - metadata = tc.metadata, - count = c, - })) - tc.count = tc.count - c - end - end - if #outlist > #inlist then return end - while #outlist < #inlist do - table.insert(outlist, ItemStack(nil)) - end - inv:set_list("main", outlist) -end - -local function free_slots(inv, listname, itemname, quantity) - local size = inv:get_size(listname) - local free = 0 - for i=1,size do - local stack = inv:get_stack(listname, i) - if stack:is_empty() or stack:get_free_space() > 0 then - if stack:is_empty() then - free = free + ItemStack(itemname):get_stack_max() - elseif stack:get_name() == itemname then - free = free + stack:get_free_space() - end - end - end - if free < quantity then - return false - else - return true - end -end - -local function inv_insert(inv, listname, itemstack, quantity, from_table, pos, input_eject) - local stackmax = itemstack:get_stack_max() - local name = itemstack:get_name() - local stacks = {} - local remaining_quantity = quantity - - -- Add the full stacks to the list - while remaining_quantity > stackmax do - table.insert(stacks, {name = name, count = stackmax}) - remaining_quantity = remaining_quantity - stackmax - end - -- Add the remaining stack to the list - table.insert(stacks, {name = name, count = remaining_quantity}) - - -- If tool add wears ignores if from_table = nil (eg, due to vendor beig admin vendor) - if minetest.registered_tools[name] and from_table then - for i in pairs(stacks) do - local from_item_table = from_table[i].item:to_table() - stacks[i].wear = from_item_table.wear - end - end - - -- if has metadata add metadata - if from_table then - for i in pairs(stacks) do - if not i then return end -- crash - local from_item_table = from_table[i].item:to_table() - if from_item_table.name == name then - if from_item_table.metadata then - stacks[i].metadata = from_item_table.metadata -- Apparently some mods *cough* digtron *cough* do use deprecated metadata strings - end - if from_item_table.meta then - stacks[i].meta = from_item_table.meta -- Most mods use metadata tables which is the correct method but ok - end - end - end - end - - -- Add to inventory or eject to pipeworks/hoppers (whichever is applicable) - local output_tube_connected = false - local output_hopper_connected = false - if input_eject and pos then - local pos_under = vector.new(pos) - pos_under.y = pos_under.y - 1 - local node_under = minetest.get_node(pos_under) - if minetest.get_item_group(node_under.name, "tubedevice") > 0 then - output_tube_connected = true - end - if node_under.name == "hopper:hopper" or node_under.name == "hopper:hopper_side" then - output_hopper_connected = true - end - end - for i in pairs(stacks) do - if output_tube_connected then - pipeworks.tube_inject_item(pos, pos, vector.new(0, -1, 0), stacks[i], minetest.get_meta(pos):get_string("owner")) - else - local leftovers = ItemStack(stacks[i]) - if output_hopper_connected then - local pos_under = {x = pos.x, y = pos.y-1, z = pos.z} - local hopper_inv = minetest.get_meta(pos_under):get_inventory() - leftovers = hopper_inv:add_item("main", leftovers) - end - if not leftovers:is_empty() then - inv:add_item(listname, leftovers) - end - end - end -end - -local function inv_remove(inv, listname, remove_table, itemstring, quantity) - local count = 0 - for i in pairs(remove_table) do - count = count + remove_table[i].item:get_count() - inv:set_stack(listname, remove_table[i].id, nil) - end - -- Add back items if too many were taken - if count > quantity then - inv:add_item(listname, ItemStack({name = itemstring, count = count - quantity})) - end -end - -local function inv_contains_items(inv, listname, itemstring, quantity, ignore_wear) - local minimum = quantity - local get_items = {} - local count = 0 - - for i=1,inv:get_size(listname) do - local stack = inv:get_stack(listname, i) - if stack:get_name() == itemstring then - if ignore_wear or (not minetest.registered_tools[itemstring] or stack:get_wear() == 0) then - count = count + stack:get_count() - table.insert(get_items, {id=i, item=stack}) - if count >= minimum then - return true, get_items - end - end - end - end - return false -end - -local function get_vendor_status(pos) - local settings = get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - if all_inactive_force then - return false, "all_inactive_force" - elseif settings.input_item == "" or settings.output_item == "" then - return false, "unconfigured" - elseif settings.inactive_force then - return false, "inactive_force" - elseif not minetest.check_player_privs(meta:get_string("owner"), {admin_shop=true}) and settings.admin_vendor == true then - return false, "no_privs" - elseif not inv_contains_items(inv, "main", settings.output_item, settings.output_item_qty, settings.accept_worn_output) and not settings.admin_vendor then - return false, "no_output" - elseif not free_slots(inv, "main", settings.input_item, settings.input_item_qty) and not settings.admin_vendor then - return false, "no_room" - else - return true - end -end - -local function make_inactive_string(errorcode) - local status_str = "" - if errorcode == "unconfigured" then - status_str = status_str.." (unconfigured)" - elseif errorcode == "inactive_force" then - status_str = status_str.." (forced)" - elseif errorcode == "no_output" then - status_str = status_str.." (out of stock)" - elseif errorcode == "no_room" then - status_str = status_str.." (no room)" - elseif errorcode == "no_privs" then - status_str = status_str.." (seller has insufficient privilages)" - elseif errorcode == "all_inactive_force" then - status_str = status_str.." (all vendors disabled temporarily by admin)" - end - return status_str -end - --- Various email and tell mod support - --- This function takes the position of a vendor and alerts the owner if it has just been emptied -local email_loaded, tell_loaded, mail_loaded = minetest.get_modpath("email"), minetest.get_modpath("tell"), minetest.get_modpath("mail") -local function alert_owner_if_empty(pos) - if no_alerts then return end - - local meta = minetest.get_meta(pos) - local settings = get_vendor_settings(pos) - local owner = meta:get_string("owner") - local alerted = stb(meta:get_string("alerted") or "false") -- check - local status, errorcode = get_vendor_status(pos) - - -- Message to send - local stock_msg = "Your vendor trading "..settings.input_item_qty.." "..minetest.registered_items[settings.input_item].description.." for "..settings.output_item_qty.." "..minetest.registered_items[settings.output_item].description.." at position "..minetest.pos_to_string(pos, 0).." has just run out of stock." - - if not alerted and not status and errorcode == "no_output" then - - if mail_loaded and mail.send then - - local success, error = mail.send({ - from = "Emerald Shop", - to = owner, - --cc = "carbon, copy", - --bcc = "blind, carbon, copy", - subject = S("Out of Stock!"), - body = stock_msg - }) - - -- if "success" is false the error parameter will contain a message - - meta:set_string("alerted", "true") - - return - - -- Rubenwardy's Email Mod: https://github.com/rubenwardy/email - elseif email_loaded then - email.send_mail("Fancy Vend", owner, stock_msg) - - meta:set_string("alerted", "true") - - return - - elseif tell_loaded then - -- octacians tell mod https://github.com/octacian/tell - tell.add(owner, "Fancy Vend", stock_msg) - - meta:set_string("alerted", "true") - - return - end - end -end - -local function run_inv_checks(pos, player, lots) - local settings = get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local player_inv = player:get_inventory() - local player_emeralds = emeraldbank.get_emeralds(player:get_player_name()) - - local ct = {} - - -- Get input and output quantities after multiplying by lot count - local output_qty = settings.output_item_qty * lots - local input_qty = settings.input_item_qty * lots - - -- Perform inventory checks - ct.player_has, ct.player_item_table = inv_contains_items(player_inv, "main", settings.input_item, input_qty, settings.accept_worn_input) - if settings.input_item == "mcl_core:emerald" then - ct.player_has = player_emeralds >= input_qty - end - ct.vendor_has, ct.vendor_item_table = inv_contains_items(inv, "main", settings.output_item, output_qty, settings.accept_worn_output) - ct.player_fits = free_slots(player_inv, "main", settings.output_item, output_qty) - ct.vendor_fits = free_slots(inv, "main", settings.input_item, input_qty) - - if ct.player_has and ct.vendor_has and ct.player_fits and ct.vendor_fits then - ct.overall = true - else - ct.overall = false - end - - return ct -end - -local function get_max_lots(pos, player) - local max = 0 - - while run_inv_checks(pos, player, max).overall do - max = max + 1 - end - - return max -end - -local function make_purchase(pos, player, lots) - if not can_buy_from_vendor(pos, player) then - return false, "You cannot purchase from this vendor" - end - - local settings = get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local player_inv = player:get_inventory() - local name = player:get_player_name() - local player_emeralds = emeraldbank.get_emeralds(name) - local status, errorcode = get_vendor_status(pos) - - -- Double check settings, vendors which were incorrectly set up before this bug fix won't matter anymore - settings.input_item_qty = math.abs(settings.input_item_qty) - settings.output_item_qty = math.abs(settings.output_item_qty) - - if status then - -- Get input and output quantities after multiplying by lot count - local output_qty = settings.output_item_qty * lots - local input_qty = settings.input_item_qty * lots - - -- Perform inventory checks - local ct = run_inv_checks(pos, player, lots) - - if ct.player_has then - if ct.player_fits then - if settings.admin_vendor then - minetest.log("action", name.." trades "..settings.input_item_qty.." "..settings.input_item.." for "..settings.output_item_qty.." "..settings.output_item.." using vendor at "..minetest.pos_to_string(pos)) - - if settings.input_item == "mcl_core:emerald" then - emeraldbank.add_emeralds(player, - input_qty) - else - inv_remove(player_inv, "main", ct.player_item_table, settings.input_item, input_qty) - end - inv_insert(player_inv, "main", ItemStack(settings.output_item), output_qty, nil) - - if minetest.get_modpath("digilines") then - send_message(pos, settings.digiline_channel, msg) - end - - return true, "Trade successful" - elseif ct.vendor_has then - if ct.vendor_fits then - minetest.log("action", name.." trades "..settings.input_item_qty.." "..settings.input_item.." for "..settings.output_item_qty.." "..settings.output_item.." using vendor at "..minetest.pos_to_string(pos)) - - inv_remove(inv, "main", ct.vendor_item_table, settings.output_item, output_qty) - if settings.input_item == "mcl_core:emerald" then - emeraldbank.add_emeralds(player, - input_qty) - else - inv_remove(player_inv, "main", ct.player_item_table, settings.input_item, input_qty) - end - inv_insert(player_inv, "main", ItemStack(settings.output_item), output_qty, ct.vendor_item_table) - inv_insert(inv, "main", ItemStack(settings.input_item), input_qty, ct.player_item_table, pos, (minetest.get_modpath("pipeworks") and settings.currency_eject)) - - -- Run mail mod checks - alert_owner_if_empty(pos) - - return true, S("Trade successful") - else - return false, S("Vendor has insufficient space") - end - else - return false, S("Vendor has insufficient resources") - end - else - return false, S("You have insufficient space") - end - else - return false, S("You have insufficient funds") - end - else - return false, S("Vendor is inactive")..make_inactive_string(errorcode) - end -end - - -local function get_vendor_buyer_fs(pos, player, lots) - local base = "size[9,9]".. - "label[0,0;"..S("Owner wants:").."]".. - "label[0,1.25;"..S("for:").."]".. - "button[0,2.7;2,1;buy;"..S("Buy").."]".. - "label[2.8,2.9;"..S("lots.").."]".. - "button[0,3.6;2,1;lot_fill;"..S("Fill lots to max.").."]".. - - "list[current_player;main;0,5.05;9,3;9]".. - mcl_formspec.get_itemslot_bg(0,5.05,9,3).. - "list[current_player;main;0,8.19;9,1;]".. - mcl_formspec.get_itemslot_bg(0,8.19,9,1).. - "listring[current_player;main]".. - - "field_close_on_enter[lot_count;false]" - - -- Add dynamic elements - local settings = get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local status, errorcode = get_vendor_status(pos) - - local itemstuff = - "item_image_button[0,0.4;1,1;"..settings.input_item..";ignore;]".. - "label[0.9,0.6;"..settings.input_item_qty.." "..minetest.registered_items[settings.input_item].description.."]".. - "item_image_button[0,1.7;1,1;"..settings.output_item..";ignore;]".. - "label[0.9,1.9;"..settings.output_item_qty.." "..minetest.registered_items[settings.output_item].description.."]" - - local status_str - if status then - status_str = S("active") - else - status_str = S("inactive")..make_inactive_string(errorcode) - end - local status_fs = - "label[4,0.4;"..S("Vendor status: ")..status_str.."]".. - "label[4,0.8;"..S("Message: ")..meta:get_string("message").."]".. - "label[4,0;"..S("Vendor owned by: ")..meta:get_string("owner").."]" - - local setting_specific = "" - if not settings.accept_worn_input then - setting_specific = setting_specific.."label[4,1.6;"..S("Vendor will not accept worn tools.").."]" - end - if not settings.accept_worn_output then - setting_specific = setting_specific.."label[4,1.2;"..S("Vendor will not sell worn tools.").."]" - end - - local fields = "field[2.2,3.2;1,0.6;lot_count;;"..(lots or 1).."]" - - local fs = base..itemstuff..status_fs..setting_specific..fields - return fs -end - -local function get_vendor_settings_fs(pos) - local base = "size[9,10]".. - "label[2.8,0.5;"..S("Input item").."]".. - "label[6.8,0.5;"..S("Output item").."]".. - "image[0,1.3;1,1;debug_btn.png]".. - "item_image_button[0,2.3;1,1;mcl_books:book;button_log;]".. - "item_image_button[0,3.3;1,1;mcl_core:gold_ingot;button_buy;]".. - - "list[current_player;main;0,5;9,3;9]".. - mcl_formspec.get_itemslot_bg(0,5,9,3).. - "list[current_player;main;0,8.24;9,1;]".. - mcl_formspec.get_itemslot_bg(0,8.24,9,1).. - "listring[current_player;main]".. - - "button_exit[0,9.2;1,1;btn_exit;"..S("Done").."]" - - -- Add dynamic elements - local pos_str = pos.x..","..pos.y..","..pos.z - local settings = get_vendor_settings(pos) - - if settings.admin_vendor then - base = base.."item_image[0,0.3;1,1;mcl_chests:chest]" - else - base = base.."item_image_button[0,0.3;1,1;mcl_chests:chest;button_inv;]" - end - - local inv = - "list[nodemeta:"..pos_str..";wanted_item;1,0.3;1,1;]".. - mcl_formspec.get_itemslot_bg(1,0.3,1,1).. - "list[nodemeta:"..pos_str..";given_item;5,0.3;1,1;]".. - mcl_formspec.get_itemslot_bg(5,0.3,1,1).. - "listring[nodemeta:"..pos_str..";wanted_item]".. - "listring[nodemeta:"..pos_str..";given_item]" - - local fields = - "field[2.2,0.8;1,0.6;input_item_qty;;"..settings.input_item_qty.."]".. - "field[6.2,0.8;1,0.6;output_item_qty;;"..settings.output_item_qty.."]".. - "field[1.3,4.1;2.66,1;co_sellers;"..S("Co-Sellers:")..";"..settings.co_sellers.."]".. - "field[3.86,4.1;2.66,1;banned_buyers;"..S("Banned Buyers:")..";"..settings.banned_buyers.."]".. - "field_close_on_enter[input_item_qty;false]".. - "field_close_on_enter[output_item_qty;false]".. - "field_close_on_enter[co_sellers;false]".. - "field_close_on_enter[banned_buyers;false]" - - local checkboxes = - "checkbox[1,2.2;inactive_force;"..S("Force vendor into an inactive state.")..";"..bts(settings.inactive_force).."]".. - "checkbox[1,2.6;depositor;"..S("Set this vendor to a Depositor.")..";"..bts(settings.depositor).."]".. - "checkbox[1,3.0;accept_worn_output;"..S("Sell worn tools.")..";"..bts(settings.accept_worn_output).."]".. - "checkbox[5,3.0;accept_worn_input;"..S("Buy worn tools.")..";"..bts(settings.accept_worn_input).."]".. - "checkbox[5,2.6;auto_sort;"..S("Automatically sort inventory.")..";"..bts(settings.auto_sort).."]" - - -- Admin vendor checkbox only if owner is admin - local meta = minetest.get_meta(pos) - if minetest.check_player_privs(meta:get_string("owner"), {admin_shop=true}) or settings.admin_vendor then - checkboxes = checkboxes.. - "checkbox[5,2.2;admin_vendor;"..S("Set vendor to an admin vendor.")..";"..bts(settings.admin_vendor).."]" - end - - - -- Optional dependancy specific elements - if minetest.get_modpath("pipeworks") or minetest.get_modpath("hopper") then - checkboxes = checkboxes.. - "checkbox[1,1.7;currency_eject;"..S("Eject incoming currency.")..";"..bts(settings.currency_eject).."]" - if minetest.get_modpath("pipeworks") then - checkboxes = checkboxes.. - "checkbox[5,1.3;accept_output_only;"..S("Accept for-sale item only.")..";"..bts(settings.accept_output_only).."]".. - "checkbox[1,1.3;split_incoming_stacks;"..S("Split incoming stacks.")..";"..bts(settings.split_incoming_stacks).."]" - end - end - - if minetest.get_modpath("digilines") then - fields = fields.. - "field[6.41,4.1;2.66,1;digiline_channel;"..S("Digiline Channel:")..";"..settings.digiline_channel.."]".. - "field_close_on_enter[digiline_channel;false]" - end - - local fs = base..inv..fields..checkboxes - return fs -end - -local function get_vendor_default_fs(pos, player) - local base = "size[16,11]".. - "item_image[0,0.3;1,1;mcl_chests:chest]".. - - "list[current_player;main;4,6.6;9,3;9]".. - mcl_formspec.get_itemslot_bg(4,6.6,9,3).. - "list[current_player;main;4,9.75;9,1;]".. - mcl_formspec.get_itemslot_bg(4,9.75,9,1).. - "listring[current_player;main]".. - - "button[1,6.85;3,1;inv_tovendor;"..S("All To Vendor").."]".. - "button[13,6.85;3,1;inv_fromvendor;"..S("All From Vendor").."]".. - "button[1,8.08;3,1;inv_output_tovendor;"..S("Output To Vendor").."]".. - "button[13,8.08;3,1;inv_input_fromvendor;"..S("Input From Vendor").."]".. - "button[1,9.31;3,1;sort;"..S("Sort Inventory").."]".. - "button_exit[0,10;1,1;btn_exit;"..S("Done").."]" - - -- Add dynamic elements - local pos_str = pos.x..","..pos.y..","..pos.z - local inv_lists = - "list[nodemeta:"..pos_str..";main;1,0.3;15,6;]".. - mcl_formspec.get_itemslot_bg(1,0.3,15,6).. - "listring[nodemeta:"..pos_str..";main]" - - local settings_btn = "" - if can_modify_vendor(pos, player) then - settings_btn = - "image_button[0,1.3;1,1;debug_btn.png;button_settings;]".. - "item_image_button[0,2.3;1,1;mcl_books:book;button_log;]".. - "item_image_button[0,3.3;1,1;mcl_core:gold_ingot;button_buy;]" - else - settings_btn = - "image[0,1.3;1,1;debug_btn.png]".. - "item_image[0,2.3;1,1;mcl_books:book]".. - "item_image[0,3.3;1,1;mcl_core:gold_ingot;button_buy;]" - end - - local fs = base..inv_lists..settings_btn - return fs -end - - -local function get_vendor_log_fs(pos) - local base = "size[9,9]".. - "image_button[0,1.3;1,1;debug_btn.png;button_settings;]".. - "item_image[0,2.3;1,1;mcl_books:book]".. - "item_image_button[0,3.3;1,1;mcl_core:gold_ingot;button_buy;]".. - "button_exit[0,8;1,1;btn_exit;"..S("Done").."]" - - -- Add dynamic elements - local meta = minetest.get_meta(pos) - local logs = minetest.deserialize(meta:get_string("log")) - - local settings = get_vendor_settings(pos) - if settings.admin_vendor then - base = base.."item_image[0,0.3;1,1;mcl_chests:chest]" - else - base = base.."item_image_button[0,0.3;1,1;mcl_chests:chest;button_inv;]" - end - - if not logs then logs = {S("Error loading logs"),} end - local logs_tl = - "textlist[1,0.5;7.8,8.6;logs;"..table.concat(logs, ",").."]".. - "label[1,0;Showing (up to "..max_logs..") recent log entries:]" - - local fs = base..logs_tl - return fs -end - -local function show_buyer_formspec(player, pos) - minetest.show_formspec(player:get_player_name(), "fancy_vend:buyer;"..minetest.pos_to_string(pos), get_vendor_buyer_fs(pos, player, nil)) -end - -local function show_vendor_formspec(player, pos) - local settings = get_vendor_settings(pos) - if can_access_vendor_inv(player, pos) then - local status, errorcode = get_vendor_status(pos) - if ((not status and errorcode == "unconfigured") and can_modify_vendor(pos, player)) or settings.admin_vendor then - minetest.show_formspec(player:get_player_name(), "fancy_vend:settings;"..minetest.pos_to_string(pos), get_vendor_settings_fs(pos)) - else - minetest.show_formspec(player:get_player_name(), "fancy_vend:default;"..minetest.pos_to_string(pos), get_vendor_default_fs(pos, player)) - end - else - show_buyer_formspec(player, pos) - end -end - -local function swap_vendor(pos, vendor_type) - local node = minetest.get_node(pos) - node.name = vendor_type - minetest.swap_node(pos, node) -end - -local function get_correct_vendor(settings) - if settings.admin_vendor then - if settings.depositor then - return "fancy_vend:admin_depo" - else - return "fancy_vend:admin_vendor" - end - else - if settings.depositor then - return "fancy_vend:player_depo" - else - return "fancy_vend:player_vendor" - end - end -end - -local function is_vendor(name) - local vendor_names = { - "fancy_vend:player_vendor", - "fancy_vend:player_depo", - "fancy_vend:admin_vendor", - "fancy_vend:admin_depo", - } - for i,n in ipairs(vendor_names) do - if name == n then - return true - end - end - return false -end - - -local function refresh_vendor(pos) - local node = minetest.get_node(pos) - if node.name:split(":")[1] ~= "fancy_vend" then - return false, "not a vendor" - end - - local settings = get_vendor_settings(pos) - local meta = minetest.get_meta(pos) - local status, errorcode = get_vendor_status(pos) - local correct_vendor = get_correct_vendor(settings) - - if status or errorcode ~= "no_output" then - meta:set_string("alerted", "false") - end - - if status then - meta:set_string("infotext", (settings.admin_vendor and "Admin" or "Player").." Vendor trading "..settings.input_item_qty.." "..minetest.registered_items[settings.input_item].description.." for "..settings.output_item_qty.." "..minetest.registered_items[settings.output_item].description.." (owned by " .. meta:get_string("owner") .. ")") - - if meta:get_string("configured") == "" then - meta:set_string("configured", "true") - if minetest.get_modpath("awards") then - local name = meta:get_string("owner") - local data = awards.player(name) - - -- Ensure fancy_vend_configure table is in data - if not data.fancy_vend_configure then - data.fancy_vend_configure = {} - end - - awards.increment_item_counter(data, "fancy_vend_configure", correct_vendor) - - total_item_count = 0 - - -- for k, v in pairs(data.fancy_vend_configure) do - -- total_item_count = total_item_count + v - -- end - - if awards.get_item_count(data, "fancy_vend_configure", "fancy_vend:player_vendor") >= 1 then - awards.unlock(name, "fancy_vend:seller") - end - if awards.get_item_count(data, "fancy_vend_configure", "fancy_vend:player_depo") >= 1 then - awards.unlock(name, "fancy_vend:trader") - end - if total_item_count >= 10 then - awards.unlock(name, "fancy_vend:shop_keeper") - end - if total_item_count >= 25 then - awards.unlock(name, "fancy_vend:merchant") - end - if total_item_count >= 100 then - awards.unlock(name, "fancy_vend:super_merchant") - end - if total_item_count >= 9001 then - awards.unlock(name, "fancy_vend:god_merchant") - end - end - end - - if settings.depositor then - if meta:get_string("item") ~= settings.input_item then - meta:set_string("item", settings.input_item) - update_item(pos, node) - end - else - if meta:get_string("item") ~= settings.output_item then - meta:set_string("item", settings.output_item) - update_item(pos, node) - end - end - else - meta:set_string("infotext", "Inactive "..(settings.admin_vendor and "Admin" or "Player").." Vendor"..make_inactive_string(errorcode).." (owned by " .. meta:get_string("owner") .. ")") - if meta:get_string("item") ~= "fancy_vend:inactive" then - meta:set_string("item", "fancy_vend:inactive") - update_item(pos, node) - end - - if not alerted and not status and errorcode == "no_room" then - minetest.chat_send_player(meta:get_string("owner"), "[Fancy_Vend]: Error with vendor at "..minetest.pos_to_string(pos, 0)..": does not have room for payment.") - meta:set_string("alerted", "true") - end - end - - if correct_vendor ~= node.name then - swap_vendor(pos, correct_vendor) - end -end - -emeraldbank.refresh_vendor = refresh_vendor - -local function move_inv(frominv, toinv, filter) - for i, v in ipairs(frominv:get_list("main") or {}) do - if v:get_name() == filter or not filter then - if toinv:room_for_item("main", v) then - local leftover = toinv:add_item("main", v) - - frominv:remove_item("main", v) - - if leftover - and not leftover:is_empty() then - frominv:add_item("main", v) - end - end - end - end -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - local name = formname:split(":")[1] - if name ~= "fancy_vend" then return end - local formtype = formname:split(":")[2] - formtype = formtype:split(";")[1] - local pos = minetest.string_to_pos(formname:split(";")[2]) - if not pos then return end - - local node = minetest.get_node(pos) - if not is_vendor(node.name) then return end - - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local player_inv = player:get_inventory() - local settings = get_vendor_settings(pos) - - -- Handle settings changes - if can_modify_vendor(pos, player) then - for i in pairs(fields) do - if stb(fields[i]) ~= settings[i] then - settings[i] = stb(fields[i]) - end - end - - -- Check number-only fields contain only numbers - if not tonumber(settings.input_item_qty) then - settings.input_item_qty = 1 - else - settings.input_item_qty = math.floor(math.abs(tonumber(settings.input_item_qty))) - end - if not tonumber(settings.output_item_qty) then - settings.output_item_qty = 1 - else - settings.output_item_qty = math.floor(math.abs(tonumber(settings.output_item_qty))) - end - - -- Check item quantities aren't too high (which could lead to additional processing for no reason), if so, set it to the maximum the player inventory can handle - if ItemStack(settings.output_item):get_stack_max() * player_inv:get_size("main") < settings.output_item_qty then - settings.output_item_qty = ItemStack(settings.output_item):get_stack_max() * player_inv:get_size("main") - end - - if ItemStack(settings.input_item):get_stack_max() * player_inv:get_size("main") < settings.input_item_qty then - settings.input_item_qty = ItemStack(settings.input_item):get_stack_max() * player_inv:get_size("main") - end - - -- Admin vendor priv check - if not minetest.check_player_privs(meta:get_string("owner"), {admin_shop=true}) and fields.admin_vendor == "true" then - settings.admin_vendor = false - end - - set_vendor_settings(pos, settings) - refresh_vendor(pos) - end - - if fields.quit then - if can_access_vendor_inv(player, pos) and settings.auto_sort then - sort_inventory(inv) - end - return true - end - - if fields.sort and can_access_vendor_inv(player, pos) then - sort_inventory(inv) - end - - if fields.buy then - local lots = math.floor(tonumber(fields.lot_count) or 1) - -- prevent negative numbers - lots = math.max(lots, 1) - local success, message = make_purchase(pos, player, lots) - if success then - -- Add to vendor logs - local logs = minetest.deserialize(meta:get_string("log")) - for i in pairs(logs) do - if i >= max_logs then - table.remove(logs, 1) - end - end - table.insert(logs, "Player "..player:get_player_name().." purchased "..lots.." lots from this vendor.") - meta:set_string("log", minetest.serialize(logs)) - - -- Send digiline message if applicable - if minetest.get_modpath("digilines") then - local msg = { - buyer = player:get_player_name(), - lots = lots, - settings = settings, - } - send_message(pos, settings.digiline_channel, msg) - end - end - -- Set message and refresh vendor - if message then - meta:set_string("message", message) - end - refresh_vendor(pos) - elseif fields.lot_fill then - minetest.show_formspec(player:get_player_name(), "fancy_vend:buyer;"..minetest.pos_to_string(pos), get_vendor_buyer_fs(pos, player, get_max_lots(pos, player))) - return true - end - - if can_access_vendor_inv(player, pos) then - if fields.inv_tovendor then - minetest.log("action", player:get_player_name().." moves inventory contents to vendor at "..minetest.pos_to_string(pos)) - move_inv(player_inv, inv, nil) - refresh_vendor(pos) - elseif fields.inv_output_tovendor then - minetest.log("action", player:get_player_name().." moves output items in inventory to vendor at "..minetest.pos_to_string(pos)) - move_inv(player_inv, inv, settings.output_item) - refresh_vendor(pos) - elseif fields.inv_fromvendor then - minetest.log("action", player:get_player_name().." moves inventory contents from vendor at "..minetest.pos_to_string(pos)) - move_inv(inv, player_inv, nil) - refresh_vendor(pos) - elseif fields.inv_input_fromvendor then - minetest.log("action", player:get_player_name().." moves input items from vendor at "..minetest.pos_to_string(pos)) - move_inv(inv, player_inv, settings.input_item) - refresh_vendor(pos) - end - end - - -- Handle page changes - if fields.button_log then - minetest.show_formspec(player:get_player_name(), "fancy_vend:log;"..minetest.pos_to_string(pos), get_vendor_log_fs(pos)) - return - elseif fields.button_settings then - minetest.show_formspec(player:get_player_name(), "fancy_vend:settings;"..minetest.pos_to_string(pos), get_vendor_settings_fs(pos)) - return - elseif fields.button_inv then - minetest.show_formspec(player:get_player_name(), "fancy_vend:default;"..minetest.pos_to_string(pos), get_vendor_default_fs(pos, player)) - return - elseif fields.button_buy then - minetest.show_formspec(player:get_player_name(), "fancy_vend:buyer;"..minetest.pos_to_string(pos), get_vendor_buyer_fs(pos, player, (tonumber(fields.lot_count) or 1))) - return - end - - -- Update formspec - if formtype == "log" then - minetest.show_formspec(player:get_player_name(), "fancy_vend:log;"..minetest.pos_to_string(pos), get_vendor_log_fs(pos, player)) - elseif formtype == "settings" then - minetest.show_formspec(player:get_player_name(), "fancy_vend:settings;"..minetest.pos_to_string(pos), get_vendor_settings_fs(pos, player)) - elseif formtype == "default" then - minetest.show_formspec(player:get_player_name(), "fancy_vend:default;"..minetest.pos_to_string(pos), get_vendor_default_fs(pos, player)) - elseif formtype == "buyer" then - minetest.show_formspec(player:get_player_name(), "fancy_vend:buyer;"..minetest.pos_to_string(pos), get_vendor_buyer_fs(pos, player, (tonumber(fields.lot_count) or 1))) - end -end) - -local vendor_template = { - description = S("Vending Machine"), - legacy_facedir_simple = true, - --paramtype2 = "facedir", - groups = {choppy=2, oddly_breakable_by_hand=2, tubedevice=1, tubedevice_receiver=1, axey=1, handy=1}, - _mcl_blast_resistance = 5, - _mcl_hardness = 0.8, - selection_box = { - type = "fixed", - fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5}, - }, - is_ground_content = false, - light_source = 8, - sounds = mcl_sounds.node_sound_wood_defaults(), - drop = drop_vendor, - on_construct = function(pos) - local meta = minetest.get_meta(pos) - meta:set_string("infotext", S("Unconfigured Player Vendor")) - meta:set_string("message", S("Vendor initialized")) - meta:set_string("owner", "") - local inv = meta:get_inventory() - inv:set_size("main", 15*6) - inv:set_size("wanted_item", 1*1) - inv:add_item("wanted_item", {name = "mcl_core:emerald"}) - inv:set_size("given_item", 1*1) - reset_vendor_settings(pos) - meta:set_string("log", "") - end, - can_dig = can_dig_vendor, - on_place = function(itemstack, placer, pointed_thing) - if pointed_thing.type ~= "node" then return end - local pointed_node_pos = minetest.get_pointed_thing_position(pointed_thing, false) - local pointed_node = minetest.get_node(pointed_node_pos) - if minetest.registered_nodes[pointed_node.name].buildable_to then - pointed_thing.above = pointed_node_pos - end - -- Set variables for access later (for various checks, etc.) - local name = placer:get_player_name() - local above_node_pos = table.copy(pointed_thing.above) - above_node_pos.y = above_node_pos.y + 1 - local above_node = minetest.get_node(above_node_pos).name - - -- If node above is air or the display node, and it is not protected, attempt to place the vendor. If vendor sucessfully places, place display node above, otherwise alert the user - if (minetest.registered_nodes[above_node].buildable_to or above_node == "fancy_vend:display_node") and not minetest.is_protected(above_node_pos, name) then - local itemstack, success = minetest.item_place(itemstack, placer, pointed_thing, nil) - if above_node ~= "fancy_vend:display_node" and success then - minetest.set_node(above_node_pos, minetest.registered_nodes["fancy_vend:display_node"]) - end - -- Set owner - local meta = minetest.get_meta(pointed_thing.above) - meta:set_string("owner", placer:get_player_name() or "") - - -- Set default meta - meta:set_string("log", minetest.serialize({"Vendor placed by "..placer:get_player_name(),})) - reset_vendor_settings(pointed_thing.above) - refresh_vendor(pointed_thing.above) - else - minetest.chat_send_player(name, "Vendors require 2 nodes of space.") - end - - if minetest.get_modpath("pipeworks") then - pipeworks.after_place(pointed_thing.above) - end - - return itemstack - end, - after_place_node = function(pos, placer, itemstack) - core.get_node_timer(pos):start(shop_timer) - end, - on_timer = function(pos, elapsed) - core.get_node_timer(pos):start(shop_timer) - emeraldbank.get_stonks(pos) - end, - on_dig = function(pos, node, digger) - -- Set variables for access later (for various checks, etc.) - local name = digger:get_player_name() - local above_node_pos = table.copy(pos) - above_node_pos.y = above_node_pos.y + 1 - - -- abandon if player shouldn't be able to dig node - local can_dig = can_dig_vendor(pos, digger) - if not can_dig then return end - - -- Try remove display node, if the whole node is able to be removed by the player, remove the display node and continue to remove vendor, if it doesn't exist and vendor can be dug continue to remove vendor. - local success - if minetest.get_node(above_node_pos).name == "fancy_vend:display_node" then - if not minetest.is_protected(above_node_pos, name) and not minetest.is_protected(pos, name) then - minetest.remove_node(above_node_pos) - remove_item(above_node_pos) - success = true - else - success = false - end - else - if not minetest.is_protected(pos, name) then - success = true - else - success = false - end - end - - -- If failed to remove display node, don't remove vendor. since protection for whole vendor was checked at display removal, protection need not be re-checked - if success then - minetest.remove_node(pos) - --minetest.handle_node_drops(pos, {drop_vendor}, digger) - minetest.add_item(pos, drop_vendor) - if minetest.get_modpath("pipeworks") then - pipeworks.after_dig(pos) - end - end - end, - tube = { - input_inventory = "main", - connect_sides = {left = 1, right = 1, back = 1, bottom = 1}, - insert_object = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local remaining = inv:add_item("main", stack) - refresh_vendor(pos) - return remaining - end, - can_insert = function(pos, node, stack, direction) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - local settings = get_vendor_settings(pos) - if settings.split_stacks then - stack = stack:peek_item(1) - end - if settings.accept_output_only then - if stack:get_name() ~= settings.output_item then - return false - end - end - return inv:room_for_item("main", stack) - end, - }, - allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - if (not can_access_vendor_inv(player, pos)) or to_list == "wanted_item" or to_list == "given_item" then - return 0 - end - return count - end, - allow_metadata_inventory_put = function(pos, listname, index, stack, player) - if not can_access_vendor_inv(player, pos) then - return 0 - end - if listname == "wanted_item" or listname == "given_item" then - local inv = minetest.get_meta(pos):get_inventory() - inv:set_stack(listname, index, ItemStack(stack:get_name())) - local settings = get_vendor_settings(pos) - if listname == "wanted_item" then - settings.input_item = stack:get_name() - elseif listname == "given_item" then - settings.output_item = stack:get_name() - end - set_vendor_settings(pos, settings) - return 0 - end - return stack:get_count() - end, - allow_metadata_inventory_take = function(pos, listname, index, stack, player) - if not can_access_vendor_inv(player, pos) then - return 0 - end - if listname == "wanted_item" or listname == "given_item" then - local inv = minetest.get_meta(pos):get_inventory() - local fake_stack = inv:get_stack(listname, index) - fake_stack:take_item(stack:get_count()) - inv:set_stack(listname, index, fake_stack) - local settings = get_vendor_settings(pos) - if listname == "wanted_item" then - settings.input_item = "" - elseif listname == "given_item" then - settings.output_item = "" - end - set_vendor_settings(pos, settings) - return 0 - end - return stack:get_count() - end, - on_rightclick = function(pos, node, clicker) - node = minetest.get_node(pos) - if node.name == "fancy_vend:display_node" then - pos.y = pos.y - 1 - end - show_vendor_formspec(clicker, pos) - core.get_node_timer(pos):start(shop_timer) - end, - on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - minetest.log("action", player:get_player_name().." moves stuff in vendor at "..minetest.pos_to_string(pos)) - refresh_vendor(pos) - end, - on_metadata_inventory_put = function(pos, listname, index, stack, player) - minetest.log("action", player:get_player_name().." moves "..stack:get_name().." to vendor at "..minetest.pos_to_string(pos)) - refresh_vendor(pos) - end, - on_metadata_inventory_take = function(pos, listname, index, stack, player) - minetest.log("action", player:get_player_name().." takes "..stack:get_name().." from vendor at "..minetest.pos_to_string(pos)) - refresh_vendor(pos) - end, - on_blast = function() - -- TNT immunity - return nil - end, -} - -if pipeworks then - vendor_template.digiline = { - receptor = {}, - effector = { - action = function() end - }, - wire = { - rules = pipeworks.digilines_rules - }, - } -end - -local player_vendor = table.copy(vendor_template) -player_vendor.tiles = { - "player_vend.png", "player_vend.png", - "player_vend.png^mcl_core_emerald.png", -} - -local player_depo = table.copy(vendor_template) -player_depo.tiles = { - "player_depo.png", "player_depo.png", - "player_depo.png^mcl_core_emerald.png", -} -player_depo.on_timer = function(pos, elapsed) - core.get_node_timer(pos):start(shop_timer) -end -player_depo.groups.not_in_creative_inventory = 1 - -local admin_vendor = table.copy(vendor_template) -admin_vendor.tiles = { - "admin_vend.png", "admin_vend.png", - "admin_vend.png^mcl_core_emerald.png", -} -admin_vendor.groups.not_in_creative_inventory = 1 - -local admin_depo = table.copy(vendor_template) -admin_depo.tiles = { - "admin_depo.png", "admin_depo.png", - "admin_depo.png^mcl_core_emerald.png", -} -admin_depo.groups.not_in_creative_inventory = 1 - -minetest.register_node(":fancy_vend:player_vendor", player_vendor) -minetest.register_node(":fancy_vend:player_depo", player_depo) -minetest.register_node(":fancy_vend:admin_vendor", admin_vendor) -minetest.register_node(":fancy_vend:admin_depo", admin_depo) - -if shopcraft then - minetest.register_craft({ - output = "fancy_vend:player_vendor", - recipe = { - { "", display_node, ""}, - { "mesecons:redstone", "mcl_core:emerald", "mesecons:redstone"}, - { "","mcl_chests:chest",""}, - } - }) -end - --- Hopper support -if minetest.get_modpath("hopper") then - hopper:add_container({ - {"side", "fancy_vend:player_vendor", "main"} - }) - - hopper:add_container({ - {"side", "fancy_vend:player_depo", "main"} - }) -end - - ---------------- --- Copy Tool -- ---------------- - -local function get_vendor_pos_and_settings(pointed_thing) - if pointed_thing.type ~= "node" then return false end - local pos = minetest.get_pointed_thing_position(pointed_thing, false) - local node = minetest.get_node(pos) - if node.name == "fancy_vend:display_node" then - pos.y = pos.y - 1 - node = minetest.get_node(pos) - end - if not is_vendor(node.name) then return false end - - local settings = get_vendor_settings(pos) - - return pos, settings -end - ---minetest.register_alias("fancy_vend:copy_tool", "mcl_core:emerald") - -minetest.register_tool(":fancy_vend:copy_tool",{ - inventory_image = "copier.png", - description = S("Geminio Wand (For copying vendor settings, right click to save settings, left click to set settings.)"), - stack_max = 1, - on_place = function(itemstack, placer, pointed_thing) - local pos, settings = get_vendor_pos_and_settings(pointed_thing) - if not pos then return end - - local meta = itemstack:get_meta() - meta:set_string("settings", minetest.serialize(settings)) - - minetest.chat_send_player(placer:get_player_name(), "Settings saved.") - - return itemstack - end, - on_use = function(itemstack, user, pointed_thing) - local pos, current_settings = get_vendor_pos_and_settings(pointed_thing) - if not pos then return end - - local meta = itemstack:get_meta() - local node_meta = minetest.get_meta(pos) - local new_settings = minetest.deserialize(meta:get_string("settings")) - if not new_settings then - minetest.chat_send_player(user:get_player_name(), "No settings to set with. Right-click first on the vendor you want to copy settings from.") - return - end - - if can_modify_vendor(pos, user) then - -- Admin vendor priv check - if not minetest.check_player_privs(node_meta:get_string("owner"), {admin_shop=true}) and new_settings.admin_vendor == true then - settings.admin_vendor = false - end - - new_settings.input_item = current_settings.input_item - new_settings.input_item_qty = current_settings.input_item_qty - new_settings.output_item = current_settings.output_item - new_settings.output_item_qty = current_settings.output_item_qty - - -- Admin vendor priv check - if not minetest.check_player_privs(node_meta:get_string("owner"), {admin_shop=true}) and new_settings.admin_vendor then - new_settings.admin_vendor = current_settings.admin_vendor - end - - set_vendor_settings(pos, new_settings) - refresh_vendor(pos) - minetest.chat_send_player(user:get_player_name(), "Settings set.") - else - minetest.chat_send_player(user:get_player_name(), "You cannot modify this vendor.") - end - end, -}) - -minetest.register_craft({ - output = "fancy_vend:copy_tool", - recipe = { - {"mcl_core:stick","", "" }, - {"", "mcl_core:obsidian","" }, - {"", "", "mcl_core:emerald"}, - } -}) - -minetest.register_craft({ - output = "fancy_vend:copy_tool", - recipe = { - {"", "", "mcl_core:stick"}, - {"", "mcl_core:obsidian","" }, - {"mcl_core:emerald", "", "" }, - } -}) - - ---------------------------- --- Vendor Upgrade System -- ---------------------------- - -local old_vendor_mods = string.split((minetest.settings:get("fancy_vend_old_vendor_mods") or "emeraldbank"), ",") -local old_vendor_mods_table = {} - -for i in pairs(old_vendor_mods) do - old_vendor_mods_table[old_vendor_mods[i]] = true -end - -local base_upgrade_template = { - description = S("Shop Upgrade (Try and place to upgrade)"), - legacy_facedir_simple = true, - --paramtype2 = "facedir", - groups = {choppy=2, oddly_breakable_by_hand=2, not_in_creative_inventory=1, axey=1, handy=1}, - _mcl_blast_resistance = 5, - _mcl_hardness = 0.8, - is_ground_content = false, - light_source = 8, - sounds = mcl_sounds.node_sound_wood_defaults(), - drop = drop_vendor, - tiles = { - "player_vend.png^mcl_core_emerald.png", - "player_vend.png^mcl_core_emerald.png", - "upgrade_front.png", - }, - on_place = function(itemstack, placer, pointed_thing) - return ItemStack(drop_vendor.." "..itemstack:get_count()) - end, - allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) - local meta = minetest.get_meta(pos) - if player:get_player_name() ~= meta:get_string("owner") then return 0 end - return count - end, - allow_metadata_inventory_put = function(pos, listname, index, stack, player) - local meta = minetest.get_meta(pos) - if player:get_player_name() ~= meta:get_string("owner") then return 0 end - return stack:get_count() - end, - allow_metadata_inventory_take = function(pos, listname, index, stack, player) - local meta = minetest.get_meta(pos) - if player:get_player_name() ~= meta:get_string("owner") then return 0 end - return stack:get_count() - end, - on_blast = function() - return nil - end, -} - -local clear_craft_vendors = {} - -if old_vendor_mods_table["emeraldbank"] then - local emeraldbank_template = table.copy(base_upgrade_template) - emeraldbank_template.can_dig = function(pos, player) - local pname = player:get_player_name() - local is_admin = core.check_player_privs(pname, {admin_shop=true}) - local meta = core.get_meta(pos) - local owner = meta:get_string("owner") - local inv = meta:get_inventory() - return inv:is_empty("stock") and (pname == owner or is_admin) - end - emeraldbank_template.on_rightclick = function(pos, node, clicker, itemstack) - local meta = core.get_meta(pos) - local nodename = core.get_node(pos).name - local owner = meta:get_string("owner") - local pname = clicker:get_player_name() - core.get_node_timer(pos):start(shop_timer) - emeraldbank.get_stonks(pos) - core.show_formspec(pname, formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, clicker)) - end - emeraldbank_template.on_timer = function(pos, elapsed) - core.get_node_timer(pos):start(shop_timer) - emeraldbank.get_stonks(pos) - end - emeraldbank_template.on_blast = function() - return nil - end - minetest.override_item("emeraldbank:shop", emeraldbank_template) - table.insert(clear_craft_vendors, "emeraldbank:shop") - minetest.override_item("emeraldbank:shop_empty", emeraldbank_template) - table.insert(clear_craft_vendors, "emeraldbank:shop_empty") -end - -if old_vendor_mods_table["currency"] then - local currency_template = table.copy(base_upgrade_template) - - currency_template.can_dig = function(pos, player) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:is_empty("stock") and inv:is_empty("customers_gave") and inv:is_empty("owner_wants") and inv:is_empty("owner_gives") and (meta:get_string("owner") == player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true})) - end - currency_template.on_rightclick = function(pos, node, clicker, itemstack) - local meta = minetest.get_meta(pos) - local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z - if clicker:get_player_name() == meta:get_string("owner") then - minetest.show_formspec(clicker:get_player_name(),"fancy_vend:currency_shop_formspec", - "size[8,9.5]".. - "label[0,0;" .. "Customers gave:" .. "]".. - "list["..list_name..";customers_gave;0,0.5;3,2;]".. - "label[0,2.5;" .. "Your stock:" .. "]".. - "list["..list_name..";stock;0,3;3,2;]".. - "label[5,0;" .. "You want:" .. "]".. - "list["..list_name..";owner_wants;5,0.5;3,2;]".. - "label[5,2.5;" .. "In exchange, you give:" .. "]".. - "list["..list_name..";owner_gives;5,3;3,2;]".. - "list[current_player;main;0,5.5;8,4;]" - ) - end - end - currency_template.on_blast = function() - return nil - end - - minetest.register_node(":currency:shop", currency_template) - - table.insert(clear_craft_vendors, "currency:shop") -end - -if old_vendor_mods_table["easyvend"] then - local nodes = {"easyvend:vendor", "easyvend:vendor_on", "easyvend:depositor", "easyvend:depositor_on"} - for i in pairs(nodes) do - minetest.register_node(":"..nodes[i], base_upgrade_template) - table.insert(clear_craft_vendors, nodes[i]) - end -end - -if old_vendor_mods_table["vendor"] then - local nodes = {"vendor:vendor", "vendor:depositor"} - for i in pairs(nodes) do - minetest.register_node(":"..nodes[i], base_upgrade_template) - table.insert(clear_craft_vendors, nodes[i]) - end -end - -if old_vendor_mods_table["money"] then - local money_template = table.copy(base_upgrade_template) - money_template.can_dig = function(pos, player) - local meta = minetest.get_meta(pos) - local inv = meta:get_inventory() - return inv:is_empty("main") and (meta:get_string("owner") == player:get_player_name() or minetest.check_player_privs(player:get_player_name(), {protection_bypass=true})) - end - money_template.on_rightclick = function(pos, node, clicker, itemstack) - local meta = minetest.get_meta(pos) - local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z - if clicker:get_player_name() == meta:get_string("owner") then - minetest.show_formspec(clicker:get_player_name(),"fancy_vend:money_shop_formspec", - "size[8,10;]".. - "list["..listname..";main;0,0;8,4;]".. - "list[current_player;main;0,6;8,4;]" - ) - end - end - money_template.on_blast = function() - return nil - end - local nodes = {"money:barter_shop", "money:shop", "money:admin_shop", "money:admin_barter_shop"} - for i in pairs(nodes) do - minetest.register_node(":"..nodes[i], money_template) - table.insert(clear_craft_vendors, nodes[i]) - end -end - -for i_n in pairs(clear_craft_vendors) do - local currency_crafts = minetest.get_all_craft_recipes(i_n) - if currency_crafts then - for i in pairs(currency_crafts) do - minetest.clear_craft(currency_crafts[i]) - end - end -end diff --git a/functions.lua b/functions.lua index ef194a8..80a7b6c 100644 --- a/functions.lua +++ b/functions.lua @@ -1,6 +1,6 @@ --- Copyright (C) 2021, 2023 Ale +-- Copyright (C) 2021, 2024 Sandro del Toro -- This file is part of Emeraldbank Minetest Mod. @@ -72,44 +72,6 @@ function emeraldbank.update_accounts() end end -function emeraldbank.inv_emeralds_to_stonks(pos) - local meta = core.get_meta(pos) - local inv = meta:get_inventory() - local stonks = meta:get_int("stonks") - local fancy_inv = inv:get_list("main") - if not fancy_inv then return end - local has_emerald = inv:contains_item("main", "mcl_core:emerald 1", true) - if has_emerald then - meta:set_int("stonks", stonks+1) - inv:remove_item("main", "mcl_core:emerald 1") - emeraldbank.inv_emeralds_to_stonks(pos) - return true - else - return false - end -end - -function emeraldbank.get_stonks(pos) - local meta = core.get_meta(pos) - local owner = meta:get_string("owner") - local player = core.get_player_by_name(owner) - local is_online = core.player_exists(owner) - emeraldbank.inv_emeralds_to_stonks(pos) - local stonks = meta:get_int("stonks") - if not player or player.is_fake_player then return end - if is_online and stonks > 0 then - core.sound_play("cash", { - to_player = owner, - gain = 1.0, - fade = 0.0, - pitch = 1.0, - }) - emeraldbank.add_emeralds(player, stonks) - meta:set_int("stonks", 0) - core.chat_send_player(owner, S("You've earned @1 Emeralds with your shops.", stonks)) - end -end - function emeraldbank.transfer_emeralds(player1, player2, num) -- Determine player names based on whether input is a string or player object local name1 = type(player1) == "string" and player1 or player1:get_player_name() @@ -154,71 +116,3 @@ function emeraldbank.transfer_emeralds(player1, player2, num) core.chat_send_player(name1, S("Invalid pay")) end end - - -function emeraldbank.upgrade_shop(pos) - local oldnode = core.get_node(pos) - local old_meta = core.get_meta(pos) - local old_meta_table = core.get_meta(pos):to_table() - local nodename = core.get_node(pos).name - local old_inv = old_meta:get_inventory() - local old_list = old_inv:get_list("stock") - local old_stack = old_inv:get_stack("stock", 1) - - -- set the new shop node - core.swap_node(pos, {name = "fancy_vend:player_vendor"}) - - -- setup the new shop node - -- Set variables for access later (for various checks, etc.) - - pos.y = pos.y + 1 - -- local above_node = minetest.get_node(pos).name - - -- -- If node above is air or the display node, and it is not protected, attempt to place the vendor. If vendor sucessfully places, place display node above, otherwise alert the user - -- if (minetest.registered_nodes[above_node].buildable_to or above_node == "fancy_vend:display_node") and not minetest.is_protected(pos, owner) then - -- if above_node ~= "fancy_vend:display_node" then - -- minetest.set_node(pos, minetest.registered_nodes["fancy_vend:display_node"]) - -- end - - -- Set owner - local owner = old_meta:get_string("owner") or "" - local meta = minetest.get_meta(pos) - meta:set_string("owner", owner) - - -- Set default meta - meta:set_string("log", minetest.serialize({"Vendor placed by "..owner,})) - emeraldbank.reset_vendor_settings(pos) - emeraldbank.refresh_vendor(pos) - - if minetest.get_modpath("pipeworks") then - pipeworks.after_place(pos) - end - - -- copy old metadata in new node - core.get_meta(pos):from_table(old_meta_table) - - -- new node - local node = core.get_node(pos) - local meta = core.get_meta(pos) - local count = meta:get_int("count") - local price = meta:get_int("price") - local shop_item = meta:get_string("shop_item") - local settings = emeraldbank.get_vendor_settings(pos) - - -- settings - settings.input_item = "mcl_core:emerald" - settings.input_item_qty = price - settings.output_item = shop_item - settings.output_item_qty = count - - -- inv - -- local inv = meta:get_inventory() - -- inv:set_size("main", 15*6) - -- inv:set_size("wanted_item", 1*1) - -- inv:set_size("given_item", 1*1) - -- inv:set_stack("main", i, old_stack) - - - emeraldbank.set_vendor_settings(pos, settings) - emeraldbank.refresh_vendor(pos) -end diff --git a/income.lua b/income.lua index 248aae7..dcbec76 100644 --- a/income.lua +++ b/income.lua @@ -1,6 +1,6 @@ --- Copyright (C) 2021, 2023 Ale +-- Copyright (C) 2021, 2024 Sandro del Toro -- This file is part of Emeraldbank Minetest Mod. diff --git a/init.lua b/init.lua index 5d9860a..1cb2167 100644 --- a/init.lua +++ b/init.lua @@ -41,8 +41,6 @@ dofile(modpath .. "/forms.lua") -- file adapted from atm mod dofile(modpath .. "/receive_fields.lua") -- file adapted from atm mod dofile(modpath .. "/receive_fields_wt.lua") -- file from atm mod dofile(modpath .. "/bank.lua") -dofile(modpath .. "/shop.lua") -dofile(modpath .. "/fancyshop.lua") -- file adapted from fancy_vend mod. dofile(modpath .. "/commands.lua") dofile(modpath .. "/hud.lua") diff --git a/mod.conf b/mod.conf index 2b3a0fa..d548da7 100644 --- a/mod.conf +++ b/mod.conf @@ -1,5 +1,5 @@ name = emeraldbank depends = mcl_core, mcl_sounds, mcl_inventory, mcl_formspec, mcl_title -optional_depends = irc, yl_matterbridge, pipeworks, digilines, awards, hopper, tell, email, mail, beerchat -description = Keep your Emeralds in a bank! And trade with shops. -supported_games = mineclonia, mineclone2 +optional_depends = irc, yl_matterbridge, awards, mail, beerchat +description = Keep your Emeralds in a bank!. +supported_games = mineclonia diff --git a/settingtypes.txt b/settingtypes.txt index 56c73b5..28b973a 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -21,23 +21,3 @@ emeraldbank.income_period (time between income) int 1800 # Length of time (in seconds) between updating emeralds player HUD emeraldbank.hud_time (HUD update time) int 3 - -[Shops] - -# If true shop can be crafted -emeraldbank.shop_craft (shop craft) bool true - -# If true old shop can be crafted -emeraldbank.old_shop_craft (old shop craft) bool false - -# The node to copy as the display node -fancy_vend.display_node (Display Node) string mcl_core:glass - -# Maximum number of mods to store per vender -fancy_vend.log_max (Log Max) int 40 - -# Speed of display item auto rotation -fancy_vend.autorotate_speed (Autorotate Speed) int 1 - -# Whether to not send mail alerts -fancy_vend.no_alerts (Don't Send Mail Alerts) bool false diff --git a/shop.lua b/shop.lua deleted file mode 100644 index b9f1728..0000000 --- a/shop.lua +++ /dev/null @@ -1,327 +0,0 @@ - - --- Copyright (C) 2021, 2023 Ale - --- This file is part of Emeraldbank Minetest Mod. - --- Emeraldbank is free software: you can redistribute it and/or modify --- it under the terms of the GNU Affero General Public License as --- published by the Free Software Foundation, either version 3 of the --- License, or (at your option) any later version. - --- Emeraldbank is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU Affero General Public License for more details. - --- You should have received a copy of the GNU Affero General Public License --- along with Emeraldbank. If not, see . - - -local S = core.get_translator(core.get_current_modname()) - -local oldshopcraft = core.settings:get_bool("emeraldbank.old_shop_craft") or false - --- privilege -core.register_privilege("admin_shop", { - description = S("Enables the user to set regular vendors to admin vendors, or edit other players shops."), - give_to_singleplayer = false, -}) - -emeraldbank.shop_timer = 5 - -local shop_timer = emeraldbank.shop_timer - -local stock_h = 3 -local stock_w = 5 - -local formspec_prefix = "emeraldbank:shop_formspec" - -emeraldbank.player_inv = - "list[current_player;main;0,4.5;9,3;9]".. - mcl_formspec.get_itemslot_bg(0,4.5,9,3).. - "list[current_player;main;0,7.74;9,1;]".. - mcl_formspec.get_itemslot_bg(0,7.74,9,1).. - "listring[current_player;main]" - - -function emeraldbank.get_shop_fs(pos, clicker) - local meta = core.get_meta(pos) - local count = meta:get_int("count") - local price = meta:get_int("price") - local shop_item = meta:get_string("shop_item") - local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z - local pname = clicker:get_player_name() - local owner = meta:get_string("owner") - local player_press_key = clicker:get_player_control().aux1 - local shop_fs = "" - local is_admin = core.check_player_privs(pname, {admin_shop=true}) - if (pname == owner or is_admin) and not player_press_key then - shop_fs = "size[9,8.75]".. - "label[0,0;"..S("Your stock:").."]".. - "list["..list_name..";stock;0,0.5;"..stock_w..","..stock_h..";]".. - mcl_formspec.get_itemslot_bg(0,0.5,stock_w,stock_h).. - "field[6.5,2;2,1;count;"..S("Count")..";"..count.."]".. - "field[6.5,3;2,1;price;"..S("Price")..";"..price.."]".. - "label[6,0;"..S("In exchange, you give:").."]".. - "item_image[6.5,0.5;1,1;"..shop_item.."]".. - mcl_formspec.get_itemslot_bg(6.5,0.5,1,1).. - "label[0,4;"..S("Owner, Use (special key + right mouse button) for customer interface").."]".. - emeraldbank.player_inv - else - shop_fs = "size[9,8.75]".. - "label[3.7,0;"..S("Owner gives:").."]".. - "item_image[4,1;1,1;"..shop_item.."]".. - mcl_formspec.get_itemslot_bg(4,1,1,1).. - "label[5,1.5;"..S("x @1", count).."]".. - "label[4,2;"..S("Price: @1", price).."]".. - "button[3.5,3;2,1;exchange;"..S("Exchange").."]".. - emeraldbank.player_inv - end - - return shop_fs - -end - - -local function swap_shop(pos, closed) - local oldnode = core.get_node(pos) - local oldnodemeta = core.get_meta(pos):to_table() - local nodename = core.get_node(pos).name - if closed then - core.swap_node(pos, {name = "emeraldbank:shop_empty"}) - else - core.swap_node(pos, {name = "emeraldbank:shop"}) - end - core.get_meta(pos):from_table(oldnodemeta) -end - -local function set_item(pos, stack, player) - local meta = core.get_meta(pos) - local itemname = stack:get_name() - local itemcount = stack:get_count() - meta:set_string("shop_item", itemname) - core.show_formspec(player:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, player) ) -end - -local function check_empty(pos) - local meta = core.get_meta(pos) - local inv = meta:get_inventory() - local count = meta:get_int("count") - local shop_item = meta:get_string("shop_item") - if inv:is_empty("stock") then - meta:set_string("shop_item", "") - swap_shop(pos, true) - elseif not inv:contains_item("stock", shop_item.." "..count, true) then - swap_shop(pos, true) - else - swap_shop(pos) - end -end - -local function after_place_node(pos, placer, itemstack) - local owner = placer:get_player_name() - local meta = core.get_meta(pos) - meta:set_string("infotext", S("Exchange shop (owned by @1)", owner)) - meta:set_string("owner", owner) - meta:set_int("count", 10) -- default count - meta:set_int("price", 5) -- default price - core.get_node_timer(pos):start(shop_timer) - local inv = meta:get_inventory() - inv:set_size("stock", stock_w*stock_h) -end - -local function on_rightclick(pos, node, clicker, itemstack) - local meta = core.get_meta(pos) - local nodename = core.get_node(pos).name - local owner = meta:get_string("owner") - local pname = clicker:get_player_name() - emeraldbank.get_stonks(pos) - --if nodename == "emeraldbank:shop" or pname == owner then - core.show_formspec(pname, formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, clicker)) - --end -end - -local function on_punch(pos, node, puncher, pointed_thing) - emeraldbank.get_stonks(pos) -end - -local function on_metadata_inventory_put(pos, listname, index, stack, player) - set_item(pos, stack, player) -- this func already show the fs - check_empty(pos) -end - -local function on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) - check_empty(pos) - -end - -local function on_metadata_inventory_take(pos, listname, index, stack, player) - -- check_empty(pos) -- CRASH - core.show_formspec(player:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, player) ) -end - - -local function on_timer(pos, elapsed) - core.get_node_timer(pos):start(shop_timer) - check_empty(pos) - emeraldbank.get_stonks(pos) -end - -local function can_dig(pos, player) - local pname = player:get_player_name() - local is_admin = core.check_player_privs(pname, {admin_shop=true}) - local meta = core.get_meta(pos) - local owner = meta:get_string("owner") - local inv = meta:get_inventory() - return inv:is_empty("stock") and (pname == owner or is_admin) -end - --- register shop node -core.register_node("emeraldbank:shop", { - description = S("Shop"), - _doc_items_longdesc = S("A shop to sell your items with emeralds."), - is_ground_content = false, - tiles = { - "default_tree.png", - "default_tree.png", - "default_tree.png^mcl_core_emerald.png" - }, - stack_max = 64, - groups = {axey=1, handy=1, building_block=1}, - sounds = mcl_sounds.node_sound_wood_defaults(), - _mcl_blast_resistance = 5, - _mcl_hardness = 1, - - after_place_node = after_place_node, - on_rightclick = on_rightclick, - on_punch = on_punch, - on_metadata_inventory_put = on_metadata_inventory_put, - on_metadata_inventory_move = on_metadata_inventory_move, - on_metadata_inventory_take = on_metadata_inventory_take, - on_timer = on_timer, - can_dig = can_dig -}) - --- register shop node -core.register_node("emeraldbank:shop_empty", { - description = S("Shop Empty"), - _doc_items_longdesc = S("A shop to sell your items with emeralds."), - is_ground_content = false, - tiles = { - "default_tree.png", - "default_tree.png", - "default_tree.png^mcl_core_emerald.png^mcl_core_barrier.png" - }, - stack_max = 64, - groups = {axey=1, handy=1, building_block=1, not_in_creative_inventory=1}, - sounds = mcl_sounds.node_sound_wood_defaults(), - drop = "emeraldbank:shop", - _mcl_blast_resistance = 5, - _mcl_hardness = 1, - - after_place_node = after_place_node, - on_rightclick = on_rightclick, - on_punch = on_punch, - on_metadata_inventory_put = on_metadata_inventory_put, - on_metadata_inventory_move = on_metadata_inventory_move, - on_metadata_inventory_take = on_metadata_inventory_take, - on_timer = on_timer, - can_dig = can_dig -}) - - -core.register_on_player_receive_fields(function(sender, formname, fields) - local prefix_len = string.len(formspec_prefix) - if formname:sub(1,prefix_len) == formspec_prefix then - - local pos_string = formname:sub(prefix_len+1) - local pos = core.string_to_pos(pos_string) - local meta = core.get_meta(pos) - local name = sender:get_player_name() - local playermeta = sender:get_meta() - local player_pos = sender:get_pos() - local old_count = meta:get_int("count") - local new_count = tonumber(fields.count) - local old_price = meta:get_int("price") - local new_price = tonumber(fields.price) - local shop_item = meta:get_string("shop_item") - local minv = meta:get_inventory() - local pinv = sender:get_inventory() - atm.read_account(name) - local bankemeralds = atm.balance[name] - - -- set or reset timer - core.get_node_timer(pos):start(shop_timer) - - -- set item count - if fields.count and string.find(fields.count, "^[0-9]+$") then - if new_count >= 1 and new_count <= 64 and new_count ~= meta:get_int("count") then - meta:set_int("count", new_count) - check_empty(pos) - end - end - - -- set price - if fields.price and string.find(fields.price, "^[0-9]+$") then - if new_price >= 1 and new_price <= 10000 and new_price ~= meta:get_int("price") then - meta:set_int("price", new_price) - end - end - - -- someone hit exchange button - if fields.exchange ~= nil and fields.exchange ~= "" then - - -- owner try exchanges - if meta:get_string("owner") == name then - core.chat_send_player(name, S("This is your own shop, you can't exchange to yourself!")) - - else - - local can_exchange = true - - -- have u money? - if bankemeralds < old_price then - can_exchange = false - core.chat_send_player(name, S("Not enough Emeralds in your account")) - end - - --there are enough items? - if not minv:contains_item("stock", shop_item.." "..old_count, true) then - can_exchange = false - core.chat_send_player(name, S("Out of Stock!")) - end - - -- do not trade air - if shop_item == "" or shop_item == "air" then - can_exchange = false - end - - if can_exchange then - minv:remove_item("stock", shop_item.." "..old_count) - core.add_item(player_pos, shop_item.." "..old_count) - emeraldbank.add_emeralds(sender, -old_price) - meta:set_int("stonks", meta:get_int("stonks")+old_price) - mcl_title.set(sender, "subtitle", {text=S("Exchanged!"), color="green"}) - check_empty(pos) - core.show_formspec(sender:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, sender) ) - end - - end - - end - - end -end) - - -if oldshopcraft then - core.register_craft({ - output = "emeraldbank:shop 3", - recipe = { - {"mcl_core:emerald", "mcl_core:emerald", "mcl_core:emerald"}, - {"mcl_core:emerald", "mcl_core:tree", "mcl_core:emerald"}, - {"mcl_core:emerald", "mcl_core:emerald", "mcl_core:emerald"}, - } - }) -end diff --git a/textures/admin_depo.png b/textures/admin_depo.png deleted file mode 100644 index 63ca2d503fce203c9467663d3971672af2f15e52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 303 zcmV+~0nq-5P)T2kDZ diff --git a/textures/admin_vend.png b/textures/admin_vend.png deleted file mode 100644 index 56d9a01f42692a37693db770ae147b44d5ee0328..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 257 zcmV+c0sj7pP)3|C+^^P0nF(-7JguiY$%8gHUO6kh`}9a zpa!5j7iKfE?JyT02k6vGkH~WY#RkAI(FPzp9XT<<4Zx-V+0R6~0GmPh(gew2fF2td zULZ9kf(?k?e&)abmJ=vAYyXA+AaM{4N-Q8;ee5a*28jazdH=aKL?jdS00000NkvXX Hu0mjf_{(Aw diff --git a/textures/copier.png b/textures/copier.png deleted file mode 100644 index e87719eadfdf498af5864b64a4a95cfef581698e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`Y)RhkE)4&HECyrsn$JLrv%n*= zn1O*?7=#%aX3dcR3bL1Y`ns||V&Y?z;Fk1}p92(9$P9@nan8@pP0cF-av2z$i&7Iy zQd1Pt@{1IFGxJhIQj1Gk>Kv?qQZAk@jv*GOlM@y&u*@*}qaM9^mx%JuS#P&$T(Eid z=HdGsS?>G)nV6WSWKIh=R=LZ-$jJD~^z>@Uf9XH|&#zg2I7i+50OPZRN}&Z-;x!<< NJYD@<);T3K0RSXALt+2` diff --git a/textures/inactive.png b/textures/inactive.png deleted file mode 100644 index 299586280ae3399b6f2f29ad0ce7e5a6abe2dfdb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 890 zcmV-=1BLvFP)_Hg5XhmNXx0kVp z%7!naZZ9&@&b@UyS6H>0w$p80)}*V|bitHHo8Bb%Msw4qY3@1Wj1Bg(hr`E#@5ebG z{6Aonf{{#0F@)Y9Bjn~(B+|ECtzyO){CoI)DiR5eVLTo~=#-I6ws6N`ON@{YZw3Oj zpAH_hzLlhzcr^OXR;gs;kk@!L`qm9WxF6rWyYZdhzcot8Y3|6LYu7$_MO8n0N9D;7cWc(CAd1#)-p1edN}ZLY1XoKpMx-fi=G2^0!|9S*3OCaM|+kkjGt!rJuo z9;c$bDk%!a)hh66m*pU%^ze>QNcD2~;st;tfws0rb5EZ9>>V5&B45qVmyA^EkJZV^ zZl}i+;E-%?g4EiI+jj0GveStXhfXJGnns_dQV)Dbj-1~=I-0;XQKbDNBftB?;md#C zy*pFLSJ6aWzdMNOmGg@uRh$B%#9KQi)*O%yE*0AO!z-R>D0n%^iE zC-RGn79#{;V*^+^4X9iOuq@EBS!>fY@AsTL_Z#o$?r&Vz^`@oa;k}~U9rkr~*;qag z*0W~-f&i>u2QW?W`u$jJZa%a$JltQ`bvt)xyILg=PM+*vzkT~tH5A(K^>{GWb>Ls8 zq6mC`FbuF{8MI2p$~=1XYg;68Vc+%Zv*b`R*}Fb5@p)%=_kbb@n7>L}T43EYX?A(J z!R&VAkR-%PC2+_xZjz+-)!EseQX(-&1~Zwj{lVY?ug{0+^XCAH0tM5wR?_Kv6~p+V z^75s_CP_P-vW#f42%_JQtVW|FKQ|ZP8UCSMDmAtl0~82wNVDnmwC~ul%i%=gOW)C> zA3c5ict$f#%G%qZPAQaiy+IlKo@d(?!}$ET+r4$KtIPVvZl8`vqi_Ew+fDIkbl(j@ zn2qn+WsNJ!Rt)1aMlvbGKU?LBA#`>Wdi5Xe~cl-p^Lk}0J8|G0vriY Qm;e9(07*qoM6N<$g2i99-2eap diff --git a/textures/player_depo.png b/textures/player_depo.png deleted file mode 100644 index 0950b4b88b1e1c04ae8603a5153d0dd3d6b8d287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 565 zcmV-50?Pe~P)q z-AmJP6vhwcOFAM9oydkQS|c6IFtri5g3VZrma;@$*@YrYDiFM|h%UOQZiEOVh!BY( zh!bF>Q?EBzIi;P?1TrvZBOew)wu#xYx2!WM=j9lC$k_9g?6F>%V9grlLS}R1|L}X(D70g))LNN~Ci}KphMc8N!1A&f16Q!{SH__-3OFOQO@A zZqFXTo(>UF15id%Gx1+TG}-HIV-7;=Xf6AI&|=6SU=mFMf7ft_55`z?x?gB3|R?C31B$R4xODnCKGu~$5@k;`Cm7Y diff --git a/textures/player_vend.png b/textures/player_vend.png deleted file mode 100644 index e59cc21475756439b29e2372064452849e5af25a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 552 zcmV+@0@wYCP)JIDtpB`J zSvvZq&k95v%S7vnMC(f|trfRKL}MYlC(c=WrRdh`VboR%Y6(HCj6@6DHI^B|E zc;Aq&W3N;7LsO>C#q)HbyGRp#A;V%%vG&yl1jsz}LiAJnLv!)Vo3Me)U*AS_WxQHf zC!&UpsTvc*$@uPx%KX8(4#ystOgO;F$V)K}Mq}a`uC+;sca)1(=7=Wt&#eRAN}#jC z2D_fxeREhe{zSC5+Me;7IP3FANdX+RmfB0f3s7HZML2T~0H+l9+hJ0Gs=7CS?#kDh zwp>#{F7p&uSeR_iHY);a#}`(hA#5#@g<4QdKn$olki->rqNVUofIkNdhDFyxvLQw* zofuAOqZeR6u!db%X;#D#a?fzicp{zi0t^xv+yw_`!68~6ciJ*n-9Is{Up{b6DRFZJ zv0G2C|(q$0)GcW#Asy7Xox1tS4Rw6^e^%y(R%%-W;*;cErIuQK!KEOr5AfN#yvN zY3clqhdkM$6BIzna03YiV;)j5uD>X^CTrJE;I~MWNj)iyhT6_M3>qRm9y6 znZs|?an=^42%sQnmY2R>0K7U$f}ElNfKm*1>mo&fsVZ+??kM58)&em=T*gzB!2(l$ zjW|KDd-W&@d?qOoUDElk3^f|ieG=f$%CHa<(XW7QuntN-#7Zp1TZ(1z?>x~jiC)6U2x}N;v1$B?sa@DTzp*aJ@fwJ~I{4?;i{itt zKPs!=VNxSOrfaE4BO-LnJ)`@*85^`b9Y za||9ertA2%=@H#-;dH;!dqiLj3+s(TW@~=SBgw5_nK% zgQ<^GNusxGob~p#Bmo!NN<@3AY=FmupFSHn0=MS@Do~2K?{<;|xJq3Z^s+NwC);yR zD0uv3!<+lGCEKhJEPnfK2^xz=Q=aoR#H~rT=@XZsHT(<3T*;$?Q4xBTY zfHFzy2|`)6h0H-ip=e9OR9eg4!OZ~ehJZ=*1VxwZU{ofiD<~GIf|!Y`OoBb&^Z7Oo uuk2{o^41AFTi;dASs4}(-~4d~oF4%^kTbR1Ynzz>0000Z@e