gumpIDs are not set properly first time a custom gump opens

Found a bug in UOX3? Or experienced a server crash? Perhaps you've noticed a broken feature? Post the details here!
Post Reply
User avatar
Xuri
Site Admin
Posts: 3704
Joined: Mon Jun 02, 2003 9:11 am
Location: Norway
Has thanked: 48 times
Been thanked: 8 times
Contact:

gumpIDs are not set properly first time a custom gump opens

Post by Xuri »

The first time a JS gump is opened after a server start/script reload, the gumpID for said JS gump - retrievable through socket.GetDWord( 7 ) - is incorrect. It is supposed to return a value based on the scriptID of the script that creates the gump, plus 0xFFFF - i.e. scriptID+0xFFFF. However, it returns the number 55463762, which when converted to hex gives us 0x34E4F52. Subtract 0xFFFF and convert back to decimal, and you're left with a value that is most definitely not a scriptID (55398227).

Repeat the exact same process a second time around without restarting the server/reloading the script, and you'll get the proper gumpID.

Here is an example-script, which when assigned to an object will open a gump, store the gumpID of said gump as a temporary value on the player's socket, start a short timer, and then force-close the gump based on the gumpID stored on the socket. It only works the second time you run it:
function onUseChecked( pUser, iUsed )
{
    var socket = pUser.socket;
   
    var skillGump = new Gump;
    skillGump.AddPage (1);
    skillGump.AddBackground(0, 0, 300, 300, 0xA3C);
    skillGump.AddButton( 270, 5, 0xa50, 1, 0, 1); //Close gump
    skillGump.AddButton( 200, 40, 2469, 1, 0, 32 ); //Next page
    skillGump.Send( pUser.socket );
    skillGump.Free();

    //Store gumpID in tempInt socket property
    socket.tempInt = socket.GetDWord( 7 );
    pUser.TextMessage( "Created gump - ID: "+socket.tempInt);

    //Start timer to destroy gump
    pUser.StartTimer( 1000, 1, true );
    return false;
}

function onTimer( timerObj, timerID )
{
    if( timerID == 1 )
    {
        var socket = timerObj.socket;

        //Fetch gumpID from tempInt socket property
        var gumpID = socket.tempInt;
        timerObj.TextMessage( "Destroying gump - ID: "+gumpID );

        //Create packet to force-close gump
        var pStream = new Packet;
        pStream.ReserveSize( 13 );
        pStream.WriteByte( 0, 0xBF ); //Command: Packet 0xBF - General Information Packet
        pStream.WriteShort( 1, 13 ); // Packet length
        pStream.WriteShort( 3, 0x04 ); //Subcommand 0x04 - Close Generic Gump
        pStream.WriteLong( 5, gumpID ); //dialogID - which gump to destroy
        pStream.WriteLong( 9, 0 );  //buttonID // response buttonID for packet 0xB1
        socket.Send( pStream );
        pStream.Free();
    }
}
Thankfully, there is another way of doing this, which is calculating the gumpID manually based on the scriptID that creates the gump, like iUsed.scripttrigger+0xffff, and storing that in a global variable (assuming you want it available in functions where the object that triggered the script might not be). However, it's still slightly worrying that the gumpID is incorrect the first time a gump is created, as I'm not sure what other parts of the code make use of this.

Knowing the gumpIDs can be used to force-close gumps created in specific JavaScripts, on a per-player basis. Potentially very useful for "refreshing" contents of gumps on the fly, and is also needed for certain standard features where gumps should not stay open indefinitely (one example being secure logout from bedrolls near a campfire, which is supposed to close automagically after 10 seconds).
-= Ho Eyo He Hum =-
Post Reply