Results 1 to 4 of 4

Thread: multiple main functions in a script

  1. #1
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    13,161

    Default multiple main functions in a script

    I was looking into an issue with VMF. That script will collect semirares for you (if configured to do so). It will also bust ghosts and fight vote monsters. All of those are on their own schedules, so when consuming adventures, it will break out to perform the designated actions and then continue. Which is to say, it essentially has a counter script built in.

    However, the script will also call other scripts to consume turns (if configured). In particular, Gingerbread City and Spacegate. Since neither of those will collect semirares, if your counter expires while running them, they proceed and you lose it.

    I'm considering making a custom counterScript, integrated with VMF, which will be active while running external scripts. Looking at how KoLmafia invokes a counterScript:

    Code:
    			KoLmafiaASH.logScriptExecution( "Starting counter script: ", scriptFile.getName(), interpreter );
    			Value v = interpreter.execute( "main", new String[]
    			{
    				expired.getLabel(),
    				String.valueOf( expired.getTurnsRemaining() )
    			} );
    			KoLmafiaASH.logScriptExecution( "Finished counter script: ", scriptFile.getName(), interpreter );
    The property "counterScript" contains the name of an ASH file.
    When a counter expires, that script is invoked via

    boolean main( string name, int remaining );

    In the context of my scripts, which only go places that take a single adventure at a time, remaining will always be 0, and the semirare (whatever) will occur on the very next adventure.

    VMF contains a function:

    void main()

    This is the method which is invoked if you simply execute the script. I wonder if I could overload it and have

    boolean main( string name, int remaining )

    and simply set VMF as its own counterScript while it is executing, and thereby having access to all its own internal state? Intriguing!
    Ph'nglui mglw'nafh Cthulhu
    R'lyeh wgah-nagl fhtagn.

  2. #2
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    13,161

    Default

    Actually, since we synchronize on the interpreter used to execute a particular script, even if I can overload the main function like that, the counterscript would be blocked when the main script was running. Thus, no updating shared data. I could still do semirares with a custom counterScript, but I'd have to update my internal variables (and drink another Lucky Lindy) after calling the external script.

    Sigh.

  3. #3
    Developer Veracity's Avatar
    Join Date
    Mar 2006
    Location
    The Unseelie Court
    Posts
    13,161

    Default

    Huh. This turns out to be easy, with a small code change in KoLmafia.

    Here's a test script:

    Code:
    // Counter Script Test
    
    location CASTLE_TOP_FLOOR = $location[ The Castle in the Clouds in the Sky (Top Floor) ];
    location LIMERICK_DUNGEON = $location[ The Limerick Dungeon ];
    
    location last_location = get_property( "semirareLocation" ).to_location();
    location next_location = ( last_location == CASTLE_TOP_FLOOR ) ? LIMERICK_DUNGEON : CASTLE_TOP_FLOOR;
    
    void counterExpired( string label, string turns_remaining )
    {
        print( "Counter '" + label + "' expires in " + turns_remaining + " turns" );
        if ( label == "Fortune Cookie" ) {
    	if ( turns_remaining.to_int() == 0 ) {
    	    print( "Last semirare = " + last_location );
    	    print( "Collecting semirare at " + next_location );
    	    adv1( next_location, 1, "" );
    	} else {
    	    print( "Nothing to do right now." );
    	}
        }
        print( "Done with counter script" );
    }
    
    void main()
    {
        print( "main@" + __FILE__ + " called" );
    
        string oldCounterScript = get_property( "counterScript" );
        string newCounterScript = "counterExpired@" + __FILE__;
    
        try {
    	set_property( "counterScript", newCounterScript );
    	cli_execute( "checkpoint" );
    
    	if ( my_inebriety() > inebriety_limit() ) {
    	    equip( $slot[ weapon ], $item[ none ] );
    	    equip( $slot[ off-hand ], $item[ Drunkula's wineglass ] );
    	}
    
    	// Adventure once
    	adv1( next_location, 1, "" );
        } finally {
    	cli_execute( "outfit checkpoint" );
    	set_property( "counterScript", oldCounterScript );
        }
    }
    I'm currently over-drunk, hence the Drunkula's wineglass.
    Note also that having last_location and next_location set in globals like that would not work if I expected multiple timers. But this is just a test.
    Test with an dummy counter:

    Code:
    > counters add 0 Test clock.gif
    
    Last semirare found 161 turns ago (on turn 5769) in The Castle in the Clouds in the Sky (Top Floor)
    
    Unexpired counters:
    Fortune Cookie (27)
    Test (0)
    
    > cstest
    
    main@cstest.ash called
    counterScript => counterExpired@cstest.ash
    Internal checkpoint created.
    Taking off The Nuge's favorite crossbow...
    Equipment changed.
    Holding Drunkula's wineglass...
    Equipment changed.
    
    Visit to Dungeon: The Limerick Dungeon in progress...
    Counter 'Test' expires in 0 turns
    Done with counter script
    
    [5931] The Limerick Dungeon
    Encounter: The Slime Puddle
    You gain 11 Roguishness
    
    Wielding The Nuge's favorite crossbow...
    Equipment changed.
    Holding green LavaCo Lampô...
    Equipment changed.
    counterScript =>
    Since that worked, I forced a semi-rare:

    Code:
    > pillkeeper semi
    
    Taking pills for Sunday - Surprise Me
    
    > cstest
    
    main@cstest.ash called
    counterScript => counterExpired@cstest.ash
    Internal checkpoint created.
    Taking off The Nuge's favorite crossbow...
    Equipment changed.
    Holding Drunkula's wineglass...
    Equipment changed.
    
    Visit to Beanstalk: The Castle in the Clouds in the Sky (Top Floor) in progress...
    Counter 'Fortune Cookie' expires in 0 turns
    Last semirare = none
    Collecting semirare at The Castle in the Clouds in the Sky (Top Floor)
    
    Visit to Beanstalk: The Castle in the Clouds in the Sky (Top Floor) in progress...
    
    [5932] The Castle in the Clouds in the Sky (Top Floor)
    Encounter: All The Rave
    You acquire an item: Mick's IcyVapoHotness Inhaler
    Done with counter script
    
    [5933] The Castle in the Clouds in the Sky (Top Floor)
    Encounter: Punk Rock Giant
    ...
    Round 4: Veracity wins the fight!
    
    Wielding The Nuge's favorite crossbow...
    Equipment changed.
    Holding green LavaCo Lampô...
    Equipment changed.
    counterScript =>

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

    Default

    Revision 20041 updates counterScript, as described.

Posting Permissions

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