PDA

View Full Version : Daily Dungeon Diver -- intelligent automation with NO-calendar-empowered prediction!



zarqon
04-08-2009, 03:01 PM
Daily Dungeon Diver 1.9

The Daily Dungeon is a frequent source of annoyance in people's runs.


"Gah! I'm ready to hit the Tower but I forgot to get my keys!"
OR
"Gah! I can't pass this test! I just wasted 5 adventures in here!"
OR
"Gah! I forgot to eat my key lime pies and I'm already full today!"
OR
"Gah! Which of these dang accessories has sleaze resistance again?"
OR
"Gah! What was the URL to Noblesse Oblige's Kingdom Calendar again?!"
OR
"GAH! ANOTHER Jarlsberg's earring!!"

For all but the last one, there's this script.

What does it do?
Daily Dungeon Diver loads the day's dungeon contents from the Noblesse Oblige calendar (http://noblesse-oblige.org/calendar/), determines whether or not you can pass all the Dungeon tests (based on current wiki data), and then proceeds to pass them all. If you can't pass any of the tests, it doesn't bother wasting any adventures there.

Details

DDD will use special items to attempt to open Locked Doors. In order of preference: Platinum Yendorian Express Cards (I don't have one so I would appreciate hearing if this works), lockpicks (if your Moxie passes the riskiness specified in statchance -- see below), and skeleton keys (but it holds one back for the tower).

DDD has a few settings which you can configure to get the best use of the script. After running the script at least once (you can abort it before it does anything), type "zlib vars" in the CLI to see the current value of these settings, and "zlib settingname = value" to change them.

ddd_goal3 -- This allows you to specify an item that you want from the treasure chest in the 3rd room. It will only open the chest if you lack the item (or, in the case of the potato sprout, if you already have the Levitating Potato in your terrarium). Default is $item[potato sprout]. Specifying "none" will skip the chest.

ddd_goal6 -- Same as previous, but for the treasure chest in room 6. You may want to use this to look for lockpicks.

ddd_takeitintheface -- Whether or not to clear elemental test rooms even if you were unable to resist the element. If false, DDD will not attempt the dungeon if there is an elemental test you cannot pass. If true (default), you will take it in the face.

ddd_dungeonblind -- Whether or not to adventure anyway in the event that the NO Kingdom Calendar information is unavailable. If ddd_dungeonblind is true, DDD will try to complete the Daily Dungeon even if it can't predict it. If false (default), it will abort if you can't load the NO data.

ddd_statchance -- This is a spectrum from 1-3 of how risky you want it to be when attempting stat tests:
1: Attempt when your stat is at least the lowest possible pass value (will require up to 5 attempts)
2 (default): Only attempt when your stat is at least the mean of the pass/fail range provided on the wiki. This is likely to pass on the first or second effort.
3: Only attempt when your stat is guaranteed to pass. Will always take only one adventure.





Acknowledgments
Special thanks to Ragnok (#49653) in Noblesse Oblige for his help in pointing me to the best way to access the daily dungeon data, which is not immediately apparent in the source of the site. Also, mad props to him for creating the Kingdom Calendar in the first place; it's a tremendously useful resource. Definitely send him some appreciation if you find this script useful.

How to use it:
Download dailydungeon.ash to your scripts directory.
Download dungeonstatchecks.txt to your data directory.
Make sure you have ZLib if you don't already.
Optionally, tweak any of the script settings as described above.
Run the script from within mafia. Users of my Hardcore Checklist need not even bother with this step -- this has been integrated and Checklist will now automatically handle getting your keys.


Changelog
4.08.09 - ver. 1.0 posted, followed shortly by a few extra lines to handle the potato sprout.
4.12.09 - 1.1 changes: there is now a "takeitintheface" variable specifying your preference on attempting elemental test rooms even if you were unable to gain resistance.
4.24.09 - 1.2 changes: show all rooms during pre-testing, even if a room fails the test.
5.26.09 - 1.3 changes: add a parameter to resist(), allowing you to determine whether or not you can achieve resistance without actually casting the spells. So currently you won't cast spells during testing.
5.28.09 - 1.4 changes: the new improved resist() function searches all of your gear and doesn't waste time swapping outfits unnecessarily when testing. And, it's smaller.
6.14.09 - 1.5 changes: moved out some functions -- now requires ZLib.
7.25.09 - 1.6 changes: use script settings rather than variables. Change default goal3 to potato sprout and default takeitintheface to true.
11.01.09 - 1.7 changes: police is_100_run setting. Moved a few things around to play better with being imported. Several other tweaks and code cleanups (smaller by 0.1K, w00t).
12.30.09 - 1.8 changes: convert to using ZLib's new vprint().
5.22.10 - 1.9 changes: ASH's new to_element() doesn't equate "heat" with "hot", so replace that before parsing the dungeon data.

Muhandes
04-09-2009, 05:45 PM
I haven't tried this script yet, but I would appreciate it if I had an option to just tell me if I can do the dungeon safely, and if not, what am I missing.

Bale
04-10-2009, 12:19 AM
I agree with Muhandes. Just let me know what will happen if I enter the dungeon. Tell me if it will use keys, tell me how many aventures it will take. Tell me what buffs I'd have to use.

zarqon
04-10-2009, 12:33 AM
You haven't tried the script have you? It does that, then waits 10 seconds. If all you want is to see whether you can pass, it's easy to abort during those 10 seconds. Seriously, try it before you comment.

If you'd prefer only information, the code is very modular so it's quite easy to write your own main() that only checks the dungeon.

Bale
04-10-2009, 12:51 AM
I admit that I didn't even try it just because I'm hesitant to use much automation that I don't comb through every line. I'll download it and take a look now. Sorry for miffing you off, Z.

Since I also don't like needing many data files I'll add about half-a-dozen lines to the main script so that I won't need it. (Short map file.)

kain
04-10-2009, 02:25 AM
badass :) Perfect for my lazy runs where I don't necessarily feel the need to eat key pies!

Muhandes
04-10-2009, 07:01 AM
Sorry for being prudent, but I'm afraid that's how I'm built.

I gave it a try today, and it wont do the dungeon because I don't have cold resistance. I'm not sure how other people handle the dungeon, but personally I do it even if I don't have the resistances, since all it does is damage you and I can usually survive that.

Anyway, nice idea, thanks for writing this.

zarqon
04-10-2009, 11:19 AM
Hmmmm, I did have that thought when I was writing it. I usually wait until I can resist it without needing to heal myself afterwards (I guess I'm prudent differently).

Would people be happy with an option (perhaps named "takeitintheface") specifying whether or not to pass elemental rooms regardless of resistance?

Bale
04-11-2009, 05:13 AM
Well, it has been a long time since I've had to "take it in the face" since I have astral shell, but way back, I always used to consider healing to be a good option. You're differently prudent.

zarqon
04-12-2009, 01:27 PM
Okay, there is now an additional boolean variable at the top called, unexpectedly, "takeitintheface", which specifies your willingness to take elemental damage from elemental test rooms. Enjoy!

@Bale: in my opinion, the more information is hard-coded in external maps, the less code mafia has to parse and the faster the script. Building a map every time you run a script irks my German sense of efficiency. :)

Muhandes
04-12-2009, 04:54 PM
Thanks for adding this option. I already got my keys this ascension, but I'm sure to use it the next one.

Bale
04-12-2009, 06:14 PM
Okay, there is now an additional boolean variable at the top called, unexpectedly, "takeitintheface", which specifies your willingness to take elemental damage from elemental test rooms. Enjoy!

@Bale: in my opinion, the more information is hard-coded in external maps, the less code mafia has to parse and the faster the script. Building a map every time you run a script irks my German sense of efficiency. :)
I hadn't thought of it that way. It's only a few lines...


dchecks["Locked Door"] = new statrange ($stat[Muscle],29,51);
dchecks["A Hairier Barrier"] = new statrange ($stat[Mysticality],29,48);
dchecks["Piledriver"] = new statrange ($stat[Muscle],26,46);
dchecks["Smooth Criminal"] = new statrange ($stat[Moxie],28,44);
dchecks["The Mystic Seal"] = new statrange ($stat[Mysticality],25,41);
dchecks["Yet Another Troll"] = new statrange ($stat[Muscle],24,40);
dchecks["Badger Badger Badger Badger"] = new statrange ($stat[Moxie],26,38);
dchecks["Magic Shell"] = new statrange ($stat[Mysticality],19,29);
dchecks["The Biggest Bathtub Ever"] = new statrange ($stat[Muscle],17,30);
dchecks["Dungeon Fever"] = new statrange ($stat[Moxie],20,28);

... but I can understand your point. I'll just edit that into my own version since I don't mind a bit of slowdown for something I run only infrequently. It's less speed efficient, but also less file-cluttery.

dj_d
04-13-2009, 07:26 AM
I must admit, when I saw the subject line, I thought to myself:
Why the hell is Zarqon bragging about not implementing "calendar empowered prediction"?

Bale
04-13-2009, 07:36 AM
I thought that at first also! LoL!

By the way, I've tried this script and it really is pretty cool. I'm going to adopt it as one of the very few automations I use with mafia. Thanks, Z.

zarqon
04-13-2009, 10:16 AM
The hyphens, my friends, the hyphens. It's subtle, I know. ;)

Raven434
04-18-2009, 07:42 AM
Can't wait to try it Z!

My last HC run got borked by 2 days for exactly the reasons you listed.

:-(

Raven434
04-28-2009, 02:42 AM
Woot!

Works like a champ!

Thanks Z!

Bale
04-29-2009, 10:13 AM
Can I ask why it casts elemental protective spells when checking the dungeon, rather than waiting until you actually go into the dungeon? That's 10 MP wasted if I decide it's a bad day for spelunking.

zarqon
04-29-2009, 11:04 AM
Because the resist() function (used both when testing and when actually spelunking) attempts to resist a given element, and returns true if the resistance was achieved.

I will add a "sim" parameter to that function when I kick this stupid flu.

nudely_appendage
05-26-2009, 09:47 PM
I know the list of resistance items is not meant to be exhaustive, but is there any reason for leaving out lihc face? It's what I usually have available first for spooky resistance...

Thanks for the script!

zarqon
05-27-2009, 01:51 PM
Thanks to a recent feature request being implemented, I now have a new version of the resist() function ready to roll out, which searches ALL your equipment for resistance gear, and doesn't need to actually equip the items to determine if you can get resistance. It's on another computer at the moment, however.

But have patience -- I should be able to put it online tomorrow afternoon (that's late tonight for all you North Americans).

EDIT: Alrighty, we've got a new resist() function online, folks. This will select from any resistance gear you have, and doesn't need to bother equipping when testing. The only downside is there is no prioritizing of gear -- but that is unnecessary for the Daily Dungeon, since it switches your outfit back for any combats. Enjoy!

Muhandes
05-28-2009, 08:23 AM
Expected }, found && (dailydungeon.ash, line 106)

zarqon
05-28-2009, 08:44 AM
Dang it. Okay, try again.

nudely_appendage
06-02-2009, 09:33 PM
There seems to be a bug in the test for resistance - you use all lower case, but it needs to be mixed case:


> ash numeric_modifier($item[White Satin Pants], "sleaze resistance")
Returned: 0.0

> ash numeric_modifier($item[White Satin Pants], "Sleaze Resistance")
Returned: 2.0

Also is there some way of creating the dailydungeondata.txt file in the data directory instead of the scripts directory? I tried
load_dailydungeon("../data/dailydungeondata.txt")
but that didn't work for me.

zarqon
06-03-2009, 05:18 AM
Use a recent daily build of mafia -- numeric_modifier() is no longer case sensitive. I recommend always trying the latest daily build before submitting bug reports.

For your other question, after the script creates the file in the scripts dir, move it to the data dir. After that, it will stay there unless you delete it. Mafia has little to no handling of paths in any of its file I/O routines (in fact, it ignores them), and since the directories are created in different places for different OS's, relative paths would be useless anyway.

Muhandes
09-26-2009, 07:39 PM
Can it use an Exotic Parrot to get elemental resistance? With sugar shield, empathy, sympathy it pretty much gives a free ticket.

zarqon
09-27-2009, 04:04 AM
That's an interesting project! Far more complicated than the existing buff/gear checks though, since we would have to calculate the necessary weight to get resistance for the specified element, then see if that weight could be achieved.

I'll put it on my to-do list. Which seems to keep growing faster than it shrinks, sadly enough.

namol
12-30-2009, 02:07 PM
There seems to be an issue with the script expecting a return value on line 86.
Value expected (dailydungeon.ash, line 86)
return vprint("There's no chest in room "+roomie+,".",-4);

I have the latest zlib, checklist and dailydungeon

Bale
12-30-2009, 06:21 PM
Looks like that line should be:


return vprint("There's no chest in room "+roomie+".",-4);

zarqon stuck in a comma at the wrong place.

zarqon
12-30-2009, 07:42 PM
OK, I moved the extraneous comma from the script to this post.,

Raven434
01-04-2010, 02:06 AM
Even with blind set to true, I am still getting:

ddd_dungeonblind TRUE

Loading daily dungeon information for 20100103...
Noblesse Oblige's daily dungeon info is not yet available today.
Unable to load room data.
Unable to complete daily dungeon.

caddel
01-29-2010, 02:09 PM
Thanks for the work its very nice

Muhandes
02-28-2010, 06:33 AM
Found something of a bug:

Room 4...
Elemental Test!
Checking resistance to spooky...
Searching items for spooky resistance...
Resistance-granting item found: coffin lid
You can't equip an off-hand item while wielding a 2-handed weapon.

[408] Daily Dungeon (Room 0)
You lose 27 hit points
Room 4 cleared.

zarqon
03-02-2010, 03:40 AM
This will be fixed in the next release of ZLib. At least, it will return false rather than true if it fails to equip the item. A better solution would be to continue the search if the item fails, but that will have to wait.

Spiny
05-20-2010, 08:54 PM
Zarqon, I think you mentioned something recently in one of your threads (maybe zlib?) that resistance checks for the daily dungeon may not work quite right anymore? Is this a good example of that?



Checking room 8: Did I Leave the Floor On? (heat resistance)...
Checking resistance to none...
Passing through: +1 adv

zarqon
05-22-2010, 07:48 AM
Oh, right! I'd fixed it on my side, but hadn't updated here. Updated now.

Theraze
01-31-2011, 05:35 AM
One change I've made, since the checkpoint clear was added... changed the cli_execute "checkpoint" call in the dailydungeon function near the bottom to be "checkpoint clear; checkpoint" because I've had a lot of times where, switching between characters, it wants to equip the gear from the wrong character and I need to run the script 2-4 times until it actually runs successfully. Since clearing checkpoints, whether manually or using the script, I haven't had it try to equip the wrong gear once since...

Edit: Sorry, the clear has to get into line 1 or 2 of the function, since it has to go before the current line 2 where it loads and tests against your equipment whether it thinks you can succeed. As the checks involve equipping your prior outfit, if your last checkpoint pre-testing is from another character, it will try to equip their gear, not your own...

Edit2: Just to be clear, I'm putting it in between these lines:
vprint("Loading daily dungeon information for "+today_to_string()+"...",2);
cli_execute("checkpoint clear");
if ((!load_dailydungeon("dailydungeondata.txt") && !to_boolean(vars["ddd_dungeonblind"])) || (count(p) == 9 && dd_precheck() == 0)) return false;


and the issue is with the outfit checkpoint in the precheck, namely here (in the resistance section, I believe):
cli_execute("outfit checkpoint");
vprint("Passing through: +1 adv","maroon",2);

That FN Ninja
06-29-2011, 04:06 PM
Small request:


Since I also don't like needing many data files I'll add about half-a-dozen lines to the main script so that I won't need it. (Short map file.)

If a small map in the script is out of the question can it at least use the Map Manager? Thanks.

Theraze
06-29-2011, 04:35 PM
You are aware that's a 2 year old, rejected feature request? :)

Anyways, he posts the map in question 3 days later...
dchecks["Locked Door"] = new statrange ($stat[Muscle],29,51);
dchecks["A Hairier Barrier"] = new statrange ($stat[Mysticality],29,48);
dchecks["Piledriver"] = new statrange ($stat[Muscle],26,46);
dchecks["Smooth Criminal"] = new statrange ($stat[Moxie],28,44);
dchecks["The Mystic Seal"] = new statrange ($stat[Mysticality],25,41);
dchecks["Yet Another Troll"] = new statrange ($stat[Muscle],24,40);
dchecks["Badger Badger Badger Badger"] = new statrange ($stat[Moxie],26,38);
dchecks["Magic Shell"] = new statrange ($stat[Mysticality],19,29);
dchecks["The Biggest Bathtub Ever"] = new statrange ($stat[Muscle],17,30);
dchecks["Dungeon Fever"] = new statrange ($stat[Moxie],20,28);

That FN Ninja
06-29-2011, 06:23 PM
I'm aware. I have it using the Map Manager locally, just thought Z might want to implement it in the official version. He took the time to make such a useful resource, it might as well be put to good use. ;) It eliminates the need for the user to download two separate files.

zarqon
07-02-2011, 07:36 AM
The Map Manager's primary purpose is to allow automatic updating of data files. This map is not likely to need updating, so daily server hits checking for map updates from everyone using this script would be wasteful and an irresponsible use of bandwidth.

Bale
07-02-2011, 08:40 AM
This map is not likely to need updating.

Another reason why 10 lines of code might be better than needing an external file for data.

zarqon
07-02-2011, 07:08 PM
Funny, I see that as another reason not to allocate each map key/index individually in the script. Are the values conditional? No. Will the values need to be changed? No. It seems to me that these are ideal conditions for populating the map in one fell swoop with file_to_map().

At heart, this is just an issue of perspective. I tend to be pretty idealistic about coding and What Things Mean, but users are pragmatic -- they don't give a ratskin belt about how something is done, only whether or not it works and how easy it is to use. They would rather not click a few times to download an additional file. I would rather not define a map in-script piece-by-piece with static information, because a single ASH command exists to perform all of those many commands at once. This leads me to conclude that the code which Bale posted is doing unnecessary work, and is not how maps of static information are meant to be populated.

Pragmatically, Bale's user-centric solution saves the users some clicks when downloading and reduces the number of files by one, and is therefore better. Idealistically, my "Best Practices" approach populates a map using a single command designed for populating entire maps at once, rather than individual commands for each value (which is needless since none of the information needs to be filtered or decided), and is therefore better.

I tip my hat to you, pragmatic friend Bale. But I shall keep to my ideals (and even my perceived ideals). :)

If a constructor existed in ASH to define an entire map in the same line on which it was declared (as it does for records), this discussion would be moot.

Bale
07-02-2011, 09:08 PM
That's fine. I don't find your approach to be offensive after all.

Though I consider one of the values of a datafile to be that you can download a new datafile if its values change or there are more options. That saves you from needing to modify the script to deal with a new restorative being added to the game. When the values don't change, then that advantage goes away.

Populating a map of merely 10 entires seems like a negligible speed difference compared to user friendliness. I understand the real issue is that it offends your sense of language efficiency. Your background as a linguist makes you feel like you would be wasting words and turning a simple concept into one that is obscured by excessive detail. That's two kinds of loss and no gain by such a standard.

zarqon
07-03-2011, 07:39 AM
it offends your sense of language efficiency.

You put it better than I did. That's it, on the knob.

Winterbay
07-03-2011, 12:11 PM
Which also explains why your version of Batbrain is ~1150 lines of code and mine is ~1720 lines.
I went for readability (as defined by me) and you went for code efficiency :)