SkunkNav.js contains navigation code for moving your character from place to place under script control. Features include:
Although written in JScript, SkunkNav can be included in any SkunkWorks project and called from any scripting language.
A route is a JScript object embodying a sequence of map locations (maplocs) to be visited in order on the way to a final destination maploc. Maplocs may be obtained from any of the SkunkWorks location functions, or from any ACO using its aco.maploc property.
You can create an empty route object in JScript as follows:
var route = new Route();
or in other scripting languages (such as VBScript) by calling the RouteNew function:
Dim route
Set route = RouteNew()
You can also get route objects from the RouteFromMaploc and RouteFromFile functions.
Once created, a route object has the following properties and methods:
Method or property |
Result type |
Description |
---|---|---|
String |
The name, if any, of this route. Defaults to the empty string. |
|
String |
If the route starts with a house or lifestone recall, the @ command that invokes it. Otherwise the empty string. |
|
Long |
The number of points in the route, including the final destination. |
|
Returns the i th waypoint in the route (where points are numbered starting at zero). |
||
JScript array |
Provides direct access to the array of points in the route. Accessible only from JScript. |
|
Long |
The index (counting from zero) of the waypoint from which to resume an interrupted route. |
|
Long |
If non-zero, the maximum time in seconds needed to execute this route. If execution takes longer than this, something must have gone astray and the route should be terminated. The default value is zero (no timeout). |
|
None |
Deletes all points from the route and resets it to an empty state. |
|
None |
Adds a point to the route. Use this method to build up your route point by point. i is optional; if present, the new point is inserted before the i th waypoint (counting from zero). If omitted, the new point is appended to the end of the route. |
|
None |
Adds your current location to the route. i is optional; if present, the new point is inserted before the i th waypoint (counting from zero). If omitted, the new point is appended to the end of the route. |
|
None |
Adds a door to the route. acoDoor is the door to be added, and must be a valid ACO. If the door is closed when your character gets there, route.Go will open it. (If the door is locked, you're on your own; there's no provision here for unlocking it.) i is optional; if present, the new point is inserted before the i th waypoint (counting from zero). If omitted, the new point is appended to the end of the route. |
|
None |
Adds a portal to the route. acoPortal is the portal to be added, and must be a valid ACO. When your character gets there, route.Go will portal through and then continue on to the next waypoint following the portal. i is optional; if present, the new point is inserted before the i th waypoint (counting from zero). If omitted, the new point is appended to the end of the route. |
|
None |
Deletes the i th waypoint from the route. |
|
None |
Appends the points in route2 to the end of this route, concatenating the two routes. route2 is not modified by this method (but this route is). |
|
Returns a new route object representing the concatenation of this route with route2. Neither this route nor route2 is modified by this method. If fOptimize is false, the two routes are concatenated verbatim. If true, redundant points at the juncture of the two routes are pruned away. Thus if route2 is the exact reverse of this route, the concatenation will be empty (if fOptimize is true). If only part of route2 matches the reversal of this route, 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: routeA2B = routeA.RouteReverse().RouteConcat(routeB, 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 route object with with the order of the points reversed. Use this method to backtrack along a route. Note that since travel by recall or portal is one-way, using RouteReverse on a route containing a recall or portal may not yield sensible results unless the route defines an explicit reverse route. See Route file format for details. |
||
None |
Saves the route to the file named by szFile. Any previous contents of the file are overwritten. |
|
None |
Loads a route from the file named by szFile. The previous contents of the route object are lost. szFile can be either a simple filename such as "MyFile.route" or a filename followed by a route name in square brackets, such as "MyFile.route[MyRoute]". Use the latter form to load a specific route from a file containing several named routes. The specified route file can be one created by route.SaveToFile, one you've typed in manually or created using RouteMaker, or one you've exported from AC Explorer Pro. See Route file format for information on how to create routes manually. If you're going to use route.FromFile to read ACX Pro route files, 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 40 paces). While they work 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. |
|
None |
Saves the route to an open text stream. Use this method to embed routes in other file types, or to save several routes to a single file. If the route has a name (i.e. if route.szName is nonempty), the route is labelled in the file with its name so it can be found again by route.FromFile. See Route file format for details. |
|
None |
Loads a route from an open text stream. The previous contents of the route object are lost. Use this method to read routes embedded in other files types, or to read several routes consecutively from a single file. |
|
None |
Moves your character from point to point along the route to the endpoint. Where possible, intermediate waypoints are taken at full running speed; where waypoints are close together, you may slow to a walk, or even stop momentarily for sharp turns. If the route includes doors, route.Go will inspect them and open them as needed. If it includes portals, route.Go will Use them and wait for you to emerge from portal space before continuing. If along the way you get stuck in a corner or something so that no progress is made for ten seconds, route.Go attempts to back out and try again from a different angle. (But don't expect miracles if you get stuck indoors.) If a door slams in your face just as you're about to go through it, route.Go should notice that no progress is being made and try to reopen the door. route.Go returns when any one of the following conditions is met:
In the first case (safe arrival), route.imaploc will equal route.cmaploc on return from route.Go. In all other cases, imaploc will be less than cmaploc. |
|
None |
Stops execution of a route in progress. Call this from an event handler to interrupt route.Go and return control to the caller of route.Go. |
|
None |
Resumes execution of an interrupted route. This is just like route.Go except that execution starts at route.imaploc instead of at the beginning of the route. |
A route file is a text file containing instructions for routing your character from place to place. You can create a route file using any text editor (such as Notepad), or interactively using the RouteMaker sample project.
In its simplest form, a route file is just a list of locations, one per line, in standard latitude-and-longitude notation. Blank lines are ignored, as are comment lines beginning with "//". Terminate the route with a line containing the word "Stop". So for instance:
// This line is ignored.
13.645N 0.543E
13.654N 0.251E
13.820N 0.096E
Stop
To specify a timeout, begin with a line containing the word "Timeout" and the desired timeout interval in seconds. For instance:
// This route shouldn't take more than 60 seconds.
Timeout 60
13.645N 0.543E
...
If you want to begin a route by recalling to your house or lifestone, put the relevant recall command on a line by itself before your first waypoint:
@house recall
13.645N 0.543E
...
Or:
@lifestone
13.645N 0.543E
...
To include a door or portal, put the name of the object after its location, separated by a semicolon, like so:
13.942N 0.694E;Door
14.821N 0.690E;Cragstone Portal
Routes that include recalls or portals can't be reversed automatically by route.RouteReverse, since recall and portal travel is one-way. However you can include an explicit reverse route by entering the word "Reverse" followed by a second list of coordinates, like so:
// Cragstone to Zaikhal:
25.945N 48.400E
26.175N 48.227E
26.381N 48.570E;Zaikhal Portal
14.410N 0.949E
Reverse
// Zaikhal to Cragstone:
14.410N 0.949E
14.821N 0.690E;Cragstone Portal
25.941N 48.341E
Stop
Or:
// House to lifestone:
@lifestone
Reverse
// Lifestone to house:
@house recall
Stop
In this case, when you call route.RouteReverse you get the explicit reversal rather than the automatically calculated one.
You can store multiple routes in one file by prefixing each one with a name in square brackets, like so:
[CtoZ]
// Cragstone to Zaikhal:
25.945N 48.400E
26.175N 48.227E
26.381N 48.570E;Zaikhal Portal
14.410N 0.949E
Reverse
// Zaikhal to Cragstone:
14.410N 0.949E
14.821N 0.690E;Cragstone Portal
25.941N 48.341E
Stop
[HtoL]
// House to lifestone:
@lifestone
Reverse
// Lifestone to house:
@house recall
Stop
The names can be any text you like, so long as they're unique within each file. To load a specific route from a multi-route file, append the route name, in square brackets, to the filename when you call RouteFromFile:
var route = RouteFromFile("MyRoutes.route[HtoL]");
In addition to the route object and its methods, SkunkNav provides the following global functions and variables:
Function or variable |
Result type |
Description |
---|---|---|
Creates and returns a new, empty route object. |
||
Creates and returns a direct, straight-line route (i.e. a route of just one point) to the given location. |
||
Creates and returns a new route object from the contents of the named file. This is just like route.FromFile except that it creates a new route object for you instead of loading into an existing route object. |
||
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 RouteFromMaploc(maploc).Go( ). |
|
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). |
|
Double |
Returns the 2D distance in map units to the given maploc. |
|
Double |
Returns the 3D distance in map units to the given maploc. |
|
Double |
Returns the compass heading to the given maploc, i.e. the direction you'd have to face to be aimed at that maploc. |
|
Double |
Returns the difference in compass heading (the amount you'd have to turn by) from your current heading to the given maploc. |
|
Double |
Returns the 2D distance in map units from maploc1 to maploc2. |
|
Double |
Returns the 3D distance in map units from maploc1 to maploc2. |
|
Double |
Returns the compass heading from maploc1 to maploc2. |
|
Returns the location of the currently selected object in maploc form, or null if the selected object has no defined geographical location (for instance if it's in your inventory). |
||
None |
Enters the currently selected portal and waits until your character emerges from portal space at the other end. |
|
Long |
Controls the amount of trace output generated by SkunkNav. Trace output goes to the debug log and may be viewed using DebugView or some similar utility. Set this variable to zero for no trace output, 1 for partial trace output, or 2 for full trace output. The default is 1 (partial output). |
Those of you migrating from ACScript may have old scripts based on ACScript's NavLib library. While NavLib should continue to work with SkunkWorks, I've provided the following compatibility functions in SkunkNav in case you want to change over. I haven't spent much effort on documenting them because (a) the originals in NavLib.js aren't terribly well documented, and (b) you really ought to use the native SkunkNav functions above instead. These compatibility functions are provided solely to make it easier to port your script incrementally from NavLib to SkunkNav.
HeadingTurn(headingNow, headingIntended)
Loc2Coords(landblock)
LocXY2Coords(landblock, x, y)
DebugPosition()
headingXY(xEW_From, yNS_From, xTo, yTo)
distance(xEW, yNS, xEWCur, yNSCur)
HeadingCurrent()
TurnToHeading(headingNew, coefficient)
RunTowardsxEWyNS(xEW, yNS, xEWCur, yNSCur, heading)
GetXEWCur()
GetYNSCur()
StepForward()
SmallJump()
PointToHeading(headingNew)
RunTowardsEastNorth(xEW, yNS)
RunTowardsXY_Ex(xEW, yNS)