mirror of
https://gitea.your-land.de/Sokomine/yl_speak_up.git
synced 2025-06-17 06:08:06 +02:00
226 lines
7.2 KiB
Lua
226 lines
7.2 KiB
Lua
-----------------------------------------------------------------------------
|
|
-- limits for trading: maximum and minimum stock to keep
|
|
-----------------------------------------------------------------------------
|
|
-- sometimes players may not want the NPC to sell *all* of their stock,
|
|
-- or not let the NPC buy endless amounts of something when only a limited
|
|
-- amount is needed
|
|
-----------------------------------------------------------------------------
|
|
|
|
-- helper function: make sure all necessary entries in the trades table exist
|
|
yl_speak_up.setup_trade_limits = function(dialog)
|
|
if(not(dialog)) then
|
|
dialog = {}
|
|
end
|
|
if(not(dialog.trades)) then
|
|
dialog.trades = {}
|
|
end
|
|
if(not(dialog.trades.limits)) then
|
|
dialog.trades.limits = {}
|
|
end
|
|
if(not(dialog.trades.limits.sell_if_more)) then
|
|
dialog.trades.limits.sell_if_more = {}
|
|
end
|
|
if(not(dialog.trades.limits.buy_if_less)) then
|
|
dialog.trades.limits.buy_if_less = {}
|
|
end
|
|
return dialog
|
|
end
|
|
|
|
|
|
-- helper function: count how many items the NPC has in his inventory
|
|
-- empty stacks are counted under the key "";
|
|
-- for other items, the amount of items of each type is counted
|
|
yl_speak_up.count_npc_inv = function(n_id)
|
|
if(not(n_id)) then
|
|
return {}
|
|
end
|
|
-- the NPC's inventory
|
|
local npc_inv = minetest.get_inventory({type="detached", name="yl_speak_up_npc_"..tostring(n_id)})
|
|
|
|
if(not(npc_inv)) then
|
|
return {}
|
|
end
|
|
local anz = npc_inv:get_size('npc_main')
|
|
local stored = {}
|
|
for i=1, anz do
|
|
local stack = npc_inv:get_stack('npc_main', i )
|
|
local name = stack:get_name()
|
|
local count = stack:get_count()
|
|
-- count empty stacks
|
|
if(name=="") then
|
|
count = 1
|
|
end
|
|
-- count how much of each item is there
|
|
if(not(stored[ name ])) then
|
|
stored[ name ] = count
|
|
else
|
|
stored[ name ] = stored[ name ] + count
|
|
end
|
|
end
|
|
return stored
|
|
end
|
|
|
|
|
|
-- helper function: update the items table so that it reflects a limitation
|
|
-- items is a table (list) with these entries:
|
|
-- [1] 0 in stock;
|
|
-- [2] sell if more than 0;
|
|
-- [3] buy if less than 10000;
|
|
-- [4] item is part of a trade offer
|
|
yl_speak_up.insert_trade_item_limitation = function( items, k, i, v )
|
|
if( i<1 or i>4) then
|
|
return;
|
|
end
|
|
if( not( items[ k ] )) then
|
|
-- 0 in stock; sell if more than 0; buy if less than 10000; item is part of a trade offer
|
|
items[ k ] = { 0, 0, 10000, false, #items }
|
|
end
|
|
items[ k ][ i ] = v
|
|
end
|
|
|
|
|
|
|
|
-- handle input to the formspec
|
|
yl_speak_up.input_trade_limit = function(player, formname, fields)
|
|
-- the player has selected an entry - edit it
|
|
if(fields and fields["edit_trade_limit"]) then
|
|
local selection = minetest.explode_table_event( fields[ "edit_trade_limit" ])
|
|
if( selection and selection['row']
|
|
and (selection['type'] == 'DCL' or selection['type'] == 'CHG')) then
|
|
-- show edit trade limit formspec
|
|
yl_speak_up.show_fs(player, "edit_trade_limit", {selected_row = selection['row']})
|
|
return
|
|
end
|
|
end
|
|
|
|
if(fields and (fields.back or fields.quit)) then
|
|
-- back to the normal trade list
|
|
yl_speak_up.show_fs(player, "trade_list")
|
|
return
|
|
end
|
|
-- else show this formspec again
|
|
yl_speak_up.show_fs(player, "trade_limit")
|
|
end
|
|
|
|
|
|
-- show the formspec
|
|
yl_speak_up.get_fs_trade_limit = function(player, selected)
|
|
local pname = player:get_player_name()
|
|
local n_id = yl_speak_up.speak_to[pname].n_id
|
|
local dialog = yl_speak_up.speak_to[pname].dialog
|
|
-- in items, existing amount and limit are collected for display
|
|
local items = {}
|
|
|
|
if(not(dialog) or not(n_id)) then
|
|
return "Error. Missing dialog when accessing trade limits."
|
|
end
|
|
-- make sure all necessary entries in the trades table exist
|
|
yl_speak_up.setup_trade_limits(dialog)
|
|
|
|
-- how many items does the NPC have alltogether?
|
|
-- there may be more than one stack of the same type; store amount
|
|
local counted_inv = yl_speak_up.count_npc_inv(n_id)
|
|
for k,v in pairs(counted_inv) do
|
|
yl_speak_up.insert_trade_item_limitation(items, k, 1, v)
|
|
end
|
|
|
|
-- items that are part of any of the trades may also be subject to limits; store item names
|
|
for trade_id, trade_data in ipairs(dialog.trades) do
|
|
if(trade_id ~= "limits") then
|
|
-- what the NPC sells may be subject to limits
|
|
local stack = ItemStack(trade_data.buy[1])
|
|
yl_speak_up.insert_trade_item_limitation(items, stack:get_name(), 4, true )
|
|
-- what the customer pays may be subject to limits as well
|
|
stack = ItemStack(trade_data.pay[1])
|
|
yl_speak_up.insert_trade_item_limitation(items, stack:get_name(), 4, true )
|
|
end
|
|
end
|
|
|
|
-- everything for which there's already a sell_if_more limit
|
|
for k,v in pairs(dialog.trades.limits.sell_if_more) do
|
|
mob_trading.insert_item_limitation( items, k, 2, v )
|
|
end
|
|
|
|
-- everything for which there's already a buy_if_less limit
|
|
for k,v in pairs(dialog.trades.limits.buy_if_less ) do
|
|
mob_trading.insert_item_limitation( items, k, 3, v )
|
|
end
|
|
|
|
-- all items for which limitations might possibly be needed have been collected;
|
|
-- now display them
|
|
local formspec = {'size[18,12]'..
|
|
'button[0.5,11.1;17,0.8;back;Back]'..
|
|
'label[7.0,0.5;List of trade limits]'..
|
|
'label[0.5,1.0;If you do not set any limits, your NPC will buy and sell as many '..
|
|
'items as his inventory allows.\n'..
|
|
'If you set \'Will sell if more than this\', your NPC '..
|
|
'will only sell if he will have enough left after the trade,\n'..
|
|
'and if you set \'Will buy if less than this\', he will '..
|
|
'only buy items as long as he will not end up with more than '..
|
|
'this.]'..
|
|
'tablecolumns[' ..
|
|
'text,align=left;'..
|
|
'color;text,align=right;'..
|
|
'color;text,align=center;'..
|
|
'text,align=right;'..
|
|
'color;text,align=center;'..
|
|
'text,align=right;'..
|
|
'color;text,align=left]'..
|
|
'table[0.1,2.3;17.8,8.5;edit_trade_limit;'..
|
|
'Description:,'..
|
|
'#FFFFFF,NPC has:,'..
|
|
'#FFFFFF,Will sell if more than this:,,'..
|
|
'#FFFFFF,Will buy if less than this:,,'..
|
|
'#EEEEEE,Item string:,'
|
|
}
|
|
|
|
-- the table event selection returns a row index - we need to translate that to our table
|
|
local item_list = {}
|
|
local row = 2
|
|
local selected_row = 1
|
|
-- TODO: sort this list in some way? alphabeticly? by limit?
|
|
for k,v in pairs( items ) do
|
|
table.insert(item_list, k)
|
|
if(selected and k == selected) then
|
|
selected_row = #item_list + 1
|
|
end
|
|
local c1 = '#FF0000'
|
|
if( v[1] > 0 ) then
|
|
c1 = '#BBBBBB'
|
|
end
|
|
local t1 = 'sell always'
|
|
local c2 = '#44EE44'
|
|
if( v[2] > 0 ) then
|
|
c2 = '#00FF00'
|
|
t1 = 'sell if more than:'
|
|
end
|
|
local t2 = 'buy always'
|
|
local c3 = '#EEEE44'
|
|
if( v[3] ~= 10000 ) then
|
|
c3 = '#FFFF00'
|
|
t2 = 'buy if less than:'
|
|
end
|
|
|
|
local desc = ''
|
|
if( k =="" ) then
|
|
desc = '<free inventory slot>'
|
|
k = '<nothing>'
|
|
elseif( minetest.registered_items[ k ]
|
|
and minetest.registered_items[ k ].description ) then
|
|
desc = minetest.registered_items[ k ].description
|
|
end
|
|
|
|
table.insert(formspec,
|
|
desc..','..
|
|
c1..','.. tostring( v[1] )..','..
|
|
c2..','..t1..','..tostring( v[2] )..','..
|
|
c3..','..t2..','..tostring( v[3] )..',#EEEEEE,'..k..',')
|
|
end
|
|
-- we need to store the table somewhere so that we know which limit is edited
|
|
yl_speak_up.speak_to[pname].trade_limit_items = items
|
|
yl_speak_up.speak_to[pname].trade_limit_item_list = item_list
|
|
|
|
table.insert(formspec, ";"..selected_row)
|
|
return table.concat(formspec, '')
|
|
end
|