From fbc88fa68dfa6df3d174508f5d861a4641cdf4de Mon Sep 17 00:00:00 2001 From: Juraj Vajda Date: Wed, 7 Nov 2018 22:15:55 -0500 Subject: [PATCH] better check for nan and finite numbers, colored messages --- chatcommands.lua | 254 +++++++++++++++++++++++++++-------------------- 1 file changed, 146 insertions(+), 108 deletions(-) diff --git a/chatcommands.lua b/chatcommands.lua index 9324b22..47ace23 100644 --- a/chatcommands.lua +++ b/chatcommands.lua @@ -1,4 +1,33 @@ --- Minetest API method. Adds definition to minetest.registered_chatcommands. +--- Returns true if given value is a finite number; otherwise false or nil if value is not of type string nor number. +function isfinite(value) + if type(value) == "string" then + value = tonumber(value) + if value == nil then return nil end + elseif type(value) ~= "number" then + return nil + end + return value > -math.huge and value < math.huge +end + +--- Returns true if given value is not a number (NaN); otherwise false or nil if value is not of type string nor number. +function isnan(value) + if type(value) == "string" then + value = tonumber(value) + if value == nil then return nil end + elseif type(value) ~= "number" then + return nil + end + return value ~= value +end + +local colors = { + ["yellow"] = "#FFEB3B", -- info + ["green"] = "#4CAF50", -- success + ["red"] = "#f44336", -- error + ["cyan"] = "#00BCD4" -- terminal info +} + +--- Minetest API method. Adds definition to minetest.registered_chatcommands. -- @param cmd the string - commnad name -- @param chatcommand definition the table minetest.register_chatcommand("mp", { @@ -19,22 +48,34 @@ minetest.register_chatcommand("mp", { if params[1] == "find" then -- item name is missing from param[2] if not params[2] then - return false, "You need to write the item name you want to find. example: /mp find default:stone. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: You need to write the item name you want to find. example: /mp find default:stone. See some suggestion from the store: ")..x_marketplace.store_get_random() end local items = x_marketplace.store_find(params[2]) if not items then - return false, "Oops there is no item like this in the store. Check out other items in the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.yellow, "MARKET PLACE: Oops there is no item like this in the store. Check out other items in the store: ")..x_marketplace.store_get_random() end - return true, items + return true, minetest.colorize(colors.cyan, items) -- -- show balance -- elseif params[1] == "balance" then - return true, "Your balance is: "..x_marketplace.get_player_balance(caller).." BitGold" + local balance = x_marketplace.get_player_balance(caller) + + -- check for number sanity, positive number + if not balance or + isnan(balance) or + not isfinite(balance) then + + local player = minetest.get_player_by_name(caller) + player:set_attribute("balance", 0) + balance = 0 + end + + return true, minetest.colorize(colors.green, "MARKET PLACE: Your balance is: "..balance.." BitGold") -- -- sell hand @@ -43,26 +84,32 @@ minetest.register_chatcommand("mp", { local player = minetest.get_player_by_name(caller) local hand = player:get_wielded_item() local item_name = hand:get_name() - local item_count = hand:get_count() local store_item = x_marketplace.store_list[item_name] - local itemstack = ItemStack({ name = item_name }) - - -- check what is the max items we can sell - if item_count > itemstack:get_stack_max() then - return false, "You can sell this item by max. of "..itemstack:get_stack_max().." item(s) at the time." - end -- item exists in the store if store_item then + local item_count = hand:get_count() + local itemstack = ItemStack(item_name) + + -- check for number sanity, positive number + if isnan(item_count) or + not isfinite(item_count) then + item_count = 1 + end + + if item_count > itemstack:get_stack_max() then + item_count = itemstack:get_stack_max() + end + player:set_wielded_item(ItemStack("")) local sell_price = store_item.sell * item_count local new_balance = x_marketplace.set_player_balance(caller, sell_price) - return true, "You sold "..item_count.." item(s) of "..item_name.." for "..sell_price.." BitGold. Your new balance is: "..new_balance.." BitGold" + return true, minetest.colorize(colors.green, "MARKET PLACE: You sold "..item_count.." item(s) of "..item_name.." for "..sell_price.." BitGold. Your new balance is: "..new_balance.." BitGold") else -- item does not exists in the store - return false, "You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: ")..x_marketplace.store_get_random() end -- @@ -77,12 +124,18 @@ minetest.register_chatcommand("mp", { -- item exists in the store if store_item then + local itemstack = ItemStack(item_name) + + if item_count > itemstack:get_stack_max() then + item_count = itemstack:get_stack_max() + end + local sell_price = store_item.sell * item_count - return true, item_name.." buy: "..store_item.buy.." sell: "..store_item.sell..". You can sell the item(s) you are holding for: "..sell_price.." BitGold. example: /mp sellhand" + return true, minetest.colorize(colors.yellow, "MARKET PLACE: "..item_name.." buy: "..store_item.buy.." sell: "..store_item.sell..". You can sell the item(s) you are holding for: "..sell_price.." BitGold. example: /mp sellhand") else -- item does not exists in the store - return false, "This item is not in store. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: This item is not in store. See some suggestion from the store: ")..x_marketplace.store_get_random() end -- @@ -93,43 +146,34 @@ minetest.register_chatcommand("mp", { local hand = player:get_wielded_item() local item_name = hand:get_name() local store_item = x_marketplace.store_list[item_name] - local itemstack = ItemStack({ name = item_name }) -- item exists in the store if store_item then - local amount = params[2] or 1 + local amount = tonumber(params[2]) local inv = player:get_inventory("main") - local itemstack = ItemStack({ - name = item_name, - count = amount - }) + local itemstack = ItemStack(item_name) - -- check if amount is a number - if not tonumber(amount) then - return false, "Amount of items must be a number. example: /mp buyhand "..math.random(1, 99) - end + -- check for number sanity, positive number + if not amount or + isnan(amount) or + not isfinite(amount) or + amount <= 0 then - -- check what is the max items we can buy - if tonumber(amount) > itemstack:get_stack_max() then - return false, "You can buy this item by max. of "..itemstack:get_stack_max().." item(s) at the time." - end - - -- check amount is positive number - if tonumber(amount) <= 0 then amount = 1 end - -- check for NaN, returns true if given value is not a number (NaN) - if (tonumber(amount) ~= tonumber(amount)) then - return false, "Not a valid command." + if amount > itemstack:get_stack_max() then + amount = itemstack:get_stack_max() end + itemstack:set_count(amount) + local buy_price = amount * store_item.buy local new_balance = x_marketplace.set_player_balance(caller, buy_price * -1) -- not enough money if not new_balance then - return false, "You don't have enought BitGold. Price for "..amount.." item(s) of "..item_name.." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold" + return false, minetest.colorize(colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..item_name.." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold") end -- drop items what doesn't fit in the inventory @@ -149,10 +193,10 @@ minetest.register_chatcommand("mp", { end end - return true, "You bought "..amount.." item(s) of "..item_name.." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold" + return true, minetest.colorize(colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..item_name.." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold") else -- item does not exists in the store - return false, "This item is not in store. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: This item is not in store. See some suggestion from the store: ")..x_marketplace.store_get_random() end -- @@ -161,33 +205,38 @@ minetest.register_chatcommand("mp", { elseif params[1] == "sellinv" then -- item name is missing from param[2] if not params[2] then - return false, "You need to write the item name you want to sell. example: /mp sellinv default:stone. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.yellow, "MARKET PLACE: You need to write the item name you want to sell. example: /mp sellinv default:stone. See some suggestion from the store: ")..x_marketplace.store_get_random() end local player = minetest.get_player_by_name(caller) - local inv = player:get_inventory("main") local store_item = x_marketplace.store_list[params[2]] - local amount = 0 -- item exists in the store if store_item then - local itemstack = ItemStack({ name = params[2] }) + local inv = player:get_inventory("main") + local itemstack = ItemStack(params[2]) + local amount = 0 for k, v in ipairs(inv:get_list("main")) do - if v:get_name() == params[2] and - v:get_count() <= itemstack:get_stack_max() then - local removed = inv:remove_item("main", v) - amount = amount + removed:get_count() + if v:get_name() == params[2] then + local amount_removed = v:get_count() + inv:remove_item("main", v) + + if amount_removed > itemstack:get_stack_max() then + amount_removed = itemstack:get_stack_max() + end + + amount = amount + amount_removed end end local sell_price = amount * store_item.sell local new_balance = x_marketplace.set_player_balance(caller, sell_price) - return true, "You sold "..amount.." item(s) of "..params[2].." for "..sell_price.." BitGold. Your new balance is: "..new_balance.." BitGold" + return true, minetest.colorize(colors.green, "MARKET PLACE: You sold "..amount.." item(s) of "..params[2].." for "..sell_price.." BitGold. Your new balance is: "..new_balance.." BitGold") else -- item does not exists in the store - return false, "You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: You cannot sell this item. Search in store for items you can sell, example: /mp find stone. See some suggestion from the store: ")..x_marketplace.store_get_random() end -- @@ -196,20 +245,17 @@ minetest.register_chatcommand("mp", { elseif params[1] == "buyinv" then -- item name is missing from param[2] if not params[2] then - return false, "You need to write the item name you want to buy. example: /mp buyinv default:stone, or check out other items in the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.yellow, "MARKET PLACE: You need to write the item name you want to buy. example: /mp buyinv default:stone, or check out other items in the store: ")..x_marketplace.store_get_random() end local player = minetest.get_player_by_name(caller) - local inv = player:get_inventory("main") local store_item = x_marketplace.store_list[params[2]] - local amount = 0 - local itemstack = ItemStack({ - name = params[2] - }) - - itemstack:set_count(itemstack:get_stack_max()) if store_item then + local itemstack = ItemStack(params[2]) + local inv = player:get_inventory("main") + local amount = 0 + itemstack:set_count(itemstack:get_stack_max()) for k, v in ipairs(inv:get_list("main")) do if v:get_name() == "" and v:get_count() == 0 then @@ -218,7 +264,7 @@ minetest.register_chatcommand("mp", { end if amount == 0 then - return false, "You don't have empty space in your inventory. Transaction cancelled." + return false, minetest.colorize(colors.yellow, "MARKET PLACE: You don't have empty space in your inventory. Transaction cancelled.") end local buy_price = amount * store_item.buy @@ -226,7 +272,7 @@ minetest.register_chatcommand("mp", { -- not enough money if not new_balance then - return false, "You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold." + return false, minetest.colorize(colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold.") end for k, v in ipairs(inv:get_list("main")) do @@ -235,76 +281,68 @@ minetest.register_chatcommand("mp", { end end - return true, "You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold" + return true, minetest.colorize(colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold") else -- item not in store - return false, "This item is not in store, check out other items from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.red, "MARKET PLACE: This item is not in store, check out other items from the store: ")..x_marketplace.store_get_random() end -- -- buy -- elseif params[1] == "buy" then - local item = params[2] + local amount = tonumber(params[3]) - -- item name is missing from param[2] - if not item then - return false, "You need to write the item name you want to buy. example: /mp buy default:stone 10, or check out other items in the store: "..x_marketplace.store_get_random() + -- check for param[2] - item name + + if not params[2] then + return false, minetest.colorize(colors.red, "MARKET PLACE: You need to write the item name you want to buy. example: /mp buy default:stone 10, or check out other items in the store: ")..x_marketplace.store_get_random() end -- item not in store if not x_marketplace.store_list[params[2]] then local suggestions = x_marketplace.store_find(params[2]) - local suggest = "" -- try suggest item from store, else show random items if suggestions then - suggest = "This item is not in store, check out other items from the store: \n"..suggestions - return false, suggest + return false, minetest.colorize(colors.yellow, "MARKET PLACE: This item is not in store, check out other items from the store: \n")..suggestions else -- still not found in the store - pick random - return false, "This item is not in store, check out other items from the store: "..x_marketplace.store_get_random() + return false, minetest.colorize(colors.yellow, "MARKET PLACE: This item is not in store, check out other items from the store: ")..x_marketplace.store_get_random() end end + -- check for param[3] - amount + local itemstack = ItemStack(params[2]) + + -- check for number sanity, positive number + if not amount or + isnan(amount) or + not isfinite(amount) or + amount <= 0 then + + amount = 1 + end + + if amount > itemstack:get_stack_max() then + amount = itemstack:get_stack_max() + end + + itemstack:set_count(amount) + -- add items to main inventory local player = minetest.get_player_by_name(caller) local store_item = x_marketplace.store_list[params[2]] - local amount = params[3] or 1 local inv = player:get_inventory("main") - local itemstack = ItemStack({ - name = params[2], - count = amount - }) - - -- check if amount is a number - if not tonumber(amount) then - return false, "Amount of items must be a number. example: /mp buy default:stone 99" - end - - -- check what is the max items we can buy - if tonumber(amount) > itemstack:get_stack_max() then - return false, "You can buy this item by max. of "..itemstack:get_stack_max().." item(s) at the time." - end - - -- check amount is positive number - if tonumber(amount) <= 0 then - amount = 1 - end - - -- check for NaN, returns true if given value is not a number (NaN) - if (tonumber(amount) ~= tonumber(amount)) then - return false, "Not a valid command." - end local buy_price = amount * store_item.buy local new_balance = x_marketplace.set_player_balance(caller, buy_price * -1) -- not enough money if not new_balance then - return false, "You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold" + return false, minetest.colorize(colors.red, "MARKET PLACE: You don't have enought BitGold. Price for "..amount.." item(s) of "..params[2].." is "..buy_price.." BitGold, but your current balance is: "..x_marketplace.get_player_balance(caller).." BitGold") end -- drop items what doesn't fit in the inventory @@ -324,7 +362,7 @@ minetest.register_chatcommand("mp", { end end - return true, "You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold" + return true, minetest.colorize(colors.green, "MARKET PLACE: You bought "..amount.." item(s) of "..params[2].." for "..buy_price.." BitGold. Your new balance is: "..new_balance.." BitGold") -- -- top 5 richest @@ -341,7 +379,7 @@ minetest.register_chatcommand("mp", { table.sort(temp_tbl, function(a, b) return a.balance > b.balance end) - local msg = "" + local msg = "MARKET PLACE: \n" local length = 5 if length > #temp_tbl then @@ -353,23 +391,23 @@ minetest.register_chatcommand("mp", { end -- print(dump(temp_tbl)) - return true, msg + return true, minetest.colorize(colors.yellow, msg) -- -- help -- elseif params[1] == "help" then local msg = - minetest.colorize("#00FFFF", "/mp find").." , find item in store\n".. - minetest.colorize("#00FFFF", "/mp balance")..", show your current balance in BitGold\n".. - minetest.colorize("#00FFFF", "/mp sellhand")..", sell item(s) currently holding in hand\n".. - minetest.colorize("#00FFFF", "/mp buyhand").." [], buy of item(s) currently holding in hand, when is not provided then amount is 1\n".. - minetest.colorize("#00FFFF", "/mp infohand")..", show more information about the item(s) you are currently holding in hand from the store\n".. - minetest.colorize("#00FFFF", "/mp buy").." [], buy of from store, if is not provided then amount is 1\n".. - minetest.colorize("#00FFFF", "/mp sellinv").." , sell all items from the 'main' inventory list\n".. - minetest.colorize("#00FFFF", "/mp buyinv").." , buy full inventory of items , empty slots in the 'main' inventory are required\n".. - minetest.colorize("#00FFFF", "/mp top")..", show top 5 richest players currently online\n".. - minetest.colorize("#00FFFF", "/mp help")..", print out this help\n" + minetest.colorize(colors.cyan, "/mp find").." , find item in store\n".. + minetest.colorize(colors.cyan, "/mp balance")..", show your current balance in BitGold\n".. + minetest.colorize(colors.cyan, "/mp sellhand")..", sell item(s) currently holding in hand\n".. + minetest.colorize(colors.cyan, "/mp buyhand").." [], buy of item(s) currently holding in hand, when is not provided then amount is 1\n".. + minetest.colorize(colors.cyan, "/mp infohand")..", show more information about the item(s) you are currently holding in hand from the store\n".. + minetest.colorize(colors.cyan, "/mp buy").." [], buy of from store, if is not provided then amount is 1\n".. + minetest.colorize(colors.cyan, "/mp sellinv").." , sell all items from the 'main' inventory list\n".. + minetest.colorize(colors.cyan, "/mp buyinv").." , buy full inventory of items , empty slots in the 'main' inventory are required\n".. + minetest.colorize(colors.cyan, "/mp top")..", show top 5 richest players currently online\n".. + minetest.colorize(colors.cyan, "/mp help")..", print out this help\n" -- print(msg) return true, msg