Bug - Waiting for Info use Ghost Dog Chow can fail

ckb

Minion
Staff member
If is possible to use too much Ghost Dog Chow if your familiar is at the max level or has >380 XP.
It fails with this message:
HTML:
<table width="95%" cellspacing="0" cellpadding="0"><tbody><tr><td style="color: white;" align="center" bgcolor="blue"><b>Results:</b></td></tr><tr><td style="padding: 5px; border: 1px solid blue;"><center><table><tbody><tr><td>Your familiar doesn't seem interested in that much dog food.</td></tr></tbody></table></center></td></tr><tr><td height="4"></td></tr></tbody></table>

Mafia does not report failure for this:

> ash use(1,$item[ghost dog chow])

Using 1 Ghost Dog Chow...
Finished using 1 Ghost Dog Chow.
Returned: true
 

Veracity

Developer
Staff member
UseItemRequest is inconsistent. It attempts to detect failure to use an item and correctly not remove it from inventory, but whether or not it "reports" on that varies.

- Sometimes it puts a "reason" into UseItemRequest.lastUpdate.
- Having done that, sometimes it prints it and goes into ERROR state.

In any case, the use() function will return false if either we are in ERROR or if UseItemRequest is set.

I guess the purpose of going into ERROR is to stop script execution. In the cases when we set the error string but do not go into ERROR, the message is intended to be informative, but not stop scripts.

Now, ASH scripts don't want "informative" messages. They want a true/false for non-fatal failures so they can (optionally) decide how they want to react.

Seems to me that all non-fatal usage failures should set a message, at least, whether or not they display it, so that the use() function will return false.

UseItemRequest should not print messages, I believe, since that is called even when we look at requests from the Relay Browser. It should print messages if it is invoked from an actual UseItemRequest - via the GUI or a script.

That's a more complicated thing than I feel like looking at, for now, so Revision 17394 sets the message - so use() will return false - but it never actually gets printed any where.
 

Veracity

Developer
Staff member
Other items that we do not remove from inventory if we notice a failure message, but do not return "false" for:

A-Boo clue
sparkler, snake, M282
enchanted bean
library card
anti-anti-antidote
thunder thigh, aqua brain, lightning milk
astral mushroom
absinthe
mojo filter
spice melange

... and on and on.
 

Veracity

Developer
Staff member
By the way - I do not intend to look harder at "using items that can fail but which do not tell use_item() to return false" at the moment until I hear more from people that actually code use_item().

1) For items that fail, do you want a (red) error message to be printed - requiring you to trap the return value or your script is aborted?

(That is how we already handle items that (someone) thought SHOULD stop script execution.)

2) Or do you want an error message to be printed to the gCLI and session log, and return false to use_item(), but not stop scripts?

(We have no examples of this, yet.)

3) Or do you want no error message, but use_item() to return false?

(This is the first item I made behave like that.)

4) Or do you want no error message and you don't care about the return value?

(This is how all those other items - and more - that I listed behave.)

We used to have options 1 and 4. I made this item behave like 3 in revision 17394.

Is that what you want for this item - or do you want 1 or 2?
Are we prepared to look at ALL items that can fail "use" and are ignored and assign them to 1, 2, 3?

I'm marking this Waiting For Information until some scripters - like, perhaps, the OP - decide to chime in.
 

ckb

Minion
Staff member
I originally wrote this bug report because I ended up in an infinite loop trying to use dog chow to level a familiar to 20. This made me realize that this is not possible in KoL, AND that the use() boolean returns true even if the item does not get used.

So - I think (4) is the worst option, because it leaves the scripter no way to get out of these loops without doing something special and specific (like a url page check, or a loop counter, or whatever).

(1) is the best way to avoid these loops.
(2) or (3) are probably nearly the same for me. If I need an error message, I can add one to my own script for a use() that returns false.

So in conclusion, I don't care much whether we choose (1) or (2) or (3), as long as we get item use() to return a failure in some way that is detectable in a script, and we choose something consistent so all / most item use() behave the same.

Curious how other scripts feel about these options too.
 
Last edited:

Veracity

Developer
Staff member
We have a large number of things that are coded to use 1). For example:

Code:
		if ( responseText.contains( "You don't have the item you're trying to use." ) )
		{
			UseItemRequest.lastUpdate = "You don't have that item.";
			KoLmafia.updateDisplay( MafiaState.ERROR, UseItemRequest.lastUpdate );
			return;
		}
This would be a user/script error.

Code:
			if ( responseText.contains( "You've already got a familiar of that type." ) )
			{
				UseItemRequest.lastUpdate = "You already have that familiar.";
				KoLmafia.updateDisplay( MafiaState.ERROR, UseItemRequest.lastUpdate );
				return;
			}
This seems like it is useless, but would harmless if we didn't stop your script; if your goal was to end up with the familiar in your terrarium, that has been achieved.

Code:
		case ItemPool.HEY_DEZE_MAP:

			// "Your song has pleased me greatly. I will reward you
			// with some of my crazy imps, to do your bidding."

			if ( !responseText.contains( "pleased me greatly" ) )
			{
				UseItemRequest.lastUpdate = "Your music was inadequate.";
				KoLmafia.updateDisplay( MafiaState.ERROR, UseItemRequest.lastUpdate );
				return;
			}

			break;
Similarly, this error is worth stopping your script for.

Code:
		case ItemPool.CHATEAU_ROOM_KEY:

			Preferences.setBoolean( "chateauAvailable", true );

			// You hike up the mountain to Chateau Mantegna and try
			// the key in various doors until you find the one it
			// unlocks. It's quite a nice room!

			if ( !responseText.contains( "you find the one it unlocks" ) )
			{
				UseItemRequest.lastUpdate = "You've already have a room at the Chateau Mantegna.";
				KoLmafia.updateDisplay( MafiaState.ERROR, UseItemRequest.lastUpdate );
				return;
			}

			break;
Again - does this need to stop your script? But it does.

Code:
		case ItemPool.THUNDER_THIGH:
		case ItemPool.AQUA_BRAIN:
		case ItemPool.LIGHTNING_MILK:
		{
			// You can't learn anything else from this, so you just throw it away.
			if ( !responseText.contains( "you just throw it away" ) )
			{
				return;
			}
			break;
		}
This doesn't stop your script. It may also do the wrong thing, since it says "you just throw it away", but we don't remove it from inventory.

Code:
		case ItemPool.ABSINTHE:

			// "You drink the bottle of absinthe. It tastes like
			// licorice, pain, and green. Your head begins to ache
			// and you see a green glow in the general direction of
			// the distant woods."

			// "No way are you gonna drink another one of those
			// until the last one wears off."

			if ( !responseText.contains( "licorice" ) )
			{
				return;
			}

			break;
Here we simply return without comment if you are already under the influence.

I think 1) and 2) are the best choices:

1) for things that really should stop your script if not trapped
2) for things after which the script can continue with no harm, whether or not it is trapped

We currently have a lot of 1), even when the script might not need to be stopped, and 4), which will not stop the script but not let the script know it failed or let the user know that something unexpected/unnecessary happened.

Evaluating all the usable items that can fail and deciding whether the failure should be 1) or 2) or 3) and making it so seems like a project.

Let's start by considering the Dog Chow. If I understand, it gives your familiar experience?

Your script needs to detect the failure so it can be coded to not loop forever. But we have two kinds of script - CLI and ASH - and if we define a failed usage as "stop your script", a CLI script will, in fact, stop immediately. So will an ASH script that ignores the return value. But one which captures/tests the return value will continue.

If I have "use 1 Ghost Dog Chow" in my CLI script, do I really want to to stop the script if it fails (option 1)? Or do I want to see "your familiar isn't hungry enough" and continue (option 2)? Or do I want to not see a message and continue (option 3 or 4)?

I think 1 and 2 are the options:

1) See a message and stop the script if the your character state is unexpected after the failure
2) See a message and continue if things are actually fine: reading a skill book when you already have the skill, for example.

As I said, evaluating all use failures is a Project.

But for Dog Chow, do you want 1 or 2? As I said, keep the CLI script in mind. Does it need to stop if it fails to level a familiar?
 

xKiv

Active member
If I have "use 1 Ghost Dog Chow" in my CLI script, do I really want to to stop the script if it fails (option 1)? Or do I want to see "your familiar isn't hungry enough" and continue (option 2)? Or do I want to not see a message and continue (option 3 or 4)?

For CLI scripts, I think the most freedom for a scripter is #1, because I can always "try; use 1 ghost dog chow", but I have no idea how a CLI script would detect and hadle a failure.
(and I would always want to see a descriptive message; I just like having feedback that confirms what the machine thinks it was doing - it's not necessarily always what I think I told it to do)
 

Theraze

Active member
For DC, I'd say 1, because if you're going to try to level up in ASH, you should already be testing if it's useful first. And regarding CLI, to interpret what xKiv says, if you are sloppy and not looking at your screen but typing wildly and without care, you can already catch the abort if you want to make things terrible. :)
 

Bale

Minion
1) For items that fail, do you want a (red) error message to be printed - requiring you to trap the return value or your script is aborted?

(That is how we already handle items that (someone) thought SHOULD stop script execution.)

2) Or do you want an error message to be printed to the gCLI and session log, and return false to use_item(), but not stop scripts?

(We have no examples of this, yet.)

3) Or do you want no error message, but use_item() to return false?

(This is the first item I made behave like that.)

4) Or do you want no error message and you don't care about the return value?

(This is how all those other items - and more - that I listed behave.)

I think that error messages are always nice which means I'm only going to consider options 1 and 2. I have use() in many of my scripts. I also sometimes pay attention to the return value so it gets trapped at those times. If I don't pay attention to the return value and something goes wrong, aborting my script is a mercy to save me from unexpected errors.

Option 1. Definitely!
 

ckb

Minion
Staff member
I forgot about CLI scripts, but I can see how (1) would be most beneficial to both abort when something goes wrong and tell scripters (and new Mafia users) how use() works, and allow for trapping values when you want to get around that.

Another vote for option (1).
 
Top