diff --git a/dialogue.lua b/dialogue.lua index e1aed43..1930800 100644 --- a/dialogue.lua +++ b/dialogue.lua @@ -107,8 +107,6 @@ function npc.dialogue.select_random_dialogues_for_npc(sex, phase, favorite_items if value.action_type == "function" then result.normal[i].responses[key].dialogue_id = dialogue_id result.normal[i].responses[key].response_id = key - minetest.log("Storing dialogue and response id: " - ..dump(result.normal[i].responses[key])) end end diff --git a/npc.lua b/npc.lua index 8d7dd18..2ef5f2f 100755 --- a/npc.lua +++ b/npc.lua @@ -38,15 +38,13 @@ end -- Each slot can hold one item up to 99 count. -- Utility function to get item name from a string -local function get_item_name(item_string) - local i,j = string.find(item_string, " ") - return item_string.sub(item_string, 1, i-1) +function npc.get_item_name(item_string) + return ItemStack(item_string):get_name() end -- Utility function to get item count from a string -local function get_item_count(item_string) - local i,j = string.find(item_string, " ") - return tonumber(item_string.sub(item_string, i+1)) +function npc.get_item_count(item_string) + return ItemStack(item_string):get_count() end local function initialize_inventory() @@ -67,11 +65,11 @@ function npc.add_item_to_inventory(self, item_name, count) if existing_item ~= nil and existing_item.item_string ~= nil then -- NPC already has item. Get count and see minetest.log("What is this? "..dump(existing_item)) - local existing_count = get_item_count(existing_item.item_string) + local existing_count = npc.get_item_count(existing_item.item_string) if (existing_count + count) < npc.INVENTORY_ITEM_MAX_STACK then -- Set item here self.inventory[existing_item.slot] = - get_item_name(existing_item.item_string).." "..tostring(existing_count + count) + npc.get_item_name(existing_item.item_string).." "..tostring(existing_count + count) return true else --Find next free slot @@ -102,8 +100,8 @@ end -- Same add method but with itemstring for convenience function npc.add_item_to_inventory_itemstring(self, item_string) - local item_name = get_item_name(item_string) - local item_count = get_item_count(item_string) + local item_name = npc.get_item_name(item_string) + local item_count = npc.get_item_count(item_string) npc.add_item_to_inventory(self, item_name, item_count) end @@ -145,7 +143,8 @@ function npc.take_item_from_inventory(self, item_name, count) end end --- Inventory functions for players +-- Inventory functions for players and for nodes +-- TODO: Need to rewrite this functions function npc.give_item_to_player(player, item_name, count) local player_name = npc.get_entity_name(player) local player_inv = minetest.get_inventory({type="player", name=player_name}) @@ -349,14 +348,20 @@ end local function choose_spawn_items(self) local number_of_items_to_add = math.random(1, 2) local number_of_items = #npc.FAVORITE_ITEMS[self.sex].phase1 - minetest.log("Number of items: "..dump(number_of_items)) + for i = 1, number_of_items_to_add do npc.add_item_to_inventory( self, npc.FAVORITE_ITEMS[self.sex].phase1[math.random(1, number_of_items)].item, - math.random(1,4) + math.random(1,5) ) end + -- Add currency to the items spawned with. Will add 5-10 tier 3 + -- currency items + local currency_item_count = math.random(5, 10) + npc.add_item_to_inventory(self, npc.trade.prices.currency.tier3, currency_item_count) + + minetest.log("Initial inventory: "..dump(self.inventory)) end local function npc_spawn(self, pos) diff --git a/trade/prices.lua b/trade/prices.lua index 483376f..47b62f9 100644 --- a/trade/prices.lua +++ b/trade/prices.lua @@ -4,21 +4,46 @@ npc.trade.prices = {} +-- Define default currency (based on lumps from default) +npc.trade.prices.currency = { + tier1 = "default:gold_lump", + tier2 = "default:copper_lump", + tier3 = "default:iron_lump" +} + +-- TODO: Set the currency depending on available mods + -- Table that contains the prices npc.trade.prices.table = {} -- Default definitions for in-game items -npc.trade.prices.table["default:apple"] = {item = "default:iron_ingot", count = 1} -npc.trade.prices.table["default:stone"] = {item = "default:wood_planks", count = 1} -npc.trade.prices.table["default:cobble"] = {item = "default:iron_ingot", count = 1} -npc.trade.prices.table["farming:cotton"] = {item = "default:iron_ingot", count = 1} -npc.trade.prices.table["farming:bread"] = {item = "default:gold_ingot", count = 1} -npc.trade.prices.table["default:sword_stone"] = {item = "default:iron_ingot", count = 2} -npc.trade.prices.table["default:pick_stone"] = {item = "default:iron_ingot", count = 1} -npc.trade.prices.table["default:shovel_stone"] = {item = "default:iron_ingot", count = 2} -npc.trade.prices.table["default:axe_stone"] = {item = "default:iron_ingot", count = 1} -npc.trade.prices.table["default:hoe_stone"] = {item = "default:iron_ingot", count = 1} +-- Tier 3 items: cheap items +npc.trade.prices.table["default:cobble"] = {tier = npc.trade.prices.currency.tier3, count = 0.1} +npc.trade.prices.table["flowers:geranium"] = {tier = npc.trade.prices.currency.tier3, count = 0.5} +npc.trade.prices.table["default:apple"] = {tier = npc.trade.prices.currency.tier3, count = 1} +npc.trade.prices.table["default:tree"] = {tier = npc.trade.prices.currency.tier3, count = 2} +npc.trade.prices.table["flowers:rose"] = {tier = npc.trade.prices.currency.tier3, count = 2} +npc.trade.prices.table["default:stone"] = {tier = npc.trade.prices.currency.tier3, count = 2} +npc.trade.prices.table["farming:seed_cotton"] = {tier = npc.trade.prices.currency.tier3, count = 3} +npc.trade.prices.table["farming:seed_wheat"] = {tier = npc.trade.prices.currency.tier3, count = 3} +npc.trade.prices.table["default:clay_lump"] = {tier = npc.trade.prices.currency.tier3, count = 3} +npc.trade.prices.table["mobs:meat_raw"] = {tier = npc.trade.prices.currency.tier3, count = 4} +npc.trade.prices.table["default:sapling"] = {tier = npc.trade.prices.currency.tier3, count = 5} +npc.trade.prices.table["mobs:meat"] = {tier = npc.trade.prices.currency.tier3, count = 5} +npc.trade.prices.table["mobs:leather"] = {tier = npc.trade.prices.currency.tier3, count = 6} +npc.trade.prices.table["default:sword_stone"] = {tier = npc.trade.prices.currency.tier3, count = 6} +npc.trade.prices.table["default:shovel_stone"] = {tier = npc.trade.prices.currency.tier3, count = 6} +npc.trade.prices.table["default:axe_stone"] = {tier = npc.trade.prices.currency.tier3, count = 6} +npc.trade.prices.table["default:hoe_stone"] = {tier = npc.trade.prices.currency.tier3, count = 6} +npc.trade.prices.table["default:pick_stone"] = {tier = npc.trade.prices.currency.tier3, count = 7} +npc.trade.prices.table["farming:cotton"] = {tier = npc.trade.prices.currency.tier3, count = 15} +npc.trade.prices.table["farming:bread"] = {tier = npc.trade.prices.currency.tier3, count = 20} +-- Tier 2 items: medium priced items + +-- Tier 1 items: expensive items +npc.trade.prices.table["default:diamond"] = {tier = npc.trade.prices.currency.tier1, count = 90} +npc.trade.prices.table["advanced_npc:marriage_ring"] = {tier = npc.trade.prices.currency.tier1, count = 100} -- Functions function npc.trade.prices.update(item_name, price) @@ -50,4 +75,28 @@ end function npc.trade.prices.remove(item_name) npc.trade.prices.table[item_name] = nil +end + +-- Gets all the item for a specified budget +function npc.trade.prices.get_items_for_currency_count(tier, count) + local result = {} + for item_name, price in pairs(npc.trade.prices.table) do + -- Check price currency is of the same tier + if price.tier == tier and price.count <= count then + result[item_name] = price + end + end + return result +end + +-- This methods will compare the given item string to the +-- currencies set in the currencies table. Returns true if +-- itemstring is a currency. +function npc.trade.prices.is_item_currency(itemstring) + if npc.get_item_name(itemstring) == npc.trade.prices.currency.tier3 + or npc.get_item_name(itemstring) == npc.trade.prices.currency.tier2 + or npc.get_item_name(itemstring) == npc.trade.prices.currency.tier1 then + return true + end + return false end \ No newline at end of file diff --git a/trade/trade.lua b/trade/trade.lua index a5ffbcc..0ce2165 100644 --- a/trade/trade.lua +++ b/trade/trade.lua @@ -99,20 +99,99 @@ function npc.trade.get_random_trade_status() end end +-- Convenience method that retrieves all the currency +-- items that a NPC has on his/her inventory +function npc.trade.get_currencies_in_inventory(self) + local result = {} + local tier3 = npc.inventory_contains(self, npc.trade.prices.currency.tier3) + local tier2 = npc.inventory_contains(self, npc.trade.prices.currency.tier2) + local tier1 = npc.inventory_contains(self, npc.trade.prices.currency.tier1) + if tier3 ~= nil then + table.insert(result, {name = npc.get_item_name(tier3.item_string), + count = npc.get_item_count(tier3.item_string)} ) + end + if tier2 ~= nil then + table.insert(result, {name = npc.get_item_name(tier2.item_string), + count = npc.get_item_count(tier2.item_string)} ) + end + if tier1 ~= nil then + table.insert(result, {name = npc.get_item_name(tier1.item_string), + count = npc.get_item_count(tier1.item_string)} ) + end + + minetest.log("Found currency in inventory: "..dump(result)) + return result +end + -- This function will return an offer object, based -- on the items the NPC has. --- Criteria: If having a near empty inventory, (< 6) NPC --- will offer to buy with a 70% chance. --- If NPC has a near full inventory (> 10 items), NPC --- will offer to sell. The prices will be selected using: --- item_price * (+/- price_item * 0.2) so item will be --- more or less 20% of the item price. +-- Criteria: The NPC will offer to sell its items +-- if it doesn't has any currency. function npc.trade.get_casual_trade_offer(self, offer_type) - return { - offer_type = offer_type, - item = "default:wood 10", - price = "default:iron_lump 20" - } + local result = {} + -- Check offer type + if offer_type == npc.trade.OFFER_BUY then + -- Create buy offer based on what the NPC can actually buy + local currencies = npc.trade.get_currencies_in_inventory(self) + -- Choose a random currency + local chosen_tier = currencies[math.random(#currencies)] + -- Get items for this currency + local buyable_items = + npc.trade.prices.get_items_for_currency_count(chosen_tier.name, chosen_tier.count) + -- Select a random item from the buyable items + local item_set = {} + for item,price in pairs(buyable_items) do + table.insert(item_set, item) + end + local item = item_set[math.random(#item_set)] + -- Choose buying quantity. Since this is a buy offer, NPC will buy items + -- at half the price. Therefore, NPC will always ask for even quantities + -- so that the price count is always an integer number + local amount_to_buy = math.random(1,5) * 2 + local price_item_count = buyable_items[item].count * ((amount_to_buy) / 2) + -- Increase the amount to buy if the result of the price is a decimal number + while price_item_count % 1 ~= 0 do + amount_to_buy = amount_to_buy + 1 + price_item_count = buyable_items[item].count * ((amount_to_buy) / 2) + end + -- Create price itemstring + local price_string = buyable_items[item].tier.." " + ..tostring( buyable_items[item].count * (amount_to_buy / 2) ) + + -- Build the return object + result = { + offer_type = offer_type, + item = item.." "..amount_to_buy, + price = price_string + } + else + -- Make sell offer, NPC will sell items to NPC at regular price + -- NPC will also offer items from their inventory + local sellable_items = {} + for i = 1, #self.inventory do + if self.inventory[i] ~= "" then + if npc.trade.prices.is_item_currency(self.inventory[i]) == false then + table.insert(sellable_items, self.inventory[i]) + end + end + end + -- Choose a random item from the sellable items + local item = sellable_items[math.random(#sellable_items)] + -- Choose how many of this item will be sold to player + local count = math.random(npc.get_item_count(item)) + -- Get and calculate price for this object + minetest.log("Item: "..dump(item)..", name: "..dump(npc.get_item_name(item))) + local price_object = npc.trade.prices.table[npc.get_item_name(item)] + local price_string = price_object.tier.." "..tostring(price_object.count * count) + -- Build return object + result = { + offer_type = offer_type, + item = npc.get_item_name(item).." "..count, + price = price_string + } + end + + return result end function npc.trade.perform_trade(self, player_name, offer)