mirror of
https://gitea.your-land.de/Sokomine/yl_speak_up.git
synced 2025-06-16 13:48:06 +02:00
added limit handling to trade formspec
This commit is contained in:
parent
e7d82c1d52
commit
0b26af1287
88
fs_edit_trade_limit.lua
Normal file
88
fs_edit_trade_limit.lua
Normal file
@ -0,0 +1,88 @@
|
||||
-- add or edit a trade limit
|
||||
|
||||
yl_speak_up.input_edit_trade_limit = function(player, formname, fields)
|
||||
-- store the new limits?
|
||||
if(fields and fields["store_limit"]) then
|
||||
if(not(fields["item_name"])
|
||||
or fields["item_name"] == ""
|
||||
or not(minetest.registered_items[fields["item_name"]])) then
|
||||
-- TODO: show error message and back
|
||||
return
|
||||
end
|
||||
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
|
||||
|
||||
-- make sure all necessary entries in the trades table exist
|
||||
yl_speak_up.setup_trade_limits(dialog)
|
||||
|
||||
local anz = tonumber(fields['SellIfMoreThan'] or "0")
|
||||
if( anz and anz > 0 and anz < 10000 ) then
|
||||
dialog.trades.limits.sell_if_more[ fields["item_name"] ] = anz;
|
||||
yl_speak_up.log_change(pname, n_id, "sell_if_more set to "..tostring(anz)..
|
||||
" for "..tostring(fields["item_name"]))
|
||||
end
|
||||
|
||||
anz = tonumber(fields['BuyIfLessThan'] or "0")
|
||||
if( anz and anz > 0 and anz < 10000 ) then
|
||||
dialog.trades.limits.buy_if_less[ fields["item_name"] ] = anz;
|
||||
yl_speak_up.log_change(pname, n_id, "buy_if_less set to "..tostring(anz)..
|
||||
" for "..tostring(fields["item_name"]))
|
||||
end
|
||||
-- save these values
|
||||
yl_speak_up.save_dialog(n_id, dialog)
|
||||
yl_speak_up.show_fs(player, "trade_limit", {selected = fields.item_name})
|
||||
return
|
||||
end
|
||||
-- TODO: implement delete button
|
||||
|
||||
-- back to the normal trade list
|
||||
yl_speak_up.show_fs(player, "trade_limit", {selected = fields.item_name})
|
||||
end
|
||||
|
||||
|
||||
-- edit a trade limit or add a new one
|
||||
yl_speak_up.get_fs_edit_trade_limit = function(player, selected_row)
|
||||
local pname = player:get_player_name()
|
||||
local items = yl_speak_up.speak_to[pname].trade_limit_items
|
||||
local item_list = yl_speak_up.speak_to[pname].trade_limit_item_list
|
||||
if(not(selected_row) or selected_row < 1
|
||||
or not(items) or not(item_list)
|
||||
or selected_row > #item_list + 1) then
|
||||
-- TODO show more helpful error message
|
||||
return "Error in get_fs_edit_trade_limit."
|
||||
end
|
||||
local selected = item_list[ selected_row - 1]
|
||||
local item_data = items[ selected ]
|
||||
-- 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
|
||||
local def = minetest.registered_items[ selected ]
|
||||
if(not(def)) then
|
||||
def = {description = '- unknown item -'}
|
||||
end
|
||||
|
||||
local formspec = {'size[8,7]',
|
||||
'item_image[-0.25,2.5;2.0,2.0;', selected, ']',
|
||||
'label[1.0,0.0;Set limits for buy and sell]',
|
||||
'label[1.5,1.0;Description:]',
|
||||
'label[4.0,1.0;', (def.description or '?'), ']',
|
||||
'label[1.5,2.0;Item name:]',
|
||||
--'label[3.5,1.0;', tostring( selected ), ']',
|
||||
'field[4.0,2.0;4,1;item_name;;', tostring( selected ), ']',
|
||||
'label[1.5,3.0;In stock:]',
|
||||
'label[4.0,3.0;', tostring( item_data[1] ), ']',
|
||||
'label[1.5,4.0;Sell if more than]',
|
||||
'field[4.0,4.0;1.2,1.0;SellIfMoreThan;;', tostring( item_data[2] ), ']',
|
||||
'label[5.0,4.0;will remain in stock.]',
|
||||
'label[1.5,5.0;Buy if less than]',
|
||||
'field[4.0,5.0;1.2,1.0;BuyIfLessThan;;', tostring( item_data[3] ), ']',
|
||||
'label[5.0,5.0;will end up in stock.]',
|
||||
'button[1.5,6.0;2,1.0;store_limit;Save]',
|
||||
'button[4.5,6.0;2,1.0;back_to_limit_list;Back]'
|
||||
-- TODO: delete button
|
||||
}
|
||||
return table.concat(formspec, '')
|
||||
end
|
225
fs_trade_limit.lua
Normal file
225
fs_trade_limit.lua
Normal file
@ -0,0 +1,225 @@
|
||||
-----------------------------------------------------------------------------
|
||||
-- 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
|
3
init.lua
3
init.lua
@ -82,6 +82,9 @@ dofile(modpath .. "fs_initial_config.lua")
|
||||
dofile(modpath .. "fs_player_offers_item.lua")
|
||||
-- inventory management, trading and handling of quest items:
|
||||
dofile(modpath .. "inventory.lua")
|
||||
-- limit how much the NPC shall buy and sell
|
||||
dofile(modpath .. "fs_trade_limit.lua")
|
||||
dofile(modpath .. "fs_edit_trade_limit.lua")
|
||||
-- trade one item(stack) against one other item(stack)
|
||||
dofile(modpath .. "trade_simple.lua")
|
||||
-- easily accessible list of all trades the NPC offers
|
||||
|
20
show_fs.lua
20
show_fs.lua
@ -49,6 +49,12 @@ minetest.register_on_player_receive_fields( function(player, formname, fields)
|
||||
elseif formname == "yl_speak_up:add_trade_simple" then
|
||||
yl_speak_up.input_add_trade_simple(player, formname, fields)
|
||||
return true
|
||||
elseif formname == "yl_speak_up:trade_limit" then
|
||||
yl_speak_up.input_trade_limit(player, formname, fields)
|
||||
return true
|
||||
elseif formname == "yl_speak_up:edit_trade_limit" then
|
||||
yl_speak_up.input_edit_trade_limit(player, formname, fields)
|
||||
return true
|
||||
-- handled in fs_initial_config.lua
|
||||
elseif formname == "yl_speak_up:initial_config" then
|
||||
yl_speak_up.input_fs_initial_config(player, formname, fields)
|
||||
@ -298,6 +304,20 @@ yl_speak_up.show_fs = function(player, fs_name, param)
|
||||
yl_speak_up.show_fs_ver(pname, "yl_speak_up:add_trade_simple",
|
||||
yl_speak_up.get_fs_add_trade_simple(player, param), 1)
|
||||
|
||||
elseif(fs_name == "trade_limit") then
|
||||
if(not(param)) then
|
||||
param = {}
|
||||
end
|
||||
yl_speak_up.show_fs_ver(pname, "yl_speak_up:trade_limit",
|
||||
yl_speak_up.get_fs_trade_limit(player, param.selected))
|
||||
|
||||
elseif(fs_name == "edit_trade_limit") then
|
||||
if(not(param)) then
|
||||
param = {}
|
||||
end
|
||||
yl_speak_up.show_fs_ver(pname, "yl_speak_up:edit_trade_limit",
|
||||
yl_speak_up.get_fs_edit_trade_limit(player, param.selected_row), 1)
|
||||
|
||||
elseif(fs_name == "initial_config") then
|
||||
if(not(param)) then
|
||||
param = {}
|
||||
|
@ -19,6 +19,12 @@ yl_speak_up.input_trade_list = function(player, formname, fields)
|
||||
return
|
||||
end
|
||||
|
||||
if(fields.trade_limit) then
|
||||
-- show a list of how much the NPC can buy and sell
|
||||
yl_speak_up.show_fs(player, "trade_limit")
|
||||
return
|
||||
end
|
||||
|
||||
-- toggle between view of dialog option trades and trade list trades
|
||||
if(fields.show_dialog_option_trades
|
||||
or fields.show_trade_list) then
|
||||
@ -186,7 +192,7 @@ yl_speak_up.get_fs_trade_list = function(player, show_dialog_option_trades)
|
||||
h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h,
|
||||
"show_trade_list",
|
||||
text, text,
|
||||
true, nil, nil, pname_for_old_fs)
|
||||
true, nil, nil, pname_for_old_fs)
|
||||
end
|
||||
-- button "add trade" for those who can edit the NPC (entering edit mode is not required)
|
||||
local text = "Add a new trade."
|
||||
@ -194,6 +200,12 @@ yl_speak_up.get_fs_trade_list = function(player, show_dialog_option_trades)
|
||||
"trade_list_add_trade",
|
||||
text, text,
|
||||
true, nil, nil, pname_for_old_fs)
|
||||
-- show a list of how much the NPC will buy and sell
|
||||
text = "Do not buy or sell more than what I will tell you."
|
||||
h = yl_speak_up.add_edit_button_fs_talkdialog(formspec, h,
|
||||
"trade_limit",
|
||||
text, text,
|
||||
true, nil, nil, pname_for_old_fs)
|
||||
end
|
||||
|
||||
local text = "That was all. Let's continue talking."
|
||||
|
Loading…
Reference in New Issue
Block a user