PriceAdvisor: Maximize your profits

PriceAdvisor 1.62

PriceAdvisor requires SmashLib and ZLib, and daily build 7915 or greater (13.8 will work).

Have you ever looked at your inventory and wondered, What's the most meat I could make with this item? Are you chafing at the confines of comparing mallsell to autosell? Do you wish you could price out every possiblity -- crafting, smashing, using, etc. -- without searching for prices for all of the possible ingredients and results? Doesn't this seem like the sort of boring calculation that a script might excel at? (At which a script might excel?)

That's what PriceAdvisor does. Taking your skills and the opportunity cost of other ingredients (plus chef/bartender uses, adventures, etc.) into account, it calculates the maximum profit you can make from an item. And it tells you exactly how to make it. Use an item? It tells you what to do with the results, too. And it gives you the profit and actions to take for any other action (even those that result in negative profit, if you have your ZLib verbosity at 4 or greater), in case you don't like the advice it thinks is best.

For example, at the time of posting, this is the advice for a Penultimate Fantasy Chest:

Code:
[B]Penultimate Fantasy chest:[/B]
mallsell 1 Penultimate Fantasy chest: 1310.0 meat
use Penultimate Fantasy chest; acquire 1 cocoa eggshell fragment; make 1 large cocoa eggshell fragment; 
acquire 1 large cocoa eggshell fragment; make 1 cocoa egg; acquire 1 spooky wad; make 1 Spooky Surprise Egg; 
mallsell 1 Spooky Surprise Egg; autosell 1 phonics down; mallsell 1 scroll of drastic healing; 
autosell 1 soft green echo eyedrop antidote; autosell 1 super-spiky hair gel; autosell 1 tiny house: 1040.7269 meat
autosell 1 Penultimate Fantasy chest: 108.0 meat

PriceAdvisor considers autoselling, mallselling, pulverizing, untinkering, malusing, cooking, cocktailcrafting, smithing, stilling, jewelrycrafting, using, multi-using, stars, pixels, supertinkering, and sugar-folding. It does not currently consider zapping. Moreover, it will not consider anything you cannot currently do because you lack the skill or access to the equipment or are the wrong gender. Except pulverizing and malusing, because wadbot's pretty darn easy to use.

PriceAdvisor has three settings which you can set via CLI after running PriceAdvisor at least once. They all default to false.
zlib priceAdvisor_obeyPriceLimit = true : Forces PriceAdvisor to never recommend doing anything where an ingredient costs more than your Mafia autoBuyPriceLimit setting.
zlib priceAdvisor_conservative = true : Is even more conservative -- PriceAdvisor will never recommend doing anything where an ingredient is not either a) available from an NPC or b) available for minimum price in the mall
zlib priceAdvisor_CLIexecutable = true : Forces PriceAdvisor to only output advice that is executable in the CLI. You'll probably only want to use this if you're using PriceAdvisor in another script.

For Scripters:
PriceAdvisor uses historical prices to minimize server hits, and also caches its own decisions, so it is most efficient when used within a script. Its main purpose within a script is to serve as a more-sophisticated valuation than simple mallsell vs. autosell can be. (If only that comparison is desired, however, all relevant functions take a boolean consider_more that can be set to false to prevent considering anything more than mall or autosell.)

The basic data structure is the price_advice record, which contains a string action and a float price.

price_advice best_advice(item it, boolean consider_more) : Returns only the most profitable price_advice.

price_advice [int] price_advisor(item it, boolean consider_more) : Returns all advice with > 0 profit, sorted from best to worst (keys 0 to count-1).

price_advice max(price_advice a, price_advice b) : Returns a copy of the price_advice with higher price. Returns a copy of a if there's a tie.

void clear_advice_cache() : resets the internal advice caches


Both best_advice() and price_advisor() are overloaded to take multiple items:
price_advice [item] best_advice(boolean [item] its, boolean consider_more)
price_advice [item] [int] price_advisor(boolean [item] its, boolean consider_more)


print() has been overloaded in a few handy ways:
void print(price_advice advice)
void print(price_advice [int] advice)


PriceAdvisor also contains some maps of interest:
float [item] meat_use : the expected value of using an item, in meat; you can also load this from use_for_meat.txt, available via MapManager.

float [item] [item] item_use : the expected value of getting an item from using an item. This is mainly loaded from use_for_items.txt, available via MapManager, but some items with conditional results (Frat Army FGF, Hippy Army MPE, etc.) are only calculated and added within PriceAdvisor.

string [item] [item] ingredients : map from ingredient to concoction and concoction type (see concoctions.txt in Mafia data files). This serves as a complement to Mafia's get_ingredients(), and like get_ingredients() it does not contain things that you can't do. Except for smashing and malusing, because you can always have wadbot do that.

Scripts using PriceAdvisor extensively are encouraged to add the lines
cli_execute("update prices http://zachbardon.com/mafiatools/updateprices.php?action=getmap");
cli_execute("update prices http://nixietube.info/mallprices.txt");

at the beginning of said script to use shared price data, and the line
cli_execute("spade prices http://zachbardon.com/mafiatools/updateprices.php");
at the end to share gathered price data.

For Users:
PriceAdvisor can be called by creating this handy alias:

alias pa => ash import <PriceAdvisor.ash> print(price_advisor($items[%%], true))

The alias allows you to list several items at once at get PriceAdvisor's advice for each. For example, pa spring, sprocket, cog is a valid use (although the advice is pretty boring).

In response to the question "How can I get PA to tell me about a whole class of items", That FN Ninja came up with this alias:

alias pam => ash import <PriceAdvisor.ash> foreach itm in $items[] if(contains_text(to_string(itm),"%%")) print(price_advisor(itm, true))

It will report on all items which share the string you give it: pam tiny plastic will tell you about all tiny plastics.

If you use PriceAdvisor extensively, I encourage you to add the lines
cli_execute("update prices http://zachbardon.com/mafiatools/updateprices.php?action=getmap");
cli_execute("update prices http://nixietube.info/mallprices.txt");

to your breakfast/login script to use shared price data, and the line
cli_execute("spade prices http://zachbardon.com/mafiatools/updateprices.php");
to your pajamas/logout script to share gathered price data.


Disclaimer: PriceAdvisor can't think for you. It can only do the math, and is limited by Mafia's customary mallprice == price of the fifth item available, which may be unrealistic for expensive or rarely-sold items. It's your responsibility to determine if its advice is realistic.

Version history:
1.62: cli-executable "trade gloomy for oily" (from heeheehee); updated to use awesome new load_current_map() from ZLib 14
1.61: improved regex from xKiv, fixed bug where container-keys were being valued at negative opportunity cost
1.6: added _obeyPriceLimit, _conservative, and _CLIexecutable vars; renamed best_advice cache -> best_cache, best_price() -> best_advice(), smashed_advice() -> smash_advice(); changed boolean parameter of smash_advice() to just be consider_more; now using currently_considering[] for all infinite recursion and circular op. cost prevention; fixed best_cache to cache based on consider_more; invalid sub-results now invalidate final result; fixed final == starting to recognize the first sell in an action; now using xKiv's regex in replace_with_multiple(); best_advice() returns newly-constructed price_advice so return value can't mess with cache. Whew.
1.51: bug fixes: final product = starting item, trying again; added vodka as a fermenting powder booze; fixed some result-is-multiple issues
1.5: really eliminated final product = starting item (I hope); switched to vprint() -- negative prices displayed only at verbosity 4+; switched to CLI-executable output
1.42: eliminated recommendations where final product = starting item, cleaned up some artifacts resulting from item_use entries overlapping with SUSE entries
1.41: clearer "do x times" advice for results dealing with multiples of an item
1.4: added handling of usable-items-that-require-something-else-and-produce-more-than-one-thing; added better output for items that have no autosell value but sell for min mallprice (so aren't worth selling)
1.3: changed fix for circular opportunity costs so it doesn't block legitimate further consideration; changed opportunity cost for autosell-valued items to be mallsell if you have to buy them; eliminated a few non-results from printing
1.2: fixed bug in max(), added consideration of untinkering, added detection of clockwork servants; now displays actions with negative profit
1.11: added trading gloomies for oily goldens, malusing elemental nuggets for wads (transmutation was interfering)
 

Attachments

  • PriceAdvisor.ash
    25.3 KB · Views: 1,374
Last edited:

slyz

Developer
I was very impressed with your script, and tried it out with a gloomy black mushroom, hoping to see it output the gloomy mushroom wine.

Code:
> pa gloomy black mushroom

Searching     for "chef-in-the-box"...
Searching for "himalayan hidalgo     sauce"...
Searching for "one-winged stab bat"...
Searching     for "rewinged stab bat"...
Searching for "twinkly nuggets"...
Searching     for "frogade"...
Searching for "squashed frog"...
Searching     for "banana smoothie"...
Searching for "oil of expertise"...
Searching     for "cherry bomb"...
Searching for "skewered cherry"...
Searching     for "sangria del diablo"...
Searching for "blatantly     canadian"...
Searching for "twinkly powder"...
Searching     for "frost™ brand sword"...
Searching for "foon of     frigidity"...
Searching for "basic meat foon"...
Searching     for "foon of fearfulness"...
Searching for "spooky powder"...
Searching     for "phial of spookiness"...
Searching for "foon of     fleshiness"...
Searching for "glistening staff"...
Searching     for "phial of sleaziness"...
Searching for "dripping meat     staff"...
Searching for "foon of foulness"...
Searching     for "phial of stench"...
Searching for "stench nuggets"...
Searching     for "foon of fulmination"...
Searching for "hot powder"...
Searching     for "flaming cardboard sword"...
Searching for "phial of     hotness"...
Searching for "cardboard sword"...
Searching     for "phial of coldness"...
Searching for "styrofoam sword"...
Searching     for "brine"...
Searching for "briny vinegar"...
Searching     for "ghostly pickling solution"...
Searching for "ghost     pickle on a stick"...
Searching for "vinegar"...
Searching     for "grogtini"...
Searching for "skewered lime"...
Searching     for "bodyslam"...
Searching for "digital key lime"...
Searching     for "star key lime"...
Searching for "cranberry cordial"...
Searching     for "gnollish autoplunger"...
Searching for "useless     powder"...
Searching for "basic meat crossbow"...
Searching     for "bubble bauble bow"...
Searching for "basic meat     helmet"...
Searching for "barskin tent"...
Searching     for "spooky staff"...
Searching for "basic meat fez"...
Searching     for "fez of etymology"...
Searching for "clown wig"...
Searching     for "demon-horned hat"...
Searching for "demonskin     trousers"...
Searching for "tighty whiteys"...
Searching     for "raspberry beret"...
Searching for "cardboard staff"...
Searching     for "flypaper staff"...
Searching for "extreme meat staff"...
Searching     for "extreme meat crossbow"...
Searching for "balloon     helmet"...
Searching for "balloon monkey"...
Searching     for "balloon shield"...
Searching for "balloon sword"...
Searching     for "forest tears"...
Searching for "pestoblade"...
Searching     for "starchy staff"...
Searching for "poutine pole"...
Searching     for "styrofoam staff"...
Searching for "starchy crossbow"...
Searching     for "curdflinger"...
Searching for "cottage"...
Searching     for "fancy schmancy cheese sauce"...
Searching for "giant     cheesestick"...
Searching for "kentucky-fried meat staff"...
Searching     for "rat appendix"...
Searching for "secret blend of herbs     and spices"...
Searching for "kentucky-fried meat crossbow"...
Searching     for "potato pistol"...
Searching for "dense meat crossbow"...
Searching     for "savory crossbow"...
Searching for "goulauncher"...
Searching     for "dense meat sword"...
Searching for "super magic power     sword x"...
Searching for "wad of tofu"...
Searching     for "soylent staff"...
Searching for "savory staff"...
Searching     for "meat face"...
Searching for "lifeless meat doll"...
Searching     for "wooden figurine"...
Searching for "heavy hot sauce"...
Searching     for "5-alarm saucepan"...
Searching for "bjorn's hammer"...
Searching     for "seal tooth"...
Searching for "spaghetti with     rock-balls"...
Searching for "pasta of peril"...
Searching     for "petrified noodles"...
Searching for "stone banjo"...
Searching     for "disco banjo"...
Searching for "banjo strings"...
Searching     for "dueling turtle"...
Searching for "stone turtle"...
Searching     for "mace of the tortoise"...
Searching for "chisel"...
Searching     for "perfume of prejudice"...
Searching for "ratgut"...
Searching     for "vesper"...
Searching for "skewered jumbo olive"...
Searching     for "dirty martini"...
Searching for "oil of slipperiness"...
Searching     for "floaty rock"...
Searching for "rock lobster"...
Searching     for "wok lobster"...
Searching for "enchanted eyepatch"...
Searching     for "clockwork pirate skull"...
Searching for "pirate zombie     head"...
Searching for "pirate zombie robot head"...
Searching     for "zombie pineal gland"...
Searching for "clockwork     bartender head"...
Searching for "clockwork     bartender-head-in-the-box"...
Searching for "clockwork     bartender-in-the-box"...
Searching for "4-d camera"...
Searching     for "chef skull"...
Searching for "chef-skull-in-the-box"...
Searching     for "clockwork chef head"...
Searching for "clockwork     chef-head-in-the-box"...
Searching for "clockwork     chef-in-the-box"...
Searching for "clockwork detective skull"...
Searching     for "hemp string"...
Searching for "beach glass bead"...
Searching     for "peace-sign necklace"...
Searching for "clay peace-sign     bead"...
Searching for "phat turquoise bracelet"...
Searching     for "phat turquoise bead"...
Searching for "spooky pirate     skeleton"...
Searching for "bone rattle"...
Searching     for "nothing-in-the-box-in-the-box"...
Searching for     "present"...
Searching for "wrapping paper"...
Searching     for "crimbo hat"...
Searching for "crimbo pants"...
Searching     for "crimbo sword"...
Searching for "boxing glove"...
Searching     for "banana spritzer"...
Searching for "bitter pill"...
Searching     for "cocoa egg"...
Searching for "concoction of clumsiness"...
Searching     for "cordial of concentration"...
Searching for "eyedrops of     newt"...
Searching for "eye of newt"...
Searching for     "eyedrops of the ermine"...
Searching for "libation of     liveliness"...
Searching for "oil of oiliness"...
Searching     for "decaying goldfish liver"...
Searching for "ointment of     the occult"...
Searching for "papotion of papower"...
Searching     for "philter of phorce"...
Searching for "potion of     potency"...
Searching for "salamander slurry"...
Searching     for "salamander spleen"...
gloomy black mushroom:
acquire     1 spooky fairy gravy; cook 1 gloomy black mushroom, 1 spooky fairy gravy;     autosell pregnant gloomy black mushroom: 83.333336 meat

I understand the 'autosell pregnant gloomy black mushroom' (item isn't malleable).
I don't really understand why it searched so many unrelated item prices...
The gloomy mushroom wine is ~20k, and the fermenting solution is 12,5k, but it doesn't seem like mixing the mushroom was even considered (the alias points to price_advisor(), not the best_price()).

I learned a lot reading the script, and I hope this output helps a little to get rid of special cases that weren't considered.
 
It searches for so many other items because of the way it handles opportunity costs. At least, so I hope. Let's take a look:

It thinks about making the pregnant mushroom, that's why it looks for chef-in-the-box -- it takes into account the cost of cooking (price of chef / 90, the same way Mafia calculates it).

As for everything else:
pregnant gloomy = gloomy + spooky gravy, so it must calculate the opportunity cost of using spooky gravy.
The only other thing that can be made from spooky gravy is the spooky glove.
The spooky glove smashes into twinkly or spooky powder. Powders cause a massive cascade of opportunity costs, always. There are many things you can do with them and the other ingredients for those things also have many things you can do with them. It's a good things those prices cache, eh?

I'm always alarmed when I see these searches too, but I've attempted to debug them and found them to be correct so many times that I just have to squash my impulse to shout "A balloon monkey is not related to this mushroom, dangit!" But it is:
balloon monkey -> long skinny balloon
long skinny balloon -> sword of static
sword of static -> bubblewrap sword
bubblewrap sword -> basic meat sword
basic meat sword -> styrofoam sword
styrofoam sword -> Frost brand sword
Frost brand sword -> cold powder
cold powder -> phial of coldness
phial of coldness -> scrumptious reagent
scrumptious reagent -> phial of spookiness
phial of spookiness -> spooky powder
spooky powder -> spooky glove
spooky glove -> spooky fairy gravy
spooky fairy gravy -> pregnant gloomy black mushroom
pregnant gloomy black mushroom -> gloomy black mushroom
Pretty insane!

As for why it didn't tell you to make gloomy mushroom wine, it's simple: the opportunity cost for using the mushroom fermenting powder made the profit < 0, so it didn't mention it. Perhaps there is a more profitable mushroom wine it thinks you should be making instead.

(At the moment, it is actually telling me to make the gloomy wine; I guess our cached prices differ.)

One special case that it doesn't consider for the gloomies is trading them in for oily goldens. I think I could incorporate that corner case, even though it doesn't address your actual questions... But I hope I've answered them.
 
Last edited:

slyz

Developer
I guessed there's was some sort of link, but since the spooky glove wasn't an ingredient for anything else I didn't find it. I had forgotten about the smashing =)

This script should keep the price list pretty much up to date by itself I guess.

I should try rerunning the gloomy mushroom, but in the output I pasted, only one price-advice was posted (autoselling the pregnant gloomy black mushroom). It seemed like the mixing wasn't considered, or gave a negative profit.
 
Exactly. It considered the mixing, but for whatever selection of prices for mushroom wines and mushroom fermenting powder it currently had, decided that the gloomy wine would give you a negative profit.

Would this sort of thing be more clear if it also displayed options that gave negative profit? That would be very easy.
 

slyz

Developer
I thought about the negative profit afterwards, but it's true I was expecting to see 3 price_advices, (however bad). It's my fault for not reading your post carefully enough.

Code:
gloomy black mushroom:
trade gloomy black mushroom to the Suspicious-Looking Guy;
acquire 1 mushroom fermenting solution;
mix 1 oily golden mushroom, 1 mushroom fermenting solution;
mallsell oily mushroom wine: 290.0 meat

There are now 18 oily mushroom wines in my store =)

About the 290 meat profit, I now have a more economical question:

oily mushroom wine: 17,950 meat (from historical_price())
mushroom fermenting solution: 12,450 meat
cost of using a bartender: 14,875/90 = 165 meat
profit = 17,950 - (12,450 + 165) = 5,335 ?

I'm thinking (guessing) the opportunity cost for making gloomy mushroom wine or a pregnant mushroom got counted in here, but I would have instinctively thought that the profit would be 5,335 meat. Is my vision of the whole concept of profit wrong ?

Also, since you are very helpful, efficient and seem to enjoy improving your scripts, how about considering clockwork servants ?
 
Yeah, to see exactly what's driving the opportunity cost you'd want to do a "pa mushroom fermenting solution" to see how much it thinks it can make with it -- it uses the best_price instead of the mall price to calculate opportunity cost.

I'd love to include clockwork servants too, but there's no built-in way to check for them. If they were permanent, I could just hit the server and look at your campsite once, then set a zlib setting "bartender_is_clockwork" or something. But innaboxen aren't permanent, and I can't have Mafia magically set that to false when the boxen blow up. So in order to know what sort of boxen you have I would have to hit the server and check every time the script loads.

That might be acceptable if PriceAdvisor were only imported into other scripts -- it would hit the server only once and then that value could be used to give lots of advice (as long as the other script did no cooking or mixing). But since PriceAdvisor is also handy to use via alias, and is loaded from the start every time the alias is used, it would hit the server every time the alias was used. That seems like too many server hits to me.

If someone has a clever way around this, or Mafia decides to track your boxen, I'd be more than happy to support clockwork servants!

I think seeing price_advices come and go as market conditions change is sufficiently unintuitive that it may be worthwhile to list negative profits as well. I'll consider it for the next release.
 

jasonharper

Developer
You can tell whether a clockwork or normal servant is currently installed via get_campground(); no server hit required.

This should always be accurate, except in the case that the servant has just blown up (or has never been installed this ascension), and the user's settings will cause it to be auto-repaired - I'm not sure how you'd predict which kind of servant it would be replaced with.
 

caphector

Member
I'm impressed by the amount of checking the script does; I did a check on Spooky Stick and it checked 554 items before deciding what my best course of action was.
 

slyz

Developer
Code:
mushroom fermenting solution:
acquire 1 stinky mushroom; mix 1 mushroom fermenting solution, 1 stinky mushroom;
mallsell stinky mushroom wine: 17494.723 meat
mallsell mushroom fermenting solution: 12450.0 meat
autosell mushroom fermenting solution: 30.0 meat

Now I (finally) get it ... creating and mallselling an oily mushroom wine will yield a profit of 5,335 meat, but only 290 meat of that comes from using a gloomy black mushroom, since the mushroom fermenting solution could yield 17,494 meat instead of its mall price of 12,450.

A newbie economist is me!

Other question: is there a particular reason why only the best advice for each mixing method is kept ?
 
You can tell whether a clockwork or normal servant is currently installed via get_campground(); no server hit required.

This is both excellent and superb. I've added it to the wiki.

Do I understand correctly that the results of get_campground() do not change during a session? It's the difference between just calling it once and calling it every time I check innaboxen. (On the other hand, it's not a server hit, so maybe I should call it every time in anticipation of some future revision that will cause its results to change.)

This should always be accurate, except in the case that the servant has just blown up (or has never been installed this ascension), and the user's settings will cause it to be auto-repaired - I'm not sure how you'd predict which kind of servant it would be replaced with.

I think I can live with this unless and until people start complaining about this behavior.

I'm impressed by the amount of checking the script does; I did a check on Spooky Stick and it checked 554 items before deciding what my best course of action was.

And then it probably just told you to autosell it anyway, right? Poor PriceAdvisor, ever hopeful it can find something better for you to do.

Other question: is there a particular reason why only the best advice for each mixing method is kept ?

The reason is that I didn't want to suggest a jillion different things, so it only suggests the best option for each type of crafting, etc. I think that like my decision to only display positive profit, this may have been a case of attempting to fix a problem that was not necessarily a problem. I'll experiment with displaying more advice and see how overwhelming it is.

Edit: I'm glad I experimented. It revealed a very nasty (and very stupid) bug in my max() function, which I have now fixed. (Clockwork servants, untinkering, negative costs, and showing all options for a create type are also included in the new version.) It's also revealed that a check I put in to stop weirdness when calculating some opportunity costs causes PA to not consider some results. Since PA is broken with this check and without it, and I haven't been able to come up with a quick fix, the bug stays for now. I'll try to hammer it out when I next have some free hours.
 
Last edited:

jasonharper

Developer
get_campground() should automatically be updated after using any item that's installed in your campground. In other words, it should not be possible to have a box servant actually installed, without it being correctly indicated in the return value.
 
Hey just wanted to say i love this script, useful and well written.

I've been using it in conjunction with a re-written and hacked together version of bales inventory control script.

Doing some string matching on the advice output you've returned, i'm auto-cleaning junk from my inventory in the most profitable way!

Haven't covered every case yet though, trying to work out from the string what to do is a bit annoying, some day i might overload yours to output in a different way (like action, required mat 1, required mat 2 or something). But thats probably something for when you're not adding your own big improvements.

Hmm... didn't mean to go off on a tangent... Nice script, interesting possibilities, i love you.
 
get_campground() should automatically be updated after using any item that's installed in your campground. In other words, it should not be possible to have a box servant actually installed, without it being correctly indicated in the return value.

That's excellent. (For the sake of the wiki, is this now true for dwellings too, as it was not in the long-ago initial commit?)

Haven't covered every case yet though, trying to work out from the string what to do is a bit annoying, some day i might overload yours to output in a different way (like action, required mat 1, required mat 2 or something). But thats probably something for when you're not adding your own big improvements.

If you take a look at how concocted_advice() is constructing the string (it does most of the constructing) you can probably get some hints on how to de-construct it. All the "acquire" bits, for example, are what are required. (In fact, Mafia can probably understand the acquire statements directly. Unfortunately, it's not going to understand my weird "create jewelry from" or "have the Mystic craft" syntax, which was designed to be more human-parsable than Mafia-parsable.)
 

Spiny

Member
I'm a little confused. In lines where it says mallsell x: # meat, is that how much you're supposed to mallsell the item for or how much profit you should get from mallselling and if it's profit, how is this derived? Does it assume selling at the current mall min (even if there's a limit?) or at 5th price (per mafia) or what? A little clarification would go a long way.

Also when the script is calculating for crafted items... does it consider components in inventory as 0 cost or does it base the components at mall price even if you have it already, so in essence profit would be higher since you're not actually buying anything?

*wonders if I'm making any sense*
 
You're making plenty of sense.

The meat amount it gives you is your profit, not the mall price at which you should sell it. Profit is derived by assuming you have what you asked about and valuing any other ingredients required for the final product at the best price you can get for that ingredient (as calculated by PriceAdvisor). This is so that not just the mallsell price but the opportunity cost (of not using that ingredient for something else) is taken into account. Profit, then, is equal to mall price of the final product minus the opportunity cost of the other components.

It assumes selling at the current (cached) fifth price, as per Mafia.

Aside: this results in occasional slightly-incorrect opportunity costs for ingredients where mallsell == mall min, because PA will value these only at autosell price. If you have to buy them from the mall, they will cost you more than PA thinks they will.

Components in inventory are not treated specially. After all, opportunity cost is still opportunity cost. The one place where they perhaps should be treated differently is in the aside above. I think I will change things thus:

- calculate the opportunity cost
- if it turns out to be the autosell value (there's nothing else worth doing with this component), check inventory.
- if you have the autosell-valued item, opportunity cost = autosell cost, since that's what you'll lose by using it as a component.
- if you don't have it, opportunity cost = mallsell cost, since that's what you'll have to spend to use it as a component.

I'm glad you've asked these questions. I'm very wordy when explaining what's going on, so I didn't want to make the first post a billion pages long, but these details are important.
 
Last edited:

Spiny

Member
This gave me a good chuckle (sorry Zarqon, I know you love your bat parts):

Code:
batgut:
autosell batgut: 12.0 meat
acquire 1 spices; cook 1 batgut, 1 spices; autosell bat haggis: -994.0 meat
 
Code:
batgut:
send 1 batgut to Zarqon: 0 meat + good karma

I'm not going to add this special case (PriceAdvisor is an unforgiving profit maximizer! It has no heart!) but it would be pretty funny.
 
Double-post, for update-ness!

Version 1.4 handles chests and lockers -- items you can use to get more than one item (or some meat) which require another item (a key).

This involves a slight addition to the use_for_items.txt file syntax (don't worry, it will autoupdate): entries of the type
Code:
item1  item2  -1
indicate that item2 is required in order to use item1.

Chests/lockers added are orcish meat locker (rusty metal key), stuffed treasure chest (stuffed key), and the three cursed chests/lockers. If you know of any other items that work this way, let me know and I'll add them too.

For that matter, if you know of any items that should be usable for items or meat that PA doesn't know about, please report those too!

Unexcitingly, buying the key to use the chest isn't worth it for anything right now. Oh well, the script is more complete even if it isn't actually more useful!
 
Top