//tool_pc_rangertr //Ranger's tracking of creatures //Modified to take weather (rain or falling snow), fog density, night, //and creature size conditions into account as tracking DC modifiers, //by Algernon's Ghost for the Vast story PW. //Debug work done by Trooper_Max. //#include "mod_inc_rngrtrak" //Tracking variables function. void GetDirection(float fFacing, object oTracker, object oCritter) { int iFacing = FloatToInt(fFacing); //Debug next line. //SendMessageToPC(oTracker, "iFacing: "+IntToString(iFacing)); //Translate iFacing to a string direction, optimized. string sDirection = "E"; if(iFacing >= 170) { if(iFacing >= 260) { if(iFacing >= 305) { if(iFacing >= 327) { if(iFacing <= 349) sDirection="ESE"; //else // sDirection="E"; // already defaulted to E } else { sDirection="SE"; } } else { if(iFacing >= 282) sDirection="SSE"; else sDirection="S"; } } else { if(iFacing >= 215) { if(iFacing >= 237) sDirection="SSW"; else sDirection="SW"; } else { if(iFacing >= 192) sDirection="WSW"; else sDirection="W"; } } } else { if(iFacing >= 80) { if(iFacing >= 123) { if(iFacing >= 147) sDirection="WNW"; else sDirection="NW"; } else { if(iFacing >= 102) sDirection="NNW"; else sDirection="N"; } } else { if(iFacing >= 35) { if(iFacing >= 57) sDirection="NNE"; else sDirection="NE"; } else { if(iFacing >= 12) sDirection="ENE"; //else // sDirection="E"; // already defaulted to E } } } //Send the direction to the tracker and return SendMessageToPC(oTracker, GetName(oCritter) + " is to the " + sDirection); return; } //Main script. void main() { object oTracker = OBJECT_SELF;//<-The PC. object oArea = GetArea(oTracker); object oTrackPlc = GetNearestObjectByTag("Tracker"); int iDC;//<-Tracking DC. //Animate the ranger attempting to track (get low). AssignCommand (oTracker, ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW, 0.5, 8.0)); //Check for Tracker placeable. if(GetIsObjectValid(oTrackPlc)) { iDC = GetWillSavingThrow(oTrackPlc); //Debug next line. //SendMessageToPC(oTracker, "Tracker Object DC: " + IntToString(iDC)); } //Exit if there is not placeable, or if DC is invalid. if(!iDC || !GetIsObjectValid(oTrackPlc)) { SendMessageToPC(oTracker, "It is impossible to sort out tracks here."); return; } /////////////////////////////////// //Weather and visibility modifiers. /////////////////////////////////// int iWeather = GetWeather(oArea); //<-Get the weather. int iNight = GetIsNight(); //<-See if it's night. int iFog = GetFogAmount(FOG_TYPE_ALL, oArea); //<-Check fog density. int iWeatherAdj; //<-Possible weather related DC modifier, begins at zero. int iVisibiltyAdj; //<-Possible visibility related DC modifier, begins at zero. //Determine Weather related modifier, if any. //Raining. if (iWeather == WEATHER_RAIN) { //DC is +1 for every hour of rain that has fallen since tracks were made, per PHB. //Generate random between 1 and 6 to simulate a random number of hours of rainfall. //We cannot determine how many hours of rain have occurred. iWeatherAdj = Random(6) + 1; } //Snowing. else if (iWeather == WEATHER_SNOW) { //DC is +10 for freshly fallen snow per PHB. iWeatherAdj = 10; } //Determine if it is night, and the night visiblity related modifier, if any. if (iNight == TRUE) { //Rain or falling snow indicates definite cloud cover and greater darkness. if (iWeatherAdj >= 1) { //DC is +6 for night cloud cover or moonless night, per PHB. iVisibiltyAdj = 6; SendMessageToPC(oTracker, "Precipitation and cloud cover are making tracking more difficult."); } //Otherwise determine random chance for a overcast or moonless night. //Set at 50%, change to suit your needs (51% + equals less visibility). else if ((Random(100) + 1) >= 51) { //DC is +6 for night cloud cover or moonless night, per PHB. iVisibiltyAdj = 6; //Debug //SendMessageToPC(oTracker, "Debug overcast."); } //If fog density is greater than 11, apply a visibility modifier. else if (iFog > 11) { iVisibiltyAdj = 3; SendMessageToPC(oTracker, "The dense fog is hampering visibility."); } //Otherwise the night modifier is +3 to the DC to track (assuming moonlight here). //Moonlight and fog apply the same modifier, per PHB. else { iVisibiltyAdj = 3; //Debug //SendMessageToPC(oTracker, "Debug moonlit."); } } //It is not night. Check for visibility modifiers. else //if (iNight == FALSE) { //Rain or falling snow make for poor visibility. if (iWeatherAdj >= 1) { iVisibiltyAdj = 3; SendMessageToPC(oTracker, "The precipitation is making tracking more difficult."); } //If fog density is greater than 11, apply a visibility modifier. if (iFog > 11) { iVisibiltyAdj = 3; SendMessageToPC(oTracker, "The dense fog is hampering visibility."); } } //Debug, next two lines. //SendMessageToPC(oTracker, "Weather Adj: " + IntToString(iWeatherAdj)); //SendMessageToPC(oTracker, "Visibility Adj: " + IntToString(iVisibiltyAdj)); //Calculate Final Base DC iDC += iWeatherAdj + iVisibiltyAdj; ////////////////////////////////////////////////////////////////// //Cycle through all creatures in the area, and do tracking checks. ////////////////////////////////////////////////////////////////// object oCritter; int iLevel = GetLevelByClass(CLASS_TYPE_RANGER, oTracker); //<-Ranger gets a bonus for level. int iCritterSize; //<-Check creature size for DC modifier. int iSizeAdj; //<-Possible creature size related DC modifier, begins at zero. int iCnt = 1; float fDistance; int iDistanceAdj; //<-DC adjust based on distance between tracker and critter. vector vCritter; oCritter = GetNearestObject(OBJECT_TYPE_CREATURE, oTracker, iCnt); while(GetIsObjectValid(oCritter) && GetArea(oCritter) == oArea) { iCritterSize = GetCreatureSize(oCritter); fDistance = GetDistanceBetween(oCritter, oTracker); iDistanceAdj = FloatToInt(fDistance/10.0); //Run through size types and determine modifier. //NWN does not use all PnP size classifications. //MEDIUM size receives no modifier. if (iCritterSize == CREATURE_SIZE_TINY) { iSizeAdj = 2; } if (iCritterSize == CREATURE_SIZE_SMALL) { iSizeAdj = 1; } if (iCritterSize == CREATURE_SIZE_LARGE) { iSizeAdj = -1; } if (iCritterSize == CREATURE_SIZE_HUGE) { iSizeAdj = -2; } //Debug next three lines. //SendMessageToPC(oTracker, "Base DC: " + IntToString(iDC)); //SendMessageToPC(oTracker, "Size Adj: " + IntToString(iSizeAdj)); //SendMessageToPC(oTracker, "Distance Adj: " + IntToString(iDistanceAdj)); //Calculate final DC, and check for immunities to being tracked. //All rangers will begin with a simulated base 4 points in tracking, //and will gain one simulated point per level for the purposes of //making tracking checks as seen in: [ if ((d20() + iLevel + 4) ] if ((d20() + iLevel + 4) > (iDC + iDistanceAdj + iSizeAdj) && !GetLocalInt(oCritter,"NOTRACK") && !GetHasFeat(FEAT_TRACKLESS_STEP, oCritter) ) { //Get and send creature information. vCritter = GetPosition(oCritter); AssignCommand(oTracker, SetFacingPoint (vCritter)); AssignCommand(oTracker, GetDirection(GetFacing(oTracker), oTracker, oCritter)); } iCnt++; oCritter = GetNearestObject(OBJECT_TYPE_CREATURE, oTracker, iCnt); } return; }