Bug - Fixed Using mall_price doesn't ignore forbiddenStores

Irrat

Member
The preference forbiddenStores is a list of player IDs which tells mafia to avoid buying from their stores.
The list is automatically populated when an attempt to purchase from the store fails as you were ignored.

However, other functions such as checking the mall price will return the price of the stores we're not going to buy from. Which can be an issue when you're scripting this and didn't account for that.

An easy example is when you expected to consume 3 mojo filters, mall price shows that there are 6 under 10k. But both stores are in your forbiddenStores.
Garbo will throw an error as it expected to buy 3 mojo filters, but failed. And mojo filters are still being reported as under 10k, but the next cheapest is beyond your price point.
This is good behavior by garbo, but bad behavior by mafia as garbo has no way to tell that it was due to the forbiddenStores without black magic.

Another scenario I've encountered is when trying to figure out if its cheaper to craft an item, or buy the item. My script will recursive itself when it doesn't have enough items, so it's always flip flopping between crafting item or buying item.
So obviously, when it can't even tell which store is cheaper because the 1-5th cheapest were all in my forbidden stores.. It couldn't resolve. It was always trying to buy the item, but was refused as its in the forbiddenStores. So it recursed then tried to buy again because it's still reported as the cheapest.

The solution I believe should be to hide the forbiddenStores from the price checks, then to provide expected behavior for how many items should be available. We should probably exclude forbiddenStores from the anti-bot measure which skips the first 5 items. So the first 5 items will always be a store not in your forbiddenStores.
 

fronobulax

Developer
Staff member
What harm happens if the player does not set any forbidden stores?

I have not checked but it does seem reasonable for mafia to share, with a script, why something could not be bought but the script should use that information, not necessarily mafia.

I have not fleshed it out but I think if forbidden stores were excluded from various price calculations you could infer something about the hidden lower prices by adding and removing stores from the forbidden list and getting prices again.

I'd support a feature request that mafia expose why it failed to buy something but I'm not sure I'd call this a bug nor support the suggested change. "The Mall is not the game" said Jick a long time ago.
 

Veracity

Developer
Staff member
I believe that if we try to purchase, we will skip forbidden stores.
I believe that if we try to purchase and discover the store is "frozen" or is ignoring you, we sill skip over it.
I believe you have the option of automatically adding those kind of stores to your forbidden list.

I can see why you'd want to exclude such stores from counting for the "5th lowest available price".
If so, however, what do we do when sharing mall prices?
Sure, we've calculated the 5th cheapest price - for you.
But unless others are forbidding exactly the same stores, it is not accurate for them.
Sure - if a store is frozen for you, it is frozen for everybody - but we don't have a way of sharing that info.
And just because a store is ignoring you, it doesn't mean it will be ignoring somebody else.
Unless they have the gall to actually buy an item from them at the offered price, which has been all it took for ME to get ignored, a couple of times. :)

Perhaps we do not share a mall price if we had to skip a forbidden store to calculate it?

I'll have to think more about this.
 

Irrat

Member
I believe that if we try to purchase, we will skip forbidden stores.
I believe that if we try to purchase and discover the store is "frozen" or is ignoring you, we sill skip over it.
I believe you have the option of automatically adding those kind of stores to your forbidden list.

I can see why you'd want to exclude such stores from counting for the "5th lowest available price".
If so, however, what do we do when sharing mall prices?
Sure, we've calculated the 5th cheapest price - for you.
But unless others are forbidding exactly the same stores, it is not accurate for them.
Sure - if a store is frozen for you, it is frozen for everybody - but we don't have a way of sharing that info.
And just because a store is ignoring you, it doesn't mean it will be ignoring somebody else.
Unless they have the gall to actually buy an item from them at the offered price, which has been all it took for ME to get ignored, a couple of times. :)

Perhaps we do not share a mall price if we had to skip a forbidden store to calculate it?

I'll have to think more about this.
Oh that's an interesting perspective I didn't consider.

Of course, one obvious option is that we have two mall prices, one we share and one we don't.

But from here, I could see a new function to include or exclude forbidden stores from the returned price. Or a preference that is by default, exclude forbidden stores.

We still need to keep the forbidden stores in the list as it will show in the mall search results in mafia unless you hide them. So it's really just a case of skipping over stores depending on the parameter provided.

I think a new function is probably the best idea? With the default being to exclude forbidden stores, but provide a boolean in the function to include them. Because at that point you are now doing profit comparisons and it is less likely to be a functional script that wants to buy stuff.

So both functions still doing the same purchase results, but one skips over stores before it returns the price. If you are intelligent enough to notice the difference then you should be able to find the function to skip that.
 

Irrat

Member
Thoughts on my creating a PR where I introduce new functions that can accept a boolean alongside the mall price functions.

The existing functions will ignore forbidden store prices. But if you provide the boolean it will report the price including forbidden stores as well.

Historical price, I think that should always include forbidden stores, since historical price is not supposed to be as accurate as mall price.

So effected functions would only be the ones that report the current mall prices. On mobile, but I think that would be mall_price, mall_prices, well_stocked. They would return the 5th item that is not in a forbidden store.
 

Veracity

Developer
Staff member
Looking at the code in MallSearchRequest, it sure looks like we do not add forbiddenStores to the saved search results.
So, I wrote a test in MallPriceManagerTest

I have a saved mall search with 60 stores containing Hell ramen.
My test extracts the list of 60 store from the search result and adds every other one to forbiddenStores.
It mocks up a MallSearchRequest to use the responseText when MallPriceManager calls searchMall.
It calls MallPriceManager.searchMall.
The list of saved PurchaseRequests has 30 results in it.

Conclusion: when we issue a MallSearchRequest and parse the results, we already ignore any store that is on forbiddenStores.

I tested again in the Purchases Frame.

I searched for mojo filter
I highlighted the second store and toggled it to forbidden.
I searched for mojo filter
The second store was not displayed.
I set "showForbiddenStores" to true.
I searched for mojo filter
The forbidden store was displayed again - in red.
I highlighted the second store and toggled it to not forbidden.
I searched for mojo filter
The second store was displayed and was not red.

Conclusion: if you set "showForbiddenStores" to true, forbidden stores will appear in the mall search results.

I suppose that mall_price could look at "showForbiddenStores", and if it is true, do its own filtering out of such.
 

Veracity

Developer
Staff member
I assume that garbo has a set of properties it saves/sets/restores around execution. You could set showForbiddenStores to false and you’ll already get the behavior you want. Do the same for showIgnoringStores, which refers to stores you attempted to buy from this session and discovered they refused to sell to you.
 

Veracity

Developer
Staff member
I’m leaning towards the following changes in mall search semantics:

1) Do not filter out forbidden and ignoring stores and stores from whom you have bought your daily limit at mall search time; the mall search results always include every store returned by KoL.
2) The Purchases frame filters what it shows you:
- daily limit reached: greyed out
- forbidden: not visible or red if showForbiddenStores
- ignoring: not visible or grey if showIgnoringStores
3) buy command filters out forbidden and ignoring and daily-limit-reached stores and buys the cheapest from what remains
4) mall_price takes all stores into account when generating historical price to publish/share but skips forbidden and ignoring and daily-limit-reached stores when calculating your personal “price to buy the 5th cheapest” item.
 

fronobulax

Developer
Staff member
I’m leaning towards the following changes in mall search semantics:

1) Do not filter out forbidden and ignoring stores and stores from whom you have bought your daily limit at mall search time; the mall search results always include every store returned by KoL.
2) The Purchases frame filters what it shows you:
- daily limit reached: greyed out
- forbidden: not visible or red if showForbiddenStores
- ignoring: not visible or grey if showIgnoringStores
3) buy command filters out forbidden and ignoring and daily-limit-reached stores and buys the cheapest from what remains
4) mall_price takes all stores into account when generating historical price to publish/share but skips forbidden and ignoring and daily-limit-reached stores when calculating your personal “price to buy the 5th cheapest” item.

I'm fine with these. I cannot figure out a case where a script could use mall_price and additions to or deletions from the forbidden list to derive a value for something lower than the fifth price. Maybe my paranoia is unjustified.
 

Ryo_Sangnoir

Developer
Staff member
I'm not sure it's worth spending much effort stopping people from mallbotting any more -- those inclined are almost surely compiling their own version of Mafia that strips out the various checks. A decent number of people are compiling their own Mafia for reasons completely unrelated to mallbotting, anyway.
 

fronobulax

Developer
Staff member
I'm not sure it's worth spending much effort stopping people from mallbotting any more -- those inclined are almost surely compiling their own version of Mafia that strips out the various checks. A decent number of people are compiling their own Mafia for reasons completely unrelated to mallbotting, anyway.
No Mallbots is deep in the social DNA of KoLmafia. Jick may have even asked for or encouraged it at one point long ago, probably when he said "The Mall is NOT the Game". Since there are folks who can get answers from Jick perhaps it is time to see what his opinion is?

While there are many local versions that may or may not bypass the checks my experience has been that there are still a lot of mafia users who lack something needed to compile and run a custom version. So if/when the requirement to edit and compile Java is removed I'm sure there will be more people using the capability than their are today.
 

Irrat

Member
Funny I briefly removed that check in my mafia, then re-added it because it made my bot worse at buying it's daily items. But I don't mallbot anyhow.
 

Veracity

Developer
Staff member
Top