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.
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 |
---|---|---|
None |
Moves your character to the given latitude and longitude by the most direct route ("as the crow flies"). |
|
None |
Moves your character to the given location by the most direct route. This is equivalent to Xnav.XrouteFromMaploc(maploc).Go( ). |
|
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. |
|
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. |
||
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. |
|
None |
Turns your character to face the given maploc, but doesn't go there. |
|
None |
Turns your character to face the given compass heading (in degrees, measured clockwise from north). |
|
Creates and returns a new, empty Xroute object. See Xroute objects for details on the methods and properties of this object. |
||
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. |
||
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. |
||
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:
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. |
||
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. |
||
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. |
||
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. |
||
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. |
||
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). |
|
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; Or in VBScript: Dim i, szTag |
|
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.) |
||
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. |
||
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. |
||
Boolean |
Returns True if the given waypoint is of the Simple type (with no special arrival action), False otherwise. |
|
Decodes map coordinates stored on the given XML element and returns them in maploc form. Useful mainly to implementors of custom waypoint types. |
||
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. |
|
Number |
Returns the 2D distance in map units to the given object. |
|
Number |
Returns the 2D distance in map units to the given maploc. |
|
Number |
Returns the 3D distance in map units to the given 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. |
|
Number |
Returns the difference in compass heading (the amount you'd have to turn by) from your current heading to the given maploc. |
|
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. |
|
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. |
|
Returns a copy of the given maploc with its heading reversed by 180 degrees. |
||
Returns a copy of the given maploc with its heading altered by dhead degrees. dhead may be positive or negative. |
||
Boolean |
Returns True if the given maploc is indoors (in a building or dungeon), False if outdoors. |
|
None |
Enters the portal specified by aco and waits until your character emerges from portal space at the other end. |
|
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.
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 |
---|---|---|
String |
The name, if any, of this route. Defaults to the empty string. |
|
Number |
The number of waypoints in the route, including the final destination. |
|
Number |
The index (counting from zero) of the waypoint from which to resume an interrupted route. (See xroute.ResumeRoute.) |
|
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. |
||
The starting coords of the route, i.e. waypt.maplocIn of the route's first waypoint. |
||
The ending coords of the route, i.e. waypt.maplocOut of the route's last waypoint. |
||
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. |
|
None |
Deletes all waypoints from the route and resets it to an empty state. |
|
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. |
|
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. |
|
None |
Deletes the i th waypoint from the route. |
|
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. |
|
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. |
||
Returns a new Xroute that is an exact copy of 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). |
||
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. |
|
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. |
|
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. |
||
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. |
|
None |
Saves the route to the file named by szFile. Any previous contents of the file are overwritten. |
|
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. |
||
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. |
||
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:
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. |
||
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.
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):
Method or property |
Result type |
Description |
---|---|---|
waypt.maploc |
The waypoint's location. |
|
waypt.distArrive |
Number |
The waypoint's arrival tolerance in map units. When you get this close to waypt.maploc, Xnav thinks you've arrived and moves on to the next waypoint in sequence. This number is not zero for the obvious reason that you can never arrive exactly at the precise target coords; the best you can hope for is to get within a pace or two. The arrival tolerance is configurable so that you can adjust it to suit your situation. For precise cornering, distArrive should be small, on the order of, say, a meter (0.004 MU). In open country, precision is less important and tolerances can be larger. The tradeoff is that greater precision (smaller distArrive) poses a greater risk of overshooting the mark and having to backtrack. |
waypt.Init(maploc, distArrive) |
None |
Sets all of the above parameters with a single call. |
The XML for a Simple waypoint looks like this:
<Simple lat="-28.6681" lng="60.3177" z="21.35" distArrive="0.01" fWalk="False"/>
z (altitude) is optional and may be omitted, but I like to include it as a kind of comment to help keep things straight in multilevel dungeons or towers. fWalk is likewise optional.
Method or property |
Result type |
Description |
---|---|---|
waypt.maploc |
The door's location and heading. You must include the correct heading so that waypt.Arrive can calculate a path aimed squarely through the door. |
|
waypt.szKey |
String |
The name of the key, if any, that unlocks the door. |
waypt.Init(maploc, szKey) |
None |
Sets all of the above parameters with a single call. |
waypt.Arrive( ) |
None |
The waypoint's arrival action, called automatically by Xnav when the waypoint is reached. For Door waypoints this does the following. If the door is already open, it just walks you through, using maploc.head to determine your path through the door. If the door is closed but unlocked, it opens it and then walks through as above. If the door is closed and locked, and szKey is the empty string (""), it throws an error. If szKey is nonempty, it searches your inventory for an item by that name. (Keyrings are not supported in this release.) If the correct key is found, it uses it to unlock the door, then opens it and walks through. If you're not carrying a key of the specified kind, it throws an error. If for some reason you fail to make it through an allegedly open door (perhaps because it slammed in your face just as you started through), waypt.Arrive will back off and retry from the top a couple of times. If you fail to make it through three times in a row, waypt.Arrive throws an error. |
The XML for a Door waypoint looks like this:
<Door lat="-8.1001" lng="72.9272" head="271.8" szKey="Dryreach Key" fWalk="False"/>
szKey and fWalk are optional and may be omitted.
Method or property |
Result type |
Description |
---|---|---|
waypt.maplocIn |
The location of the jumpoff point. |
|
waypt.maplocOut |
The location of the landing point, including accurate altitude (maplocOut.z) so that waypt.Arrive can tell when you've hit bottom. |
|
waypt.healthReq |
Number |
The minimum health needed to survive the jump. |
waypt.Init(maplocIn, maplocOut, healthReq) |
None |
Sets all of the above parameters with a single call. |
waypt.Arrive( ) |
None |
The waypoint's arrival action, called automatically by Xnav when the waypoint is reached. For Jump waypoints this does the following. First it checks to make sure you have at least healthReq points of health. If not, it throws an error. It then jumps you off the ledge and waits until your z coordinate reaches maplocOut.z. If this fails to happen within ten seconds, it throws an error. waypt.Arrive doesn't include any code to heal you before or after the jump, but if you have healing code that works for you, it shouldn't be hard to insert it. |
The XML for a Jump waypoint looks like this:
<Jump healthReq="50" fWalk="False"> <maplocIn lat="-1.082" lng="0.025" z="-42.0"/> <maplocOut lat="-1.1195" lng="0.0250" z="-72.0"/> </Jump>
fWalk is optional and may be omitted.
Method or property |
Result type |
Description |
---|---|---|
waypt.szName |
String |
The portal name, i.e. aco.szName of the portal's ACO. |
waypt.maplocIn |
The portal's location. |
|
waypt.maplocOut |
The portal's destination coords. |
|
waypt.Init(szName, maplocIn, maplocOut) |
None |
Sets all of the above parameters with a single call. |
waypt.Arrive( ) |
None |
The waypoint's arrival action, called automatically by Xnav when the waypoint is reached. For Portal waypoints this checks the immediate neighborhood of maplocIn for a portal whose name matches szName. If it fails to find one, it will accept any portal at the correct coords. It then calls Xnav.UseAcoPortal to initiate portal travel and wait for emergence from portal space. |
The XML for a Portal waypoint looks like this:
<Portal szName="Abandoned Mine" fWalk="False">
<maplocIn lat="34.904" lng="54.505"/>
<maplocOut lat="-0.476" lng="-0.046"/>
</Portal>
fWalk is optional and may be omitted.
Method or property |
Result type |
Description |
---|---|---|
waypt.szRecall |
String |
The specific recall command ("@lifestone" or whatever). |
waypt.maplocIn |
The location to recall from. This can be Nothing (null in JScript) to recall from wherever you happen to be standing, or it can be a specific location if you want to go there first before recalling. |
|
waypt.maplocOut |
The recall destination coords. |
|
waypt.Init(szRecall, maplocIn, maplocOut) |
None |
Sets all of the above parameters with a single call. |
waypt.Arrive( ) |
None |
The waypoint's arrival action, called automatically by Xnav when the waypoint is reached. For Recall waypoints this issues the recall command by pasting the text of szRecall into the chat line and pressing Enter. It then calls Xnav.WaitForPortal to wait for the recall to complete. |
The XML for a Recall waypoint looks like this:
<Recall szRecall="@lifestone" fWalk="False">
<maplocIn lat="25.123" lng="54.655"/>
<maplocOut lat="-73.2092" lng="20.2947"/>
</Recall>
The maplocIn element is optional and may be omitted. fWalk is likewise optional.
Method or property |
Result type |
Description |
---|---|---|
waypt.xroute |
The route to include. If you want to save this waypoint to a file, waypt.xroute must refer to another named route in the same file. Including routes from different files is not supported. |
|
waypt.fReverse |
Boolean |
True if waypt.xroute should be executed in reverse order. The default is False (forward order). |
waypt.Init(xroute, fReverse) |
None |
Sets all of the above parameters with a single call. |
waypt.Arrive( ) |
None |
The waypoint's arrival action, called automatically by Xnav when the waypoint is reached. For Include waypoints this executes the included route in forward or reverse order as specified by waypt.fReverse. |
The XML for an Include waypoint looks like this:
<Include szName="Jumpoff" fReverse="False" fWalk="False"/>
where szName is the name of the included route, which must be defined in the same Xroute file as the including route. fReverse and fWalk are optional and may be omitted.
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 |
---|---|---|
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. |
|
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. |
|
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. |
||
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. |
||
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. |
|
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. |
|
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. |
|
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. |
||
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. |
|
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. |
|
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:
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 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 |
---|---|---|
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. |
|
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.
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 |
---|---|---|
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. |
|
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. |
|
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.
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. |
Version 1.2 (released November 18, 2004):