Author: Jaga Te'lesin
Author Website: http://home.earthlink.net/~johncboat/AreaTransV1.zip (Script Download)
Script Name: Seamless Area Transition
Description: A seamless, configurable, and powerful edge-to-edge area transition for you all to play with.  It comes with a readme for instructions, a demo Module to show off it's capabilities, and an importable ERF for your existing module(s).
Author Comments: A list of it's benefits...
  1. Only 1 script to install, period!
  2. No Heartbeat hooks for minimum CPU hit.
  3. Customizable settings for transition sensitivity.
  4. Capability for totally irregular "triggers" for transitions if the user desires.
  5. Not just N/S/E/W transitions, but DIAGONAL area transitions as well!
  6. Object error-handling code so it won't crash your server.
  7. Optimized use of variables to minimize memory usage over a long period of time.
  8. Requires VERY few changes to any existing module, other than square linked area size.
  9. No Waypoints at all to create!  A smart script KNOWS where to send the character(s).
Instructions on Use: Q. What is it?
A. A very easy to use, powerful, and configurable "seamless area transitioner" for Neverwinter Nights.  It "links" module areas edge-to-edge seamlessly.  Built primarily for large, open worlds it's the ideal solution.  It can work equally well for smaller modules if need be.


Q. How do I install it into my Module?
A. Simply copy the contents of the script named "area_trans" to one in your module of the same name.  If you choose to name it differently, remember the new name for later.  Or, optionally import the .ERF file included in this Zip into your module.


Q. How do I use it?
A. As the enclosed demo shows, areas are surrounded by generic "triggers", all identical except for their orientation.  I prefer to make them 4 tiles long by 1/3 of a tile wide, then completely surround each of the areas I want to link with the triggers.  Each trigger refers to the area_trans script in only one place:  the OnEnter event for itself.  Once you have the triggers in place, and their OnEnter setup, you need to change the Tags on your linked areas...


Q. How do I setup my areas so they become linked?
A. Easier than you'd think.  They are in a "matrix" arrangement, as the diagram below shows:

           X  values
 Y
     000_000  001_000  002_000
 v
 a   000_001  001_001  002_001
 l
 u   000_002  001_002  002_002
 e
 s


You can use a matrix as large as 000 through 999 for the area setup, giving you effectively 1 million linked areas, but I can't ever imagine someone going that nuts with it.  The Area TAG names NEED TO BE CHANGED to a format following the example above: lower numbers for X and Y are toward the upper left, larger toward the lower right.  If you need more clairification, check out the TAG names for the Areas in the sample module.  It should make more sense then.  Simply make sure the numbers you use are all 3 digit, sequential, and separated by underscores (_).

Last but not least, make sure the three user-configurable variables in the script itself are set correctly.  The first is the most important.  If it isn't set right, the links won't work at all.  If your areas are 8x8 as in the example mod, the "float fMaxAreaDim = 80.0f;" line is already correct.  It's 10.0f per square in the area, and the areas *MUST* be completely square (ie - 10x10, 15x15, etc).  The other two settings don't really need to be changed, but are there for you to tweak if they don't quite fit your circumstances.

Script 1:

/////////////////////////////////////////////////////////
///  You can download the entire ZIP at the following
///  web address:
///  http://home.earthlink.net/~johncboat/AreaTransV1.zip
/////////////////////////////////////////////////////////

script_code:  //////////////////////////////////////////////////////////
//////  ALL-IN-ONE SEAMLESS AREA TRANSITIONER (NWN) //////
//////  Date:  July 16, 2002  -  Version 1.0        //////
//////  Created by:  Jaga Te'lesin                  //////
//////  jaga-nwn@earthlink.net                      //////
//////////////////////////////////////////////////////////
//////    Copyright Notice:                         //////
//////  You may use this script for personal use    //////
//////  however you like.  But if you redistribute  //////
//////  you *must* leave all code untouched and     //////
//////  with all comments intact.                   //////
//////////////////////////////////////////////////////////

void main()
{
    float fMaxAreaDim = 80.0f;      // 10.0 per tile in one dimension.  Areas under 4x4 not recommended.
                                    //   Note:  Linked areas -should- be square only!
    float fLandingOffset = 8.0f;    // Distance out from edge in destination Area that PC will land (8 to 10 recommended)
    float fDiagTransSize = 14.0f;   // Size out from any corner to sense diagonal movement (10 to 20 recommended)

    object oPC = GetEnteringObject();
    if ((oPC != OBJECT_INVALID) && (GetIsPC(oPC)))
    {
        location lPCLoc = GetLocation(oPC);
        vector vPCVector = GetPositionFromLocation(lPCLoc);
        float vNorthDist = fMaxAreaDim - vPCVector.y;
        float vSouthDist = vPCVector.y;
        float vEastDist = fMaxAreaDim - vPCVector.x;
        float vWestDist = vPCVector.x;
        float fLeast = fMaxAreaDim;
        int nDir;
        if (vNorthDist <= fLeast)
        {
            nDir = 1;  // NORTH
            fLeast = vNorthDist;
        }
        if (vSouthDist <= fLeast)
        {
            nDir = 2;  // SOUTH
            fLeast = vSouthDist;
        }
        if (vEastDist <= fLeast)
        {
            nDir = 3;  // EAST
            fLeast = vEastDist;
        }
        if (vWestDist <= fLeast)
        {
            nDir = 4;  // WEST
            fLeast = vWestDist;
        }
        if ((vSouthDist > (fMaxAreaDim-fDiagTransSize)) && (vWestDist < fDiagTransSize))
            nDir = 5;  // NORTHWEST
        if ((vSouthDist > (fMaxAreaDim-fDiagTransSize)) && (vWestDist > (fMaxAreaDim-fDiagTransSize)))
            nDir = 6;  // NORTHEAST
        if ((vSouthDist < fDiagTransSize) && (vWestDist < fDiagTransSize))
            nDir = 7;  // SOUTHWEST
        if ((vSouthDist < fDiagTransSize) && (vWestDist > (fMaxAreaDim-fDiagTransSize)))
            nDir = 8;  // SOUTHEAST

        string sDestAreaX, sDestAreaY, sDestAreaTag;
        string sCurAreaTag = GetTag(GetArea(oPC));
        string sCurAreaX = GetStringLeft(sCurAreaTag,3);
        string sCurAreaY = GetStringRight(sCurAreaTag,3);
        int nCurAreaX = StringToInt(sCurAreaX);
        int nCurAreaY = StringToInt(sCurAreaY);
        switch (nDir)
        {
            case 1:  // NORTH
            {
                --nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY > 9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sCurAreaX + "_" + sDestAreaY;
                break;
            }
            case 2:  // SOUTH
            {
                ++nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY >9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sCurAreaX + "_" + sDestAreaY;
                break;
            }
            case 3:  // EAST
            {
                ++nCurAreaX;
                if (nCurAreaX <= 9) sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                sDestAreaTag = sDestAreaX + "_" + sCurAreaY;
                break;
            }
            case 4:  // WEST
            {
                --nCurAreaX;
                if (nCurAreaX <= 9)
                    sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                sDestAreaTag = sDestAreaX + "_" + sCurAreaY;
                break;
            }
            case 5:  // NORTHWEST
            {
                --nCurAreaX;
                if (nCurAreaX <= 9) sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                --nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY > 9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sDestAreaX + "_" + sDestAreaY;
                break;
            }
            case 6:  // NORTHEAST
            {
                ++nCurAreaX;
                if (nCurAreaX <= 9)
                    sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                --nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY >9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sDestAreaX + "_" + sDestAreaY;
                break;
            }
            case 7:  // SOUTHWEST
            {
                --nCurAreaX;
                if (nCurAreaX <= 9)
                    sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                ++nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY >9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sDestAreaX + "_" + sDestAreaY;
                break;
            }
            case 8:  // SOUTHEAST
            {
                ++nCurAreaX;
                if (nCurAreaX <= 9)
                    sDestAreaX = "00" + IntToString(nCurAreaX);
                else if ((nCurAreaX > 9) && (nCurAreaX <= 99))
                         sDestAreaX = "0" + IntToString(nCurAreaX);
                     else sDestAreaX = IntToString(nCurAreaX);
                ++nCurAreaY;
                if (nCurAreaY <= 9) sDestAreaY = "00" + IntToString(nCurAreaY);
                else if ((nCurAreaY >9) && (nCurAreaY <=99))
                         sDestAreaY = "0" + IntToString(nCurAreaY);
                     else sDestAreaY = IntToString(nCurAreaY);
                sDestAreaTag = sDestAreaX + "_" + sDestAreaY;
                break;
            }

        }
        object oDestArea = GetObjectByTag(sDestAreaTag);
        if (oDestArea != OBJECT_INVALID)
        {
            vector vDestVect;
            location lNewLoc;
            switch (nDir)
            {
                case 1:  // NORTH
                {
                    lNewLoc = Location(oDestArea,Vector(vPCVector.x,fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 2:  // SOUTH
                {
                    lNewLoc = Location(oDestArea,Vector(vPCVector.x,fMaxAreaDim - fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 3:  // EAST
                {
                    lNewLoc = Location(oDestArea,Vector(fLandingOffset,vPCVector.y),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 4:  // WEST
                {
                    lNewLoc = Location(oDestArea,Vector(fMaxAreaDim - fLandingOffset,vPCVector.y),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 5:  // NORTHWEST
                {
                    lNewLoc = Location(oDestArea,Vector(fMaxAreaDim - fLandingOffset,fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 6:  // NORTHEAST
                {
                    lNewLoc = Location(oDestArea,Vector(fLandingOffset,fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 7:  // SOUTHWEST
                {
                    lNewLoc = Location(oDestArea,Vector(fMaxAreaDim - fLandingOffset,fMaxAreaDim - fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
                case 8:  // SOUTHEAST
                {
                    lNewLoc = Location(oDestArea,Vector(fLandingOffset,fMaxAreaDim - fLandingOffset),GetFacingFromLocation(lPCLoc));
                    break;
                }
            }
            AssignCommand(oPC,ClearAllActions());
            AssignCommand(oPC,JumpToLocation(lNewLoc));
        }
    }
}