[APPROVED] Runebooks - by Rais (Updated February 5th, 2006)

Want to contribute to the Ultima Offline eXperiment? Submit your JS/DFN/Code fixes and/or other UOX3 improvements 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:

Runebooks - by Rais (Updated February 5th, 2006)

Post by Xuri »

Update: A rewritten version of this has been included in the develop branch of UOX3 on GitHub, and can be added in-game by GMs using 'add item runebook or crafted by Inscribers using 8 empty scrolls, 1 blank recall rune, 1 Recall scroll and 1 Gate Travel scroll.

This is a script originally written by Rais - though I've fixed it up a bit by adding some error-checking to the targeting parts, and added runebook-renaming.

Copy & paste the script into a text file which you save as (for instance) runebooks.js in your UOX3\JS\CUSTOM folder.

Then add the runebooks.js script to JSE_FILEASSOCIATIONS.SCP with a unique Script ID, and assign it to the runebooks either through the DFNs using the SCRIPT=<scriptID> tag, or using the 'SETSCPTRIG <scriptID> command ingame.
// Runebook.js (v0.98)
// Gump driven runebook - 95% osi style
// Rais 22nd May 02
// Contact: uox_rais@hotmail.com
// Updated by Xuri 5th February 06 (xuri@sensewave.com)

// Setup:
// Copy this file (Runebook.js) to js/custom
// Edit jse_fileassociations.scp in the js folder and add:
// 20001=js/custom/runebook.js (20001 is the script ID, can be changed but must be unique)

// Example usage:
// In game, do the following
// 'add 0xe3b (add's a book - can be ANY item)
// 'setscptrig 20001 (Set the script to run on the book)
// (if you changed the ID in scpTrig.scp, then use the ID you assigned)

// Tag's Used:
// cchar.ItemUsed holds the serial of the item used (the book)
// item.RuneBook holds the locations and other info
// item.InUsage holds the data on whether or not the book is in use by anyone

// Updates:
// 25th May 02: Recall and Gate spells added
// 26th May 02: Charges and 'New book' check
// Pack checks for Runes and scrolls
// 9th April 02: Fixed erroneous targeting, added Rename button & function, fixed up small stuff to make script work again =)
// 5th February 06: Updated redundant SpawnItem method to CreateDFNItem

// Issues:
// tItem.container.serial - is that legal? .serial shouldnt work
// checkout .serial[0-4]
// Gump buttons are 'Changing' when pressed - 3D client only

function onUseChecked( srcChar, iUsed )
{
   // get users socket
   var srcSock = srcChar.socket;
   
   // is it in users pack
   // If item is on ground, .container returns null. Freeks out .container.serial
   if( iUsed.container == null )
      iCont = 0;
   else
      var iCont = iUsed.container.serial; // Serial of the pack its in
   var cPack = srcChar.pack.serial; // Serial of users pack
   if( iCont != cPack)
      iCont = false;
   
   //Range Check
   range=iUsed.InRange( srcChar, 3);
   //If both range and container failed the check, then get outa here
   if( iCont == false && range== false)
   {
      srcSock.SysMessage("You are too far away to use this.");
      return false;
   }
   
   //Are we using the item allready?
   //Get the serial of the item we have just used
   var Serial = new Array;
   Serial[0]=iUsed.GetSerial(1);
   Serial[1]=iUsed.GetSerial(2);
   Serial[2]=iUsed.GetSerial(3);
   Serial[3]=iUsed.GetSerial(4);
   
   //Get the stored serial from tag
   var oldSerial = new Array;
   var iCheck = new String(srcChar.GetTag("ItemUsed"));
   var oldSerial = iCheck.split(',');
   
   //Compare the 2, if the same, then we are allready using this item
   if( iUsed.GetTag("InUsage") == 1 )
//   if( Serial[0] == oldSerial[0] && Serial[1] == oldSerial[1] && Serial[2] == oldSerial[2] && Serial[3] == oldSerial[3] )
   {
      srcChar.SysMessage( "Someone is already already using this runebook!" );
      return false;
   }
   else
      srcChar.SetTag("ItemUsed", Serial[0] + "," + Serial[1] + "," + Serial[2] + "," + Serial[3]);
      iUsed.SetTag( "InUsage", 1 );
   
   // Make a noise as the gump opens
   srcChar.SoundEffect( 0x58, false );
   var myString=new String(iUsed.GetTag("RuneBook"));
   
   var retString = displaygump (srcSock, srcChar, myString);
   if (retString!=myString) //The names have changed... IE new book
      iUsed.SetTag("RuneBook", retString); //Save the tag here, will then have all the 'Blank's filled in
   iUsed.type=50;
   return false;
}

function onGumpPress(srcSock,myButton, gumpData)
{
   //Calc char
   var srcChar = srcSock.currentChar;
   
   //get the items's serial (tag from item used)
   var oldSerial = new Array;
   var iCheck = new String(srcChar.GetTag("ItemUsed"));
   var oldSerial = iCheck.split(',');
   //Convert serial into actual numbers not strings
   oldSerial[0] = parseInt(oldSerial[0]);
   oldSerial[1] = parseInt(oldSerial[1]);
   oldSerial[2] = parseInt(oldSerial[2]);
   oldSerial[3] = parseInt(oldSerial[3]);
   //Find out what the item is from the serial
   var iUsed=CalcItemFromSer(oldSerial[0], oldSerial[1], oldSerial[2], oldSerial[3]);
   // Do range checks again - just in case they have called up the gump and done a runner
   // If item is on ground, .container returns null. Freeks out .container.serial
   if( iUsed.container == null )
      iCont = 0;
   else
      var iCont = iUsed.container.serial; // Serial of the pack its in
   var cPack = srcChar.pack.serial; // Serial of users pack
   if( iCont != cPack)
      iCont = false;
   //Range Check
   range=iUsed.InRange( srcChar, 3);
   //If both range and container failed the check, then get outa here
   if( iCont == false && range== false)
   {
      srcSock.SysMessage("You are too far away to use this.");
      return;
   }

   //Get the locations again
   myString=new String(iUsed.GetTag("RuneBook"));
   var myBook= new Array;
   var myBook = myString.split(',');
   Charges=parseInt(myBook[65]);
   //Button ID 0 (Cancel gump)
   if(myButton==0)
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      iUsed.SetTag("InUsage", 0);
      return;
   }

   //press any of the blue buttons and use a charge
   if (myButton >=1 && myButton <=16)
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      iUsed.SetTag( "InUsage", 0 );

      //Check if we have any charges
      if(Charges == 0)
      {
         srcSock.SysMessage("This book is out of charges.");
         return;
      }

      //Make sure we are not clicking on a 'Blank'
      if(myBook[((myButton-1)*4)+1] != "Blank" )
      {
         //Make char move a little
         srcChar.DoAction(16);
         srcChar.Teleport( parseInt(myBook[((myButton-1)*4)+2]), parseInt(myBook[((myButton-1)*4)+3]), parseInt(myBook[((myButton-1)*4)+4]) );
         //Removce a charge
         Charges -= 1;
         //Save Tag
         myString=myBook[0]+","; //Book Name
         for (i=0;i<=15;i++)
         {
            myString=myString+myBook[(i*4)+1] + "," + myBook[(i*4)+2] + "," + myBook[(i*4)+3] + "," + myBook[(i*4)+4] + ",";
         }
         myString=myString+Charges; //don't forget the charges
         iUsed.SetTag("RuneBook", myString);
      }
      return;
   }

   //Charge book Button
   if(myButton==17)
   {
      srcSock.CustomTarget( 1, "Select scrolls to add." );
      iUsed.SetTag("InUsage", 0);
   }
   //Add Rune Button
   if(myButton==18)
   {
      srcSock.CustomTarget( 0, "Select rune to add." );
      iUsed.SetTag("InUsage", 0);
   }
   
   //Rename Runebook
   if( myButton == 19 )
   {
      srcChar.SetTag( "toolser1", iUsed.GetSerial(1) );
      srcChar.SetTag( "toolser2", iUsed.GetSerial(2) );
      srcChar.SetTag( "toolser3", iUsed.GetSerial(3) );
      srcChar.SetTag( "toolser4", iUsed.GetSerial(4) );
      srcChar.SysMessage("What name do you want to give this Runebook? (50 chars max)" );
      srcChar.SpeechInput(1, iUsed );
   }

   //myButton>100 & <115 = Remove rune button
   if(myButton>=100 && myButton<=116)
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      iUsed.SetTag("InUsage", 0);

      // Do a Pack check here - when lockdowns get implemented ppl would be able to steel runes
      // If item is on ground, .container returns null. Freeks out .container.serial
      if( iUsed.container == null )
         iCont = 0;
      else
         var iCont = iUsed.container.serial; // Serial of the pack its in
      var cPack = srcChar.pack.serial; // Serial of users pack
      if( iCont != cPack)
      {
         srcSock.SysMessage("That has to be in your pack.");
         return;
      }

      place=myButton-100;
      //Anything in that location?
      if(myBook[(place*4)+1]=="Blank")
         return;

      //Make new rune and set the location and name
      //var newRune = SpawnItem( srcSock, srcChar, "0x1f14", false );
      var newRune = CreateDFNItem( srcSock, srcChar, "0x1f14", 1, "ITEM", true )
      newRune.morex=parseInt(myBook[(place*4)+2]);
      newRune.morey=parseInt(myBook[(place*4)+3]);
      newRune.morez=parseInt(myBook[(place*4)+4]);
      newRune.name="A recall rune for "+myBook[(place*4)+1];
      //Clear the tag entry for the location
      myBook[(place*4)+1]="Blank";
      myBook[(place*4)+2]=" ";
      myBook[(place*4)+3]=" ";
      myBook[(place*4)+4]=" ";

      //do an order type thing here - don't want blanks in the middle of the book
      var newBook = new Array;
      var count=0;
      for (i=0;i<=15;i++)
      {
         newBook[(i*4)+1] = "Blank";
         newBook[(i*4)+2] = " ";
         newBook[(i*4)+3] = " ";
         newBook[(i*4)+4] = " ";
         if(myBook[(i*4)+1]!="Blank")
         {
            newBook[(count*4)+1] = myBook[(i*4)+1];
            newBook[(count*4)+2] = myBook[(i*4)+2];
            newBook[(count*4)+3] = myBook[(i*4)+3];
            newBook[(count*4)+4] = myBook[(i*4)+4];
            count += 1;
         }
      }

      //Re-save the tag
      myString=myBook[0]+","; //Book Name
      for (i=0;i<=15;i++)
      {
         myString=myString+newBook[(i*4)+1] + "," + newBook[(i*4)+2] + "," + newBook[(i*4)+3] + "," + newBook[(i*4)+4] + ",";
      }
      myString=myString+Charges; //don't forget the charges
      iUsed.SetTag("RuneBook", myString);
         return;
   }

   //Recall button
   if(myButton>=120 && myButton<=135)
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      iUsed.SetTag( "InUsage", 0 );
       
      place=myButton-120;
      //Anything in that location?
      if(myBook[(place*4)+1] == "Blank")
         return;

      //do we have the spell
      if(srcChar.HasSpell(32) == false)
      {
         srcSock.SysMessage("You don't have that spell.");
         return;
      }

      //Set the runebook's morexyz to the runes location, cast recall so player can target the book
      iUsed.morex=parseInt(myBook[(place*4)+2]);
      iUsed.morey=parseInt(myBook[(place*4)+3]);
      iUsed.morez=parseInt(myBook[(place*4)+4]);
      srcChar.CastSpell(32);
   }

   //Gate button
   if(myButton>=140 && myButton<=155)
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      iUsed.SetTag( "InUsage", 0 );
       
      place=myButton-140;
      //Anything in that location?
      if(myBook[(place*4)+1]=="Blank")
         return;

      //do we have the spell
      if(srcChar.HasSpell(52) == false)
      {
         srcSock.SysMessage("You don't have that spell.");
         return;
      }

      //Set the runebook's morexyz to the runes location, cast gate so player can target the book
      iUsed.morex=parseInt(myBook[(place*4)+2]);
      iUsed.morey=parseInt(myBook[(place*4)+3]);
      iUsed.morez=parseInt(myBook[(place*4)+4]);
      srcChar.CastSpell(52);
   }
}

//Add Rune
function onCallback0( srcSock, myTarget )
{
   //Get what char is doing this
   var srcChar = srcSock.currentChar;

   //What item have we targeted?
   var StrangeByte = srcSock.GetWord( 1 ); //If Strangebyte is null or different than 0, it's not a dynamic object
   if( StrangeByte != 0 || (StrangeByte == 0 && myTarget.isChar) )
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      srcChar.SysMessage( "You need to target a recall scroll." );
      return;
   }

   //get the original items's serial (tag from item used)
   var oldSerial = new Array;
   var iCheck = new String(srcChar.GetTag("ItemUsed"));
   var oldSerial = iCheck.split(',');
   //Convert serial into actual numbers not strings
   oldSerial[0] = parseInt(oldSerial[0]);
   oldSerial[1] = parseInt(oldSerial[1]);
   oldSerial[2] = parseInt(oldSerial[2]);
   oldSerial[3] = parseInt(oldSerial[3]);
   //Find out what the item is from the serial
   var iUsed=CalcItemFromSer(oldSerial[0], oldSerial[1], oldSerial[2], oldSerial[3]);

   //Get the locations again
   myString=new String(iUsed.GetTag("RuneBook"));
   var myBook= new Array;
   var myBook = myString.split(',');

   //Clear the tag
   srcChar.SetTag("ItemUsed", "0,0,0,0");

   //Pack check - So we don't nick runes
   // If item is on ground, .container returns null. Freeks out .container.serial
   if( myTarget.container == null )
      iCont = 0;
   else
      var iCont = myTarget.container.serial; // Serial of the pack its in
   var cPack = srcChar.pack.serial; //Serial of users pack
   if( iCont != cPack)
   {
      srcSock.SysMessage( "That has to be in your backpack." );
      return;
   }

   // is the item of the right type?
   var iID = myTarget.id;
   if( iID != 0x1F14 && iID != 0x1F15 && iID != 0x1F16 && iID != 0x1F16 )
   {
      srcSock.SysMessage( "That is not a recall rune." );
      return;
   }

   // Check we have a marked rune
   var name = myTarget.name;
   var x = myTarget.morex;
   var y = myTarget.morey;
   var z = myTarget.morez;
   if( x == 0 && y == 0 && z == 0 )
   {
      srcSock.SysMessage( "That is a blank rune." );
      return;
   }

   //Make var place HI, so if no 'Blanks' are found - we know book is full
   var place=16;
   //first of all, lets find a 'Blank' position in book
   for(i=0; i<=16 ; i++)
   {
      if (myBook[(i*4)+1]=="Blank")
      {
         place=i;
         i=17;
      }
      if (i==16) //Gone too far, no blanks
         place=16;
   }

   //If place is less than 16 then we have a valid space in the book.
   if (place<=15)
   {
      myBook[(place*4)+1]=name.substr(18,20);
      myBook[(place*4)+2]=x;
      myBook[(place*4)+3]=y;
      myBook[(place*4)+4]=z;
      //Make a new string to save
      myString=myBook[0]+","; //Book Name
      for (i=0;i<=15;i++)
      {
         myString=myString+myBook[(i*4)+1] + "," + myBook[(i*4)+2] + "," + myBook[(i*4)+3] + "," + myBook[(i*4)+4] + ",";
      }
      myString=myString+myBook[65]; //don't forget the charges
      //Save the tag
      iUsed.SetTag("RuneBook", myString);
      //delete the rune
      srcChar.SysMessage( "You've added a rune named "+myTarget.name+" to your Runebook." );
      myTarget.Delete();
   }
   else
      srcSock.SysMessage( "The book is full.");
}

function displaygump(srcSock, srcChar, myString)
{
   //Sort out the names and locations
   var myBook= new Array;
   var myBook = myString.split(',');
   Charges=parseInt(myBook[65]);
   //Check if its a new book, if so setup name and charges
   if (myBook[1]==null)
   {
      myBook[0]="Runebook";
      //Be generous - start with 5 charges on a new book
      Charges=5;
   }
   var myGump = new Gump;
   myGump.AddPage(1);
   myGump.AddGump( 0, 0, 0x898 );
   
   //Front Page
   myGump.AddButton( 25, 5, 0x9aa, 1, 0, 17 );//Charge book button
   myGump.AddText( 55, 10, 0, "Charge book (" + Charges + ")");

   myGump.AddButton( 25, 25, 0x9aa, 1, 0, 19 );//Rename Book button
   myGump.AddText( 55, 30, 0, "Rename book");
   
   myGump.AddButton( 189, 5, 0x9aa, 1, 0, 18 );//add rune button
   myGump.AddText( 219, 10, 0, "Add rune" );
   
   myGump.AddButton( 31, 178, 0x8b1, 0, 2, 0 );//No1 at bottom of page
   myGump.AddButton( 66, 178, 0x8b2, 0, 3, 0 );
   myGump.AddButton( 101, 178, 0x8b3, 0, 4, 0 );
   myGump.AddButton( 136, 178, 0x8b4, 0, 5, 0 );
   myGump.AddButton( 201, 178, 0x8b5, 0, 6, 0 );
   myGump.AddButton( 236, 178, 0x8b6, 0, 7, 0 );
   myGump.AddButton( 271, 178, 0x8b7, 0, 8, 0 );
   myGump.AddButton( 306, 178, 0x8b8, 0, 9, 0 );
   myGump.AddGump( 31, 178, 0x8b1 ); //Mask the button with a piccy, that way you don't see the button 'press'
   myGump.AddGump( 66, 178, 0x8b2 );
   myGump.AddGump( 101, 178, 0x8b3 );
   myGump.AddGump( 136, 178, 0x8b4 );
   myGump.AddGump( 201, 178, 0x8b5 );
   myGump.AddGump( 236, 178, 0x8b6 );
   myGump.AddGump( 271, 178, 0x8b7 );
   myGump.AddGump( 306, 178, 0x8b8 );

   myGump.AddButton( 293, 5, 0x89e, 0, 2, 0 );//Turn Page button
   myGump.AddGump( 293, 5, 0x89e );

   myGump.AddGump( 25, 40, 0x39 );//Draw the decoreative line under charges
   myGump.AddGump( 55, 40, 0x3a );
   myGump.AddGump( 71, 40, 0x3a );
   myGump.AddGump( 87, 40, 0x3a );
   myGump.AddGump( 103, 40, 0x3a );
   myGump.AddGump( 119, 40, 0x3a );
   myGump.AddGump( 129, 40, 0x3b );
   myGump.AddGump( 189, 40, 0x39 );//and the same on facing page
   myGump.AddGump( 219, 40, 0x3a );
   myGump.AddGump( 235, 40, 0x3a );
   myGump.AddGump( 251, 40, 0x3a );
   myGump.AddGump( 267, 40, 0x3a );
   myGump.AddGump( 283, 40, 0x3a );
   myGump.AddGump( 293, 40, 0x3b );

   for (i = 0; i <= 15; i++)
   {
      if(myBook[(i*4)+1]==null || myBook[(i*4)+1]=="Blank")
      {
         myBook[(i*4)+1]="Blank";
         myBook[(i*4)+2]=" ";
         myBook[(i*4)+3]=" ";
         myBook[(i*4)+4]=" ";
         var color =0;
      }
      else
         var color=10;
      bx=28; //Left offset of button (left hand page)
      by=56;
      tx=41; //Left offset of text (left page)
      ty=52;

      if (i>=8)
         lhs=1; //left hand side of page
      else
         lhs=0;
      myGump.AddButton( bx+(lhs*162), by+((i-(lhs*8))*15), 0x837, 1, 0, i+1 );
      myGump.AddText(tx+(lhs*162), ty+((i-(lhs*8))*15), color, myBook[(i*4)+1]);
   }
   //Draw the pages
   for( i = 0; i<=7; i++)
   {
      myGump.AddPage(i+2);
      //Default stuff each page
      myGump.AddGump( 0, 0, 0x898 );
      myGump.AddButton( 31, 178, 0x8b1, 0, 2, 0 );
      myGump.AddGump( 31, 178, 0x8b1 );
      myGump.AddButton( 66, 178, 0x8b2, 0, 3, 0 );
      myGump.AddGump( 66, 178, 0x8b2 );
      myGump.AddButton( 101, 178, 0x8b3, 0, 4, 0 );
      myGump.AddGump( 101, 178, 0x8b3 );
      myGump.AddButton( 136, 178, 0x8b4, 0, 5, 0 );
      myGump.AddGump( 136, 178, 0x8b4 );
      myGump.AddButton( 201, 178, 0x8b5, 0, 6, 0 );
      myGump.AddGump( 201, 178, 0x8b5 );
      myGump.AddButton( 236, 178, 0x8b6, 0, 7, 0 );
      myGump.AddGump( 236, 178, 0x8b6 );
      myGump.AddButton( 271, 178, 0x8b7, 0, 8, 0 );
      myGump.AddGump( 271, 178, 0x8b7 );
      myGump.AddButton( 306, 178, 0x8b8, 0, 9, 0 );
      myGump.AddGump( 306, 178, 0x8b8 );
      myGump.AddGump( 25, 40, 0x39 );//Draw the decoreative line under charges
      myGump.AddGump( 55, 40, 0x3a );
      myGump.AddGump( 71, 40, 0x3a );
      myGump.AddGump( 87, 40, 0x3a );
      myGump.AddGump( 103, 40, 0x3a );
      myGump.AddGump( 119, 40, 0x3a );
      myGump.AddGump( 129, 40, 0x3b );
      myGump.AddGump( 189, 40, 0x39 );//and the same on facing page
      myGump.AddGump( 219, 40, 0x3a );
      myGump.AddGump( 235, 40, 0x3a );
      myGump.AddGump( 251, 40, 0x3a );
      myGump.AddGump( 267, 40, 0x3a );
      myGump.AddGump( 283, 40, 0x3a );
      myGump.AddGump( 293, 40, 0x3b );

      //Custom Stuff each page
      myGump.AddButton( 28, 56, 0x837, 1, 0, (i*2)+1 );
      myGump.AddButton( 190, 56, 0x837, 1, 0, (i*2)+2 );

      if( myBook[((i*2)*4)+1]=="Blank")
         var color =0;
      else
         var color=10;
      myGump.AddText(41, 52, color, myBook[((i*2)*4)+1]);

      if( myBook[((i*2)*4)+5]=="Blank")
         var color =0;
      else
         var color=10;
      myGump.AddText(203, 52, color, myBook[((i*2)*4)+5]);

      myGump.AddText(43,67,0,myBook[((i*2)*4)+2] + " "+ myBook[((i*2)*4)+3] + " " + myBook[((i*2)*4)+4] ); //XYZ Position
      myGump.AddText(205,67,0,myBook[((i*2)*4)+6] + " "+ myBook[((i*2)*4)+7] + " " + myBook[((i*2)*4)+8] ); //XYZ Position

      myGump.AddButton( 35, 110, 0x985,1,0,(100+(i*2))); // Drop rune
      myGump.AddText(45,110,0,"Drop Rune");
      myGump.AddButton( 193, 110, 0x985,1,0,(100+(i*2)+1));
      myGump.AddText(203,110,0,"Drop Rune");

      if (i <= 6) //don't want the next page button on the last page, only previuos page button
      {
         myGump.AddButton( 293, 5, 0x89e, 0, i+3, 0 );//Turn Page button
         myGump.AddGump( 293, 5, 0x89e );
      }
      myGump.AddButton( 25, 5, 0x89d, 0, i+1, 0 );//Turn Page button
      myGump.AddGump( 25, 5, 0x89d );

      myGump.AddButton( 35, 130, 0x8df, 1, 0, (120+(i*2)) );//Recall Button
      myGump.AddGump( 35, 130, 0x8df );
      myGump.AddButton( 110, 130, 0x8f3, 1, 0, (140+(i*2)) );//Gate Button
      myGump.AddGump( 110, 130, 0x8f3 );

      myGump.AddButton( 193, 130, 0x8df, 1, 0, (120+(i*2))+1 );//Recall Button
      myGump.AddGump( 193, 130, 0x8df );
      myGump.AddButton( 268, 130, 0x8f3, 1, 0, (140+(i*2))+1 );//Gate Button
      myGump.AddGump( 268, 130, 0x8f3 );
   }
   myGump.Send( srcSock );

   //When drawing the gump, we check for NULL's in the names, we change them to blanks
   //Remake string so it can be saved to a tag
   myString=myBook[0]+","; //Book Name
   for (i=0;i<=15;i++)
   {
      myString=myString+myBook[(i*4)+1] + "," + myBook[(i*4)+2] + "," + myBook[(i*4)+3] + "," + myBook[(i*4)+4] + ",";
   }
   myString=myString+Charges; //don't forget the charges
   return myString;
}


//Charge Book
function onCallback1( srcSock, myTarget )
{
   //Get what char is doing this
   var srcChar = srcSock.currentChar;

   //What item have we targeted?
   var StrangeByte = srcSock.GetWord( 1 ); //If Strangebyte is null or different than 0, it's not a dynamic object
   if( StrangeByte != 0 || (StrangeByte == 0 && myTarget.isChar) )
   {
      //Clear the tag
      srcChar.SetTag("ItemUsed", "0,0,0,0");
      srcChar.SysMessage( "You need to target a recall scroll." );
      return;
   }

   //get the original items's serial (tag from item used)
   var oldSerial = new Array;
   var iCheck = new String(srcChar.GetTag("ItemUsed"));
   var oldSerial = iCheck.split(',');
   //Convert serial into actual numbers not strings
   oldSerial[0] = parseInt(oldSerial[0]);
   oldSerial[1] = parseInt(oldSerial[1]);
   oldSerial[2] = parseInt(oldSerial[2]);
   oldSerial[3] = parseInt(oldSerial[3]);
   //Find out what the item is from the serial
   var iUsed=CalcItemFromSer(oldSerial[0], oldSerial[1], oldSerial[2], oldSerial[3]);

   //Get the locations again
   myString=new String(iUsed.GetTag("RuneBook"));
   var myBook= new Array;
   var myBook = myString.split(',');
   Charges=parseInt(myBook[65]);
   
   //Pack check - So we don't nick scrolls
   // If item is on ground, .container returns null. Freeks out .container.serial
   if( myTarget.container == null )
      iCont = 0;
   else
      var iCont = myTarget.container.serial; // Serial of the pack its in
   var cPack = srcChar.pack.serial; //Serial of users pack
   if( iCont != cPack)
   {
      srcSock.SysMessage( "That has to be in your backpack." );
      return;
   }

   // is the item of the right type?
   var iID = myTarget.id;
   if( iID != 0x1F4c )
   {
      srcSock.SysMessage( "That is not a recall scroll." );
      return;
   }

   //Get how many is in pile we targeted
   tAmount = myTarget.amount;
   //How many do we need to fill the book (max 10 charges)
   ChargesRequired = 10 - Charges;
   if (ChargesRequired>=tAmount)
   {
      Charges += tAmount; //If there are less scrolls then required then use um all
      myTarget.Delete();
   }
   else
   {
      Charges=10;
      myTarget.amount -= ChargesRequired; //More than enouth, then just use what we need
   }

   //Save the tag
   myString=myBook[0]+","; //Book Name
   for (i=0;i<=15;i++)
   {
      myString=myString+myBook[(i*4)+1] + "," + myBook[(i*4)+2] + "," + myBook[(i*4)+3] + "," + myBook[(i*4)+4] + ",";
   }
   myString=myString+Charges; //don't forget the charges
   iUsed.SetTag("RuneBook", myString);
}

function onSpeechInput(pUser, iUsed, pSpeech, pSpeechID)
{
   iUsed.SetTag("InUsage", 0);
   if(pSpeech == null || pSpeech == " ")
   {
      pUser.SysMessage( "That name is too short, or no name was entered." );
      return;
   }
       
       switch(pSpeechID)
       {
   case 1: //Rename Runebook
      if( pSpeech.length > 50 )
      {
         pUser.SysMessage( "That name is too long. Maximum 50 chars." );
         return;
      }
      iUsed.name = pSpeech;
      pUser.SysMessage("The new name of the Runebook is: "+iUsed.name );
      break;
   }
}
Last edited by Xuri on Mon Dec 29, 2008 6:22 pm, edited 3 times in total.
-= Ho Eyo He Hum =-
grimalden
UOX3 Neophyte
Posts: 36
Joined: Sat Mar 19, 2005 4:18 am
Has thanked: 0
Been thanked: 0

Post by grimalden »

Okay, this question shows I have no idea what I'm doing and I'm suprised I've made it as far as I have. In fileassociations, do i need to create a

//--------
[CUSTOM
//--------
{
20001=js/custom
}

blah blah blah thing? It's not finding the script when i use 'setscptrig.

And I also I'd like to think everyone on the forum for being the sh*t for helping everyone like me out who doesn't speak the language.
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:

Post by Xuri »

Yep! The actual filepath depends on where you place the script (personally I find that placing custom scripts in a custom subfolder eases script-management a lot), but in general you just add a new line with a unique script ID (not used elsewhere in the jse_fileassociations.scp file), like this:

2001=custom/runebooks.js

Then you either reload the Javascript Engine from UOX3 console (press * then ? for a menu), or restart UOX3.

Once ingame, do 'SETSCPTRIG 2001 and target whichever item you wish to function like a runebook (doesn't have to be an actual book).
-= Ho Eyo He Hum =-
grimalden
UOX3 Neophyte
Posts: 36
Joined: Sat Mar 19, 2005 4:18 am
Has thanked: 0
Been thanked: 0

Post by grimalden »

okay. I had to put it in the commands section in the jsefileassociation. It works, but when loading scripts for the UOX3 server it gives me a red error message. Any thoughts? Ignore it since it seems to be just fine?
grimalden
UOX3 Neophyte
Posts: 36
Joined: Sat Mar 19, 2005 4:18 am
Has thanked: 0
Been thanked: 0

Post by grimalden »

after crashing my server using the runebook, it not says someones already using it. I've reloaded already. :?
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:

Post by Xuri »

Hm you shouldn't have to put it in the commands section. Put it in an empty line just below 5004=item/moongate.js, and just before the } there which indicates the end of the "normal JS script"-section. Place all your custom scripts (unless they are commands, or spells, or skills) above that bracket, and you should be fine.

I just tested the script now, and it seemed to work fine - could add a rune to my runebook and rename it and everything. Though the first time I tried the Add Rune button, the script crashed for some reason. :( Not sure why, and can't seem to recapture that bug now. Perhaps it was an oversight from me somehow.
-= Ho Eyo He Hum =-
grimalden
UOX3 Neophyte
Posts: 36
Joined: Sat Mar 19, 2005 4:18 am
Has thanked: 0
Been thanked: 0

Post by grimalden »

Yeah, I had moved it again last night before I went to sleep. Works great. Thanks for all the help.
Lok1728
UOX3 Newbie
Posts: 14
Joined: Fri Feb 03, 2006 2:54 am
Has thanked: 0
Been thanked: 0

Post by Lok1728 »

This is a great script and just implemented it today. However, in trying to drop a rune from the rune book I get a JS error on the server. Also, I go to open the runebook again and it says "Somebody is already using this runebook!"

Here's the error received on the server:

| ERROR: JS script failure: Message (TypeError: undefined is not a function)
| ERROR: Filename: (null)
Line Number: 0
| ERROR: Erroneous Line: (null)
Token Ptr: (null)
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:

Post by Xuri »

It's just a bit out of date. I'll fix it up right now and post it when I'm done.

EDIT: Updated the script in the first post. Copy & paste :)
-= Ho Eyo He Hum =-
karther77
UOX3 Newbie
Posts: 8
Joined: Wed Nov 08, 2006 5:19 am
Location: California
Has thanked: 0
Been thanked: 0
Contact:

Post by karther77 »

Just loaded the runebook and I think it works great. I have only found one thing that does not work as intended. WHen you name the book to something you like, then use location in book to go somewhere then go somewhere else the book changes the name back to say runebook.

Beyond that all should be fine.
Karther-Ranger of Yew
(NuFf SaId)
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:

Post by Xuri »

That can be fixed (I think, haven't tested) by removing the line saying
iUsed.name="Runebook";
at the bottom of the first function in the script (function onUse).

I'm guessing that line was put there as a way of initializing runebooks in general - renaming them from "a book "to "Runebook" - but the general effect is that it will rename the runebook to "Runebook" every single time you double-click on it :P

I have now updated the script posted in the parent post here and removed the offending line.
-= Ho Eyo He Hum =-
GaryMartin
UOX3 Newbie
Posts: 4
Joined: Sat Mar 14, 2009 6:35 am
Has thanked: 0
Been thanked: 0

Post by GaryMartin »

I am using the exact script from the first post in this thread and with the new version I am having the "already using" errors. When first created, the runebook will work great for a while, but at some point it bugs out and can't be opened.

I can go in with a GM account and 'settag InUsage,0 to get them working again, but it's kinda annoying.

Any ideas? Thanks!


Lok1728 wrote:This is a great script and just implemented it today. However, in trying to drop a rune from the rune book I get a JS error on the server. Also, I go to open the runebook again and it says "Somebody is already using this runebook!"

Here's the error received on the server:

| ERROR: JS script failure: Message (TypeError: undefined is not a function)
| ERROR: Filename: (null)
Line Number: 0
| ERROR: Erroneous Line: (null)
Token Ptr: (null)
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:

Post by Xuri »

Hm. Perhaps the script needs some kind of "fail-safe-device".. i.e. something that resets the InUsage value if certain conditions apply, since at the moment it will never be reset if say, the server/client crashes while the runebook is in use.
-= Ho Eyo He Hum =-
GaryMartin
UOX3 Newbie
Posts: 4
Joined: Sat Mar 14, 2009 6:35 am
Has thanked: 0
Been thanked: 0

Post by GaryMartin »

Xuri wrote:Hm. Perhaps the script needs some kind of "fail-safe-device".. i.e. something that resets the InUsage value if certain conditions apply, since at the moment it will never be reset if say, the server/client crashes while the runebook is in use.
Apart from the obvious annoyance factor, would it hurt anything if two users actually *were* using it at the same time? Sure, it could set the wrong location on the book to recall against, but is it unsafe to just ignore concurrency in this respect?

I don't think it was a client crash that bugged it, but a player death. The gump was *not* open at the time but it had been used during the play session.
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:

Post by Xuri »

Possibly not. I guess you could just comment out the InUsage parts. Depending on how the various "checks" are setup in this script you could run into some minor exploits regarding recalling/gating, but I'm not sure as I haven't studied the script in detail for quite a long while. =D
-= Ho Eyo He Hum =-
Ghostwolf
UOX3 Novice
Posts: 73
Joined: Mon Feb 11, 2008 9:41 am
Location: Hanging Around
Has thanked: 0
Been thanked: 0
Contact:

Post by Ghostwolf »

Somehow after every worldsave, adding runes and possible other events the name of runebook reverts back to "a runebook". I've even tried 'rename but it still goes back to "a runebook" after a while.
HumbleMeister
UOX3 Newbie
Posts: 7
Joined: Wed Jan 13, 2010 4:09 am
Has thanked: 0
Been thanked: 0

Post by HumbleMeister »

HI, I downloaded the world pack described here, then copied the latest 4.0 all-in-one release over the directories. the runebook.js file was already there, and identical to this post.. so i only modified the file jse_fileassociations.scp as the instructions say and then reloaded the java while the server was running.. taged a book like the instructions said and I have a functioning rune book :-). no errors to that point. I then did a account and world save, shut down the server. shut down with no errors. then I started it up again and I got this warning error message below (toward the end of the code box) that I had never seen before this, and the 20001 points to the runebook.js mods. What does it mean and what should I do?

WARNING: Script Number (20001) does not have a Console Registration function

Code: Select all

o------------------------------------------------------------------------------o
| UOX Server start up!
| Welcome to Ultima Offline eXperiment 3 v0.98-4.0c
o------------------------------------------------------------------------------o
| Processing INI Settings                                                [done]
| Initializing and creating class pointers...
o------------------------------------------------------------------------------o
| Starting JavaScript Engine....
| JavaScript engine startup complete.
o------------------------------------------------------------------------------o
o------------------------------------------------------------------------------o
| Loading server scripts...
|    o Clearing AddMenuMap entries(0)
|
| Section                items :   7758 entries                          [done]
| Section                  npc :    688 entries                          [done]
| Section               create :    802 entries                          [done]
| Section              regions :    138 entries                          [done]
| Section                 misc :    581 entries                          [done]
| Section               skills :     67 entries                          [done]
| Section             location :    143 entries                          [done]
| Section                menus :     11 entries                          [done]
| Section               spells :     64 entries                          [done]
| Section               newbie :     57 entries                          [done]
| Section               titles :      4 entries                          [done]
| Section              advance :     10 entries                          [done]
| Section                house :    103 entries                          [done]
| Section               colors :     29 entries                          [done]
| Section                spawn :    511 entries                          [done]
| Section                 html :      5 entries                          [done]
| Section                 race :     22 entries                          [done]
| Section              weather :      9 entries                          [done]
| Section            harditems :     16 entries                          [done]
| Section              command :      5 entries                          [done]
| Section             msgboard :      5 entries                          [done]
| Section                carve :     97 entries                          [done]
| Section            creatures :    345 entries                          [done]
| Section                 maps :     43 entries                          [done]
o------------------------------------------------------------------------------o
| Loading JS Scripts
|   o Loaded  118 scripts from section SCRIPT_LIST
|   o Loaded   54 scripts from section COMMAND_SCRIPTS
|   o Loaded    2 scripts from section MAGIC_SCRIPTS
|   o Loaded   17 scripts from section SKILLUSE_SCRIPTS
|   o Loaded    0 scripts from section PACKET_SCRIPTS
|   o Loaded    3 scripts from section CONSOLE_SCRIPTS
o------------------------------------------------------------------------------o
| Loading skill advancement                                              [done]
| Loading dictionaries...
|              Dictionary.UNK                                          [loaded]
|              Dictionary.ZRO                                          [loaded]
|              Dictionary.ENG                                          [loaded]
|              Dictionary.FRE                                          [loaded]
|                                                                        [done]
| Loading teleport                                                       [done]
| Loading GoPlaces                                                       [done]
o------------------------------------------------------------------------------o
| Preparing to open *.mul files...
| (If they don't open, fix your paths in uox.ini or filenames in maps.dfn)
|       c:/Program Files/Ultima Online/map0.mul                          [done]
|       c:/Program Files/Ultima Online/statics0.mul                      [done]
|       c:/Program Files/Ultima Online/staidx0.mul                       [done]
|       c:/Program Files/Ultima Online/mapdif0.mul                       [done]
|       c:/Program Files/Ultima Online/stadif0.mul                       [done]
|       c:/Program Files/Ultima Online/mapdifl0.mul                      [done]
|       c:/Program Files/Ultima Online/stadifi0.mul                      [done]
|       c:/Program Files/Ultima Online/stadifl0.mul                      [done]
|       c:/Program Files/Ultima Online/map1.mul                          [done]
|       c:/Program Files/Ultima Online/statics1.mul                      [done]
|       c:/Program Files/Ultima Online/staidx1.mul                       [done]
|       c:/Program Files/Ultima Online/mapdif1.mul                       [done]
|       c:/Program Files/Ultima Online/stadif1.mul                       [done]
|       c:/Program Files/Ultima Online/mapdifl1.mul                      [done]
|       c:/Program Files/Ultima Online/stadifi1.mul                      [done]
|       c:/Program Files/Ultima Online/stadifl1.mul                      [done]
|       c:/Program Files/Ultima Online/map2.mul                          [done]
|       c:/Program Files/Ultima Online/statics2.mul                      [done]
|       c:/Program Files/Ultima Online/staidx2.mul                       [done]
|       c:/Program Files/Ultima Online/mapdif2.mul                       [done]
|       c:/Program Files/Ultima Online/stadif2.mul                       [done]
|       c:/Program Files/Ultima Online/mapdifl2.mul                      [done]
|       c:/Program Files/Ultima Online/stadifi2.mul                      [done]
|       c:/Program Files/Ultima Online/stadifl2.mul                      [done]
|       c:/Program Files/Ultima Online/map3.mul                          [done]
|       c:/Program Files/Ultima Online/statics3.mul                      [done]
|       c:/Program Files/Ultima Online/staidx3.mul                       [done]
|       c:/Program Files/Ultima Online/map4.mul                          [done]
|       c:/Program Files/Ultima Online/statics4.mul                      [done]
|       c:/Program Files/Ultima Online/staidx4.mul                       [done]
|       c:/Program Files/Ultima Online/tiledata.mul                      [done]
| Caching Multis....                                                     [done]
o------------------------------------------------------------------------------o
| Loading custom ore data                                                [done]
| Loading creation menus                                                 [done]
o------------------------------------------------------------------------------o
| Loading Spawn Regions                                                  [done]
| Loading Regions                                                        [done]
| Loading Races                                                          [done]
| Loading Weather                                                        [done]
| Loading Commands
|    o Loading command levels
|                                                                        [done]
| Loading World now             100%                                     [done]
| ASCII world loaded in 165.91sec
| Loading Guilds                                                         [done]
o------------------------------------------------------------------------------o
| Clearing all trades                                                    [done]
| Initializing multis                                                    [done]
| Initializing Jail system                                               [done]
| Initializing Status system                                             [done]
| Loading custom titles                                                  [done]
| Loading temporary Effects                                              [done]
| Loading creatures                                                      [done]
| Starting World Timers                                                  [done]
o------------------------------------------------------------------------------o
| Compiled on Mar 22 2009 (04:45:18)
| Compiled by The Official DevTeam
| Contact: http://openuo.sourceforge.net/
o------------------------------------------------------------------------------o
| Loading Accounts
|  o Processing accounts file
| Creating and Initializing Console Thread                               [done]
o--|- --W-A-R-N-I-N-G-:- ---S-c-r-i-p-t- -N-u-m-b-e-r- -(-2-0-0-0-1-)- -d-o-e-s-
 n-o-t- have- -a- -C-o-n-s--o-l-e-R--e-g-i-s-t-r-
---|- --a--t-i-on --f-uonct|i on
UOX: Startup Complete|
o------------------------------------------------------------------------------o
| Thread: CheckConsoleThread has started
| No players currently online. Starting bulletin board maintenance
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:

Post by Xuri »

This reply is more than 1 year and 10 months too late, but I'll post it anyway. The error in question is most likely caused by having setup the runebook-script in the [CONSOLE_SCRIPTS]-section of jse_fileassociations.scp instead of the [SCRIPT_LIST]-section. Just in case anyone else ever runs into the same problem :P
-= Ho Eyo He Hum =-
Post Reply