missingManuel.ash - Yet Another Manuel Script!

heeheehee

Developer
Staff member
(side note: There is a way to get Cyrus using a couple days setup in Ed, and a way to get him using, apparently, 10 turns and 30k from the mall. For reasons that I cannot begin to understand, the people who know how to do it the latter way consider it a "secret".)

My guess would be that it involves abusing a number of bugs and/or oversights in the game's code, as opposed to the oversight that is (practically) unbounded +spell%. *shrug*
 

Veracity

Developer
Staff member
I still don't understand. Even if the original intent was "nyeah, nyeah, I have Cyrus factoids and you don't!" (which is just mean-spirited), now that anyone can get the factoids by spending a few days building up lots of Ka in Ed, even that motivation is gone. Unless it is now replaced by "neah nyeah, you will have to waste several days of game time for no good reason if you want Cyrus factoids" - which also seems mean-spirited.

I don't get it.
 

Bale

Minion
You're overthinking it. The only intent is "nyeah, nyeah, I'm awesome because I know something you don't know."
 

heeheehee

Developer
Staff member
I still don't understand. Even if the original intent was "nyeah, nyeah, I have Cyrus factoids and you don't!" (which is just mean-spirited), now that anyone can get the factoids by spending a few days building up lots of Ka in Ed, even that motivation is gone. Unless it is now replaced by "neah nyeah, you will have to waste several days of game time for no good reason if you want Cyrus factoids" - which also seems mean-spirited.

I don't get it.

Said bugs would presumably be useful in future scenarios where Toxic Vengeance + fist of the mummy would fall short, e.g. with damage mitigation and a fairly brutal exponent.
 

Veracity

Developer
Staff member
So, you are saying that there is a bug, they told TPTB about it, TPTB said "we don't care and will not fix it", at which point Bale's explanation kicks in.

Got it.
 

Bale

Minion
Actually, if the situation is that it is a bug TPTB don't want to fix, then a better reason for staying quiet is that TPTB will fix the bug if everyone knows it so they'll lose the ability.

In other news, if anyone is willing to tell me the trick, I'd like to easily and quickly get Cyrus' factoids without needing to Ed him.
 

ckb

Minion
Staff member
Zomg! Me too. Tell me the secrets!
Also, the truth will set you free. I don't understand the reasoning behind hinting at a solution without actually telling people what it is. Unless it does not actually exist.
 

Turing

Member
I got rid of BlockedAreas, so a whole bunch of old monsters are now showing up. Some have been found (and are on some fax network), and some have not. Time will tell which ones need to be removed.
 

Veracity

Developer
Staff member
Nice!

A couple comments about blockedMonsters:

Gnollish Sorceress, 7-Foot Dwarf,

Considering that the giant pair of tweezers came back, we can hope! But if so, there will be 2 7-foot Dwarfs, so may as well wait.

Deadwood Tree, Fur Tree, Hangman's Tree, Pumpkin Tree,

We have one tree from this event - the toilet-papered tree - so again, let's hope Riff added the others but people have not been pulling Plants.

Skeleton Invader, Two Skeleton Invaders, Three Skeleton Invaders, Four Skeleton Invaders,

We have five skeleton invaders.

Servant Of Lord Flameface, space beast matriarch,
Caveman Dan, Crimbomega, Rudolphus of Crimborg];

Believe it or not, Servant of Lord Flameface and Rudolphus of Crimborg are in the fax network right now.

The other ones look good to me. Thanks for this script!
 

Turing

Member
Trees, invaders, servant and Rudolphus should now show up. I'll add the sorceress and 7 foot-dwarf if they appear in the deck. Thanks for the feedback!
 

Aramada

Member
Got some weird results when I ran the new script - there were a huge number of monsters that I have all the factoids for, and have had them forever, but they are showing up as totally missing. (Using Mafia v. 17.1 r 16167)

ancient protector spirit (The Hidden Apartment Building) {3}, ancient protector spirit (The Hidden Hospital) {3}, ancient protector spirit (The Hidden Office Building) {3}, ancient protector spirit (The Hidden Bowling Alley) {3}, ancient protector spirit (obsolete) {3}, [The F'c'le] clingy pirate (female) {3}, clingy pirate (male) {3}, Clingy Pirate (female) {3}, [Junkyard] Batwinged Gremlin (tool) {3}, Erudite Gremlin (tool) {3}, Spider Gremlin (tool) {3}, Vegetable Gremlin (tool) {3}, [Lair of the Ninja Snowmen] Ninja Snowman (Hilt) {3}, [El Vibrato Island] Bizarre Construct (translated) {3}, Hulking Construct (translated) {3}, Industrious Construct (translated) {3}, Lonely Construct (translated) {3}, Menacing Construct (translated) {3}, Towering Construct (translated) {3}, animated nightstand (Mahogany 1) {3}, animated nightstand (White 1) {3}, Slime Tube monster {3}

Like I said, I've had all of these factoids forever, so I don't know why the script isn't detecting them.

(Also, oddly, it is listing Ninja Snowman (Hilt) {3} BOTH under [Lair of the Ninja Snowmen] AND [Unsorted]

Thoughts?

~Aramada
 

Aramada

Member
Probably related to Mafia update; script probably hasn't caught up yet.

Gotcha!

Also, along with the Servant of Lord Flameface, two other buring world event monsters now have factoids (and are in the fax network): blazing bat, and snakefire in the grassfire. Just FYI.

~Aramada
 

Bale

Minion
Turing, with the recent changes to KoLmafia I recommend that instead of parsing manuel names and checking current factoids you make a change to the script.

Now it should be better to check the monster ID number in "<a name='mon(\\d+)'.+?</table>" and use to_monster(entry.group(1)) to get KoLmafia's unique monster name. It will save you a step, allowing you to make use of KoLmafia's data files to handle all the heavy lifting so you need to update the script less frequently.

Actually it would probably be easier to use mafia's new function to just remove all manuel parsing from the script. cli_execute("checkmanuel"); and then do foreach m in mon missed = 3 - monster_factoids_available(m); I think that would work.
 

Veracity

Developer
Staff member
Well, he's putting all the monsters into categories ("areas" or "locations"). Hopefully, get_monsters(loc) returns monsters with correct ids - but the fact is, KoLmafia still doesn't know all the ids, and if you have one in Manuel that KoLmafia doesn't know yet, when you visit the page, KoLmafia will now print the info we need to update, but the monster returned by get_monsters will not be updated yet.

I would suggest something like the following, if he wishes to retain areas:

visit all pages of manuel. This will update KoLmafia's id -> monster map with new monsters
Get a map of all monsters with ids using (surprise!) all-monsters_with_id().
for all areas, look only at monsters which have ids. For each monster with an id, print manuel info, and remove from list of all monsters
for all remaining monsters with ids, check factoid count, as Bale suggests, and print manuel info for them in a "New ID found" area.

When KoLmafia adds monster ids for old monsters - and changes or adds disambiguation, as needed - your script will automatically adapt; the "New ID found" list will, eventually, shrink away to zero.
 

Veracity

Developer
Staff member
OK, I decided to see what I could do to missingManuel to try out what I suggested there. Turns out, I wanted a bit more KoLmafia support in the form of new or improved ASH functions. Revision 16169 has:

boolean flush_monster_manuel_cache()

Since visiting a Monster Manuel page will not replace an entry which has 3 factoids, even if the current character doesn't know 3 factoids for the monster, we need to do this before visiting all the pages.

int monster_factoids_available( monster m, boolean cache_only )

The second parameter is new. It says "if the monster is not in the cache, assume you have actually visited the page and it is not there, rather than going to look at the Manuel page, just in case."

Given that, this is a proof of concept modification of missingManuel.ash.

Code:
script "missingManuel.ash";

static boolean [monster] blocked_monsters = $monsters[
		Hockey Elemental, Count Bakula, Infinite Meat Bug, The Master of Thieves, Crazy Bastard, Baiowulf, Hypnotist of Hey Deze, The Temporal Bandit, Knott Slanding, Pooltergeist (Ultra-Rare), QuickBASIC Elemental, The Nuge,
		The Whole Kingdom, The Hermit,
		Don Crimbo, Edwing Abbidriel, Crys-Rock, Trollipop, The Colollilossus, The Fudge Wizard, The Abominable Fudgeman, Uncle Hobo, Underworld Tree,
		Hammered Yam Golem, Soused Stuffing Golem, Plastered Can of Cranberry Sauce, Inebriated Tofurkey,
		space beast matriarch,
		The Darkness (blind),
		CDMoyer's Butt, Hotstuff's Butt, Jick's Butt, Mr. Skullhead's Butt, Multi Czar's Butt, Riff's Butt,
		Slime2, Slime3, Slime4, Slime5,
		Ed the Undying (1), Ed the Undying (2), Ed the Undying (3), Ed the Undying (4), Ed the Undying (5), Ed the Undying (6), Ed the Undying (7),
		Count Drunkula (Hard Mode), Falls-From-Sky (Hard Mode), Great Wolf of the Air (Hard Mode), Mayor Ghost (Hard Mode), The Unkillable Skeleton (Hard Mode), Zombie Homeowners' Association (Hard Mode),
		wild seahorse,
		giant pumpkin-head, large-headed werewolf, oddly-proportioned ghost,
		All-Hallow's Steve, The Sagittarian, general seal, Frank "Skipper" Dan\, the Accordion Lord, Chef Boy\, R&D, spirit alarm clock,
		Disorganized Files, Endless Conference Call, Hideous Slide Show, Tedious Spreadsheet, Unoptimized Database, Your Overflowing Inbox, Chatty Coworker, The Book Of Faces, The Tome Of Tropes, The Water Cooler, Totally Malicious 'Zine, The Best Game Ever,
		Caveman Dan, Crimbomega];

boolean [monster] get_all_monsters()
{
    boolean [monster] all_monsters = all_monsters_with_id();

    // Remove uncopyable monsters that have a known id

    // Here is how we would do it if KoLmafia had a "nocopy" proxy field
    /*
    foreach m in all_monsters {
	if ( m.nocopy ) {
	    remove all_monsters[ m ];
	}
    }
    */

    foreach m in blocked_monsters {
	remove all_monsters[ m ];
    }

    return all_monsters;
}

void visit_page( string page )
{
    print( page );
    visit_url( "questlog.php?which=6&vl=" + page.to_lower_case() );
}

void visit_all()
{
    flush_monster_manuel_cache();
    visit_page("A");
    visit_page("B");
    visit_page("C");
    visit_page("D");
    visit_page("E");
    visit_page("F");
    visit_page("G");
    visit_page("H");
    visit_page("I");
    visit_page("J");
    visit_page("K");
    visit_page("L");
    visit_page("M");
    visit_page("N");
    visit_page("O");
    visit_page("P");
    visit_page("Q");
    visit_page("R");
    visit_page("S");
    visit_page("T");
    visit_page("U");
    visit_page("V");
    visit_page("W");
    visit_page("X");
    visit_page("Y");
    visit_page("Z");
    print("Now I know my ABCs!");
    visit_url("questlog.php?which=6&vl=-");
}

int three, two, one, zero;

string GetLocName(string locName)
{
	if (locName == "Foyer") return "Vanya's Castle";
	if (locName == "A Well-Groomed Lawn") return "Landscaper's Map";
	if (locName == "Post-War Junkyard") return "Junkyard";
	if (locName == "1st Floor, Shiawase-Mitsuhama Building") return "Shiawase-Mitsuhama Building";
	return locName;
}

boolean print_all = false;

boolean process_monster ( monster m, string loc, boolean print_header )
{
    int missed = 3 - monster_factoids_available( m, true );

    if (missed == 0) {
	three += 1;
	if ( !print_all ) {
	    return print_header;
	}
    }

    if (missed == 1)
	two += 1;
    else if (missed == 2)
	one += 1;
    else if (missed == 3)
	zero += 1;

    if ( print_header ) {
	print("[" + GetLocName(loc) + "]");
    }

    if (missed > 2) {
	print(m + " {" + missed + "}", "red");
    }
    else {
	print(m + " {" + missed + "}");
    }

    return false;
}

void CheckManuel ()
{
    print_all = user_confirm("Display full list?");

    print("Checking Monster Manuel...", "blue");
    visit_all();
    print("Done checking Monster Manuel!", "blue");

    boolean [monster] all_monsters = get_all_monsters();

    print("=================================");
    boolean print_header;
    foreach loc in $locations[] {
	print_header = true;
	monster [int] mon_list = get_monsters(loc);
	foreach i, m in mon_list {
	    if ( m.id > 0 && all_monsters contains m ) {
		print_header = process_monster( m, loc.to_string(), print_header );
		remove all_monsters[ m ];
	    }
	}
	if ( !print_header ) {
	    print("=================================");
	}
    }

    print_header = true;
    foreach m in all_monsters {
	print_header = process_monster( m, "Unsorted", print_header );
    }
	
    print("");
    print("You have casually researched " + one + " creatures.");
    print("You have thoroughly researched " + two + " creatures.");
    print("You have exhaustively researched " + three + " creatures.");
    print("You have not researched " + zero + " creatures.");
    print("Total creatures: " + (one + two + three + zero) + ".");
    print("Done.", "blue");
}

void main ()
{
	string page = visit_url("questlog.php?which=6");
	if (contains_text(page, "[Monster Manuel]"))
	{
		CheckManuel();
	}
	else
	{
		print("Thank you, Mario, but your Monster Manuel is in another castle!", "blue");
		print("Perhaps you should consider getting one?");
		print("");
		print("=================================");
		print("[Every Single Area]");
		print("NOTHING!  ABSOLUTELY NOTHING!", "red");
		print("=================================");
		print("");
		print("You have casually researched 0 creatures.");
		print("You have thoroughly researched 0 creatures.");
		print("You have exhaustively researched 0 creatures.");
		print("You have not researched ANY creatures.");
		print("Done.", "blue");
	}
}
It does not have "Extra Areas" to put things like wandering bees, and such; it just looks at all KoL locations and sees what monsters are listed there, and everything else goes into Unsorted. That's inferior to missingManuel, but I'll leave it to you to figure out how to do that. ;)

Here is the output of this script, given my Manuel:

> mm.ash

Checking Monster Manuel...
A
B
C
D
E
F
G
H
I
J
K
L
M
Monster #906 has name 'Mob Penguin goon' but Manuel calls it 'Mob Penguin Goon'
Monster #1667 has name 'Your winged yeti' but Manuel calls it 'Mraderick'
N
O
P
Q
R
S
T
U
V
Monster #1669 has name 'You the Adventurer' but Manuel calls it 'Veracity the Adventurer'
W
X
Y
Z
Now I know my ABCs!
Done checking Monster Manuel!
=================================
[Crimbo Town Toy Factory (2009)]
wire-crossin' elf {3}
=================================
[Atomic Crimbo Toy Factory]
mutant doll-dressing elf {3}
mutant gift-wrapping elf {3}
mutant whistle-carving elf {3}
=================================
[Old Crimbo Town Toy Factory]
Mob Penguin Enforcer {3}
=================================
[Simple Tool-Making Cave]
flint-scraping cave elf {3}
hunter-gatherer cave elf {3}
=================================
[Crimborg Collective Factory]
Rudolphus of Crimborg {3}
=================================
[Crimbo Town Toy Factory (2005)]
Striking Gift-Wrapper Elf {3}
Doc, the Reindeer {3}
Rudolph the Red {3}
=================================
[Market Square, 28 Days Later]
drunken zombie half-orc hobo {3}
fiendish zombie can of asparagus {3}
Zombie Knob Goblin Assistant Chef {3}
zombie yeast beast {3}
=================================
[The Mall of Loathing, 28 Days Later]
white zombie {3}
zombie apathetic lizardman {3}
Zombie Clown {3}
zombie frat boy {3}
zombie hippy {3}
zombie zmobie {3}
=================================
[Wrong Side of the Tracks, 28 Days Later]
Zombie eXtreme Snowboarding Orc {3}
Zombie Goth Giant {3}
Zombie N00b {3}
Zombie Quiet Healer {3}
=================================
[The Icy Peak in The Recent Past]
Mob Penguin Soprano {3}
=================================
[The SMOOCH Army HQ]
Pener Crisp {1}
Deuce Freshly {1}
=================================
[Unsorted]
mutant gila monster {3}
rock snake {3}
snakefire in the grass {3}
blazing bat {3}

You have casually researched 0 creatures.
You have thoroughly researched 2 creatures.
You have exhaustively researched 1567 creatures.
You have not researched 30 creatures.
Total creatures: 1599.
Done.
Note that I have actually exhaustively researched 1568 creatures, not 1567. I think the discrepancy is because I have both the "Mob Penguin goon" and the "Mob Penguin Goon", and, as discussed elsewhere, we don't do that quite right yet.

Anyway, I hope this is helpful!
 

Veracity

Developer
Staff member
So, I was wondering how this would work with a monster unknown to KoLmafia. I faxed in a Gnollish Sorceress and fought her. Running mm.ash:

Checking Monster Manuel...
...
G
New monster #17 found in Manuel with name 'Gnollish Sorceress' and image 'gnollmage.gif'
...
[Unsorted]
Gnollish Sorceress {3}
...
I am pleased to say that it gave exactly the info we need to add the monster to KoLmafia - name, image, monster ID - although I suppose it could report on phylum, initiative, Atk:, and so on.

I am sorry to say that it didn't seem to record the fact that I know a factoid.

I'll fix that.
 
Top