Xnav

Xnav is a new, rebuilt-from-the-ground-up navigation package for SkunkWorks. It offers all the capabilites of SkunkNav and more, but should not be thought of as an upward-compatible replacement for SkunkNav. Key differences include:

The Xnav programming model involves a three-level object hierarchy. At the root is the global Xnav object, which is created automatically at script load by Xnav.vbs. This object has methods for creating Xroute objects, which embody routing information and do the actual work of moving you around. Xroutes in turn are built from waypoint objects of various types. A waypoint can be thought of as a single "go here and do this" instruction. A route is a series of such waypoints executed in order.

The Xnav distribution package includes:

Altogether there are 19 VBScript modules in the package. I realize this is a rather large number of rather small modules to add to your projects, but I believe in modularity and this is how my own code is organized. You needn't include all 19 modules in every project; XrouteEdit and XrouteConvert are optional, and you can omit any waypoint types you aren't using. However the indispensible core set of modules is still fairly large. See XrouteEdit.swx for an example of the proper include order.

The Xnav object

You access most top-level Xnav functions through the global Xnav object. This object is created and initialized automatically by Xnav.vbs on script load. Its properties and methods are as detailed below. Many of these functions will be familiar to SkunkNav users, but do take note of the new Xnav.FunctionName( ) syntax for invoking them.

Method or property

Result type

Description

Xnav.GoToLatLng(lat, lng)

None

Moves your character to the given latitude and longitude by the most direct route ("as the crow flies").

Xnav.GoToMaploc(maploc)

None

Moves your character to the given location by the most direct route. This is equivalent to Xnav.XrouteFromMaploc(maploc).Go( ).

Xnav.GoToMaplocEx(maploc, distArrive)

None

Moves your character to the given location by the most direct route. distArrive specifies how close, in MU, your character must come to the target location before stopping. If distArrive is greater than 3 meters (0.0125 MU), your character will run the whole distance. If distArrive is less than 3 meters, you character will run most of the way and walk the last few meters.

Xnav.MaplocZeroInOnMaploc(maplocTarget, distArrive)

Maploc

Moves your character to the given location by the most direct route. distArrive specifies how close, in MU, your character must come to the target location. This is not a suggestion but a guarantee: MaplocZeroInOnMaploc will retry as needed and will not return until you are within distArrive of the specific target. It then returns your exact arrival coords in maploc form. Use this function when you need to position your character very precisely on a particular spot.

Xnav.StopNav( )

None

Stops the execution of any route in progress and returns control to the caller of xroute.Go. Has no effect if there is no route in progress. Note that in SkunkNav this was a method of the route object. Here it's a method of the global Xnav object, so you don't need to have a reference to the executing route in order to call it.

Xnav.TurnTowardMaploc(maploc)

None

Turns your character to face the given maploc, but doesn't go there.

Xnav.TurnToHead(head)

None

Turns your character to face the given compass heading (in degrees, measured clockwise from north).

Xnav.XrouteNew( )

Xroute

Creates and returns a new, empty Xroute object. See Xroute objects for details on the methods and properties of this object.

Xnav.XrouteFromMaploc(maploc)

Xroute

Creates and returns a new Xroute object representing a direct, straight-line route (i.e. a route of just one waypoint) to the given location.

Xnav.XrouteFromFile(szFile)

Xroute

Creates and returns a new Xroute object from the contents of the named file, which must be an XML file in the Xroute format. szFile can be either a simple filename such as "MyFile.xroute" or a filename followed by a route name in square brackets, such as "MyFile.xroute[MyRoute]". Use the latter form to load a specific route from a file containing several named routes. Xroute files can be created using the XrouteEdit tool included with Xnav, by calling xroute.SaveToFile on an Xroute object in memory, or by typing in the XML manually using a text editor.

Xnav.XrouteFromFile is just like xroute.FromFile except that it creates a new Xroute object instead of loading into an existing one.

Xnav.XrouteFromXml(elem, fInterpolate)

Xroute

Creates and returns a new Xroute object from the contents of the XML DOM element elem, which must be a valid Xroute element. If fInterpolate is False, the route is created from the XML as is. If fInterpolate is True, legs longer than half an MU (120 meters) are automatically broken up into shorter legs by inserting extra waypoints (of the Simple variety). There are a couple of reasons you might want to do this:

  • Long legs require long timeouts. If you get hung up early in a long leg, it could be a long time before Xnav notices you didn't make it to the next waypoint. Putting in extra waypoints keeps the timeouts reasonable.
  • Long legs have more room for lateral drift. Aiming precisely at a distant waypoint is harder than aiming at a nearby one, and you can get correspondingly farther off the straight-line course before Xnav notices the deviation. Sometimes this is OK, but if you'd rather stay close to the road, frequent waypoints can help.

You can of course insert extra waypoints explicitly into your route definition, or you can use fInterpolate to do it automatically as the route is loaded.

Xnav.XrouteFromXml is just like xroute.FromXml except that it creates a new Xroute object instead of loading into an existing one.

Xnav.XrouteFromSz(szXml, fInterpolate)

Xroute

Creates and returns a new Xroute object from the given XML text in memory. This function works just like Xnav.XrouteFromXml except that the XML is passed in string form rather than in structured XML DOM form.

Xnav.DictSzXrouteFromFile(szFile)

Dictionary

Reads all the routes in the Xroute file named by szFile and returns a Scripting.Dictionary object whose Keys are route names and whose Items are the corresponding Xroutes.

Xnav.DictSzXrouteFromXdoc(xdoc)

Dictionary

Reads all the routes defined by an XML document in memory and returns a Scripting.Dictionary object whose Keys are route names and whose Items are the corresponding Xroutes. xdoc must be a valid XML DOM document representing an Xroute file.

Xnav.XdocNewXrouteFile( )

XML DOM document

Creates and returns an XML document representing an empty Xroute file. This does not actually create a file on disk, it just creates the document in memory. It's up to the caller to save it to disk if so desired by calling the document's save method.

Xnav.RegisterType(szTag, szFunc)

None

Registers a waypoint type. szTag is the unique XML tag name of the new type, and szFunc is the name of that type's global instantiator function. If you're implementing a custom waypoint type, it's your responsibility to register the type on script load; see Custom waypoints for details. Users of custom waypoint types shouldn't have to worry about this (other than including the appropriate script modules in their projects).

Xnav.rgszTag(i)

String

Returns the XML tag name of the i th registered waypoint type (counting from zero), or the empty string ("") if there are fewer than i types registered. Use this to enumerate the registered waypoint types as follows (in JScript):

var i, szTag;
for (i = 0; (szTag = Xnav.rgszTag(i)) != ""; i++)
    {
    ...
    }

Or in VBScript:

Dim i, szTag
i = 0
Do
    szTag = Xnav.rgszTag(i)
    If szTag = "" Then Exit Do
    ...
    i = i + 1
Loop

Xnav.WayptFromTag(szTag)

Waypoint

Creates and returns a new, empty waypoint of the type specified by szTag, which must be a registered waypoint type. (Well-behaved waypoint types register themselves automatically on script load; see Custom waypoints for more info.)

Xnav.WayptFromXml(elem)

Waypoint

Creates and returns a new waypoint from the contents of the XML DOM element elem, which must be a valid waypoint element of some registered type.

Xnav.ElemFromWaypt(xdoc, waypt, fVerbose)

XML DOM element

Creates and returns an XML element representing the waypoint waypt. xdoc is the document context in which the element should be created, but note that ElemFromWaypt does not actually insert the element into the document. That's left up to the caller. If fVerbose is True, all waypoint parameters are made explicit in the XML, even those with default values. If fVerbose is False, parameters with default values may be omitted.

Xnav.FSimpleWaypt(waypt)

Boolean

Returns True if the given waypoint is of the Simple type (with no special arrival action), False otherwise.

Xnav.MaplocOfElem(elem)

Maploc

Decodes map coordinates stored on the given XML element and returns them in maploc form. Useful mainly to implementors of custom waypoint types.

Xnav.SetElemMaploc(elem, maploc, fZ, fHead)

None

Encodes map coordinates from the given maploc onto the given XML element. If fZ and/or fHead are True, the z and/or head components of the maploc are encoded as well as lat and lng. Useful mainly to implementors of custom waypoint types.

Xnav.DistToAco(aco)

Number

Returns the 2D distance in map units to the given object.

Xnav.DistToMaploc(maploc)

Number

Returns the 2D distance in map units to the given maploc.

Xnav.Dist3DToMaploc(maploc)

Number

Returns the 3D distance in map units to the given maploc.

Xnav.HeadToMaploc(maploc)

Number

Returns the compass heading to the given maploc, i.e. the direction you'd have to face to be aimed at that maploc.

Xnav.DheadToMaploc(maploc)

Number

Returns the difference in compass heading (the amount you'd have to turn by) from your current heading to the given maploc.

Xnav.HeadNormalize(head)

Number

Returns the given heading normalized to within the range 0 to 360 degrees. Headings within this range are returned unchanged; headings outside this range are normalized by adding or subtracting multiples of 360.

Xnav.DheadNormalize(dhead)

Number

Returns the given turning angle normalized to within the range −180 to +180 degrees. Angles within this range are returned unchanged; angles outside this range are normalized by adding or subtracting multiples of 360.

Xnav.MaplocReverseHead(maploc)

Maploc

Returns a copy of the given maploc with its heading reversed by 180 degrees.

Xnav.MaplocAddDhead(maploc, dhead)

Maploc

Returns a copy of the given maploc with its heading altered by dhead degrees. dhead may be positive or negative.

Xnav.FIndoorMaploc(maploc)

Boolean

Returns True if the given maploc is indoors (in a building or dungeon), False if outdoors.

Xnav.UseAcoPortal(aco)

None

Enters the portal specified by aco and waits until your character emerges from portal space at the other end.

Xnav.WaitForPortal( )

None

Waits until your character enters portal space and then emerges again at the other end. Taking whatever action is needed to enter portal space in the first place is the caller's responsibility; WaitForPortal just waits for the trip to finish.

The Xnav package includes a Trace facility to aid debugging. Tracing is turned off by default within the Xnav object and its sub-objects (Xroutes and waypoints). You can turn it on by adding a call to Trace(Xnav) in the Main function of your script. Trace output goes to opmDebugLog and may be viewed using DebugView or some similar tool. For more info see the comments in Trace.vbs.

Xroute objects

An Xroute (see XrouteCls.vbs) is an object embodying a sequence of waypoints to be visited in order on the way to a final destination. Each waypoint can define an action to be taken when that waypoint is reached. Unlike the single global Xnav object, you can have as many Xroute objects as you like, one for each route you want to travel.

Create an empty Xroute object by calling Xnav.XrouteNew. For instance in JScript:

var xroute = Xnav.XrouteNew();

Or in VBScript:

Dim xroute
Set xroute = Xnav.XrouteNew()

You can also get Xroute objects from various Xnav methods such as Xnav.XrouteFromMaploc, Xnav.XrouteFromFile, and Xnav.XrouteFromXml.

Once created, an Xroute object has the following properties and methods. Again, most of these will be familiar in concept if not in detail to users of SkunkNav.

Method or property

Result type

Description

xroute.szName

String

The name, if any, of this route. Defaults to the empty string.

xroute.cwaypt

Number

The number of waypoints in the route, including the final destination.

xroute.iwaypt

Number

The index (counting from zero) of the waypoint from which to resume an interrupted route. (See xroute.ResumeRoute.)

xroute.rgwaypt(i)

Waypoint

Returns the i th waypoint object in the route (counting from zero). This property is read-only and cannot be used to store or replace waypoints in the route. Use xroute.InsertWaypt and xroute.DeleteWaypt for that.

xroute.maplocFirst

Maploc

The starting coords of the route, i.e. waypt.maplocIn of the route's first waypoint.

xroute.maplocLast

Maploc

The ending coords of the route, i.e. waypt.maplocOut of the route's last waypoint.

xroute.csecTravel

Number

An estimate of the total time in seconds needed to execute this route. This includes both travel time from waypoint to waypoint and the time needed to perform special waypoint actions such as portaling or opening doors. It does not include the time needed to get to the route's first waypoint, since Xnav doesn't know where you'll be starting from. For that reason it's a good idea to include your starting point (the place you expect to be standing when you call xroute.Go) as the first waypoint in the route.

xroute.Clear( )

None

Deletes all waypoints from the route and resets it to an empty state.

xroute.InsertMaploc(i, maploc)

None

Inserts a Simple waypoint (one with no arrival action) before the i th waypoint in the route (counting from zero). If i is iNil (-1), the new waypoint is appended to the end of the route. maploc specifies the map coordinates of the new waypoint.

xroute.InsertWaypt(i, waypt)

None

Inserts a waypoint of any type before the i th waypoint in the route (counting from zero). If i is iNil (-1), the new waypoint is appended to the end of the route. waypt is the waypoint object to insert; see Waypoint objects for information on how to create waypoints for insertion.

xroute.DeleteWaypt(i)

None

Deletes the i th waypoint from the route.

xroute.Append(xroute2, fOptimize)

None

Appends the waypoints in xroute2 to the end of xroute, concatenating the two routes. xroute2 is not modified by this method (but xroute is). See xroute.XrouteConcat for details on the meaning of fOptimize.

xroute.XrouteConcat(xroute2, fOptimize)

Xroute

Returns a new Xroute representing the concatenation of xroute with xroute2. Neither xroute nor xroute2 is modified by this method.

If fOptimize is False, the two routes are concatenated verbatim. If True, redundant waypoints at the juncture of the two routes are pruned away. Thus if xroute2 is the exact reverse of xroute, the concatenation will be empty (if fOptimize is True). If only part of xroute2 matches the reversal of xroute, then only that portion of both routes will be removed, leaving the unique portions intact.

For example, suppose merchant A and merchant B share a shop, or occupy different stalls in the same bazaar. The route in to A will be very similar to the route in to B, except at end where the two routes diverge. The naive way to get from A to B would be to concatenate the reverse of route A with route B, like so:

xrouteA2B = xrouteA.XrouteReverse().XrouteConcat(xrouteB, False);

While this works, it has the effect of taking your character out of the shop, then turning him around and heading right back in to B. By specifying fOptimize as True, this is avoided; the redundant part of the combined route is removed, and your character backtracks only to the point where the routes diverge before continuing on to B.

xroute.XrouteClone( )

Xroute

Returns a new Xroute that is an exact copy of xroute.

xroute.XrouteReverse( )

Xroute

Returns a new Xroute with with the order of the waypoints reversed. Use this method to backtrack along a route. If the route includes any waypoints that cannot be reversed (such as Portal or Recall waypoints), XrouteReverse fails and returns Nothing (null in JScript).

xroute.FromFile(szFile)

None

Loads route information from the Xroute file named by szFile. The previous contents of xroute are lost. szFile can be either a simple filename such as "MyFile.xroute" or a filename followed by a route name in square brackets, such as "MyFile.xroute[MyRoute]". Use the latter form to load a specific route from a file containing several named routes.

xroute.FromFile is just like Xnav.XrouteFromFile except that it loads into an existing Xroute object instead of creating a new one.

xroute.FromXml(elem, fInterpolate)

None

Loads route information from the contents of the XML DOM element elem, which must be a valid Xroute element. The previous contents of xroute are lost. If fInterpolate is False, the route is created from the XML as is. If fInterpolate is True, legs longer than half an MU (120 meters) are automatically broken up into shorter legs by inserting extra waypoints (of the Simple variety). See Xnav.XrouteFromXml for a discussion of why you might want to do this.

xroute.FromXml is just like Xnav.XrouteFromXml except that it loads into an existing Xroute object instead of creating a new one.

xroute.FromSz(szXml, fInterpolate)

Xroute

Loads route information from the given XML text in memory. This function works just like xroute.FromXml except that the XML is passed in string form rather than in structured XML DOM form.

xroute.FromAcxRte(szFile)

None

Loads route information from a route file exported by AC Explorer Pro. The previous contents of xroute are lost. Make sure your ACX Pro terrain data is up to date before calculating and exporting the route. Do this in ACX Pro by choosing "Update terrain..." from the Update menu. Also note that routes calculated in this way are accurate only to about 0.1 map unit (about 24 meters). While they work fairly well on flat or hilly terrain, in rugged mountainous regions you may find your character running along the bottom of a cliff he's supposed to be on top of. There's not much I can do about this without more precise route information from ACX Pro.

Actually this feature is a lot less useful than it once was. With the proliferation of settlement portals, just about any route calculated by ACX Pro includes a settlement portal as a shortcut. Unfortunately the portal coords in the AC-Spedia database aren't nearly accurate enough for reliable routing to a specific settlement portal without accidentally walking through two or three others on the way there.

xroute.SaveToFile(szFile)

None

Saves the route to the file named by szFile. Any previous contents of the file are overwritten.

xroute.XdocSave( )

XML DOM document

Saves the route to a new XML document in memory and returns a reference to the document. It's then up to the caller to save it to disk if so desired by calling the document's save method.

xroute.ElemSave(xdoc)

XML DOM element

Creates and returns an Xroute XML element representing the route. xdoc is the document context in which the element should be created, but note that ElemSave does not actually insert the element into the document. That's left up to the caller.

xroute.Go( )

NSC

Moves your character from waypoint to waypoint along the route. If the waypoint is of the Simple type, your character will pass through it without stopping and continue to the next waypoint. If the waypoint is of some other type, xroute.Go calls on the waypoint object to perform its arrival action when the waypoint is reached. These actions may include unlocking and open doors, using portals, etc., depending on the waypoint type.

When the last waypoint is reached and its action (if any) successfully carried out, xroute.Go returns a navigation stop code of nscArrived. In this case xroute.iwaypt will equal xroute.cwaypt on return from xroute.Go. If before the last waypoint is reached you call Xnav.StopNav from inside an event handler, xroute.Go stops all motion and returns nscCanceled. In this case xroute.iwaypt will be less than xroute.cwaypt. You can resume a route interrupted by Xnav.StopNav by calling xroute.ResumeRoute.

xroute.Go calls skapi.GoToMaploc to do the actual navigation from point to point, using timeouts based on the point-to-point distance as well as your current Run skill level and burden. If for some reason you fail to complete a leg within the calculated timeout, xroute.Go will back off and retry a couple of times in hopes of evading whatever obstacle was blocking your progress. If you time out on the same leg three times in a row, xroute.Go fails and throws an error up the call stack.

Other cases in which xroute.Go can fail and throw an error include:

  • You accidentally pass too close to a portal somewhere along the route and get transported elsewhere. (Planned portal travel via Portal waypoints is expected and doesn't cause an error.)
  • You unexpectedly log out while executing a route.
  • You get killed while executing a route.
  • You press Ctrl+Break from the keyboard to forcibly terminate a route gone haywire.
  • Some waypoint arrival action detects a situation it doesn't like and throws an error. (For instance you come to a locked door and don't have the right key.)

In all such error cases xroute.Go stops all motion and leaves you standing at the point where the error was detected (at the lifestone in the case of death).

You can manually pause a route in progress by pressing the Pause key on the keyboard. xroute.Go stops all motion and leaves you standing where you are until you press Pause again to resume route execution. This is different than StopNav/ResumeRoute in that control remains within xroute.Go while you're paused. As far as the caller is concerned, everything is proceeding normally. Time spent paused in this way doesn't count against the per-leg timeout, so you can remain paused as long as you like without causing an error. This feature is useful for responding to chat that comes in during route execution, which otherwise would be difficult due to the way skapi.GoToMaploc uses keystrokes to control your motion.

xroute.ResumeRoute( )

NSC

Resumes execution of a route interrupted by Xnav.StopNav. This is just like xroute.Go, with all the same error conditions and result codes, except that execution starts at xroute.iwaypt instead of at the beginning of the route.

One property of SkunkNav routes that Xroutes do not have is an explicit timeout property. Instead, Xnav relies on skapi.GoToMaploc to calculate a reasonable timeout value automatically for each leg.

Also, the szRecall property of SkunkNav routes is implemented in Xnav by the Recall waypoint type. In Xnav you can insert a recall anywhere in your route, if that makes sense. For instance in some situations you might want to run to a safe place before doing the recall.

Finally, if you're looking for xroute.StopRoute, you'll find that function implemented as Xnav.StopNav.

Waypoint objects

Waypoints are the building blocks of Xroutes. Waypoints are themselves objects, each defining a specific "go here and do this" instruction. The "go here" part is a map location (maploc) for Xnav to navigate to, and the "do this" part is an action to take when you get there. Using custom waypoint types, that action may be any scriptable action at all, including but not limited to: unlocking and opening doors; portaling; recalling; buffing; equipping or unequipping weapons or armor; interacting with inventory items, landscape objects, NPCs, or portalbots; etc. A waypoint's action may (or may not) have the effect of transporting you to another location where the route continues with the next waypoint.

Each waypoint type has a unique XML tag name that identifies that type in the XML route files. You use that tag to add a waypoint to a route as follows:

If you already have the desired waypoint parameters in XML form, you can combine the first three steps by using Xnav.WayptFromXml to create a fully initialized waypoint from an XML element.

Xnav comes with a number of predefined waypoint types. You can also define your own waypoint types to perform whatever custom actions you need. See Custom waypoints for details on how to do this. For instance, you'll notice I have not included a predefined waypoint type for spell-based recalls (mainly because it would pull in too many extra support modules to do it right). However if you have spellcasting code that works for you, it shouldn't be hard to define a custom waypoint type for this using WayptRecallCls.vbs as a template.

The predefined waypoint types are as follows (with their tag names shown in bold):

Custom waypoints

Waypoints are objects. Waypoint types are classes. You define a custom waypoint type, then, by defining a class with the specific set of properties and methods that Xnav expects waypoints to have.

The properties and methods your waypoint class must implement are as follows:

Method or property

Result type

Description

waypt.szTag

String

The XML tag name of this waypoint type. This must be a valid XML tag (i.e. alphanumeric, beginning with a letter), and must be unique among all waypoint types. You cannot reuse an existing tag name unless you're implementing an upward-compatible replacement for that waypoint type.

waypt.fWalk

Boolean

All waypoint types must provide storage for this read/write property, but the actual property value is initialized and maintained by the Xnav core code. All you're required to do is declare a property variable for Xnav to use. Strictly speaking, fWalk should be a property of the legs between waypoints, not of the waypoints themselves. However since there is no separate data structure representing the legs, the waypoint is a convenient place to store this value.

waypt.maplocIn

Maploc

The location Xnav should navigate to before calling waypt.Arrive, i.e. the "go here" part of the instruction. For example in the case of a Portal waypoint, this would be the coords of the portal itself. If waypt.Arrive can happen anywhere, for instance in the case of a Recall waypoint, maplocIn may be Nothing (null in JScript). In that case Xnav will skip the "go here" step and call waypt.Arrive directly from the previous waypoint's maplocOut.

waypt.maplocOut

Maploc

The location where waypt.Arrive leaves you. For example in the case of a Portal waypoint, this would be the portal's exit coords. maplocIn and maplocOut need not be very far apart; for instance in the case of a Door waypoint, they're just a few paces apart on opposite sides of the door. For a Jump waypoint, maplocIn is at the top of the jump and maplocOut is at the bottom. If waypt.Arrive doesn't involve any motion (for instance in the case of a buffing waypoint), maplocOut should be the same as maplocIn.

waypt.distArrive

Number

The waypoint's arrival tolerance in map units. Xnav calls waypt.Arrive when you get this close to maplocIn. (This is the value passed as the distArrive argument to skapi.GoToMaploc.) For some purposes, such as jumping off a ledge, you want to approach the target coords quite closely before acting. In other cases, for instance when approaching a portal, you want to allow plenty of leeway to avoid stumbling through it by accident. For some waypoint types distArrive will be the same for all waypoints of that type. For others, you might want to make it a configurable parameter of each waypoint instance.

waypt.csecArrive

Number

The estimated time in seconds needed to execute waypt.Arrive. This is used by xroute.csecTravel to estimate an overall execution time for the entire route.

waypt.Arrive( )

None

Perform this waypoint's arrival action, i.e. the "do this" part of the instruction. This is where you do the actual work of your custom waypoint type, be it spellcasting, equipping items from inventory, talking to NPCs, using summoned portals, or what have you. This method must not return until the action is complete and your toon is ready to move again. So if your custom action involves travel through portal space, for instance, you must wait for OnEndPortalSelf before returning. Xnav.WaitForPortal is a convenient way to do this.

waypt.WayptReverse( )

Waypoint

Create and return a new waypoint of the same type representing the reversal of this waypoint, with maplocIn and maplocOut swapped and any other type-specific waypoint parameters similarly reversed. This is used by xroute.XrouteReverse to reverse a route waypoint by waypoint. So for instance the reversal of a Door waypoint navigates the same door in the opposite direction. A waypoint that puts on armor going one direction might take it off again going the other direction. If your waypoint action is not reversible (such as actions involving portal travel), return Nothing (null in JScript) from WayptReverse, and xroute.XrouteReverse will fail.

waypt.FromMaplocCur( )

None

Initialize a newly created waypoint by taking parameters from skapi.maplocCur and/or skapi.acoSelected as appropriate. For instance a Portal waypoint checks that skapi.acoSelected is a portal and initializes itself appropriately for that portal. This method is used by XrouteEdit's Insert command.

waypt.FromXml(elem)

None

Initialize a newly created waypoint by taking parameters from the XML element elem. This is used by xroute.FromFile and xroute.FromXml to restore a saved route from XML. If your waypoint state includes maploc information (as most do), you can use Xnav.MaplocOfElem to retrieve it.

waypt.ToXml(elem, fVerbose)

None

Save type-specific waypoint parameters as XML attributes or sub-elements of the given XML element elem. If fVerbose is True, all waypoint parameters should be made explicit in the XML, even those with default values. (Verbose mode is used by XrouteEdit to display detailed waypoint info.) If fVerbose is False (the normal mode used by xroute.SaveToFile et al.), parameters with default values may be safely omitted from the XML. However in any case you must save away enough info to completely reconstruct the waypoint from the XML. If your waypoint state includes maploc information (as most do), you can use Xnav.SetElemMaploc to store it.

In addition to the required properties and methods listed above, your custom waypoint type may implement any type-specific properties and methods you need to store and configure your per-instance waypoint parameters (such as the portal name in the case of a Portal waypoint). My practice is to provide an Init method for setting all the type-specific parameters in one call, as well as exposing each parameter individually.

Apart from your class definition, two more steps are needed to make your custom waypoint type usable with Xnav. First, you must write a one-line global function (not a method of your class) that creates and returns an empty instance of your waypoint type. If you're coding in JScript, this is in addition to the regular constructor function that defines your class (since Xnav is written in VBScript and can't call JScript class constructors directly).

Second, you must register this function along with your XML tag name by calling Xnav.RegisterType. This tells Xnav how to instantiate waypoints of your type, and also tells XrouteEdit what waypoint types are available for insertion into routes. The best place to do this is in your global init code (code that's not part of any function), right next to the definition of your instantiator function. This ensures that your waypoint type gets registered automatically on script load.

So in JScript the general outline of a custom waypoint definition would look something like this:

// Waypoint class constructor:
function MyWayptType()
    {
    this.szTag = "MyTag";
    this.fWalk = false;
    this.distArrive = 0.01;
    // etc.
    }

// Waypoint instantiator function required by Xnav:
function MyInstantiator()
    {
    return new MyWayptType();
    }

// Register the waypoint type:
Xnav.RegisterType("MyTag", "MyInstantiator");

Or in VBScript:

' Waypoint class definition:
Class MyWayptType
    Public szTag
    Public fWalk
    Public distArrive
    ' etc.
    Private Sub Class_Initialize()
        szTag = "MyTag"
        distArrive = 0.01
        ' etc.
    End Sub
End Class

' Waypoint instantiator function required by Xnav:
Public Function MyInstantiator()
    Set MyInstantiator = New MyWayptType
End Function

' Register the waypoint type:
Call Xnav.RegisterType("MyTag", "MyInstantiator")

Once the type has been defined, the life cycle of a custom waypoint goes roughly as follows:

Xroute files

An Xroute file is an XML file containing one or more route definitions. You can create Xroute files interactively using XrouteEdit, from script by calling xroute.SaveToFile, or manually by typing in the XML in a text editor.

The XML in an Xroute file is organized as a three-level hierarchy of elements. At the root is an XrouteFile element that serves as a container for one or more Xroute elements. Each Xroute element has a single attribute, szName, whose value is the route's name. An Xroute element may also contain as child elements one or more waypoint elements of various types. The detailed format of each waypoint element depends on the waypoint type.

Here's an excerpt from the included Subway.xroute by way of illustration. (The ellipses (...) are not part of the format; I'm just using them here for brevity.)

<XrouteFile>
    <Xroute szName="Entrance">
        <Portal szName="Abandoned Mine">
            <maplocIn lat="34.904" lng="54.505"/>
            <maplocOut lat="-0.476" lng="-0.046"/>
        </Portal>
    </Xroute>
    <Xroute szName="Jumpoff">
        <Simple lat="-0.476" lng="-0.046"/>
        <Simple lat="-0.58" lng="-0.015"/>
        ...
        <Jump healthReq="50">
            <maplocIn lat="-1.082" lng="0.025"/>
            <maplocOut lat="-1.1195" lng="0.0250" z="-72.0"/>
        </Jump>
    </Xroute>
    <Xroute szName="Qalaba'r">
        <Include szName="Jumpoff"/>
        <Simple lat="-1.205" lng="0.025"/>
        <Simple lat="-1.225" lng="0.025" fWalk="True"/>
        <Portal szName="Qalaba'r Portal">
            <maplocIn lat="-1.225" lng="-0.004"/>
            <maplocOut lat="-75.042" lng="19.643"/>
        </Portal>
    </Xroute>
    ...
</XrouteFile>

Here we see three route definitions called Entrance, Jumpoff, and Qalaba'r. The route names can be any text you like, so long as they're unique within the file. To load a specific route from a multi-route file, append the route name, in square brackets, to the filename when you call Xnav.XrouteFromFile:

var xroute = Xnav.XrouteFromFile("Subway.xroute[Qalaba'r]");

The Entrance route in this example contains just one waypoint of type Portal. The Jumpoff route contains a series of Simple waypoints (most of them omitted above for brevity), followed by a Jump waypoint. The Qalaba'r route uses an Include waypoint to embed the Jumpoff route, then finishes by walking to the appropriate portal and portaling through.

The best way to get a feel for the details of the file format is to use XrouteEdit to create a number of routes using various waypoint types, then open the resulting XML files in a text editor for study.

XrouteEdit

XrouteEdit is an interactive, in-game editor for Xnav route files. You can run XrouteEdit by itself using the included XrouteEdit.swx, or you can add editing capabilities to your own script by including XrouteEdit.vbs along with the rest of the Xnav machinery in your SkunkWorks project. Like Xnav.vbs, XrouteEdit instantiates itself as a global XrouteEdit object on script load. This object has the following properties and methods:

Method or property

Result type

Description

XrouteEdit.Edit(szFile)

None

Displays the in-game editing controls, if they're not already displayed, and loads the route file specified by szFile. This can be either an Xnav-format .xroute file or a SkunkNav-format .route file. In the latter case, XrouteEdit calls XrouteConvert to convert the routes to Xnav format, so be sure to include XrouteConvert.vbs in your project if you want to use this feature. If szFile is the empty string (""), a new, empty route file is created. XrouteEdit.Edit returns as soon as the specified file has been loaded or created, leaving the editing controls up on screen. The user can then edit the file in parallel with other script activities.

XrouteEdit.fDisplayed

Boolean

True if the editing controls are displayed, False otherwise.

The in-game editing controls look like this:

The five buttons at the upper right are the top-level file commands. New creates a new, empty route file. (If you haven't yet saved changes to the currently open file, you'll be prompted to do so.) Open brings up a file browser dialog that lets you choose an existing route file to open. This can be either an Xnav-format .xroute file, or a SkunkNav-format .route file, in which case it will be converted automatically to Xnav format as it's read in. (If you've included XrouteEdit.vbs as part of your own project, and you want to use this automatic conversion, be sure to include XrouteConvert.vbs as well.) I recommend test-driving any converted routes before saving them to make sure the conversion worked properly and also to fill in any door headings or portal exit coords missing from the older route format.

Save saves the open file to disk. You'll be prompted to confirm the filename. Press Enter to keep the current filename, or edit the name to save to a different file. Saving is done on a per-file basis, not a per-route basis. If the file defines more than one route, they'll all be saved to the target filename. See Xnav.XrouteFromFile for information on how to access individual named routes in a multi-route file.

Revert prompts you for confirmation, then discards any unsaved changes to the current file and reverts to the previously saved version of the file. For a newly created file that has never been saved, Revert deletes all routes and returns it to an empty state. If you've made changes that you don't want to keep, and find that New, Open, or Quit won't let you proceed without saving, use Revert to discard the unsaved changes first.

Quit does the obvious: prompts you to save any unsaved changes, and then closes the editing panel.

At the top left of the panel is the name of the file being edited, or the words "New route file" for a newly created file that hasn't yet been saved. The filename appears in red if there are any unsaved changes, otherwise it's black.

Below that is a dropdown list of routes defined in that file. If the file contains multiple named routes, their names appear in this list. If it contains just one unnamed route, "Default route" will be the only choice. To the right of the dropdown are two buttons for adding and deleting routes in the file. To add a route, click Add, type a route name into the popup input box, and press Enter. To delete a route, select it from the dropdown list, click Del, and type OK (in uppercase) to the popup confirmation box.

Below the route dropdown is a scrollable list of waypoints in the chosen route. The four columns of this list are, in order from left to right:

Below the waypoint list is a row of controls giving more detailed waypoint properties. Click a waypoint in the list to highlight it and its properties will show up here. On the left is the precise type of the waypoint (its unique XML tag). In the middle is a dropdown list of type-specific properties for that waypoint type. These will be different for each waypoint type, and include such things as the portal name for a Portal-type waypoint, or the name of the key that unlocks a Door-type waypoint. On the right is the value of the chosen property. You can edit the property value and press Enter to store it back into the waypoint. (Remember to press Enter or your input will be lost.)

At the bottom is a row of controls for adding and deleting waypoints. Choose a waypoint type from the dropdown on the left and click Insert to insert a waypoint of that type in front of the highlighted waypoint. To insert at the end, highlight End in the waypoint list. For Simple waypoints, the new waypoint's input coords default to the place where you're standing when you click Insert. For such things as doors and portals, the new waypoint's parameters are taken from skapi.acoSelected (i.e. the object bracketed by the in-game targeting highlight). So for instance to add a portal to the route, select it using, say, the Backspace or \ key, choose Portal from the waypoint type dropdown, and click Insert.

To delete a waypoint, highlight it in the waypoint list and click Delete. (You can't delete the End entry.)

Using these controls you can build up a route by manually walking your character from point to point, choosing the appropriate waypoint types, and clicking Insert. Lather, rinse, repeat.

However there's a quicker way to create simple routes that use only a few basic waypoint types. Manually move your character to the place where you want the route to begin, then click Record. The Record button starts flashing and you'll see a message saying that your movements are now being recorded. Run or walk around and you'll see waypoints being added automatically to the waypoint list. Like Insert, Record inserts in front of the highlighted waypoint, so be sure you have the highlight where you want it before clicking Record.

During recording, XrouteEdit tries to be smart about creating waypoints only at places where you motion deviates substantially from a straight line. So as long as you're moving straight ahead, you should see the last waypoint being continuously updated, rather than a bunch of new waypoints being added. Once you turn a corner, though, that waypoint will be closed out and a new leg started.

If during recording you Use a door or portal by selecting it and pressing the Use key ('R' in the default keymap), XrouteEdit will notice and add a waypoint of the appropriate type to your route. However if you just run through a portal or an open door without using the Use key, XrouteEdit won't notice that, so be sure to Use any such objects that you want to record. If a door is already open, you may have to Use it twice (once to close it and once to open it again so you can go through), but that's OK; XrouteEdit will record it just once.

At present, XrouteEdit isn't smart enough to detect recalls or jumps during recording, so you'll have to insert those waypoint types using the Insert button.

To stop recording, click the flashing Record button again. Using various other controls, such as the Go button or the route dropdown, also stops recording.

You can test-drive your route at any time during editing using the buttons at the lower right. Go starts the route from the beginning and visits each waypoint in turn. Stop interrupts a route in progress. Resume resumes an interrupted route starting at the highlighted waypoint.

While XrouteEdit provides a fairly friendly interface to most routing options, it may not be the most convenient way to deal with very complex routes or exotic waypoint types. Remember that Xroute files are XML files and you can always edit them directly with Notepad or your favorite XML editor.

XrouteConvert

Xnav uses a different route file format than SkunkNav. As a result, SkunkNav route files cannot be read directly by Xnav but must first be converted to the new file format. You can do this conversion interactively using XrouteEdit or, if you have a lot of routes to convert, you can write a script to do the conversion using XrouteConvert.

Including XrouteConvert.vbs in your project gives you access to the global XrouteConvert object, which (like all the other Xnav global objects) is created and initialized automatically on script load. This object has the following methods:

Method or property

Result type

Description

XrouteConvert.ConvertFolder(szFolder)

None

Searches the folder specified by szFolder for SkunkNav-format .route files and converts them to Xnav-format .xroute files. The original .route files are not altered or deleted, but new .xroute files are created alongside them.

XrouteConvert.ConvertFile(szFile)

None

Converts a single SkunkNav-format .route file specified by szFile to an Xnav-format .xroute file. The original .route file is not altered or deleted, but a new .xroute file is created alongside it.

XrouteConvert.XdocReadFile(szFile)

XML DOM document

Reads the SkunkNav-format .route file specified by szFile into memory as an XML document in the Xroute format and returns a reference to that document. You can then save the document to a file using its save method, or extract Xroutes from it using Xnav.XrouteFromXml and related functions. The original .route file on disk is not altered or deleted.

XrouteConvert is reasonably smart about converting SkunkNav routing features to their nearest Xnav equivalents; however, since the detailed mechanics of route execution differ, you should test-drive the converted routes to make sure they converted successfully and also to fill in any missing door headings or portal exit coords.

Support modules

Xnav depends on a number of general-purpose support modules and utility functions, which are included with the package and described briefly below. You may find some of them useful apart from their role in supporting Xnav. For detailed documentation, see comments in the modules themselves.

Filename

Description

AcoUtil.vbs

Miscellaneous ACO-related utility functions.

Assess.vbs

Assessment-related utilities, including functions to assess an ACO and return its OAI, to read an item's inscription, to detect whether a door or chest is open or closed, and if closed, to open it, etc.

Error.vbs

Error-handling functions, including a facility for emulating JScript's try/catch feature in VBScript.

Pauser.vbs

Implements a simple Pause feature that uses the Pause key on the keyboard to pause and resume a running script. Also supports the use of Ctrl+Break to interrupt a running script.

Registry.vbs, RegvarCls.vbs

Registry access utilities.

Trace.vbs

Implements a facility for logging a detailed execution trace to opmDebugLog for debugging purposes. Tracing can be dynamically turned on and off script-wide, by module, or by function.

XmlUtil.vbs

XML utility functions.

Change history

Version 1.2 (released November 18, 2004):