PriceAdvisor: Maximize your profits

Baconslicer

New member
Found something odd today:

> pa tiny plastic Susie

tiny plastic Susie:
smash tiny plastic Susie; autosell twinkly powder: 60.0 meat
994: 0.0 meat

Returned: void

This looks odd; there's no mall price listed, and we have this mystery line about 994, which is the item# for tiny plastic Susie.
 
This looks odd; there's no mall price listed, and we have this mystery line about 994, which is the item# for tiny plastic Susie.

Well, what you quote definitely looks wrong. None of my output should produce 994 as advice! (I hope.) I get the right results, though, so this is going to be hard for me to test:
Code:
[B]tiny plastic Susie:[/B]
mallsell tiny plastic Susie: 1234567.0 meat
smash tiny plastic Susie; autosell twinkly powder: 60.0 meat
Looks like someone was being funny with their price...

What versions of PriceAdvisor and Mafia gave you the wonky result?


You might want to look at concoctions.txt and do some parsing, not unlike that little snippet that I posted a link to earlier.

Here's the thing: get_ingredients() does all the work for me, and in fact does the filtering I was originally going to do. PA works exactly as originally intended. Parsing concoctions.txt to get a similar result to get_ingredients() would be non-trivial: it's easy to parse for concoction and concoction type (and even then overlapping recipes are a problem: see my workaround for including creation of wads via both malus and transmutation), but to parse variable numbers of ingredients, where sometimes you need more than one of some ingredients? No thanks, I'm not duplicating the work the devs have so kindly already done for me. If you provide or convince Mafia to provide a get_ingredients() two-argument function like the one I suggested, or something like it, I'm more than happy to include the "pretend I have all skills" option in PA. It would make testing easier, for one thing. But there's just no way I'm doing the work myself. I hate complicated file parsing.

If I were to do this, I'd do something similar to the universal consume() for cook/smith/fold/whatever. Or set aliases? I don't know -- you should be able to do that with ASH, right?

Oh, the advice is easy enough to change: you can do it yourself, in fact: the little strings that Concoctions section of the main price_advice() function passes to concocted_advice() are what you'd want to change. I believe Mafia would be pretty happy with a universal "make".

This doesn't solve the "then do x times" issue, which is itself a bit of a hack. Ideally you'd replace every number in the string after a "then do x times" with that number * x, but again. I hate parsing things, and I'm not great friends with regular expressions. They would probably make this much easier.

If you or someone else wanted to provide a function do_x_times(string action, int x) that would do that replacement, I would love to get rid of the hack-y syntax I'm currently using. Extra bonus points if it can replace singular items with plural as necessary, soothing my OCD soul.

Regarding the dailies: you might want to add in support for demon summoning (if it's ever worth it... heh).

Ah. As an option for thin black candles, etc.? That's a good special case to keep in mind if MPA becomes a source of advice.

I also hacked together a .txt with all (most?) relevant effects and durations (but it'll need updating regularly, I suppose).

That's really neat! I must admit one portion I was dreading was making such a map -- I couldn't see any way around it. Updating can be handled with the least fuss using Zarqon's wonderful Map Manager, although it would be best to be sure this is the final format before committing to it.

Hobo skills are probably not strictly within the purview of PA; "use hobo skill book; perm hobo skill; sell in /trade for.... I dunno how much per day" is not terribly reasonable advice, especially since Mafia only checks mall prices, not trade prices.

I might give that a shot if you give me a list of functions you might want.

price_advice mpa_advice(item), assuming Castle farming with nothing special happening, would be the minimum necessary. It would return a price_advice with the string being something like "use item; adventure in the Castle for <duration> turns" and price being "Castle benefit * duration" meat, less any opportunity cost.

If you're feeling ambitious, price_advice mpa_advice(item, location) (and any other arguments you think interesting, like a boolean for olfaction or an int for combat rate modifier) would both be useful for PA (which either prompt or call it with default assumptions) and require you to write a bunch of code which other scripters of meat/profit things would probably find very handy.

The only issue is that your script would probably want to use PA for various things (value of item drop depends on best_price of item dropped, etc.). Ugh, circular inclusion. Maybe they're not as separable as I thought.

Well, we better start spreading the word, then, eh?

I'm getting three or so notifications per day, which is very gratifying. Hardly enough to change market behavior just yet, though!
 
Last edited:

dj_d

Member
This is a good idea; combined with the percentage of original price idea it should provide decent levels of protection from crazy.

I won't be doing make_it_so until PA is a little more mature, but these are all things to keep in mind.

How about just making the string result cli_execute-able? It sort of looks like it already is, although I haven't played with it enough to find exceptions. Then you don't need a make_it_so flag; you can just run a script that cli_executes the results of the function (and the user can use at their own risk).

farm.ash users are a pretty adventurous sort; I bet some of them would try it. :)
 
How about just making the string result cli_execute-able?

Possible, except for some exceptions I've outlined in my previous post. I need a decent do_x_times() function to transform my advice strings.

farm.ash users are a pretty adventurous sort; I bet some of them would try it. :)

And have them on my conscience? Not yet!
 

dj_d

Member
well, you can inline ash or serialize.
Code:
 step1; ash for x from 1 to 2 {cli_execute(step2)}; step3;
Code:
step1; step2; step2; step3;
Granted, they're not as easy to read, so you'd want a special flag to request that format. But it should work easily.
 
As for sugar-folding, that's hardly the only advice given by PA which doesn't correspond to Mafia CLI syntax. Even "cook" isn't proper CLI syntax! Even if I were to switch all the "wrong" commands to be readable by the CLI, there remain hacks like "then do x times" which Mafia doesn't understand. Right now, parsing the advice is non-trivial, I'm afraid.

You don't have to tell me this believe me, i've already written a script that parses all your advice and executes it.

My point was that fold is not only incorrect cli syntax, but is actually a different item conversion method which you don't consider. I see that folding items aren't in concoctions.txt so thats obviously why you didn't include them.
 

heeheehee

Developer
Staff member
My point was that fold is not only incorrect cli syntax, but is actually a different item conversion method which you don't consider. I see that folding items aren't in concoctions.txt so thats obviously why you didn't include them.

Incidentally, they are in foldgroups.txt. Just kinda throwing this out there.

stuff about get_ingredients
Yeah, as stated, I'm a moron and hadn't actually looked at your code closely.

Oh, the advice is easy enough to change: you can do it yourself, in fact: the little strings that Concoctions section of the main price_advice() function passes to concocted_advice() are what you'd want to change. I believe Mafia would be pretty happy with a universal "make".

I'd imagine a "do_x_times" would just be a for loop, that is (obviously receiving inputs, somehow):
Code:
boolean do_x_times(int x, string act1, string act2, string act3) // Number of times you want to do this, then what you want to do.
// Either set the actions beforehand (ideal solution) or here.
for(i=0,i<x,i++) {
	cli_execute[act1; act2; act3]
}

price_advice mpa_advice(item), assuming Castle farming with nothing special happening, would be the minimum necessary. It would return a price_advice with the string being something like "use item; adventure in the Castle for <duration> turns" and price being "Castle benefit * duration" meat, less any opportunity cost.
I'd assume... use warm subject gift certificates, smash equips, and autosell everything else (except possibly thin black candles)?

If you're feeling ambitious, price_advice mpa_advice(item, location) (and any other arguments you think interesting, like a boolean for olfaction or an int for combat rate modifier) would both be useful for PA (which either prompt or call it with default assumptions) and require you to write a bunch of code which other scripters of meat/profit things would probably find very handy.

I can do better. Check available skills for combat rate modifiers, olfaction, and other item drop bonuses. Possibly use the modifier maximizer to maximize item/meat drops (although it really doesn't do love songs too well, and I don't like how it ignores Summon Hobo Underling, especially for boss fights). Include an option for purchasing buffs (i.e. Phat loot, polka, empathy, cantata/sonata) from buffbots. The whole location ordeal, I suppose I could mash together something from zarqon's profit.ash, as mentioned. Crediting him, of course.

Edit: Oof. And Olfaction would probably want to prompt a string, unless you want to olfact the most profitable monster in the zone... Heh.

The only issue is that your script would probably want to use PA for various things (value of item drop depends on best_price of item dropped, etc.). Ugh, circular inclusion. Maybe they're not as separable as I thought.

But this script would only use PA for items that grant item/meat drops. EDIT: Blah, I fail. Just get the value of items dropped from a specific location before checking individual items. Circular inclusion would only be "for items that grant item/meat drops".

Ooh, and I could add on a little bit to MPA for items dropped by familiar (mayflower bouquet, mimic, June FotMs)! Whee! EDIT: Not so great of an idea. Not too useful.

Edit: Would you want it in increased MPA (That is to say, estimated MPA with effect - estimated MPA without effect)?
 
Last edited:

Baconslicer

New member
Well, what you quote definitely looks wrong. None of my output should produce 994 as advice! (I hope.) I get the right results, though, so this is going to be hard for me to test:

What versions of PriceAdvisor and Mafia gave you the wonky result?
This was PA 1.4.2, Mafia r7939. It's working correctly today though (using Mafia r7940). I was on a pretty terrible internet connection yesterday, so that may have been messing things up. I'll let you know if I see it again.
 

heeheehee

Developer
Staff member
Okay. I've made some progress on the whole increased MPA from adding on another effect. As I said, it's just a crude derivative of zarqon's profit.ash (actually, a derivative of a derivative... but you get the point), so it has the same limitations as the original script. Namely, 1) it doesn't work too well with Slime Tube (it assumes that all monsters have the same encounter rate), and 2) it doesn't account for multiple drops of an item from a single monster.

Edit: Granted, the first problem is inherent to Mafia itself, so unless the devs fix this (by making a specific exception), we'll just have to find clever workarounds.
Double edit: I just remembered that Mafia kinda sucks at handling love songs, so that'll be another thing to hardcode.
Triple edit(!): Okay, I think I've got the slime tube working. It was a funky (and ugly!) workaround using set_location(). I could add support for familiars dropping items (mayflower bouquet or June IotMs), but it won't really result in a change of dMPA (change in MPA), as these drops are not correlated to familiar weight.

Basically, how it works right now is it prompts for a location and an item to use, then it runs through the whole script twice: once with just current effects, once with the effect from the item. It should -theoretically- work, but I haven't tested it extensively.
Edit: Basically, what you'd want to do to get value of item based on increased MPA is multiply MPA returned by duration of effect. Using, perhaps, that map I provided earlier?

From here, I probably have one potentially problematic goal: fix the whole multiple-drops issue.
Edit: And add support for noncombats... -sigh-
 

Attachments

  • profit_fx.ash
    7.9 KB · Views: 33
Last edited:

Spiny

Member
This was PA 1.4.2, Mafia r7939. It's working correctly today though (using Mafia r7940). I was on a pretty terrible internet connection yesterday, so that may have been messing things up. I'll let you know if I see it again.

Either one of the recent builds of mafia or the latest version of PA is indeed suggesting numbers such as the 994... I noticed it when it would have said useless powder... not sure if anything else stuck out for me though.
 
Re: weird numerical output: I suspect that this was a case of Mafia interpreting some of my string concatenation as addition. If so, using Mafia r7941 or greater should fix it.

If it still happens with r7941 or greater, I'll look into it further.
 

caphector

Member
Is there any easy way to go through a list of items? I'd been hoping to do "pa tiny plastic *", but Mafia's CLI doesn't support variables like that.
 
Is there any easy way to go through a list of items? I'd been hoping to do "pa tiny plastic *", but Mafia's CLI doesn't support variables like that.

I would try setting an alias like this:
alias pam => ash import <PriceAdvisor.ash> foreach itm in $items[] if(contains_text(to_string(itm),"%%")) print(price_advisor(itm, true))

then type the following into the cli:

"pam tiny plastic"
 
My point was that fold is not only incorrect cli syntax, but is actually a different item conversion method which you don't consider. I see that folding items aren't in concoctions.txt so thats obviously why you didn't include them.

Eh, I called it folding because that's what KoL calls it.

foldgroups.txt and zapgroups.txt are on the list of things to support. And non-meat currency trade-ins, too (though not in time for the end of Crimbux). There will probably be an option to ignore zapping, so that scripts using PA as a valuator won't get erroneous advice that assumes you can zap infinitely.

I should probably do something for using the still, too; it takes valueOfStill into account, but I think that's 0 by default.

well, you can inline ash or serialize.

Intriguing stuff. This could be handy, although, as you say, it's pretty ugly. But executable!

However, I think I figured out enough minimal matcher-ness to do what I want. I'd appreciate if anyone more familiar with regexes would look it over, but it seems to serve well enough for what I wanted.
Code:
// replace_with_multiple(string, int) : Returns a copy of str
// with all integers replaced with integer * multiplier
string replace_with_multiple(string str, int multiplier)
{
	matcher integer = create_matcher("([\\d,]+)", str);
	string replaced = str;
	int multiplicand = 0;
	
	while(find(integer))
	{
		multiplicand = to_int(group(integer, 1));
		replaced = replace_string(replaced, group(integer, 1), to_string(multiplier * multiplicand));
	}
		
	return replaced;
}

Switching to CLI-readable output also required:
1. Not pluralizing. My OCD soul is sad.
2. Instead of "use these ingredients"-style output, "make result"-style.

Version 1.5 should be parseable -- bug reports are welcome!

Version 1.5 does not include any price limits, though. Here's what I'm thinking about those:
Set up a boolean zlib var for limiting prices.
If var is true, don't offer advice where any purchase is greater than Mafia's autoBuyPriceLimit property.

Does this sound good to people? Do you want a _conservative option too, as dj_d outlined in post 34? Would these be better as arguments, or as zlib variables? What should the defaults be, true or false?

heeheehee, it sounds like you're chugging right along! Exciting stuff! The output I want is not exactly MPA, but whatever the net gain from using the item is. So it should include duration already. Ideally (from my lazy point of view) you'd have a function I can call that just returns a price_advice record, and I'd just use it.

Re: circularity. Ideally you'd want to use best_price() for any items dropped to value them, right?

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

Ooh, neat alias! May I include it in the first post?
 
Regarding tiny plastics, this might be a time to mention that (if you haven't noticed already), PA does not offer advice about using doll houses and dollhives. I don't know what the drop rates are, so I can't calculate an expected value. It looks like the wiki is slowly gathering this information (and since I'm not helping, I can hardly complain!), so I hope to be able to include it at some future point.
 

heeheehee

Developer
Staff member
Yeah. Most of my problems that I've encountered were innate to the script itself before I took it up. So no noncombat support yet, although I'm working on that. As such, the whole combat modifiers will have to wait (I'll end up with a bit to figure out whether combats or noncombats are more profitable).

I suppose I could incorporate it myself, but it seems like a lot of code to splice into your already sizable script. So I guess the easiest thing to do would be to import profit_fx into your script... need to figure out how exactly that'd behave.

On a different note, it looks like profit_fx uses the rough equivalent of best_price() with consider_more() set to false. That's how it should work, at least. So yeah, I guess I'm good in that respect.

Edit: I also haven't gotten around to working underwater effects into the script yet. *sigh*
Oh, and it might be more accurate to reword the initial post to say something along the lines of "needs SmashLib.ash, which needs ZLib.ash". Heh. As stated, I've barely even looked at your code, which I should probably do before making an add-on for it. xD

Double edit: By the way, can someone confirm that if changing my_location() results in a change of item%, then at least one of the zones is sea-related? [[Edit: A moron is me. I totally forgot about old soft shoes. Oh well, changing a != to a < solves that potential problem.]]

Triple edit: Also, totally forgot that it doesn't check if you have effects about to wear off. Let's just assume that's not the case (if it is, your actual increase in MPA will be higher). Except in the case of Fishy, as you can tell (I had a bunch of residual effects from fighting Mother Slime):
You will want to olfact Decent White Shark for 5276.3374 MPA rather than 3881.333.
Your Meat/Adv at The Briniest Deepests would go from 2638.1687 to 5276.3374.
Using glistening maki would increase your Meat/Adv at The Briniest Deepests by 2638.1687 meat per adventure.
Therefore glistening maki yields 118717.59 meat (over 45 turns).

Quadruple (!) edit: Gah. Sushi doesn't count as an item. Good news, I've gotten another update to the profit_fx.ash -- I'll reupload it, now that both sea and slimetube are properly supported. However, it now relies solely on relfx.txt, which will also be uploaded for your benefit.

If you are planning to use this script, use the new version of relfx.txt. I've changed the overall layout, which is trivial with OpenOffice Calc. =D

Ooh, also: it now calculates turns received of Holiday Bliss, sauce pot duration is now correct, and it takes warm belly into account if you have it active and fishy results from the "item" used. Input is now a string (case-insensitive) to accommodate for sushi. Returns no change in MPA if such an item does not exist in the map... heh. Fixed bonus familiar weight. And added colorful/more detailed output. Whee!

But I totally forgot to check if your familiar can breathe underwater (and if you can), providing that your zone is in the sea. Also totally forgot about the case that you have enough pressure-mitigating effects that the pressure penalty is 0. I'll add those in a future update.
 
Last edited:

Spiny

Member
Hrmmm...

Last night, using v1.42 to look up frat army FGF, it recommended to use all of them and do this or that with what was obtained from them.

When I look up llama llama gong, it suggests:
mallsell llama lama gong: 3000.0 meat

This got me thinking... why isn't it also suggesting the relevant items one can acquire from using the gong? Feathers in particular but there are other things as well. The same can be said for the tiny bottle of absinthe, astral mushroom...

Are these not mentioned because of the adventure burning costs?
 

heeheehee

Developer
Staff member
This got me thinking... why isn't it also suggesting the relevant items one can acquire from using the gong? Feathers in particular but there are other things as well. The same can be said for the tiny bottle of absinthe, astral mushroom...

Are these not mentioned because of the adventure burning costs?

If you look at his code, he has the items obtained from FGFs, MPEs, and dead mimics/(small/large) boxen? hardcoded. I guess an additional output could be "at the expense of x adventures", which displays if x>0. I guess for gongs, that'd be 3/12(8?)/15, depending on which path you take and what item it is (for instance, what step in the mole process? 1 or two? Actually, now that I think about it, Path of Mole would have to be restricted to 12 only, as you can't shrug moleform.
 
First: her code.

The FGF/MPE/dead mimics are in the code rather than read from the map because their outcomes are conditional (on how you did the Farm sidequest and whether you have a wand).

Spiny: exactly. At the moment, if you don't get the item directly, PA doesn't advise about it. (Things like high-tier smithing and using the wok cost adventures, but you know exactly what you're going to get, and you get absolutely nothing else from those adventures.)

Actually, it's not so much that they are not mentioned because of adventure burning cost as because adventuring makes them a more complicated case and I haven't worked that sort of thing out yet. Because you are actually adventuring to get these items, rather than just consuming adventures, you get side benefits: you might starfish stasis for MP, you might get some meat or item drops from monsters you are fighting... it's not simple. It ties in so much to a generalized gains-from-adventuring idea that I'm not even sure it fits within the scope of PA.
 
Top