New Content - Implemented Protonic Accelerator

How are you doing your combats?

My afterAdventure script keeps track of the nextparanormal activity, and when it's up, equips the protopack, kills a bricko ooze and goes to fight the ghost.
The combat itself should be handled by my autoattack, however, for some reason, it isn't firing properly specifically against those 2 ghosts only.

When this happens the cli shows this:
https://puu.sh/sJy3S/4d538a6cee.png
https://puu.sh/sJy5e/ce841284bb.png

I'm not sure if it is a mafia or native problem (since well, it is my kol autoattack that isn't firing properly), but it certainly looks weird, and it's rather uninformative about what happens. (Unlike say, when my macro aborts or when I have autoattack turned off).
 

Bale

Minion
My afterAdventure script keeps track of the nextparanormal activity, and when it's up, equips the protopack, kills a bricko ooze and goes to fight the ghost.

my afterAdventureScript does the second part, but it doesn't check for the lack of a protonpack and do the first part. Would you lend me your code to get me started on that?
 

Veracity

Developer
Staff member
I'm trying to figure out why I am now 'aborting' on the ghosts. I can't find anything that is causing it, my CCS is simply: "shoot, shoot, shoot, trap" for each of the ghosts. It was working, but now it stops.
I expect that this will be working now as of revision 17491

I am having a similar issue, though in my case it's my kolnative autoattack not properly firing. This, hoewever, only happens against the ghost in the Palindome and in the spookyraven wine cellar.
If your KoL autoattack is not firing, that has to be a KoL problem. I think.

Nope, it just broke on The ghost of Jim Unfortunato, as usual. When it does, it doesn't even seem to try firing the autoattack, and it prints the effectively the full combat frame of the first round of the combat (including pictures and all) in the gCLI.
My afterAdventure script keeps track of the nextparanormal activity, and when it's up, equips the protopack, kills a bricko ooze and goes to fight the ghost.
The combat itself should be handled by my autoattack, however, for some reason, it isn't firing properly specifically against those 2 ghosts only.
Can I see that part of your afterAdventureScript, please? equipping, fight BRICKO ooze, fight ghost?
 
Bale will probably find it familiar looking, since it spawned out his busting snipped posted earlier in this thread.
I wasn't really planning to publish this yet. It could use a little cleanup at least, but whatever, it should be understandable enough. Currently, the script is kinda stupid, and doesn't check stuff like you actually owning a protopack, but like I said, I wasn't really planning to share it around just yet.
It doesn't even check if you are already adventuring with the protopack, though that might be taken care of by the strict inequality in the turns check. I rarely find myself actually adventuring with the protopack, except in run, between the CSA backpack, Bjorn and Carpe items.

Code:
void SaveSetup() {
	if (!SetupSaved) {
		print("Saving setup ...", "green");
		fam = my_familiar();
		throne = my_enthroned_familiar();
		bjorn = my_bjorned_familiar();
		foreach eqSlot in $slots[]
			equipment[eqSlot] = equipped_item(eqSlot);
		aa = get_auto_attack();
		aas = get_property("afterAdventureScript"); 
		set_property("afterAdventureScript", ""); //Note Awkward workaround: required to stop nested calls of the after Adventure script (as would otherwise happen after any of the adv1() calls in the script). The nesting messes up the restoration of the setup
		SetupSaved = TRUE; //To prevent overriding the first saved setup, in case multiple of the functions in the script get called in succession (like picking a bricko fight and then busting a ghost). 
//Specifically done at the end, because Restoring a partial setup can get kinda messy (folder holder slots are in $slots[], as I found out the hard way after wondering for a while why my folder holder would randomly be empty every once in a while).
	}
}

void RestoreSetup() {
	if (SetupSaved) {
		set_property("afterAdventureScript", aas);
		if (aa != get_auto_attack())
			set_auto_attack(aa);
		if(fam != my_familiar()) 
			use_familiar(fam);
		foreach eqSlot in $slots[]
		{
			if (equipped_item(eqSlot) != equipment[eqSlot])
				equip(eqSlot, equipment[eqSlot]);
		}
		if (throne != my_enthroned_familiar()) 
			enthrone_familiar( throne );
		if (bjorn != my_bjorned_familiar())
			bjornify_familiar(bjorn);
		print("... Restored setup", "green");
	}
}

void BrickoPrime() {
	location ghostLocation = to_location(get_property("ghostLocation"));
		if (to_boolean(get_property("kingLiberated")) && ghostLocation == $location[none] && total_turns_played() > get_property("nextParanormalActivity").to_int() ) {
		if (get_property("_brickoFights").to_int()<10) {
			SaveSetup();
			set_auto_attack(99148055);
			outfit("birthday suit");
			if (chooseFamiliar() != my_familiar()) use_familiar(chooseFamiliar());
			cli_execute("/outfit Free Drops");	
			equip($slot[back],$item[protonic accelerator pack]);
			cli_execute("maximize .25 ML, Item, empty, -equip sneaky pete's leather jacket, -equip sneaky pete's leather jacket (collar popped)");
			use( 1, $item[BRICKO Ooze] );
			location ghostLocation = to_location(get_property("ghostLocation"));
			if  ( ghostLocation != $location[none] )
				cli_execute("/timer 51 Ghost!");
		}
		else {
			SaveSetup();
			equip($slot[back],$item[protonic accelerator pack]);
			adv1(my_location(),0,"");
			location ghostLocation = to_location(get_property("ghostLocation"));
			if  ( ghostLocation != $location[none] )
				cli_execute("/timer 51 Ghost!");
		}
	}
}

void main() {
	try {
		if ( can_interact() )
		{
			lightsOut(); //Handles the lights out Quest
			digitizeMonster(); //Picks up digitize wanderers in helpful zones. Will equip a protopack if the timing is just right, to save the brickofight.
			brickoPrime();
			bustGhost(); //Basically Bales function, but with though with similar outfit switching
		}
	} 
	finally { RestoreSetup(); }
}

A few notes: chooseFamiliar() is my own little function, basically a simplified implementation of: http://kolmafia.us/showthread.php?18051-FamiliarDrops-Get-profitable-drops-from-familiars&p=138341 (I really should see if I can adapt that script, it does so much more).
"Free Drops" is the outfit I setup for aftercore purposes to use whenever I'm working on some sort of quest where I don't really need a specialized outfit. Bounty hunting would be the most obvious example, though I haven't done that in a while. It holds equipments that cause drops in or after combat, or other otherwise can make these combats more valuable. Currently it's holding holds the CSA backpack, stinky cheese sword, kol con 13 snowglobe, pantsgiving, screege, cheengs, xiblaxian holo-wrist-puter and a crown of thrones (enthroned familiar varies, but it's usually something like a warbear drone or pottery owl just to collect drops).
The reason I use cli_execute() is to get the normal kol functionality: it will equip the items in the outfit when it can, and leave the other slots empty (to be filled up by the maximize call later). If I use the ash outfit() command it will abort if I currently don't have my stinky cheese sword (because I'm currently running with the eye for example), and while I can catch that return value, I would rather it just equip what it can and ignore the rest.


As for the autoattack problem that started all this: I currently have a little abort in the function to stop when it runs into those two ghosts, so I can check it out in vanilla kol to see what the fuck happens, but that one I posted earlier was the only one I ran into today, and I just ascended, so that will probably be a while.
 
Last edited:
As for the autoattack problem that started all this: I currently have a little abort in the function to stop when it runs into those two ghosts, so I can check it out in vanilla kol to see what the fuck happens, but that one I posted earlier was the only one I ran into today, and I just ascended, so that will probably be a while.

That was easier than I thought: the first ghost I fought after breaking the prism was Emily. My autoattack didn't fire at all, without any messages in vanilla, so I made a kol bug report.
 

Veracity

Developer
Staff member
For reference, my script also automatically busts ghosts.

Code:
    item back_item = equipped_item( BACK );
    
    if ( have_protonic_accelerator ) {
	boolean have_goals = count( get_goals() ) > 0;
	while ( turns > 0 ) {
	    location paranormal = get_property( "ghostLocation" ).to_location();
	    int next_ghost_turn = get_property( "nextParanormalActivity" ).to_int();
 	    int delay = next_ghost_turn - total_turns_played();

	    if ( paranormal != NO_LOCATION) {
		bust_ghost( paranormal );
		equip( back, back_item );
 		continue;
	    }

	    if ( delay <= 0 ) {
		equip( back, PROTONIC_ACCELERATOR_PACK );
	    }

	    int current = min( max( 1, delay ), turns );
	    boolean ignore = adventure( current, loc, filter );
	    equip( back, back_item );
	    if ( have_goals && count( get_goals() ) == 0 ) {
		return;
	    }

	    turns -= current;
	}
	return;
    }
This makes use of both the "ghostLocation" and "nextParanormalActivity" settings. Here is how it does the actual busting:

Code:
void bust_ghost( location paranormal )
{
    if ( paranormal != NO_LOCATION ) {
	cli_execute( "checkpoint" );

	item back_item = equipped_item( BACK );
	if ( back_item != PROTONIC_ACCELERATOR_PACK ) {
	    equip( back, PROTONIC_ACCELERATOR_PACK );
	}

	item acc3_item = equipped_item( ACC3 );
	if ( paranormal == PALINDOME && acc3_item != TALISMAN_O_NAMSILAT ) {
	    equip( ACC3, TALISMAN_O_NAMSILAT );
	}

	if ( paranormal == ICY_PEAK && numeric_modifier( "Cold Resistance" ) < 5 ) {
	    outfit( "Slimesuit" );
	}

	try {
	    boolean ignore = adv1( paranormal, 0, "bust_ghost_filter" );
	}
	finally {
	    cli_execute( "outfit checkpoint" );
	}
    }
}

void bust_ghost()
{
    location paranormal = get_property( "ghostLocation" ).to_location();
    bust_ghost( paranormal );
}
It suits up and restores equipment and uses adv1 with a combat filter.

Code:
string bust_ghost_filter( int round, monster mon, string page )
{
    boolean [string] subtypes = mon.sub_types;

    if ( subtypes contains "ghost" ) {
	String stun =
	    have_lovebugs ? "skill Summon Love Gnats" :
	    can_noodle ? "skill Entangling Noodles" :
	    "skip";

	switch ( round ) {
	case 0:
	    return stun;
	case 1:
	case 2:
	case 3:
	    return "skill Shoot Ghost";
	case 4:
	    return "skill Trap Ghost";
	}
    }

    return "";
}
This has worked flawlessly until once today. I'd just run a bunch of adventures in the Gingerbread City and Nose Chakra, ignoring paranormal activity.

Code:
[13221] Gingerbread Upscale Retail District
Paranormal activity reported at The Haunted Conservatory.
I eventually ran my script, which noticed that ghostLocation was set.

Code:
[13337] The Haunted Conservatory
Encounter: The ghost of Lord Montague Spookyraven
...
After Battle: Bustin' that ghost made you feel really good! (+20 Stats)
After Battle: You gain 7 Beefiness
After Battle: You gain 13 Wizardliness
After Battle: You gain 15 Cheek
Paranormal activity reported at The Icy Peak.
It immediately alerted me to more Paranormal activity. Fair enough, since it had been 115 turns since the previous one was reported. I immediately went there.

Code:
[13337] The Icy Peak
Encounter: GT1
Round 0: GT1 says: ""
How odd. a time-spinner prank. That did not interrupt my previous ghost busting. So, I assume the ghost is still there.

Code:
[13337] The Icy Peak
Encounter: Knott Yeti
Nope. And it continued adventuring at the Icy Peak until I stopped it, since we never cleared ghostLocation after failing to find a ghost there on the expected turn.

I suppose my script could do that, but this was unexpected: paranormal activity reported, no ghost there, and no longer (if ever) actually listed in the charpane.

FWIW, revision 17554 clears ghostLocation when parsing the Quest Log and sets it to the current ghostLocation, if there actually is one.
 

Veracity

Developer
Staff member
So, perhaps a visit to the quest log page 1, if no ghost was found, in order to clear/reset ghostLocation is in order.

Something for scripts to do, or for KoLmafia itself?
 

Veracity

Developer
Staff member
Well.... we visit the quest page when you log in. So, if you log in anew, we will reset an improper setting. But it's not a solution to what happened to me:

- Got a paranormal activity notice.
- I ignored it for over 100 turns without the Protonic Accelerator Pack equipped.
- Eventually, I equipped the pack and busted the ghost
--> Notice that even though it was more than 50 turns since the last notice, it was in the previously announced place.
- That very fight announced more paranormal activity
--> But the ghost was not there. I automated that, so am not sure whether KoL announced it in the Quest Log/Charpane
--> When I stopped the script 10 or 15 turns later, after I noticed it was repeatedly adventuring in the Icy Peak, and went to the Relay Browser, it was not there at that time.

I will try this tomorrow without automation. I'll do my Gingerbread turns (with the pack) and my Chakra turns (without the pack) and will bust the ghost in the Relay Browser.

Will it immediately announce paranormal activity?
Will the location be in the quest log?

If "yes" and "no", then perhaps KoLmafia itself should hit the quest log after paranormal activity is announced on the same round we bust a ghost.

In any case, I updated my script to hit the quest log if it busts a ghost and "ghostLocation" is still set - either new paranormal activity was detected, or it was a false alarm, so to speak.
 

Bale

Minion
If you get a paranormal activity notification as you bust a ghost, it doesn't happen. Annoying KoL bug that I blundered into once.
 

Veracity

Developer
Staff member
I just did. Thank you confirming that. I think that means that we simple don't set ghostLocation on the turn where we bust a ghost.
 

Bale

Minion
Yeah. I'm guessing that in the KoL code, killing a ghost clears the ghost location. Unfortunately the new ghost is assigned before the data is cleared instead of after. Bad order of operations.
 

Veracity

Developer
Staff member
OK. We first reset ghostLocation if we just busted a ghost and then check to see if there is no paranormal activity announced - which could be a bad order of execution. Except, we like doing all the monster-specific stuff first. So, revision 17588 will not look for new paranormal activity after we have just busted a ghost.
 

taltamir

Member
almost-dead walkie-talkie can be used by people without the protonic accelerator pack to kill the ghosts for the factoids.
using it from the CLI with "use almost-dead walkie-talkie" unlocks the ghost but does not actually inform you where it is located.
Code:
Using 1 almost-dead walkie-talkie...
Finished using 1 almost-dead     walkie-talkie.
While manually using it does inform you of the location. I think using it should also print to CLI the target location.
Note that you can actually find out the location by checking your quest log.

incidentally, because it is not being processed by mafia, using "prefref ghostLocation" shows empty value when using the almost-dead walkie talkie. Despite there being a value as per quest log
 
Last edited:
Top