//:://///////////////////////////////////////////// //:: area_trans //::////////////////////////////////////////////// /* SEAMLESS AREA TRANSITIONS v1.1 Version 1: - areas can be different sizes - a module can have more than one grid ("Region") Version 1.1: - SetLocalInt(oPC, "AREATRANS_DIRECTION_BACKUP", nDir) new local integer used in diagonal transitions if the diagonal direction fails, the nearest cardinal direction (N, S, E, or W) is used in its place to find a transition area - int AREATRANS_SQUARES_PER_GRID_UNIT new global used to correct math error in FindAreaContainingGridTag() - string GetDirectionName(int nDir) new function to encapsulate code for generating name from direction integer Otherwise this script shares functionality with and is compatible with Jaga's Seamless Area Transitioner. http://nwvault.ign.com/View.php?view=scripts.Detail&id=89 by Jaga Te'lesin (jaga-nwn@earthlink.net) Jaga's work was the inspiration for this rewrite. For instructions please see the Read Me. */ //::////////////////////////////////////////////// //:: Created: The Magus (2013 mar 9) //:: Modified: The Magus (2013 mar 12) v1.1 //::////////////////////////////////////////////// // GLOBALS --------------------------------------------------------------------- // USER CONFIGURABLE object AREATRANS_DATA = GetModule(); // Data Object holding area tags for each grid coord const int AREATRANS_DEBUG = FALSE; // TRUE turns debugging feedback on const int AREATRANS_GRID_CARTESIAN = FALSE; // use FALSE If this script is replacing Jaga's AreaTrans in an existing module // The original Area Trans Grid was NOT cartesian // TRUE will expect Grid coordinates to be cartesian const float AREATRANS_DIAGONAL_OFFSET = 3.5f; // Distance out from any corner to sense diagonal movement (8 to 15 recommended) const float AREATRANS_LANDING_OFFSET = 4.0f; // Distance out from edge in destination Area that PC will land (8 to 10 recommended) const float AREATRANS_DELAY = 0.0f; // Delay before zoning const float AREATRANS_REFACTORY_PERIOD = 9.0f; // delay to prevent zoning on arrival in new area const int AREATRANS_FLEXIBLE_GRID = TRUE; // TRUE - each area regardless of size occupies only one grid coordinate // FALSE - an area depending on size, may occupy more than one grid coordinate. See below. const float AREATRANS_GRID_UNIT = 40.0; // INFLEXIBLE GRIDS: // default area dimension in meters for each grid. // This becomes the smallest size you can use for a dimension of an area // The dimensions of larger areas must be a multiple of this figure. // FLEXIBLE GRID: // Unused int AREATRANS_SQUARES_PER_GRID_UNIT = FloatToInt(AREATRANS_GRID_UNIT/10.0); // DO NOT ADJUST THESE Directional constants const int ERROR = -1; const int NORTH = 1; // bit 1 const int SOUTH = 2; // bit 2 const int EAST = 4; // bit 3 const int WEST = 8; // bit 4 const int NORTHEAST = 5; // north + east const int SOUTHEAST = 6; // south + east const int NORTHWEST = 9; // north + west const int SOUTHWEST = 10; // south + west // OTHER DATA ------------------------------------------------------------------ struct GRIDCOORD { string prefix; string Xtag; string Ytag; string Ztag; int Xpos; int Ypos; int Zpos; }; // FUNCTION DECLARATIONS ------------------------------------------------------- // leftover from Jaga's Seamless Area Transitioner. To be modified someday with unique VFX. - [FILE: area_trans] void TransportEffect( object oTarget , float fDuration ); // Converts an integer to a string for use in the grid coord tag - [FILE: area_trans] string GetCoordString(int nCoord); // Returns the first prefix of a tag, without the underscore - [FILE: area_trans] string GetTagPrefix(string sTag); // Takes a Grid Tag and breaks it down into its components - [FILE: area_trans] struct GRIDCOORD ParseGridTag(string sGridTag); // Returns a tag representing coordinates on grid - [FILE: area_trans] string GetGridTagAtPositionInArea(struct GRIDCOORD GridCoord, vector vPosition); // Returns a tag representing coordinates on grid - [FILE: area_trans] string GetGridTagAtDirection(struct GRIDCOORD GridCoord, int nDir, int nDist=1); // Called by GetTransitionArea. - [FILE: area_trans] // Looks for the area origin, by crawling from one grid node to the next FROM the grid node that the PC is transitioning to object FindAreaContainingGridTag(string sDestGridTag, int nDir, object oPC); // Returns an integer representing the direction that the PC is transitioning from the area - [FILE: area_trans] // returns -1 on Error int GetTransitionDirection(vector vPCVector, float fAreaThisHeight, float fAreaThisWidth, object oPC); // Returns the name of the direction - [FILE: area_trans] string GetDirectionName(int nDir); // Returns an area object in nDir direction from the grid coords sPCGridTag - [FILE: area_trans] object GetTransitionArea(string sDestGridTag, int nDir, object oPC); // FUNCTION IMPLEMENTATIONS ---------------------------------------------------- void TransportEffect (object oTarget, float fDuration) { effect eZoneEffect1 = EffectVisualEffect(VFX_DUR_INVISIBILITY); //effect eZoneEffect2 = EffectVisualEffect(VFX_IMP_ACID_L); ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eZoneEffect1,oTarget,(fDuration*2.0f)); //ApplyEffectToObject(DURATION_TYPE_INSTANT,eZoneEffect2,oTarget); } string GetCoordString(int nCoord) { string sCoord = IntToString(abs(nCoord)); if ((nCoord < 10) && (nCoord > -1)) return ("p0"+sCoord); else if ((nCoord > 9) && (nCoord < 100)) return ("p"+sCoord); else if ((nCoord > -10) && (nCoord < 0)) return ("n0"+sCoord); else if ((nCoord > -100) && (nCoord < -9)) return ("n"+sCoord); return ""; } string GetTagPrefix(string sTag) { string sTagPrefix = ""; int iPos1 = FindSubString(sTag, "_"); int iPos2; int iLastPos = GetStringLength(sTag)-1; if (iPos1 > 0) { sTagPrefix = GetStringLeft(sTag, iPos1); // returns prefix without underscores } else if (iPos1 == 0) { // we have a leading underscore iPos2 = FindSubString(sTag, "_", ++iPos1);// look for a second underscore if (iPos2 != -1 && iPos2 != 1 && iPos2 != iLastPos) // ignore: _XXXXX , __XXXX , _XXXX_ { sTagPrefix = GetSubString(sTag, iPos1, iPos2 - iPos1); } } return sTagPrefix; } struct GRIDCOORD ParseGridTag(string sGridTag) { struct GRIDCOORD GridCoord; GridCoord.prefix = GetStringLeft(sGridTag, (GetStringLength(sGridTag)-9) ); string sAreaTagCoord = GetStringRight(sGridTag, 9); GridCoord.Xtag = GetStringLeft(sAreaTagCoord,3); // X-coordinate of current area (from Tag) GridCoord.Ytag = GetSubString(sAreaTagCoord,3,3); // Y-coordinate of current area (from Tag) GridCoord.Ztag = GetStringRight(sAreaTagCoord,3); // Z-coordinate of current area (from Tag) GridCoord.Xpos = StringToInt(GetStringRight(GridCoord.Xtag,2)); if(!(GetStringLeft(GridCoord.Xtag,1)=="p")) GridCoord.Xpos *= -1; GridCoord.Ypos = StringToInt(GetStringRight(GridCoord.Ytag,2)); if(!(GetStringLeft(GridCoord.Ytag,1)=="p")) GridCoord.Ypos *= -1; GridCoord.Zpos = StringToInt(GetStringRight(GridCoord.Ztag,2)); if(!(GetStringLeft(GridCoord.Ztag,1)=="p")) GridCoord.Zpos *= -1; return GridCoord; } string GetGridTagAtPositionInArea(struct GRIDCOORD GridCoord, vector vPosition) { int nPosX = GridCoord.Xpos + FloatToInt( (vPosition.x/AREATRANS_GRID_UNIT) ); int nPosY; // This bit of code is required to make this code compatible with the original seamless area trans grid coordinates // the original seamless area transitions used a non-cartesian grid in which numbers increased going south and east // On a cartesian grid numbers increase going north and east if(!AREATRANS_GRID_CARTESIAN) nPosY = GridCoord.Ypos - FloatToInt( (vPosition.y/AREATRANS_GRID_UNIT) ); else nPosY = GridCoord.Ypos + FloatToInt( (vPosition.y/AREATRANS_GRID_UNIT) ); // construct grid tag in same manner as area tag return( GridCoord.prefix + GetCoordString(nPosX) + GetCoordString(nPosY) + GridCoord.Ztag ); } string GetGridTagAtDirection(struct GRIDCOORD GridCoord, int nDir, int nDist=1) { int nPosX = GridCoord.Xpos; int nPosY = GridCoord.Ypos; if(AREATRANS_GRID_CARTESIAN) { //if(nDir==NORTH || nDir==NORTHEAST || nDir==NORTHWEST) if(nDir&NORTH) nPosY += nDist; //else if(nDir==SOUTH || nDir==SOUTHEAST || nDir==SOUTHWEST) else if(nDir&SOUTH) nPosY -= nDist; } else { //if(nDir==NORTH || nDir==NORTHEAST || nDir==NORTHWEST) if(nDir&NORTH) nPosY -= nDist; //else if(nDir==SOUTH || nDir==SOUTHEAST || nDir==SOUTHWEST) else if(nDir&SOUTH) nPosY += nDist; } //if(nDir==EAST || nDir==NORTHEAST || nDir==SOUTHEAST) if(nDir&EAST) nPosX += nDist; //else if(nDir==WEST || nDir==NORTHWEST || nDir==SOUTHWEST) else if(nDir&WEST) nPosX -= nDist; // construct grid tag in same manner as area tag return( GridCoord.prefix + GetCoordString(nPosX) + GetCoordString(nPosY) + GridCoord.Ztag ); } object FindAreaContainingGridTag(string sDestGridTag, int nDir, object oPC) { // if nothing is found look for the valid area tag by cycling through nearby grid coordinates string sAreaGridTag; int nMax = FloatToInt(320.0/AREATRANS_GRID_UNIT)-1; int nMaxSouth, nMaxWest, nDist; int nSouth, nWest; if(nDir!=NORTH) nMaxSouth = nMax; if(nDir!=EAST) nMaxWest = nMax; struct GRIDCOORD SearchCoord = ParseGridTag(sDestGridTag); object oArea = OBJECT_INVALID; while(oArea==OBJECT_INVALID) { if(nSouth (fAreaThisHeight-10.0)); if(!bNorth) bSouth = (vPCVector.y <= 10.0); bEast = (vPCVector.x > (fAreaThisWidth-10.0)); if(!bEast) bWest = (vPCVector.x <= 10.0); // On Northern edge tile (area) if(bNorth) { // On North-Eastern corner tile if(bEast) { float fNorthDist = fAreaThisHeight - vPCVector.y; // Distance from North edge float fEastDist = fAreaThisWidth - vPCVector.x; // Distance from East edge if(fNorthDist<=AREATRANS_DIAGONAL_OFFSET && fEastDist<=AREATRANS_DIAGONAL_OFFSET) { nDir = NORTHEAST; if(fEastDist((10.0*nAreaDestWidth)-AREATRANS_LANDING_OFFSET)) fX = ((10.0*nAreaDestWidth)-AREATRANS_LANDING_OFFSET); fY = AREATRANS_LANDING_OFFSET; } else if(nDir==SOUTH) { int nAreaDestWidth = GetAreaSize(AREA_WIDTH, oAreaDest); fX = vPCVector.x * (nAreaDestWidth/IntToFloat(nAreaThisWidth)); if(fX((10.0*nAreaDestWidth)-AREATRANS_LANDING_OFFSET)) fX = ((10.0*nAreaDestWidth)-AREATRANS_LANDING_OFFSET); fY = (10.0*GetAreaSize(AREA_HEIGHT, oAreaDest)) - AREATRANS_LANDING_OFFSET; } else if(nDir==EAST) { int nAreaDestHeight = GetAreaSize(AREA_HEIGHT, oAreaDest); fX = AREATRANS_LANDING_OFFSET; fY = vPCVector.y * (nAreaDestHeight/IntToFloat(nAreaThisHeight)); if(fY((10.0*nAreaDestHeight)-AREATRANS_LANDING_OFFSET)) fY = ((10.0*nAreaDestHeight)-AREATRANS_LANDING_OFFSET); } else if(nDir==WEST) { int nAreaDestHeight = GetAreaSize(AREA_HEIGHT, oAreaDest); fX = (10.0*GetAreaSize(AREA_WIDTH, oAreaDest)) - AREATRANS_LANDING_OFFSET; fY = vPCVector.y * (nAreaDestHeight/IntToFloat(nAreaThisHeight)); if(fY((10.0*nAreaDestHeight)-AREATRANS_LANDING_OFFSET)) fY = ((10.0*nAreaDestHeight)-AREATRANS_LANDING_OFFSET); } else if(nDir==NORTHEAST) { fX = AREATRANS_LANDING_OFFSET; fY = AREATRANS_LANDING_OFFSET; } else if(nDir==SOUTHEAST) { fX = AREATRANS_LANDING_OFFSET; fY = (10.0*GetAreaSize(AREA_HEIGHT, oAreaDest)) - AREATRANS_LANDING_OFFSET; } else if(nDir==SOUTHWEST) { fX = (10.0*GetAreaSize(AREA_WIDTH, oAreaDest)) - AREATRANS_LANDING_OFFSET; fY = (10.0*GetAreaSize(AREA_HEIGHT, oAreaDest)) - AREATRANS_LANDING_OFFSET; } else if(nDir==NORTHWEST) { fX = (10.0*GetAreaSize(AREA_WIDTH, oAreaDest)) - AREATRANS_LANDING_OFFSET; fY = AREATRANS_LANDING_OFFSET; } } if(AREATRANS_DEBUG) { SendMessageToPC(oPC,"AREA FROM ("+GetTag(oAreaThis)+") TO ("+GetTag(oAreaDest)+")"); SendMessageToPC(oPC,"GRID FROM ("+GetGridTagAtPositionInArea(AreaThis,vPCVector)+") TO ("+sDestGridTag+")"); SendMessageToPC(oPC,"POSITION FROM ("+FloatToString(vPCVector.x,6)+", "+FloatToString(vPCVector.y,6)+") TO ("+FloatToString(fX,6)+", "+FloatToString(fY,6)+")"); } if(oAreaDest!=OBJECT_INVALID) { //if(!GetIsPC(oPC)) // SetCommandable(TRUE, oPC); // Enable pursuit - by providing transition to go to //SetLocalObject(oPC, "TRANSITION_LAST", OBJECT_SELF); //SetLocalLocation(oPC,"TRANSITION_LAST", lLocPC); //effect eZoneEffect3 = EffectVisualEffect(VFX_IMP_ACID_L); // ZoneIn effect for end-of-transition location lDestination = Location(oAreaDest, Vector(fX, fY), GetFacingFromLocation(lLocPC)); SetLocalInt(oPC,"m_nZoning",TRUE); TransportEffect(oPC,AREATRANS_DELAY); string sDir = GetDirectionName(nDir); SendMessageToPC(oPC, "... heading "+GetStringUpperCase(GetStringLeft(sDir,1))+GetStringRight(sDir,GetStringLength(sDir)-1)+" ..."); DelayCommand( AREATRANS_DELAY, AssignCommand(oPC, JumpToLocation(lDestination) ) ); DelayCommand( AREATRANS_DELAY+AREATRANS_REFACTORY_PERIOD, DeleteLocalInt(oPC,"m_nZoning") ); /* DelayCommand( AREATRANS_DELAY, ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eZoneEffect3,lDestination) ); */ } else if(AREATRANS_DEBUG) SendMessageToPC(oPC,"Movement to an invalid area attempted. Area was not found with specified TAG."); }