ShopKeeper

Hi,

I've recently taken on a shop in Eleusis and looking for scripts to make it easier. I've got one now that helps with the pricing of items, which is great. Now I'm looking for one to help me see what's actually been sold or is missing from the store.. So what I'm looking for is something like...

I do "checkstore", and the script goes wares, adds everything in the store to a database.
The next time I do "checksales", it goes wares again, and then in a neat format displays what's now missing or has been added.
When I'm done restocking I'll do "checkstore" again to update the database.

If no one has anything like that I'd be interested in paying someone 50 credits to make it for me!
image
«1

Comments

  • I actually wouldn't mind something like this, but it would have to be for Nexus or zMUD.

  • I'm surprised Achaea hasn't just done what MKO did and created Shoplog which told you what has sold and for how much.
    Melaina Naftis - Spectral Arbiter of the Krymenian Academy
  • Melaina said:
    I'm surprised Achaea hasn't just done what MKO did and created Shoplog which told you what has sold and for how much.
    People have asked for it. Frequently. I'm sure you'll probably find a number of threads in the Golden Dais section specifically about it.

    However, development resources are limited, so they can't do everything; saying "hasn't just done" completely ignores how much work this would actually be, and what else doesn't get done as a result of doing it. Things are rarely simple when you're talking about complicated - and, in Achaea's case, often very old - systems.
  • I guess I must learn databases and use gmcp info to do this for me.
    image
  • You don't need databases. Not even sure it would make it easier if you did use one.
  • I have been tempted to make a script like this for the longest time (since I ran shops in Shallam).  Just never have time.

  • edited May 2017
    Can you save the data in tables when you close mudlet?
    image
  • @Rangor Look into table.save and table.load. You'll want to set up event handlers for the sysExitEvent to save and sysLoadEvent to load.
  • AhmetAhmet Wherever I wanna be
    You can save tables, yes, but I'd recommend databases in case of crash.

    Though, for this script, you can just save the tables when you use the shopcheck alias or whatever it is, so that won't be an issue.
    Huh. Neat.
  • Ty. Should be fairly easy with the gmcp inventory lists then.
    image
  • JonathinJonathin Retired in a hole.
    I might have a crack at this later.
    I am retired and log into the forums maybe once every 2 months. It was a good 20 years, live your best lives, friends.
  • Antonius said:
    @Rangor Look into table.save and table.load. You'll want to set up event handlers for the sysExitEvent to save and sysLoadEvent to load.
    Ive thought about creating something similar as well, but am terrible with gmcp when it comes to items and how list and what not work. However you could definitely use these events, but I just table.load on login trigger and save within functions used to update information in the table at the end of it.
  • SkyeSkye The Duchess Bellatere
    Jarrod actually threw together something for carts during the crafter's fair a few years back. One thing that I find important functionally is that checking your shop wares shouldn't override the original list of stock.

    I check my shop stock every day but I only restock after a certain amount of items has sold because this allows me to take inventory and refresh stock more easily. Stockroom space is very limited, so I cycle items sold to make things look fresh.

    To this end, I keep pretty extensive spreadsheets haha. I could do better with them, but haven't really had the time.


  • KayeilKayeil Washington State
    Caelan said:
    Skye said:
    Jarrod actually threw together something for carts during the crafter's fair a few years back. One thing that I find important functionally is that checking your shop wares shouldn't override the original list of stock.

    I check my shop stock every day but I only restock after a certain amount of items has sold because this allows me to take inventory and refresh stock more easily. Stockroom space is very limited, so I cycle items sold to make things look fresh.

    To this end, I keep pretty extensive spreadsheets haha. I could do better with them, but haven't really had the time.
    I did the spreadsheet thing for a while.  Then I said to myself, I says, "Self!, this is dumb. It's a game"

    And @Skye I don't know if you know this,  but I secretly LOVE your marketing messages.  The salesmanship and humor is unparalleled. Even though I haven't bought food in ..well, since mutton.. I absolutely love the thought of you wandering the streets like the Peanut guy at a ballpark, hawking your wares.  (totally serious)
    She really does have top notch marketing and her shops are really awesome. You can tell she puts a lot of effort into every little thing from the wares to how she cycles them so it's like there's always something new to see or try out.
    What doesn't kill you gives you exp.

  • @Kipposhi claims the bounty.

    <br><p>function asInventoryList(gmcpItems)</p>
    <p>    local tableResult = {}</p>
    <p><br></p>
    <p>    for _, item in ipairs(gmcpItems) do</p>
    <p>        local listItem = tableResult[item.name]</p>
    <p>        if not listItem then </p>
    <p>            tableResult[item.name] = 0</p>
    <p>        end</p>
    <p><br></p>
    <p>        tableResult[item.name] = tableResult[item.name] + 1</p>
    <p>    end</p>
    <p><br></p>
    <p>    return tableResult</p>
    <p>end</p>
    <p><br></p>
    <p>function updateInventory()</p>
    <p>    inventoryList =  asInventoryList(gmcp.Char.Items.List.items)</p>
    <p>end</p>
    <p><br></p>
    <p>function compareInventory()</p>
    <p>    tempinventoryList = asInventoryList(gmcp.Char.Items.List.items)</p>
    <p><br></p>
    <p>    missingItems = {}</p>
    <p><br></p>
    <p>    for name, count in pairs(inventoryList) do</p>
    <p>        if not tempinventoryList[name] or tempinventoryList[name] < count then</p>
    <p>        </p>
    <p>            local currentCount = tempinventoryList[name] or 0</p>
    <p>        </p>
    <p>            table.insert(missingItems, { name = name, diff = count - currentCount })</p>
    <p>        end</p>
    <p>    end</p>
    <p><br></p>
    <p>	for _, v in ipairs(missingItems) do</p>
    <p>		cecho("\n<green>Item: " ..v.name.. " - <blue>Sold: " ..v.diff)</p>
    <p>	end	</p>
    <p>	</p>
    <p>end</p>

    image
  • edited June 2017
    updated.... 

    Run updateInventory() when you're saving your normal stocking levels.

    run compareInventory() when you want to see what's missing since you ran updateInventory()
    inventoryList = {}</code></pre><pre class="CodeBlock"><code><pre class="CodeBlock"><code>


    function asInventoryList(gmcpItems)

    local tableResult = {}


    for _, item in ipairs(gmcpItems) do

    local listItem = tableResult[item.name]

    if not listItem then

    tableResult[item.name] = 0

    end


    tableResult[item.name] = tableResult[item.name] + 1

    end


    return tableResult

    end


    function updateInventory()

    inventoryList = asInventoryList(gmcp.Char.Items.List.items)


    saveInventory()


    end


    function saveInventory()

    if string.char(getMudletHomeDir():byte()) == "/"

    then _sep = "/"

    else _sep = "\\"

    end -- if

    shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"

    table.save(shop_inventory, inventoryList)


    end -- func


    function loadInventory()

    if string.char(getMudletHomeDir():byte()) == "/"

    then _sep = "/"

    else _sep = "\\"

    end -- if

    shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"

    if (io.exists(shop_inventory)) then

    table.load(shop_inventory, inventoryList)

    end -- if

    end -- func


    function compareInventory()

    tempinventoryList = asInventoryList(gmcp.Char.Items.List.items)

    loadInventory()

    missingItems = {}


    for name, count in pairs(inventoryList) do

    if not tempinventoryList[name] or tempinventoryList[name] < count then

    local currentCount = tempinventoryList[name] or 0

    table.insert(missingItems, { name = name, diff = count - currentCount })

    end

    end


    for _, v in ipairs(missingItems) do

    cecho("\n<green>Item: " ..v.name.. " - <blue>Sold: " ..v.diff)

    end

    end


    image
  • KayeilKayeil Washington State
    edited June 2017
    Thank you @Rangor and @Kipposhi for sharing! I do all of my shopkeeping manually since I can't code and this makes up for the lack of a shop log greatly and saves me some time from going through the list myself every day. I really appreciate the time you're saving me!

    Edit: My only suggestion if this is ever updated again is if it can me made to monitor multiple shops instead of one. I spoke to @Kogan and he told me he could do it with what's there if I needed him to (not sure yet), but I think that'd be highly beneficial for Chancellors who run multiple city shops.
    What doesn't kill you gives you exp.

  • If you have more than one shop, you can copy paste it and rename everywhere it says "inventory" to shopname_inventory and you'll have one script for each shop
    image
  • Kayeil said:
    Thank you @Rangor and @Kipposhi for sharing! I do all of my shopkeeping manually since I can't code and this makes up for the lack of a shop log greatly and saves me some time from going through the list myself every day. I really appreciate the time you're saving me!

    Edit: My only suggestion if this is ever updated again is if it can me made to monitor multiple shops instead of one. I spoke to @Kogan and he told me he could do it with what's there if I needed him to (not sure yet), but I think that'd be highly beneficial for Chancellors who run multiple city shops.
    Multiple cityshops, what a luxury.
    image
  • Rangor said:
    If you have more than one shop, you can copy paste it and rename everywhere it says "inventory" to shopname_inventory and you'll have one script for each shop

    You could do that, but there's no real need. It's just a change to a few lines of code to get it to support multiple shops, just by making "inventoryList" a dictionary using room number as the key, rather than a list for just a single room's worth of items. Hopefully @Kipposhi doesn't mind me making some tweaks to his stuff. If you've already got an inventory list saved, you'll probably want to go and update it after updating the script.

    inventoryList = {}
    
    function asInventoryList(gmcpItems)
    	local tableResult = {}
    
    	for _, item in ipairs(gmcpItems) do
    		local listItem = tableResult[item.name]
    		
    		if not listItem then
    			tableResult[item.name] = 0
    		end
    
    		tableResult[item.name] = tableResult[item.name] + 1
    	end
    
    	return tableResult
    end
    
    function updateInventory()
    	inventoryList[gmcp.Room.Info.num] = asInventoryList(gmcp.Char.Items.List.items)
    
    	saveInventory()
    end
    
    function saveInventory()
    	if string.char(getMudletHomeDir():byte()) == "/" then 
    		_sep = "/"
    	else 
    		_sep = "\\"
    	end -- if
    
    	shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"
    
    	table.save(shop_inventory, inventoryList)
    end -- func
    
    function loadInventory()
    	if string.char(getMudletHomeDir():byte()) == "/" then 
    		_sep = "/"
    	else 
    		_sep = "\\"
    	end -- if
    
    	shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"
    
    	if (io.exists(shop_inventory)) then
    		table.load(shop_inventory, inventoryList)
    	end -- if
    end -- func
    registerAnonymousEventHandler("sysLoadEvent", "loadInventory")
    
    function compareInventory()
    	tempinventoryList = asInventoryList(gmcp.Char.Items.List.items)
    
    	loadInventory()
    
    	missingItems = {}
    
    	for name, count in pairs(inventoryList[gmcp.Room.Info.num]) do
    		if not tempinventoryList[name] or tempinventoryList[name] < count then
    			local currentCount = tempinventoryList[name] or 0
    
    			table.insert(missingItems, { name = name, diff = count - currentCount })
    		end
    	end
    
    	for _, v in ipairs(missingItems) do
    		cecho("\nItem: " ..v.name.. " - Sold: " ..v.diff)
    	end
    end
    
  • Antonius said:
    Rangor said:
    If you have more than one shop, you can copy paste it and rename everywhere it says "inventory" to shopname_inventory and you'll have one script for each shop

    You could do that, but there's no real need. It's just a change to a few lines of code to get it to support multiple shops, just by making "inventoryList" a dictionary using room number as the key, rather than a list for just a single room's worth of items. Hopefully @Kipposhi doesn't mind me making some tweaks to his stuff. If you've already got an inventory list saved, you'll probably want to go and update it after updating the script.

    inventoryList = {}
    
    function asInventoryList(gmcpItems)
    	local tableResult = {}
    
    	for _, item in ipairs(gmcpItems) do
    		local listItem = tableResult[item.name]
    		
    		if not listItem then
    			tableResult[item.name] = 0
    		end
    
    		tableResult[item.name] = tableResult[item.name] + 1
    	end
    
    	return tableResult
    end
    
    function updateInventory()
    	inventoryList[gmcp.Room.Info.num] = asInventoryList(gmcp.Char.Items.List.items)
    
    	saveInventory()
    end
    
    function saveInventory()
    	if string.char(getMudletHomeDir():byte()) == "/" then 
    		_sep = "/"
    	else 
    		_sep = "\\"
    	end -- if
    
    	shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"
    
    	table.save(shop_inventory, inventoryList)
    end -- func
    
    function loadInventory()
    	if string.char(getMudletHomeDir():byte()) == "/" then 
    		_sep = "/"
    	else 
    		_sep = "\\"
    	end -- if
    
    	shop_inventory = getMudletHomeDir() .. _sep .. "shop_inventory.lua"
    
    	if (io.exists(shop_inventory)) then
    		table.load(shop_inventory, inventoryList)
    	end -- if
    end -- func
    registerAnonymousEventHandler("sysLoadEvent", "loadInventory")
    
    function compareInventory()
    	tempinventoryList = asInventoryList(gmcp.Char.Items.List.items)
    
    	loadInventory()
    
    	missingItems = {}
    
    	for name, count in pairs(inventoryList[gmcp.Room.Info.num]) do
    		if not tempinventoryList[name] or tempinventoryList[name] < count then
    			local currentCount = tempinventoryList[name] or 0
    
    			table.insert(missingItems, { name = name, diff = count - currentCount })
    		end
    	end
    
    	for _, v in ipairs(missingItems) do
    		cecho("\nItem: " ..v.name.. " - Sold: " ..v.diff)
    	end
    end
    
    oo, clever. I mostly contributed with the cecho, all the fors and pairs and ipairs confuse the blip out of me. especially what the asInventoryList does. :)
    image
  • KayeilKayeil Washington State
    Rangor said:
    Kayeil said:
    Thank you @Rangor and @Kipposhi for sharing! I do all of my shopkeeping manually since I can't code and this makes up for the lack of a shop log greatly and saves me some time from going through the list myself every day. I really appreciate the time you're saving me!

    Edit: My only suggestion if this is ever updated again is if it can me made to monitor multiple shops instead of one. I spoke to @Kogan and he told me he could do it with what's there if I needed him to (not sure yet), but I think that'd be highly beneficial for Chancellors who run multiple city shops.
    Multiple cityshops, what a luxury.
    Indeed! I don't know how it works in other cities but I know Cyrene's Chancellor runs more than one for the city. I think Targossas has several org shops as well? Including one in Cyrene that's run by one of their Houses, I think (Luminai?). Thanks for the updates guys!
    What doesn't kill you gives you exp.

  • I don't forums much, but if you need any more help send me a message IG or something.
  • can someone break this down for the completely code-illiterate me? Am I meant to just c/p all this into a single script, then create aliases that call on these functions? 
  • Merewyn said:
    can someone break this down for the completely code-illiterate me? Am I meant to just c/p all this into a single script, then create aliases that call on these functions? 
    Yep!
    image
  • KlendathuKlendathu Eye of the Storm
    Tysandyr, I need to send you a project i've got for work, about 10k rows of VBA code in a spreadsheet, needs commenting. Thanks,

    Tharos, the Announcer of Delos shouts, "It's near the end of the egghunt and I still haven't figured out how to pronounce Clean-dat-hoo."
  • 1: codecodecodecode  'R
    2: codecodecodecode  '2
    3: codecodecodecode  'D
    4: codecodecodecode  '2
    5: codecodecodecode  'R
    6: codecodecodecode  '2

    I got you bae
    "All we have to decide is what to do with the time that is given to us."

Sign In or Register to comment.