Results 1 to 8 of 8

Thread: random_attributes not being passed to consult scripts

  1. #1

    Default random_attributes not being passed to consult scripts

    string main( int initround, monster foe, string url ) {

    // always returns false
    print("untouchable: "+foe.random_attributes['untouchable'],"purple");

    // returns true when true
    print("untouchable: "+last_monster( ).random_attributes['untouchable'],"purple");

    }

    To work around it, I've simply added a line of code to override the passed foe:
    foe = last_monster();

  2. #2
    Minion Bale's Avatar
    Join Date
    Jun 2008
    Posts
    13,287

    Default

    That's intended behavior.

    A better discussion is if the intention is the best implementation.

  3. #3

    Default

    Since last_monster() is an instance of the current monster you are fighting, rather than a generic version of that monster (and that's a recent change), this should likely be updated too.

  4. #4
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,197

    Default

    string main( int initround, monster foe, string url ) {
    Originally Posted by DoctorRotelle View Post
    This is a bug in your consult script. FightRequest.java does this to call a consult script:

    Code:
    				String[] parameters = new String[3];
    				parameters[0] = String.valueOf( FightRequest.currentRound );
    				parameters[1] = MonsterStatusTracker.getLastMonsterName();
    				parameters[2] = FightRequest.lastResponseText;
    The first parameter is a string which is the current round number. When you declare it to be an integer, as you did, KoLmafia converts it to an integer and gives it to you.

    The second parameter is a string which is the name of the monster you are fighting. When you convert it to a monster, as you did, KoLmafia finds the base monster with that name.

    The third parameter is the text of the fight page. It is NOT a "url".

    Consult scripts have NEVER had a "monster" object as their second parameter. People insist on doing it, however, and back before we would temporarily register unknown monsters, ASH didn't know how to convert the unknown "lastMonsterName" into a monster object and would give you $monster[none]. That was still a bug in the consult script, but we now register unknown monsters into temporary monster objects so that buggy consult scripts could continue to work.

    Your "work around" is exactly what you should have been doing all along.
    Last edited by Veracity; 05-25-2015 at 01:44 AM.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  5. #5

    Default

    http://wiki.kolmafia.us/index.php?ti...onsult_Scripts

    Someone with permissions should correct the example code samples to reflect "string foe_name" instead of "monster mob" & "monster foe" in the examples. Perhaps a few notes about the fact they're strings which are being cast as something and not reliable for the use such as I had intended.

  6. #6
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,197

    Default

    Or, we could do a fair bit of whackage to how ASH functions are invoked internally.

    The public way to execute an ASH function is in Interpreter.java:

    Code:
    	public Value execute( final String functionName, final String[] parameters )
    or

    Code:
    	public Value execute( final String functionName, final String[] parameters, final boolean executeTopLevel )
    Note that "parameters" is an array of String objects.

    These end up calling:

    Code:
    	private Value executeScope( final Scope topScope, final String functionName, final String[] parameters,
    				    final boolean executeTopLevel )
    and

    Code:
    	private boolean requestUserParams( final Function targetFunction, final String[] parameters, Object[] values )
    That last method gets the parameter list from the targetFunction and iterates over it, taking input Strings from the parameter list (until it runs out) or prompting the user (thereafter). For each function parameter/string value pair, it coerces the string into the desired data type by calling:

    Code:
    					value = DataTypes.parseValue( type, input, false );
    That is how the monster name ends up as a $monster value, if the consult script says the second prameter is a "monster" rather than a "string".

    The above is exactly how we want it to behave if you are calling an ASH function from the CLI: you specify the function name, give it a comma delimited list of strings to use as parameters, and if you didn't give enough, we prompt.

    So, when a consult script is invoked internally, as you saw from the code I first cited, we pass it an array of strings - just as if the user had typed those.

    Seems to me we could change the above four methods to all take Object[] parameters. And then, we would call DataTypes.parseValue( Type, String, boolean ) ONLY if the parameter was a String. Otherwise, we'd call a new method: DataTypes.coerceValue( Type, Object, boolean ), which would try to convert the Object into a Value of the specified type, using other methods already available in the DataTypes module. For example:

    Code:
    	public static final Value makeItemValue( final AdventureResult ar )
    or

    Code:
    	public static final Value makeMonsterValue( final MonsterData monster )
    That last one would be what would be used if we invoked a consult script like this:

    Code:
    				Object[] parameters = new String[3];
    				parameters[0] = IntegerPool.get( FightRequest.currentRound );
    				parameters[1] = MonsterStatusTracker.getLastMonster();
    				parameters[2] = FightRequest.lastResponseText;
    				consultInterpreter.execute( "main", parameters );
    The round number would be a real integer and would thus not be converted to a string and parsed back into an integer.
    The monster name would now be the real monster object - the same one you get from last_monster().

    That actually doesn't seem that difficult. Seems odd to change the whole mechanism in which we invoke ASH functions in order to change how we invoke consult scripts, but, what the heck.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  7. #7
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,197

    Default

    I changed this to a Feature Request, to reflect that...
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  8. #8
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    11,197

    Default

    CCS:

    Code:
    [ default ]
    consult consult.ash
    attack with weapon
    consult.ash:

    Code:
    void main(int initround, monster foe, string page)
    {
        print( "initround = " + initround );
        print( "monster = " + foe );
        foreach attribute in foe.random_attributes
    	print( "-> " + attribute );
    }
    Entering a battle and pressing the "script" button:

    Code:
    [514] Oil Peak
    Encounter: electrified, clingy oil tycoon
    Round 0: Veracity wins initiative!
    You lose 1 hit point
    initround = 1
    monster = oil tycoon
    -> electrified
    -> clingy
    Round 1: Veracity attacks!
    ...
    I'd say that works. Revision 15870

    For reference, here is the Type.coerceValue method:

    Code:
    	public Value coerceValue( final Object object, final boolean returnDefault )
    	{
    		if ( object instanceof String )
    		{
    			return this.parseValue( (String) object, returnDefault );
    		}
    		if ( object instanceof Integer )
    		{
    			int integer = ( (Integer) object ).intValue();
    			switch ( this.type )
    			{
    			case DataTypes.TYPE_BOOLEAN:
    				return DataTypes.makeBooleanValue( integer );
    			case DataTypes.TYPE_INT:
    				return DataTypes.makeIntValue( integer );
    			case DataTypes.TYPE_FLOAT:
    				return DataTypes.makeFloatValue( integer );
    			case DataTypes.TYPE_STRING:
    				return new Value( DataTypes.STRING_TYPE, String.valueOf( integer ) );
    			case DataTypes.TYPE_ITEM:
    				return DataTypes.makeItemValue( integer, returnDefault );
    			case DataTypes.TYPE_SKILL:
    				return DataTypes.makeSkillValue( integer, returnDefault );
    			case DataTypes.TYPE_EFFECT:
    				return DataTypes.makeEffectValue( integer, returnDefault );
    			case DataTypes.TYPE_FAMILIAR:
    				return DataTypes.makeFamiliarValue( integer, returnDefault );
    			case DataTypes.TYPE_MONSTER:
    				return DataTypes.makeMonsterValue( integer, returnDefault );
    			case DataTypes.TYPE_THRALL:
    				return DataTypes.makeThrallValue( integer, returnDefault );
    			case DataTypes.TYPE_SERVANT:
    				return DataTypes.makeServantValue( integer, returnDefault );
    			}
    			return null;
    		}
    		if ( object instanceof MonsterData )
    		{
    			MonsterData monster = (MonsterData) object;
    			switch ( this.type )
    			{
    			case DataTypes.TYPE_INT:
    				return DataTypes.makeIntValue( monster.getId() );
    			case DataTypes.TYPE_STRING:
    				return new Value( DataTypes.STRING_TYPE, monster.getName() );
    			case DataTypes.TYPE_MONSTER:
    				return DataTypes.makeMonsterValue( monster );
    			}
    			return null;
    		}
    		return null;
    	}
    "this" the type of the user's variable - the parameter in the argument list.
    "object" is the parameter passed in.

    So, if you provide a String, we call parseValue, just as before, to parse the string into the correct type the script asks for.
    If you provide an integer, for all datatypes that have a natural integer associated with them, we generate the correct object.
    And if you provide a MonsterData, we'll give you the monster ID, the name, or the specific monster, as desired.

    So, consult scripts that want "foe" to be a "monster" get the same object as last_monster() returns.
    And scripts that want "foe" to be a string get the monster name, just as before.

    This could be fleshed out to have additional data types that have "make" functions in the DataTypes package, but, for now, Strings, Integers, and MonsterData objects are all we're using.
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

Similar Threads

  1. BatBrain -- a central nervous system for consult scripts
    By zarqon in forum Custom Combat Settings
    Replies: 2112
    Last Post: 12-20-2017, 10:00 AM
  2. Replies: 25
    Last Post: 04-05-2015, 08:20 PM
  3. Feature - Implemented Duplicate scripts cause "not found" error for consult scripts
    By nightslide in forum Bug Reports
    Replies: 6
    Last Post: 06-10-2013, 08:07 PM
  4. Multiple consult scripts?
    By fxer in forum Scripting Discussion
    Replies: 2
    Last Post: 03-04-2013, 08:43 PM
  5. Passing variables to consult scripts from the ccs
    By Captain Kirk in forum Custom Combat Settings
    Replies: 0
    Last Post: 08-17-2008, 06:53 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •