From 4d4374730e4e3fd4bf42637eb0e612594ce9ad7a Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Wed, 6 Jun 2018 19:37:31 +0200 Subject: [PATCH] Trading: Allow to sell compass --- mods/ENTITIES/mobs_mc/villager.lua | 109 +++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 12 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index b0b6f813c..47d28f24b 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -6,6 +6,7 @@ -- TODO: Per-player trading inventories -- TODO: Particles -- TODO: 4s Regeneration I after trade unlock +-- FIXME: Possible to lock all trades -- intllib local MP = minetest.get_modpath(minetest.get_current_modname()) @@ -21,6 +22,20 @@ local player_trading_with = {} --################### -- LIST OF VILLAGER PROFESSIONS AND TRADES + +-- TECHNICAL RESTRICTIONS (FIXME): +-- * You can't use a clock as requested item +-- * You can't use a compass as requested item if its stack size > 1 +-- * You can't use a compass in the second requested slot +-- This is a problem in the mcl_compass and mcl_clock mods, +-- these items should be implemented as single items, then everything +-- will be much easier. + +local COMPASS = "mcl_compass:compass" +if minetest.registered_aliases[COMPASS] then + COMPASS = minetest.registered_aliases[COMPASS] +end + local E1 = { "mcl_core:emerald", 1, 1 } -- one emerald local professions = { farmer = { @@ -143,11 +158,10 @@ local professions = { { { "mcl_core:paper", 24, 36 }, E1 }, }, --- { - -- TODO: compass - -- the difficulty lies in supporting the compass group, not the concrete item --- { { "mcl_compass:compass", 1, 1 }, E1 }, --- }, + { + -- subject to special checks + { { "mcl_compass:compass", 1, 1 }, E1 }, + }, { -- TODO: replace with empty map @@ -446,9 +460,47 @@ local update_offer = function(inv, player, sound) if not trade then return false end - if inv:contains_item("input", inv:get_stack("wanted", 1)) and - (inv:get_stack("wanted", 2):is_empty() or inv:contains_item("input", inv:get_stack("wanted", 2))) and - (trade.locked == false) then + local wanted1, wanted2 = inv:get_stack("wanted", 1), inv:get_stack("wanted", 2) + local input1, input2 = inv:get_stack("input", 1), inv:get_stack("input", 2) + + -- BEGIN OF SPECIAL HANDLING OF COMPASS + -- These 2 functions are a complicated check to check if the input contains a + -- special item which we cannot check directly against their name, like + -- compass. + -- TODO: Remove these check functions when compass and clock are implemented + -- as single items. + local check_special = function(special_item, group, wanted1, wanted2, input1, input2) + if minetest.registered_aliases[special_item] then + special_item = minetest.registered_aliases[special_item] + end + if wanted1:get_name() == special_item then + local check_input = function(input, wanted, group) + return minetest.get_item_group(input:get_name(), group) ~= 0 and input:get_count() >= wanted:get_count() + end + if check_input(input1, wanted1, group) then + return true + elseif check_input(input2, wanted1, group) then + return true + else + return false + end + end + return false + end + -- Apply above function to all items which we consider special. + -- This function succeeds if ANY item check succeeds. + local check_specials = function(wanted1, wanted2, input1, input2) + return check_special(COMPASS, "compass", wanted1, wanted2, input1, input2) + end + -- END OF SPECIAL HANDLING OF COMPASS + + if ( + ((inv:contains_item("input", wanted1) and + (wanted2:is_empty() or inv:contains_item("input", wanted2))) or + -- BEGIN OF SPECIAL HANDLING OF COMPASS + check_specials(wanted1, wanted2, input1, input2)) and + -- END OF SPECIAL HANDLING OF COMPASS + (trade.locked == false)) then inv:set_stack("output", 1, inv:get_stack("offered", 1)) if sound then minetest.sound_play("mobs_mc_villager_accept", {to_player = name}) @@ -558,10 +610,30 @@ mobs:register_mob("mobs_mc:villager", { -- enough items in input after the trade local wanted1 = inv:get_stack("wanted", 1) local wanted2 = inv:get_stack("wanted", 2) + local input1 = inv:get_stack("input", 1) + local input2 = inv:get_stack("input", 2) wanted1:set_count(wanted1:get_count()*2) wanted2:set_count(wanted2:get_count()*2) - if inv:contains_item("input", wanted1) and - (wanted2:is_empty() or inv:contains_item("input", wanted2)) then + -- BEGIN OF SPECIAL HANDLING FOR COMPASS + local special_checks = function(wanted1, input1, input2) + if wanted1:get_name() == COMPASS then + local compasses = 0 + if (minetest.get_item_group(input1:get_name(), "compass") ~= 0) then + compasses = compasses + input1:get_count() + end + if (minetest.get_item_group(input2:get_name(), "compass") ~= 0) then + compasses = compasses + input2:get_count() + end + return compasses >= wanted1:get_count() + end + return false + end + -- END OF SPECIAL HANDLING FOR COMPASS + if (inv:contains_item("input", wanted1) and + (wanted2:is_empty() or inv:contains_item("input", wanted2))) + -- BEGIN OF SPECIAL HANDLING FOR COMPASS + or special_checks(wanted1, input1, input2) then + -- END OF SPECIAL HANDLING FOR COMPASS return -1 else -- If less than double the wanted items, @@ -612,11 +684,24 @@ mobs:register_mob("mobs_mc:villager", { local accept local name = player:get_player_name() if listname == "output" then - inv:remove_item("input", inv:get_stack("wanted", 1)) + local wanted1 = inv:get_stack("wanted", 1) + inv:remove_item("input", wanted1) local wanted2 = inv:get_stack("wanted", 2) if not wanted2:is_empty() then inv:remove_item("input", inv:get_stack("wanted", 2)) end + -- BEGIN OF SPECIAL HANDLING FOR COMPASS + if wanted1:get_name() == COMPASS then + for n=1, 2 do + local input = inv:get_stack("input", n) + if minetest.get_item_group(input:get_name(), "compass") ~= 0 then + input:set_count(input:get_count() - wanted1:get_count()) + inv:set_stack("input", n, input) + break + end + end + end + -- END OF SPECIAL HANDLING FOR COMPASS local trader = player_trading_with[name] local tradenum = player_tradenum[name] local trades @@ -649,7 +734,7 @@ mobs:register_mob("mobs_mc:villager", { if trade.trade_counter >= 12 then trade.locked = true elseif trade.trade_counter >= 2 then - local r = math.random(1, math.random(1, 9)) + local r = math.random(1, math.random(4, 10)) if r == 1 then trade.locked = true end