• You've discovered RedGuides, an EverQuest multi-boxing and scripting community 🧙‍♀️⚙️. We want you to play several EQ characters at once, come join us and say hello! 👋

  • A TLP without truebox has thawed (Very Vanilla ready)
    Frostreaver

Plugin Creation

Status
Not open for further replies.

soultaker

Member
Joined
Feb 2, 2005
RedCents
60¢
UPDATE SOME OF THESE ARE OUT OF DATE WILL BE WORKING ON THIS THREAD HERE SOON TO UPDATE THE PLUGINS


As This thread develops links will be made here to Player made Plugins.


1. To Create a plugin, you need to use the command line program mkplugin.exe, which exists in the main directory of the MacroQuest2 source files. MacroQuest Site Download

Example

mkplugin myplugin

This will create a plugin named "MQ2Myplugin"
If you don't know how to use DOS, you should do this:

Start->Run: c:\mq2\mkplugin myplugin

Replace c:\mq2\ with the path to where you have the MacroQuest2 source files at.


2. Add the new plugin to your Visual Studio workspace (Visual C++ is part of Visual Studio, so this is the same as adding it to your Visual C++ workspace).

In VS .NET, go to File->Add Project->Existing project, and select the MQ2Myplugin.vcproj.

In VS 6, Go to Projects->Insert Projects into workspace, then select MQ2Myplugin.dsp.

3. Open the MQ2Myplugin.cpp file. Select all of it, and replace it with the code you're copying

4. Compile the plugin.

5. Load the plugin.

Example: /plugin mq2myplugin


**Note there is a nice help file that can be used for combileing Macroquest and all its features in the Download. Also this is a Windows help file so if you are not on a Windows based OS chances are it will not work.** Here is a copy of that file:
 
These two Plugins are being posted because many in "our" community, already many have and use them. THey have now been placed from free to VIP section on MQ2 Boards. Any support for these will need to come from members of this site, No further updates from MQ2 will be posted on these. we try our best to acknowledge their VIP section.


MQ2MoveUtils plugin (2004.06.23) - tonio
- Updated 2005.03.24 by Quagmire

Rich (BB code):
 /*
MQ2MoveUtils plugin (2004.06.23) - tonio
- Updated 2005.06.26 by Quagmire
- Updated 2005.07.09 by Outlander
- Updated 2005.07.14 by Outlander
- Updated 2005.07.19 by Outlander

* Corrections 2005.07.19
Modified /stick movestuck logic when you are close to mob and are switched to walk mode, this was causing
movestuck logic to be executed incorrectly.

*Corrections and additions 2005.07.14
Added break Circle functionality so that when you manually move Circle is turned off
Added MoveStuck logic to MoveTo and Circle commands
Adjusted the stuck distance to take into account the speedmodifier currently on the character.
Adjusted the the MoveStuck stuckDist to be 1/3 of what it normally is if your under water.

*Corrections and additions 2005.07.08
Added Version Number at top of help commands
Added /stick id <spawn id> functionality
Added break MoveTo functionality so that when you manually move MoveTo is turned off

Currently contains three commands:
/stick -- /follow-like command, works for any pc/npc, default distance is melee range ("/stick help" for more options)
/circle -- autofaces character to run in a circle
/moveto -- moves character to a specific loc, such as an anchor spot

"/stick" command by me
"/circle" command lifted from CyberTech's MQ2Twister plugin
"/moveto" command from rswiders


*/

#include "../MQ2Plugin.h"

PreSetup("MQ2MoveUtils");
CHAR szVersion[30]="MQ2MoveUtils Version 20050714";
CHAR szMsg[MAX_STRING]={0};

VOID CircleCommand(PSPAWNINFO pChar, PCHAR szLine);
float getRand(float n);

bool bCircling=false;
bool bDrunken=false;
float CircleX=0.0f;
float CircleY=0.0f;
float CircleRadius=0.0f;
SYSTEMTIME stPrevCirc;

int millisDiff(SYSTEMTIME &stCurr, SYSTEMTIME &stPrev);

VOID StickCommand(PSPAWNINFO pChar, PCHAR szLine);
VOID DoUnstickBind(PCHAR Name, BOOL Down);
void ReleaseKeys();
void DoWalk(bool walk = false);
void DoFwd(bool hold, bool walk = false);
void DoBck(bool hold);
void DoLft(bool hold);
void DoRgt(bool hold);
void Load_INI(void);
bool IsBardClass(void);
void stickText();
void breakStick(bool stopMoving = true, bool quite = false);
float angularDistance(float h1, float h2);

bool MoveBindsLoaded=false;
bool stickOn=false;
bool setDist=false;
bool stickPaused=false;
bool stickHold=false;
bool moveBehind=false;
bool moveBehindOnce=false;
bool moveBack=false;
bool movePin=false;
bool casting=false;
bool mPause=false;
bool prevMoveBehind=false;
bool prevMovePin=false;
bool looseStick=false;
bool underwater=false;
bool stickhasmovedfwd=false;
short stickVerbosity=1;
short keysDown=0;
float stickDist=0.0;
float breakDist=250.0;
float currentDist=0.0;
float stickDistMod=0.0;
float stickDistModP=1.0;
PSPAWNINFO stickTarget;
eSpawnType stickTarget_Type;
SYSTEMTIME stPrevStick;

bool autoPauseEnabled=true;
bool breakDistEnabled=true;
bool breakOnWarpEnabled=true;
bool breakOnGateEnabled=true;

// stuck added by Outlander
int stuck=0;
int stuckCheck=0;
int stuckFree=0;
float prevX=0.0f;
float prevY=0.0f;
float prevZ=0.0f;
float stuckDist=0.0f;
float turnDirection=0.0f;
float pulseAvg=0.0f;
bool stuckLogic;

VOID MoveToCommand(PSPAWNINFO pChar, PCHAR szLine);
void HandleMoveTo();
bool bMoveToOn=false;
float LocX=0.0f;
float LocY=0.0f;
float moveDist=10.0;
float moveDistMod=0.0;

class MQ2StickType *pStickType = 0;

class MQ2StickType : public MQ2Type
{
public:
   enum StickMembers {
      Status=1,
      Active=2,
      Distance=3,
      MoveBehind=4,
      MovePause=5,
      MoveBack=6,
      Loose=7,
      Paused=8,
      Behind=9,
      Stopped=10,
      Pin=11,
   };

   MQ2StickType():MQ2Type("stick")
   {
      TypeMember(Status);
      TypeMember(Active);
      TypeMember(Distance);
      TypeMember(MoveBehind);
      TypeMember(MovePause);
      TypeMember(MoveBack);
      TypeMember(Loose);
      TypeMember(Paused);
      TypeMember(Behind);
      TypeMember(Stopped);
      TypeMember(Pin);
   }

   ~MQ2StickType()
   {
   }

   bool GetMember(MQ2VARPTR VarPtr, PCHAR Member, PCHAR Index, MQ2TYPEVAR &Dest)
   {
      PMQ2TYPEMEMBER pMember=MQ2StickType::FindMember(Member);
      if (!pMember)
         return false;
      switch((StickMembers)pMember->ID)
      {
      case Status:
         strcpy(DataTypeTemp,"OFF");
         if( stickOn ) {
            strcpy(DataTypeTemp,"ON");
         }
         if( stickPaused ) {
            strcpy(DataTypeTemp,"PAUSED");
         }
         Dest.Ptr=DataTypeTemp;
         Dest.Type=pStringType;
         return true;
      case Active:
         Dest.DWord=stickOn;
         Dest.Type=pBoolType;
         return true;
      case Distance:
         Dest.Float=stickDist;
         Dest.Type=pFloatType;
         return true;
      case MoveBehind:
         Dest.DWord=moveBehind;
         Dest.Type=pBoolType;
         return true;
      case MovePause:
         Dest.DWord=mPause;
         Dest.Type=pBoolType;
         return true;
      case MoveBack:
         Dest.DWord=moveBack;
         Dest.Type=pBoolType;
         return true;
      case Loose:
         Dest.DWord=looseStick;
         Dest.Type=pBoolType;
         return true;
      case Paused:
         Dest.DWord=stickPaused;
         Dest.Type=pBoolType;
         return true;
      case Behind:
         if (ppTarget && pTarget) {
            PSPAWNINFO psTarget = (PSPAWNINFO)pTarget;
            PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
            Dest.DWord=(GetDistance(pChSpawn,psTarget) > stickDist || fabs(angularDistance(psTarget->Heading,pChSpawn->Heading)) > 45.0 )?false:true;
         } else
         Dest.DWord=false;
         Dest.Type=pBoolType;
         return true;
      case Stopped:
         if( ppTarget && pTarget ) {
            PSPAWNINFO psTarget = stickHold?stickTarget:(PSPAWNINFO)pTarget;
            PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
            Dest.DWord=(GetDistance(pChSpawn,psTarget)<=stickDist)?true:false;
         } else
         Dest.DWord=false;
         Dest.Type=pBoolType;
         return true;
      case Pin:
         Dest.DWord=movePin;
         Dest.Type=pBoolType;
         return true;
      }
      return false;
   }

    bool ToString(MQ2VARPTR VarPtr, PCHAR Destination)
   {
      strcpy(Destination,"OFF");
      if( stickOn ) {
         strcpy(Destination,"ON");
      }
      if( stickPaused ) {
         strcpy(Destination,"PAUSED");
      }
      return true;
   }

   bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
   {
      return false;
   }
   bool FromString(MQ2VARPTR &VarPtr, PCHAR Source)
   {
      return false;
   }
};

BOOL dataStick(PCHAR szName, MQ2TYPEVAR &Ret)
{
   Ret.DWord=1;
   Ret.Type=pStickType;
   return true;
}

VOID CircleHelp()
{
   WriteChatColor(szVersion,CONCOLOR_YELLOW);
   WriteChatColor("Usage: /circle on|off|drunken <radius> [<y> <x>]",USERCOLOR_DEFAULT);
   WriteChatColor("  Y and X are optional, if not specified will use your currect loc.",USERCOLOR_DEFAULT);
   WriteChatColor("  Y and X are in the same order that /location prints them.",USERCOLOR_DEFAULT);
   WriteChatColor("  If you call '/circle on <radius>' while not circling, it will start with your current loc and specified radius.",USERCOLOR_DEFAULT);
   WriteChatColor("  If you call '/circle on <radius>' while already circling, it will update with your new loc and radius.",USERCOLOR_DEFAULT);
   WriteChatColor("  If you call '/circle on' while already circling, it will update with your new loc using original radius.",USERCOLOR_DEFAULT);
}

VOID CircleCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   breakStick();
   CHAR szTemp[MAX_STRING]={0};
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
   GetArg(szTemp,szLine,1);

   if (!stricmp(szTemp,"help") || szLine[0]==0) {
      CircleHelp();
      return;
   } else if (!stricmp(szTemp,"on") || !stricmp(szTemp,"drunken")) {
      if( !stricmp(szTemp,"drunken") )
         bDrunken=true;
      else
         bDrunken=false;
      GetArg(szTemp,szLine,2);
      if (!strlen(szTemp)) {
         if (!bCircling) {
            CircleHelp();
            return;
         } else if (!CircleRadius) {
            // /circle on was called while we were already circling, but no radius was defined. oddddddd.
            CircleHelp();
            return;
         }
      } else {
         CircleRadius = (float)atof(szTemp);
      }

      GetArg(szTemp,szLine,3);
      if (!strlen(szTemp)) {
         CircleY = pChSpawn->Y + CircleRadius * (float)sin(pChSpawn->Heading * (float)PI / 256.0);
      } else {
         CircleY = (float)atof(szTemp);
      }

      GetArg(szTemp,szLine,4);
      if (!strlen(szTemp)) {
         CircleX = pChSpawn->X - CircleRadius * (float)cos(pChSpawn->Heading * (float)PI / 256.0);
      } else {
         CircleX = (float)atof(szTemp);
      }

      if (CircleRadius) bCircling = true;
      sprintf(szMsg, "Circling Radius %g, center %g %g", CircleRadius, CircleY, CircleX);
      WriteChatColor(szMsg, CONCOLOR_YELLOW);
   } else {
      if (!stricmp(szTemp,"off")) {
         bCircling = false;
      }
   }

}

void StickHelp()
{
   WriteChatColor(szVersion,CONCOLOR_YELLOW);
   WriteChatColor("Usage: /stick [on|hold|off|pause|unpause|reload|id] [<dist>|<spawnid>] [behind|behindonce|pin] [mpause] [moveback] [loose] [-<dist>] [<perc>%] [uw]");
   WriteChatColor("   /stick            - Sticks you within melee range of your target");
   WriteChatColor("   /stick hold       - Stores your current target, sticks to it even if you lose/change target");
   WriteChatColor("   /stick off        - Breaks off from stick (moving manually also breaks off from stick");
   WriteChatColor("   /stick pause      - Pauses following (can move normally while paused)");
   WriteChatColor("   /stick unpause    - Resumes following");
   WriteChatColor("   /stick reload     - Reload values from ini file");
   WriteChatColor("   /stick <dist>     - Sticks you within <dist> units of your target");
   WriteChatColor("   /stick behind     - Keeps you behind your target");
   WriteChatColor("   /stick behindonce - Moves behind your target once");
   WriteChatColor("   /stick pin        - Keeps you to the side of your target");
   WriteChatColor("   /stick mpause     - Causes manual movement to pause stick instead of breaking it");
   WriteChatColor("   /stick moveback   - Moves character back to try to stay at exactly stick distance");
   WriteChatColor("   /stick loose      - Checks distance/angle less often, and turns slower, for a more human-controlled look");
   WriteChatColor("   /stick uw         - Looks up or down to track target, useful for underwater /stick");
   WriteChatColor("   /stick -<dist>    - Substracts <dist> from the stick distance");
   WriteChatColor("   /stick <perc>%    - Multiplies stick distance by <perc> percent");
   WriteChatColor("   /stick id <spawn> - Sticks to the pc/npc with the spawn ID");
}

VOID StickCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   char currentArg[MAX_STRING];
   int argn=1;

   srand ( time(NULL));
   int trand = rand()%100;
   turnDirection *= (trand>50)?1.0f:-1.0f;

   GetArg(currentArg,szLine,argn++);

   if( !strncmp(currentArg,"pause",6) ) {
      ReleaseKeys();
      stickPaused = true;
      return;
   } else if( !strncmp( currentArg,"unpause",8 ) ) {
      stickPaused = false;
      return;
   }

   if (!stickOn)
      DoWalk(false);
   ReleaseKeys();
   stickOn=true;
   stickPaused=false;
   stickHold=false;
   setDist=false;
   moveBehind=false;
   moveBehindOnce=false;
   prevMoveBehind=false;
   movePin=false;
   prevMovePin=false;
   moveBack=false;
   mPause=false;
   looseStick=false;
   underwater=false;
   stickhasmovedfwd=false;
   stuck=0;
   stickTarget=NULL;
   stickTarget_Type=NONE;
   stickDistMod=0.0f;
   stickDistModP=1.0f;


   while( *currentArg ) {
      if( !strncmp(currentArg,"on",3) ) {
         stickOn = true;
      } else if( strstr(currentArg,"%") ) {
         stickDistModP = (float)atof(currentArg) / 100.0f;
         if( setDist )
            stickDist *= stickDistModP;
         stickOn = true;
      } else if( isdigit(currentArg[0]) || currentArg[0]=='.' ) {
         setDist = true;
         stickDist = (float)atof(currentArg) * stickDistModP + stickDistMod;
         stickOn = true;
      } else if( currentArg[0]=='-' ) {
         stickDistMod = (float)atof(currentArg);
         if( setDist )
            stickDist += stickDistMod;
         stickOn = true;
      } else if( !strncmp(currentArg,"mpause",7) ) {
         mPause = true;
         stickOn = true;
      } else if( !strncmp(currentArg,"moveback",9) ) {
         moveBack = true;
         stickOn = true;
      } else if( !strncmp(currentArg,"loose",6) ) {
         looseStick = true;
         stickOn = true;
      } else if( !strncmp(currentArg,"uw",3 ) ) {
         underwater=true;
         stickOn=true;
      } else if( !strncmp(currentArg,"off",4) ) {
         breakStick();
         break;
      } else if( !strncmp(currentArg,"hold",5) ) {
         stickOn = true;
         if( ppTarget && pTarget ) {
         if (((PSPAWNINFO) pTarget)->SpawnID == ((PSPAWNINFO) pLocalPlayer)->SpawnID) {
            WriteChatColor("You cannot stick hold to yourself.");
            breakStick(true, true);
            return;
         }
            stickHold = true;
            stickTarget = (PSPAWNINFO)pTarget;
         stickTarget_Type = stickTarget ? GetSpawnType(stickTarget) : NONE;
         }
      } else if( !strncmp(currentArg,"id",3) ) {
         GetArg(currentArg,szLine,argn++);
         if( isdigit(currentArg[0]) ) {
             stickTarget = (PSPAWNINFO) GetSpawnByID(atoi(currentArg));
             if( stickTarget ) {
                 if (((PSPAWNINFO) stickTarget)->SpawnID == ((PSPAWNINFO) pLocalPlayer)->SpawnID) {
                    WriteChatColor("You cannot stick id to yourself.");
                    breakStick(true, true);
                    return;
                 }
                 stickOn = true;
                 stickHold = true;
                 stickTarget_Type = stickTarget ? GetSpawnType(stickTarget) : NONE;
             }
          } else {
              WriteChatColor("When using ID the next parameter MUST be the spawn ID.");
              breakStick(true, true);
              return;
          }
      } else if( !strncmp(currentArg,"behind",7) ) {
         stickOn=true;
         moveBehind=true;
       moveBehindOnce=false;
       movePin=false;
      } else if( !strncmp(currentArg,"behindonce",11) ) {
         stickOn=true;
         moveBehindOnce=true;
       moveBehind=false;
       movePin=false;
      } else if( !strncmp(currentArg,"pin",3) ) {
         stickOn=true;
         movePin=true;
       moveBehind=false;
       moveBehindOnce=false;
      } else if( !strncmp(currentArg,"reload",7) ) {
         breakStick();
         Load_INI();
         WriteChatColor("Ini file reloaded.");
         break;
      } else {
         breakStick();
         StickHelp();
         break;
      }
      GetArg(currentArg,szLine,argn++);
   }
   if( stickOn ) {
      stickHold = stickHold && stickTarget && stickTarget->SpawnID;
      if( (ppTarget && pTarget) || (stickHold && stickTarget && stickTarget->SpawnID) ) {
         if( FindSpeed((PSPAWNINFO)pCharSpawn) < 0 ) {
            DoFwd(false);
         }
         currentDist=GetDistance((PSPAWNINFO)pCharSpawn,sti  ckHold?stickTarget:((PSPAWNINFO)pTarget));
      }
      stickText();
   }
}

VOID DoUnstickBind(PCHAR Name, BOOL Down)
{
   if( ! Down ) {
      keysDown--;
      if( keysDown == 0 && mPause ) {
         stickPaused = false;
         moveBehind = prevMoveBehind;
         movePin = prevMovePin;
      }
   } else {
      keysDown++;
      if((!stickPaused && stickOn) || bMoveToOn || bCircling) {
         if( mPause && strncmp(Name,"UNSTICK_STRAFE_RGT",12) && strncmp(Name,"UNSTICK_STRAFE_LFT",19) ) {
            stickPaused = true;
         } else if( !strncmp(Name,"UNSTICK_STRAFE_RGT",12) || !strncmp(Name,"UNSTICK_STRAFE_LFT",19) ) {
            if( mPause ) {
               prevMoveBehind = moveBehind || prevMoveBehind;
               prevMovePin = movePin || prevMovePin;
               moveBehind = false;
            } else {
               prevMoveBehind = moveBehind = false;
               prevMovePin = movePin = false;
            }
         } else {
            breakStick((strncmp(Name,"UNSTICK_BCK",12) && strncmp(Name,"UNSTICK_FWD",12)));
         }
      }
   }
}

VOID HandleCircle() {
   static int counter = 0;
   float distance;
   float heading;
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
   PSPAWNINFO pLPlayer = (PSPAWNINFO) pLocalPlayer;
   if (!pChSpawn || !pChSpawn->pActorInfo || !pLPlayer || !pLPlayer->pCharInfo) {
      WriteChatColor("Null pointer, breaking stick");
      breakStick();
      return;
   }

   if ( ( ((long) (pChSpawn->pActorInfo->CastingSpellID)) >= 0 && !(IsBardClass()) ) || (pChSpawn->StandState != STANDSTATE_STAND && pChSpawn->StandState != STANDSTATE_DUCK)|| pLPlayer->pCharInfo->Stunned==1 ) {
      if( !casting ) {
         casting = true;
         DoFwd(false);
         ReleaseKeys();
      }
   } else if( casting ) {
      casting = false;
   }

   if (!GetCharInfo() || !bCircling) return;

   float X = pChSpawn->X - CircleX;
   float Y = pChSpawn->Y - CircleY;
   distance = sqrt(X*X + Y*Y);

   if( !casting || !autoPauseEnabled ) {
      if (distance>(CircleRadius*(2.0/3.0))) {
         float newHeading;
         float pulseMoved=GetDistance(pChSpawn->X,pChSpawn->Y,prevX,prevY);
         if( pulseMoved < 5) pulseAvg = (pulseAvg + pulseMoved)/2;
         prevX=pChSpawn->X;
         prevY=pChSpawn->Y;
         prevZ=pChSpawn->Z;
   
         float SpeedModifier = *((float*) &(((PSPAWNINFO) pLocalPlayer)->pActorInfo->Unknown0x0af[25]));
     
         if( stickhasmovedfwd && ((pulseAvg < (stuckDist + SpeedModifier) && !pChSpawn->pActorInfo->UnderWater) ||
             (pulseAvg < ((stuckDist + SpeedModifier)/3) && pChSpawn->pActorInfo->UnderWater))&&
              GetDistance(pChSpawn->X,pChSpawn->Y,(float)LocX,(float)LocY) > moveDist && stuckLogic ) {
             stuck++;
             if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
                 newHeading =(float) ( pChSpawn->Heading + turnDirection);
                 if( newHeading >= 512.0f) newHeading -= 512.0f;
                 if( newHeading < 0.0f ) newHeading += 512.0f;
                 pChSpawn->Heading = newHeading;

                 //check to see if we are heading directly away from our target if so then go back
                 newHeading=(float) atan2(pChSpawn->Y - CircleY,  CircleX - pChSpawn->X) * 180.0f / (float)PI + 90.0f;
                 newHeading += (float) 90.0f * (CircleRadius/distance);
                 newHeading *= 512.0f/360.0f;
                 if( newHeading >= 512.0f ) newHeading -= 512.0f;
                 if( newHeading < 0.0f ) newHeading += 512.0f;

                 newHeading += 265.0f;
                 if( newHeading >= 512.0f) newHeading -= 512.0f;
                 if( newHeading < 0.0f ) newHeading += 512.0f;
                 if( pChSpawn->Heading > (newHeading - fabs(turnDirection/2)) &&  pChSpawn->Heading <  (newHeading + fabs(turnDirection/2)) ) {
                     newHeading -= 265.0f;
                     if( newHeading >= 512.0f) newHeading -= 512.0f;
                     if( newHeading < 0.0f ) newHeading += 512.0f;
                     pChSpawn->Heading = newHeading;
                     stuck = stuckCheck;
                     turnDirection *= -1.0f;
                 }
             }
             stuckFree=0;

         } else if( stuck > 0 ) {
             if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
                 newHeading =(float) ( pChSpawn->Heading - turnDirection );
              pChSpawn->Heading = newHeading;
             }
             stuck--;
             if(stuckFree++ > stuckCheck*3 ) {
                 stuck=0;
             }
         } else {
            heading=(float) atan2( pChSpawn->Y - CircleY,  CircleX - pChSpawn->X) * 180.0f / (float)PI + 90.0f;
            heading += 90.0f * (CircleRadius/distance);
            heading *= 512.0f/360.0f;
            if( heading >= 512.0f ) heading -= 512.0f;
            if( heading < 0.0f ) heading += 512.0f;
            if( bDrunken ) {
               gFaceAngle = (float)heading;
            } else {
               pChSpawn->Heading = (float)heading;
            }
         }
         DoFwd(true);
      }
   }
}

float angularDistance(float h1, float h2)
{
   if( h1 == h2 ) return 0.0;

   if( fabs(h1-h2) > 256.0 )
      *(h1<h2?&h1:&h2) += 512.0;

   return (fabs(h1-h2)>256.0)?(h2-h1):(h1-h2);
}

void HandleStick()
{
   if( (stickHold && (!stickTarget || !(stickTarget->SpawnID) || stickTarget_Type!=GetSpawnType(stickTarget))) || (!stickHold && ((!ppTarget) || (!pTarget))) ) {
      breakStick();
      return;
   }
   PSPAWNINFO psTarget = stickHold?stickTarget:(PSPAWNINFO)pTarget;
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
   PSPAWNINFO pLPlayer = (PSPAWNINFO) pLocalPlayer;
   if (!pChSpawn || !pChSpawn->pActorInfo || !psTarget || !pLPlayer || !pLPlayer->pCharInfo) {
      WriteChatColor("Null pointer, breaking stick");
      breakStick();
      return;
   }

   float newHeading=0.0f;
   float prevDist = currentDist;

   if( !setDist )
      stickDist = (psTarget->StandState?get_melee_range(pLocalPlayer,(EQPlayer *)psTarget):15.0f) * stickDistModP + stickDistMod;

   currentDist=GetDistance(pChSpawn,psTarget);
   if( breakOnWarpEnabled && (currentDist-prevDist) > breakDist ) {
      breakStick();
      return;
   }
   if ( ( ((long) (pChSpawn->pActorInfo->CastingSpellID)) >= 0 && !(IsBardClass()) ) || (pChSpawn->StandState != STANDSTATE_STAND && pChSpawn->StandState != STANDSTATE_DUCK)|| pLPlayer->pCharInfo->Stunned==1 || psTarget->SpawnID == pChSpawn->SpawnID ) {
      if( !casting ) {
         casting = true;
         ReleaseKeys();
      }
   } else if( casting ) {
      casting = false;
   }

   if( (!stickPaused && !casting) || !autoPauseEnabled ) {
      float pulseMoved=GetDistance(pChSpawn->X,pChSpawn->Y,prevX,prevY);
      if( pulseMoved < 5) pulseAvg = (pulseAvg + pulseMoved)/2;
      prevX=pChSpawn->X;
      prevY=pChSpawn->Y;
      prevZ=pChSpawn->Z;

      float SpeedModifier = *((float*) &(((PSPAWNINFO) pLocalPlayer)->pActorInfo->Unknown0x0af[25]));
      if( stickhasmovedfwd && ((pulseAvg < (stuckDist + SpeedModifier) && !pChSpawn->pActorInfo->UnderWater) ||
          (pulseAvg < ((stuckDist + SpeedModifier)/3) && pChSpawn->pActorInfo->UnderWater))&&
          ((currentDist - stickDist) > 10.0) && stuckLogic ) {
          stuck++;
          if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
              newHeading =(float) ( pChSpawn->Heading + turnDirection);
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;
              pChSpawn->Heading = newHeading;

              //check to see if we are heading directly away from our target if so then go back
              newHeading = (float) (atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * 256.0 / (float)PI);
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;

              newHeading += 265.0f;
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;
              if( pChSpawn->Heading > (newHeading - fabs(turnDirection/2)) &&  pChSpawn->Heading <  (newHeading + fabs(turnDirection/2)) ) {
                  newHeading -= 265.0f;
                  if( newHeading >= 512.0f) newHeading -= 512.0f;
                  if( newHeading < 0.0f ) newHeading += 512.0f;
                  pChSpawn->Heading = newHeading;
                  stuck = stuckCheck;
                  turnDirection *= -1.0f;
              }
          }
          stuckFree=0;
      } else if( stuck > 0 ) {
          if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
              newHeading =(float) ( pChSpawn->Heading - turnDirection );
           pChSpawn->Heading = newHeading;
          }
          stuck--;
          if(stuckFree++ > stuckCheck*3 ) {
              stuck=0;
          }
      } else {
          newHeading = (float) (atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * 256.0 / (float)PI);
          if( newHeading >= 512.0f) newHeading -= 512.0f;
          if( newHeading < 0.0f ) newHeading += 512.0f;
          if (stickhasmovedfwd && fabs(pChSpawn->Heading - newHeading) >= 200 && currentDist < 10) {
             DoBck(true);
             return;
          } else {
             DoBck(false);
          }
          if( looseStick ) {
             gFaceAngle = newHeading;
          } else {
             pChSpawn->Heading = newHeading;
          }

          //underwater = pChSpawn->pActorInfo->UnderWater==5;
          if( underwater ) {
             double lookAngle = (float) atan2(psTarget->Z + psTarget->AvatarHeight*StateHeightMultiplier(psTarget->StandState) -
             pChSpawn->Z - pChSpawn->AvatarHeight*StateHeightMultiplier(pChSpawn->StandState),
             currentDist) * 256.0f / (float)PI;
             if ( looseStick ) {
                gLookAngle = lookAngle;
             } else {
                pChSpawn->CameraAngle = (FLOAT)lookAngle;
             }
          }
          if ( currentDist > (stickDist * 3) ) {
             // too far away, dont do pin or behind
          } else if( moveBehind || moveBehindOnce ) {
             float angDist = angularDistance(psTarget->Heading,pChSpawn->Heading);
             if( fabs(angDist) > 45.0 ) {
                if(angDist < 0.0) {
                   // strafe left
                   DoLft(true);
                } else {
                   // strage right
                   DoRgt(true);
                }
             } else {
                moveBehindOnce = false;
                DoLft(false);
                DoRgt(false);
             }
          } else if (movePin) {
             FLOAT angDist = angularDistance(psTarget->Heading,pChSpawn->Heading);
             if((angDist > 0 && angDist <= 112) || angDist < -144) {
                DoLft(true);
             } else if ((angDist < 0 && angDist > -112) || angDist > 144) {
                DoRgt(true);
             } else {
                DoLft(false);
                DoRgt(false);
             }
          }
      }
      if(pChSpawn->StandState == STANDSTATE_DUCK && stuckLogic ) pChSpawn->StandState = STANDSTATE_STAND;
      if( currentDist > stickDist) {
         // if distance is less than 10, walk
         DoFwd(true, ((currentDist - stickDist) <= 10.0));
      } else if( moveBack && currentDist < (stickDist-5.0) ) {
         DoBck(true);
      } else {
         DoFwd(false);
         DoBck(false);
      }
   }
}

void
Load_INI(VOID)
{
   char szTemp[MAX_STRING], szTemp2[MAX_STRING];

   // Defaults
   GetPrivateProfileString("Defaults","AutoPause","on",szTemp,MAX_STRING,INIFileName);
   autoPauseEnabled=(strncmp(szTemp,"on",3)==0);
   sprintf(szTemp,"%s",autoPauseEnabled?"on":"off");
   WritePrivateProfileString("Defaults","AutoPause",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","BreakOnWarp","on",szTemp,MAX_STRING,INIFileName);
   breakOnWarpEnabled=(strncmp(szTemp,"on",3)==0);
   sprintf(szTemp,"%s",breakOnWarpEnabled?"on":"off");
   WritePrivateProfileString("Defaults","BreakOnWarp",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","BreakDist","250.0",szTemp,MAX_STRING,INIFileName);
   breakDist = (float)atof(szTemp);
   sprintf(szTemp,"%.1f",breakDist);
   WritePrivateProfileString("Defaults","BreakDist",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","BreakOnGate","on",szTemp,MAX_STRING,INIFileName);
   breakOnGateEnabled=(strncmp(szTemp,"on",3)==0);
   sprintf(szTemp,"%s",breakOnGateEnabled?"on":"off");
   WritePrivateProfileString("Defaults","BreakOnGate",szTemp,INIFileName);

   stickVerbosity=(short)GetPrivateProfileInt("Defaults","Verbosity",1,INIFileName);
   sprintf(szTemp,"%d",stickVerbosity);
   WritePrivateProfileString("Defaults","Verbosity",szTemp,INIFileName);

   // Character specific
   GetPrivateProfileString(GetCharInfo()->Name,"AutoPause",autoPauseEnabled?"on":"off",szTemp,MAX_STRING,INIFileName);
   autoPauseEnabled=(strncmp(szTemp,"on",3)==0);

   GetPrivateProfileString(GetCharInfo()->Name,"BreakOnWarp",breakOnWarpEnabled?"on":"off",szTemp,MAX_STRING,INIFileName);
   breakOnWarpEnabled=(strncmp(szTemp,"on",3)==0);

   sprintf(szTemp2,"%.1f",breakDist);
   GetPrivateProfileString(GetCharInfo()->Name,"BreakDist",szTemp2,szTemp,MAX_STRING,INIFileName);
   breakDist = (float)atof(szTemp);

   GetPrivateProfileString(GetCharInfo()->Name,"BreakOnGate",breakOnGateEnabled?"on":"off",szTemp,MAX_STRING,INIFileName);
   breakOnGateEnabled=(strncmp(szTemp,"on",3)==0);

   stickVerbosity=(short)GetPrivateProfileInt(GetChar  Info()->Name,"Verbosity",stickVerbosity,INIFileName);

   GetPrivateProfileString("Defaults","stuckDist","0.8",szTemp,MAX_STRING,INIFileName);
   stuckDist = (float)atof(szTemp);
   sprintf(szTemp,"%.1f",stuckDist);
   WritePrivateProfileString("Defaults","stuckDist",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","turnDirection","10.0",szTemp,MAX_STRING,INIFileName);
   turnDirection = (float)atof(szTemp);
   sprintf(szTemp,"%.1f",turnDirection);
   WritePrivateProfileString("Defaults","turnDirection",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","stuckCheck","5",szTemp,MAX_STRING,INIFileName);
   stuckCheck = (int)atoi(szTemp);
   sprintf(szTemp,"%i",stuckCheck);
   WritePrivateProfileString("Defaults","stuckCheck",szTemp,INIFileName);

   GetPrivateProfileString("Defaults","StuckLogic","on",szTemp,MAX_STRING,INIFileName);
   stuckLogic=(strncmp(szTemp,"on",3)==0);
   sprintf(szTemp,"%s",stuckLogic?"on":"off");
   WritePrivateProfileString("Defaults","StuckLogic",szTemp,INIFileName);
}

bool IsBardClass()
{
   if(strncmp(pEverQuest->GetClassDesc(GetCharInfo2()->Class),"Bard",5))
      return false;
   else
      return true;
}

PLUGIN_API VOID OnPulse(VOID)
{
//  *((float *)&(((PSPAWNINFO)pLocalPlayer)->pActorInfo->Unknown0x0af[25])) = 0.95f;
   if (bCircling) {
      if( bDrunken ) {
         SYSTEMTIME stCurr;
         GetSystemTime(&stCurr);
         if( millisDiff(stCurr,stPrevCirc) > 900 + (int)getRand(600.0) ) {
            GetSystemTime(&stPrevCirc);
            HandleCircle();
         }
      } else {
         HandleCircle();
      }
   }
   if( stickOn ) {
      if( looseStick ) {
         SYSTEMTIME stCurr;
         GetSystemTime(&stCurr);
         if( millisDiff(stCurr,stPrevStick) > 100 + (int)getRand(200.0) ) {
            GetSystemTime(&stPrevStick);
            HandleStick();
         }
      } else {
         HandleStick();
      }
   }
   if (bMoveToOn) {
      HandleMoveTo();
   }
}

void ReleaseKeys() {
   DoWalk(false);
   DoFwd(false);
   DoBck(false);
   DoRgt(false);
   DoLft(false);
}

void DoWalk(bool walk) {
   bool state_walking = (*EQADDR_RUNWALKSTATE) ? false : true;
   float SpeedModifier = *((float*) &(((PSPAWNINFO) pLocalPlayer)->pActorInfo->Unknown0x0af[25]));
   if (SpeedModifier < 0)
      walk = false; // we're snared, dont go into walk mode no matter what
   if ( (walk && !state_walking) || (!walk && state_walking) ) {
      MQ2Globals::ExecuteCmd(FindMappableCommand("run_walk"),1,0);
      MQ2Globals::ExecuteCmd(FindMappableCommand("run_walk"),0,0);
   }
}

void DoFwd(bool hold, bool walk) {
   static bool held = false;
   if ( hold ) {
      stickhasmovedfwd = true;
      DoWalk(walk);
      DoBck(false);
      if (!held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("forward"),1,0);
      held = true;
   } else {
      DoWalk(false);
      if (held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("forward"),0,0);
      held = false;
   }
}

void DoBck(bool hold) {
   static bool held = false;
   if( hold ) {
      DoFwd(false);
      if (!held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("back"),1,0);
      held = true;
   } else {
      if (held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("back"),0,0);
      held = false;
   }
}

void DoLft(bool hold) {
   static bool held = false;
   if( hold ) {
      DoRgt(false);
      if (!held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("strafe_left"),1,0);
      held = true;
   } else {
      if (held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("strafe_left"),0,0);
      held = false;
   }
}

void DoRgt(bool hold) {
   static bool held = false;
   if( hold ) {
      DoLft(false);
      if (!held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("strafe_right"),1,0);
      held = true;
   } else {
      if (held)
         MQ2Globals::ExecuteCmd(FindMappableCommand("strafe_right"),0,0);
      held = false;
   }
}

float getRand(float n)
{
   return (n * rand() / (RAND_MAX+1.0f));
}

int millisDiff(SYSTEMTIME &stCurr, SYSTEMTIME &stPrev)
{
   SYSTEMTIME stResult;
   FILETIME ftPrev, ftCurr, ftResult;
   ULARGE_INTEGER prev,curr,result;

   GetSystemTime(&stCurr);
   SystemTimeToFileTime(&stPrev,&ftPrev);
   SystemTimeToFileTime(&stCurr,&ftCurr);
   prev.HighPart = ftPrev.dwHighDateTime;
   prev.LowPart = ftPrev.dwLowDateTime;
   curr.HighPart = ftCurr.dwHighDateTime;
   curr.LowPart = ftCurr.dwLowDateTime;
   result.QuadPart = curr.QuadPart - prev.QuadPart;
   ftResult.dwHighDateTime = result.HighPart;
   ftResult.dwLowDateTime = result.LowPart;
   FileTimeToSystemTime(&ftResult,&stResult);

   return ((int)(stResult.wSecond * 1000 + stResult.wMilliseconds));
}

void stickText()
{
   char szTemp[MAX_STRING];

   if( stickVerbosity == 1 ) {
      if( stickPaused ) {
         WriteChatColor("Stick paused.");
      } else if( stickOn ) {
         if( stickHold ) {
            sprintf(szTemp,"You are now sticking to %s.",stickTarget->DisplayedName);
         } else if( ppTarget && pTarget ) {
            sprintf(szTemp,"You are now sticking to %s.",((PSPAWNINFO)pTarget)->DisplayedName);
         } else {
            sprintf(szTemp,"Need a target for stick.");
         }
         WriteChatColor(szTemp);
      } else {
         WriteChatColor("You are no longer sticking to anything.");
      }
   }
}

void breakStick(bool stopMoving, bool quite)
{
   stickOn=false;
   stickPaused=false;
   stickHold=false;
   setDist=false;
   moveBehind=false;
   prevMoveBehind=false;
   moveBehindOnce=false;
   movePin=false;
   prevMovePin=false;
   moveBack=false;
   mPause=false;
   looseStick=false;
   underwater=false;
   bMoveToOn=false;
   bCircling=false;
   stuck=0;
   stickTarget=NULL;
   stickDistMod=0.0;
   stickDistModP=1.0;
   if( stopMoving )
      ReleaseKeys();
   else {
      DoWalk(false);
      DoLft(false);
      DoRgt(false);
   }
   if (!quite)
      stickText();
}

class MQ2MoveToType *pMoveToType = 0;

class MQ2MoveToType : public MQ2Type
{
public:
   enum MoveToMembers {
      Moving=1,
      Stopped=2
   };

   MQ2MoveToType():MQ2Type("moveto")
   {
      TypeMember(Moving);
      TypeMember(Stopped);
   }

   ~MQ2MoveToType()
   {
   }

   bool GetMember(MQ2VARPTR VarPtr, PCHAR Member, PCHAR Index, MQ2TYPEVAR &Dest)
   {
      PMQ2TYPEMEMBER pMember=MQ2MoveToType::FindMember(Member);
      if (!pMember)
         return false;
      switch((MoveToMembers)pMember->ID)
      {
      case Moving:
         Dest.DWord=bMoveToOn;
         Dest.Type=pBoolType;
         return true;
      case Stopped:
         PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
         Dest.DWord=(GetDistance(pChSpawn->X,pChSpawn->Y,(float)LocX,(float)LocY)<=moveDist)?true:false;
         Dest.Type=pBoolType;
         return true;
      }
      return false;
   }

    bool ToString(MQ2VARPTR VarPtr, PCHAR Destination)
   {
      if( bMoveToOn ) {
         strcpy(Destination,"ON");
      } else {
         strcpy(Destination,"OFF");
      }
      return true;
   }

   bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
   {
      return false;
   }
   bool FromString(MQ2VARPTR &VarPtr, PCHAR Source)
   {
      return false;
   }
};

BOOL dataMoveTo(PCHAR szName, MQ2TYPEVAR &Ret)
{
   Ret.DWord=1;
   Ret.Type=pMoveToType;
   return true;
}

VOID MoveToHelp()
{
   WriteChatColor(szVersion,CONCOLOR_YELLOW);
   WriteChatColor("Usage: /moveto loc|off <y> <x> [<dist>|-<dist>]",USERCOLOR_DEFAULT);
   WriteChatColor("  Y and X are in the same order that /location prints them.",USERCOLOR_DEFAULT);
   WriteChatColor("  You can not call '/moveto <y> <x>' while circling or sticking.",USERCOLOR_DEFAULT);
   WriteChatColor("  /moveto <dist>   - Moves you within <dist> units of your target, default is 50");
   WriteChatColor("  /moveto -<dist>  - Subtracts <dist> units from the move distance");
}

VOID MoveToCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   breakStick();
   CHAR szTemp[MAX_STRING]={0};
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
   GetArg(szTemp,szLine,1);

   if (!stricmp(szTemp,"help") || szLine[0]==0 || bCircling || stickOn) {
      MoveToHelp();
      return;
   } else if (!stricmp(szTemp,"loc")) {
      GetArg(szTemp,szLine,2);
      if (!strlen(szTemp)) {
         MoveToHelp();
         return;
      } else {
         LocY = (float) atof(szTemp);
      }

      GetArg(szTemp,szLine,3);
      if (!strlen(szTemp)) {
         MoveToHelp();
         return;
      } else {
         LocX = (float) atof(szTemp);
      }

      GetArg(szTemp,szLine,4);
      if (strlen(szTemp)) {
         if( isdigit(szTemp[0]) || szTemp[0]=='.' ) {
            moveDist = (float)atof(szTemp);
         } else if( szTemp[0]=='-' ) {
            moveDistMod = (float)atof(szTemp);
            moveDist += moveDistMod;
         }
      }

      bMoveToOn=true;
      sprintf(szMsg, "Moving to loc %g %g", LocY, LocX);
      if (stickVerbosity)
         WriteChatColor(szMsg, CONCOLOR_YELLOW);
   } else if (!stricmp(szTemp,"off")) {
      bMoveToOn = false;
      if (stickVerbosity)
         WriteChatColor("MoveTo off.", CONCOLOR_YELLOW);
   } else {
      MoveToHelp();
      return;
   }
}

void HandleMoveTo()
{
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;
   PSPAWNINFO pLPlayer = (PSPAWNINFO) pLocalPlayer;
   if (!pChSpawn || !pChSpawn->pActorInfo || !pLPlayer || !pLPlayer->pCharInfo) {
      WriteChatColor("Null pointer, breaking stick");
      breakStick();
      return;
   }

   if ( ( ((long) (pChSpawn->pActorInfo->CastingSpellID)) >= 0 && !(IsBardClass()) ) || (pChSpawn->StandState != STANDSTATE_STAND && pChSpawn->StandState != STANDSTATE_DUCK)|| pLPlayer->pCharInfo->Stunned==1 ) {
      if( !casting ) {
         casting = true;
         DoFwd(false);
         ReleaseKeys();
      }
   } else if( casting ) {
      casting = false;
   }

   if( !casting || !autoPauseEnabled ) {
      float newHeading;
      float pulseMoved=GetDistance(pChSpawn->X,pChSpawn->Y,prevX,prevY);
      if( pulseMoved < 5) pulseAvg = (pulseAvg + pulseMoved)/2;
      prevX=pChSpawn->X;
      prevY=pChSpawn->Y;
      prevZ=pChSpawn->Z;

      float SpeedModifier = *((float*) &(((PSPAWNINFO) pLocalPlayer)->pActorInfo->Unknown0x0af[25]));
     
      if( stickhasmovedfwd && ((pulseAvg < (stuckDist + SpeedModifier) && !pChSpawn->pActorInfo->UnderWater) ||
          (pulseAvg < ((stuckDist + SpeedModifier)/3) && pChSpawn->pActorInfo->UnderWater))&&
          GetDistance(pChSpawn->X,pChSpawn->Y,(float)LocX,(float)LocY) > moveDist && stuckLogic ) {
          stuck++;
          if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
              newHeading =(float) ( pChSpawn->Heading + turnDirection);
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;
              pChSpawn->Heading = newHeading;

              //check to see if we are heading directly away from our target if so then go back
              newHeading = (float) (atan2(LocX - pChSpawn->X, LocY - pChSpawn->Y) * 256.0 / (float)PI);
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;

              newHeading += 265.0f;
              if( newHeading >= 512.0f) newHeading -= 512.0f;
              if( newHeading < 0.0f ) newHeading += 512.0f;
              if( pChSpawn->Heading > (newHeading - fabs(turnDirection/2)) &&  pChSpawn->Heading <  (newHeading + fabs(turnDirection/2)) ) {
                  newHeading -= 265.0f;
                  if( newHeading >= 512.0f) newHeading -= 512.0f;
                  if( newHeading < 0.0f ) newHeading += 512.0f;
                  pChSpawn->Heading = newHeading;
                  stuck = stuckCheck;
                  turnDirection *= -1.0f;
              }
          }
          stuckFree=0;
      } else if( stuck > 0 ) {
          if(fmod((float)stuck,(float)stuckCheck) == 0.0f) {
              newHeading =(float) ( pChSpawn->Heading - turnDirection );
           pChSpawn->Heading = newHeading;
          }
          stuck--;
          if(stuckFree++ > stuckCheck*3 ) {
              stuck=0;
          }
      } else {
          newHeading = (float) (atan2(LocX - pChSpawn->X, LocY - pChSpawn->Y) * 256.0 / (float)PI);
          if( newHeading >= 512.0f)
             newHeading -= 512.0f;
          if( newHeading < 0.0f )
             newHeading += 512.0f;
          pChSpawn->Heading = newHeading;
      }
      if( GetDistance(pChSpawn->X,pChSpawn->Y,(float)LocX,(float)LocY) > moveDist) {
         DoFwd(true);
      } else {
         bMoveToOn=false;
         if (stickVerbosity)
            WriteChatColor("Arrived at MoveTo location", CONCOLOR_YELLOW);
         DoFwd(false);
      }
   }
}

VOID CreateBinds(){
   if (MoveBindsLoaded)
      return;
   MoveBindsLoaded=true;
   AddMQ2KeyBind("UNSTICK_FWD",DoUnstickBind);
   AddMQ2KeyBind("UNSTICK_BCK",DoUnstickBind);
   AddMQ2KeyBind("UNSTICK_LFT",DoUnstickBind);
   AddMQ2KeyBind("UNSTICK_RGT",DoUnstickBind);
   AddMQ2KeyBind("UNSTICK_STRAFE_LFT",DoUnstickBind);
   AddMQ2KeyBind("UNSTICK_STRAFE_RGT",DoUnstickBind);
   SetMQ2KeyBind("UNSTICK_FWD",false,pKeypressHandler->NormalKey[FindMappableCommand("forward")]);
   SetMQ2KeyBind("UNSTICK_FWD",true,pKeypressHandler->AltKey[FindMappableCommand("forward")]);
   SetMQ2KeyBind("UNSTICK_BCK",false,pKeypressHandler->NormalKey[FindMappableCommand("back")]);
   SetMQ2KeyBind("UNSTICK_BCK",true,pKeypressHandler->AltKey[FindMappableCommand("back")]);
   SetMQ2KeyBind("UNSTICK_LFT",false,pKeypressHandler->NormalKey[FindMappableCommand("left")]);
   SetMQ2KeyBind("UNSTICK_LFT",true,pKeypressHandler->AltKey[FindMappableCommand("left")]);
   SetMQ2KeyBind("UNSTICK_RGT",false,pKeypressHandler->NormalKey[FindMappableCommand("right")]);
   SetMQ2KeyBind("UNSTICK_RGT",true,pKeypressHandler->AltKey[FindMappableCommand("right")]);
   SetMQ2KeyBind("UNSTICK_STRAFE_LFT",false,pKeypressHandler->NormalKey[FindMappableCommand("strafe_left")]);
   SetMQ2KeyBind("UNSTICK_STRAFE_LFT",true,pKeypressHandler->AltKey[FindMappableCommand("strafe_left")]);
   SetMQ2KeyBind("UNSTICK_STRAFE_RGT",false,pKeypressHandler->NormalKey[FindMappableCommand("strafe_right")]);
   SetMQ2KeyBind("UNSTICK_STRAFE_RGT",true,pKeypressHandler->AltKey[FindMappableCommand("strafe_right")]);
}

VOID DestroyBinds()
{
   if (!MoveBindsLoaded)
      return;
   RemoveMQ2KeyBind("UNSTICK_FWD");
   RemoveMQ2KeyBind("UNSTICK_BCK");
   RemoveMQ2KeyBind("UNSTICK_LFT");
   RemoveMQ2KeyBind("UNSTICK_RGT");
   RemoveMQ2KeyBind("UNSTICK_STRAFE_LFT");
   RemoveMQ2KeyBind("UNSTICK_STRAFE_RGT");
}

// Called once, when the plugin is to initialize
PLUGIN_API VOID InitializePlugin(VOID)
{
   DebugSpewAlways("Initializing MQ2MoveUtils");

   // Add commands, macro parameters, hooks, etc.
   AddCommand("/circle",CircleCommand,0,1,1);
   AddCommand("/stick",StickCommand);
   AddMQ2Data("Stick",dataStick);
   AddCommand("/moveto",MoveToCommand,0,1,1);
   AddMQ2Data("MoveTo",dataMoveTo);

   pStickType = new MQ2StickType;

   srand((unsigned int)time(NULL));
   if (gGameState==GAMESTATE_INGAME) {
      CreateBinds();
   }
   GetSystemTime(&stPrevCirc);
   GetSystemTime(&stPrevStick);
}

// Called once, when the plugin is to shutdown
PLUGIN_API VOID ShutdownPlugin(VOID)
{
   DebugSpewAlways("Shutting down MQ2MoveUtils");

   // Remove commands, macro parameters, hooks, etc.
   RemoveMQ2Data("Stick");
   RemoveCommand("/circle");
   RemoveCommand("/stick");
   RemoveMQ2Data("MoveTo");
   RemoveCommand("/moveto");

   delete pStickType;
   delete pMoveToType;

   DestroyBinds();
}

PLUGIN_API DWORD OnIncomingChat(PCHAR Line, DWORD Color)
{
   if( breakOnGateEnabled && (stickHold?(stickTarget!=NULL):(ppTarget && pTarget)) ) {
      char szTemp[MAX_STRING];

      sprintf(szTemp,"%s Gates.",stickHold?stickTarget->DisplayedName:((PSPAWNINFO)pTarget)->DisplayedName);
      if( ! strcmp(szTemp,Line) ) {
         DoFwd(false);
         stickOn = false;
      }
   }

   return 0;
}

PLUGIN_API VOID SetGameState(DWORD GameState)
{
   if (GameState==GAMESTATE_INGAME) {
      CreateBinds();
      Load_INI();
   } else {
      stickOn=false;
      stickPaused=false;
      stickHold=false;
      setDist=false;
      stickTarget=NULL;
      bCircling=false;
   }
}

// Called after entering a new zone
PLUGIN_API VOID OnZoned(VOID)
{
   DoWalk(false);
}



MQ2Twist.cpp - Bard song twisting plugin for MacroQuest2
koad 03-24-04 Original plugin
CyberTech 03-31-04 w/ code/ideas from Falco72 & Space-boy
Cr4zyb4rd 08-19-04 taking over janitorial duties
Pheph 08-24-04 cleaning up use of MQ2Data

Rich (BB code):
 // MQ2Twist.cpp - Bard song twisting plugin for MacroQuest2
//
//    koad 03-24-04 Original plugin (http://macroquest.sourceforge.net/phpBB2/viewtopic.php?t=5962&start=2)
//    CyberTech 03-31-04 w/ code/ideas from Falco72 & Space-boy
//    Cr4zyb4rd 08-19-04 taking over janitorial duties
//    Pheph 08-24-04 cleaning up use of MQ2Data

/*
   MQ2Twist Version 1.3

      Usage:   
         /twist # # # # # - Twists in the order given.
            Valid options are 1 thru 9 for song gems, and 10 thru 19 for item clicks.
            These may be mixed in any order, and repeats are allowable. Up to 10 may be
            specified.
            If a song is specified with a duration longer than standard (ie, selos)
            that song will be twisted based on it's duration.  For example, riz+mana+selos
            would be a 2 song twist with selos pulsed every 2.5 min.
         /twist once # # # # # - Twists in the order given, then reverts to original twist
         /twist hold <gem #> - Pause twisting and sing only the specified song
            /sing <gem#> - alias for /twist hold
         /twist stop/end/off - stop twisting, does not clear the twist queue
            /stoptwist - alias for above
         /twist or /twist start - Resume the twist after using /twist hold or /twist stop
       /twist reset - Reset timers for item clicks and long duration songs
         /twist delay # - 10ths of a second, minimum of 30, default 33
         /twist adjust # - in ticks, how early to recast long duration songs
         /twist reload - reload the INI file to update item clicks
         /twist slots - List the slots/items defined in the INI and their #'s
         /twist quiet - Toggles songs listing and start/stop messages for one-shot twists

      ----------------------------
      Item Click Method:
         MQ2Twist uses /itemnotify slotname rightmouseup to perform item clicks.

         The INI file allows you to specify items by name (with name=itemname), or by
       inventory slot (with slot=slotname).  If both a name and slot are defined for an
       item, the plugin will attempt to swap the item into that slot (via the /exchange
       command) and replace the original item when casting is complete.
      
       The example INI file below contains examples of the types of usage.

      ----------------------------
      Examples:
         /twist 1
            Sing gem 1 forever
         /twist 1 2 3
            Twist gems 1,2, and 3 forever
         /twist 1 2 3 10
            Twist gems 1,2,3, and clicky 10, forever
         /twist hold 4 or /sing 4
            Sing gem 4 until another singing-related /twist command is given

      ----------------------------
      MQ2Data Variables:
         bool   Twist         Currently Twisting: true/false, if NULL plugin is not loaded
         Members:
            bool     Twisting  Currently twisting: true/false.
            int      Current   Returns the curent gem number being sung, -1 for item, or 0 if not twisting
            int      Next      Returns the next gem number to be sung, -1 for item, or 0 if not twistsing
            string   List      Returns the twist sequence in a format suitable for /twist

      ----------------------------
     
     The ini file has the format:
         [MQ2Twist]
         Delay=32       Delay between twists. Lag & System dependant.
       Adjust=1       This defines  how many ticks before the 'normal' recast time to cast a long song.
                        Long songs are defined as songs greater than 3 ticks in length.  If set to 1 tick,
                        and a song lasts 10 ticks, the song will be recast at the 8 tick mark, instead of
                        at the 9 tick mark as it normally would.

         [Click_10] thru [Click_19]
         CastTime=30              Casting Time, -1 to use the normal song delay
         ReCastTime=0             How often to recast, 0 to twist normally.
         Name="Fife of Battle"    Item name for /itemnotify
       Slot=neck                Slot name for /itemnotify

         Delay, CastTime and ReCastTime are specified in 10ths of a
         second, so 10 = 1 second, and so on.

         INI File Example:
            [MQ2Twist]
            Delay=31
         Quiet=0

            ;Shadowsong cloak
            [Click_10]
            CastTime=30
            ReCastTime=350
            Name=Shadowsong Cloak
            Slot=DISABLED

            ;girdle of living thorns (current belt will be swapped out)
            [Click_11]
            CastTime=0
            ReCastTime=11600
            Name=Girdle of Living Thorns
            Slot=waist

            ;nature's melody
            [Click_12]
            CastTime=-1
            ReCastTime=135
            Name=DISABLED
            Slot=mainhand

            ;lute of the flowing waters
            [Click_13]
            CastTime=0
            ReCastTime=0
            Name=Lute of the Flowing Waters
            Slot=DISABLED

            [Click_14] ... [Click_19]
            CastTime=33
            ReCastTime=0
            Name=DISABLED
            Slot=DISABLED

      ----------------------------

Changes:
   10-05-04
      Support "swap in and click" items

    09-15-04
      Support extra spell slot from Omens of War AA

    09-01-04
      Command: /twist quiet to toggle some of the spam on/off
      Various code fixes/speedups

    08-29-04
      Moved LONGSONG_ADJUST into INI file and made /twist adjust command to set it on
      the fly

   08-25-04
      Changed output for /twist once to be slightly less misleading
      Reset click/song timers every time they're called with /twist hold or /twist once;
      if the user's specifying that song, they obviously want to cast it anyway.
      Removed the variable MissedNote as close inspection revealed the only place it was
      checked for was the line that set it. /boggle
      Minor code tweaks, cleanups, formatting changes, etc

   08-24-04 (Pheph)
      Modified it to use only one TLO, as I found it somewhat messy having 4 different ones.
      All the functionality of the old TLO's are now members of ${Twist}
      ${Twising} is now ${Twist.Twisting}, or just ${Twist}
      ${TwistCurrent} is now ${Twist.Current}
      ${TwistNext} is now ${Twist.Next}
      ${TwistList} is now ${Twist.List}

   08-23-04
      Reset_ItemClick_Timers was being called far too often.  Now the only time we reset
     is if a new list of songs are specified.  "/twist ${TwistList}" is a useful alias
     if you for some reason want the old behavior.
      Sing or /twist hold now resets the cast/item timer for that song only, rather than
     the entire list.
     Command: /twist reset calls Reset_ItemClick_Timers without interfering with the
     state of the current twists.
    
   08-22-04
      Command: /twist once [songlist] will cycle through the songs entered once, then
     revert to the old twist, starting with the song that was interrupted.
     Removed command "/twist on", it was making the string compare for "once" annoying,
     and I didn't think it was worth the effort for a redundant command.
      /twist delay with no argument now returns the delay without resetting it.  Values
     less than 30 now give a warning...maybe they're not bards or have some other
     reason for using a low value.

   08-19-04
      Minor revamp of item notification.  Removed ITEMNOTIFY define and kludged in some
      changes from Virtuoso65 to get casting by item name working.  /cast is no longer
      used.
      Added INI file support for above change.  File now uses distinct entries for item
      names and slots.  *Quotes not required for multi-word item names in INI.*
      Fixed the MQ2Data value TwistCurrent to display the current song as-advertised, and
      added a new value TwistNext with the old behavior of showing the next song in the
      queue. (Useful in scripting)
      Removed a few DebugSpews that were mega-spamming my debugger output.
      CastTime of -1 in the INI file now causes the default delay to be used.
   
   06-01-04
      Added LONGSONG_ADJUST (default to 1 tick) to help with the timing of recasting long
      songs, such as selo's.
      Twisting is now paused when you sit (this would include camping).  This fixes
      problems reported by Chyld989 (twisting across chars) and Kiniktoo (new autostand on
      cast 'feature' in EQ makes twisting funky)

   05-19-04
      Added workaround for incorrect duration assumption for durationtype=5 songs, such as
      Cassindra's Chant of Clarity or Cassindra's Chorus of Clarity.
      Added check of char state before casting a song. Actually added for 1.05
         Checked states and resulting action are:
            Feigned, or Ducking = /stand
            Stunned = Delay
            Dead - Stop twisting.
         If you're a monk using this to click your epic, you'll want to disable the autostand on feign code =)


   05-05-05
      Fixed CTD on song unmem or death, while twisting.  Oops
      Removed circle functionality.  It's better suited for a plugin like the MQ2MoveUtils
         plugin by tonio at http://macroquest.sourceforge.net/phpBB2/viewtopic.php?t=6973

   05-01-04
      Fixed problem with using pchar before state->ingame causing CTD on eq load (thanks MTBR)
      Fixed vc6 compile error w/ reset_itemclick_timers
      Replaced various incantations of pChar and pSpawn with GetCharInfo()
      Fixed /circle behavior w/ unspecified y/x
      Fixed /circle on when already circling and you want to update loc
      Added output of parsed circle parameters on start.

   04-25-04
      Converted to MQ2Data
         Top Level Objects:
            bool   Twisting      (if NULL plugin is not loaded)
            int      TwistCurrent
            string   TwistList
      Removed $Param synatax for above
      Added check to make sure item twists specified are defined
      Fixed error with twist parameter processing
      Changed twist startup output to be more verbose
      Command: /twist on added as alias for /twist start
      INI File is now named per-character (MQ2Twist_Charname.ini)
         * Be sure to rename existing ini files
      Modified twist routine to take into account songs with
         non-0 recast times or longer than 3 tick durations,
         and only re-cast them after the appropriate delay.
         This is for songs like Selos 2.5 min duration, etc.
         * Note that this makes no attempt to recover if the song
         effect is dispelled, your macro will need to take care
         of that.
      Added ability to compile-time change the method used for
         clicking items.

   04-13-04
      Changed /circle command to allow calling w/o specifying loc
      Corrected a problem with multiple consecutive missed notes
      Added handling of attempting to sing while stunned
      Command: /twist slots, to list the slot to # associations
      Command: /twist reload, to reload the ini file on the fly
      Command: /twist end, /twist off as aliases for /twist stop
      Command: /sing #, as an alias for /twist hold #

      Added support for item clickies.  Clickies are specified
      as "gem" 10-19. For example, /twist 1 2 10 12

      Added INI file support for storing item clicky info
      and default twist delay.

   04-11-04
      Integrated the /circle code from Easar, runs in a circle.  type
      /circle for help.
*/

#include "../MQ2Plugin.h"

PreSetup("MQ2Twist");

typedef struct _ITEMCLICK {
   int cast_time;
   int recast;
   long castdue;
   int disabled;
   int nousename;
   CHAR slot[MAX_STRING];
   CHAR name[MAX_STRING];
} ITEMCLICK;

int MQ2TwistEnabled = 0;
const int MAX_SONG=10;
int LONGSONG_ADJUST=1; // In TICKS, not seconds.  Used for long songs (greater than 3 ticks in duration). See docs.
int CAST_TIME=33;
int NumSongs=0;
int AltNumSongs=0;
int Song[MAX_SONG*2];
int AltSong[MAX_SONG*2];
long SongNextCast[MAX_SONG*2];
ITEMCLICK ItemClick[MAX_SONG];
int CurrSong=0;
int AltCurrSong=0;
int PrevSong=0;
int HoldSong=0;
long CastDue=0;
bool bTwist=false;
bool altTwist=false;
bool quiet;
CHAR SwappedOutItem[MAX_STRING];
CHAR SwappedOutSlot[MAX_STRING];

long GetTime();
VOID TwistCommand(PSPAWNINFO pChar, PCHAR szLine);
VOID StopTwistCommand(PSPAWNINFO pChar, PCHAR szLine);
VOID SingCommand(PSPAWNINFO pChar, PCHAR szLine);
BOOL dataTwist(PCHAR szIndex, MQ2TYPEVAR &Ret);
CHAR MQ2TwistTypeTemp[MAX_STRING]={0};

//get current timestamp in tenths of a second
long GetTime()
{
   SYSTEMTIME st;
   ::GetSystemTime(&st);
   long lCurrent=0;
   lCurrent  = st.wDay    * 24 * 60 * 60 * 10;
   lCurrent += st.wHour        * 60 * 60 * 10;
   lCurrent += st.wMinute           * 60 * 10;
   lCurrent += st.wSecond                * 10;
   lCurrent += (long)(st.wMilliseconds/100);
   return (lCurrent);
}

VOID MQ2TwistDoCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   HideDoCommand(pChar, szLine, FromPlugin);
}

VOID DoSwapOut()
{
   CHAR szTemp[MAX_STRING];
   if (SwappedOutItem[0]) {
      sprintf(szTemp,"/exchange \"%s\" %s",SwappedOutItem,SwappedOutSlot);
      MQ2TwistDoCommand(NULL, szTemp);
      SwappedOutItem[0]=0;
   }
}

VOID DoSwapIn(int Index)
{
   CHAR szTemp[MAX_STRING];
   if (strnicmp(ItemClick[Index].slot,"DISABLED",8)) {
      sprintf(szTemp,"${InvSlot[%s].Item.Name}",ItemClick[Index].slot);
      ParseMacroData(szTemp);
      strcpy(SwappedOutItem,szTemp);
      strcpy(SwappedOutSlot,ItemClick[Index].slot);
      sprintf(szTemp,"/exchange \"%s\" %s",ItemClick[Index].name,ItemClick[Index].slot);
      MQ2TwistDoCommand(NULL, szTemp);
   }
}

VOID Reset_ItemClick_Timers()
{
   int i;
   for (i=0;i<10;i++) {
      ItemClick.castdue = 0;
   }
   for (i=0;i<MAX_SONG*2;i++) {
      SongNextCast = 0;
   }
}


VOID Update_INIFileName() {
   if (GetCharInfo()) {
      sprintf(INIFileName,"%s\\MQ2Twist_%s.ini",gszINIPath,GetCharInfo()->Name);
   } else {
      sprintf(INIFileName,"%s\\MQ2Twist.ini",gszINIPath);
   }
}

VOID Load_MQ2Twist_INI()
{
   CHAR szTemp[MAX_STRING]={0};
   CHAR szSection[MAX_STRING]={0};

   Update_INIFileName();

   CAST_TIME = GetPrivateProfileInt("MQ2Twist","Delay",33,INIFileName);
   sprintf(szTemp, "%d", CAST_TIME);
   WritePrivateProfileString("MQ2Twist","Delay",szTemp,INIFileName);
   quiet = GetPrivateProfileInt("MQ2Twist","Quiet",0,INIFileName)? 1 : 0;
   sprintf(szTemp, "%d", quiet);
   WritePrivateProfileString("MQ2Twist","Quiet",szTemp,INIFileName);
   
   LONGSONG_ADJUST = GetPrivateProfileInt("MQ2Twist","Adjust",1,INIFileName);
   sprintf(szTemp, "%d", LONGSONG_ADJUST);
   WritePrivateProfileString("MQ2Twist","Adjust",szTemp,INIFileName);
   
   for (int i=0;i<10;i++) {
      sprintf(szSection, "Click_%d", i+10);
      ItemClick.cast_time = GetPrivateProfileInt(szSection,"CastTime",0,INIFileName);
      ItemClick.recast = GetPrivateProfileInt(szSection,"ReCastTime",0,INIFileName);

      GetPrivateProfileString(szSection,"Name","DISABLED",ItemClick.name,MAX_STRING,INIFileName);
      GetPrivateProfileString(szSection,"Slot","DISABLED",ItemClick.slot,MAX_STRING,INIFileName);
      if(!strnicmp("DISABLED", ItemClick.name, 8)) {
         if (!strnicmp("DISABLED", ItemClick.slot, 8)) {
            ItemClick.disabled = true;
            DebugSpew("MQ2Twist: Slot %d disabled",i+1);
         } else {
            ItemClick.nousename = true;
            ItemClick.disabled = false;
         }
      } else ItemClick.disabled = false;
      // Write the values above back to disk, mostly to initialize it for easy editing.
      sprintf(szTemp, "%d", ItemClick.cast_time);
      WritePrivateProfileString(szSection,"CastTime",szTemp,INIFileName);
      // If the CastTime is set to -1 in the INI file, use the default.
      ItemClick.cast_time = ItemClick.cast_time==-1 ? CAST_TIME : ItemClick.cast_time;

      sprintf(szTemp, "%d", ItemClick.recast);
      WritePrivateProfileString(szSection,"ReCastTime",szTemp,INIFileName);
      WritePrivateProfileString(szSection,"Name",ItemClick.name,INIFileName);
      WritePrivateProfileString(szSection,"Slot",ItemClick.slot,INIFileName);
      DebugSpewAlways("Initializing MQ2Twist: Processed %s", szSection);
   }
}

VOID SingCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   CHAR szTemp[MAX_STRING]={0};
   CHAR szMsg[MAX_STRING]={0};
   int i;

   GetArg(szTemp,szLine,1);
   i=atoi(szTemp);

   if (i>=1 && i<=19) { // valid range?
      HoldSong = i;
      bTwist=true;
      CastDue = -1;
      sprintf(szMsg, "MQ2Twist::Holding Twist and casting gem %d", HoldSong);
      WriteChatColor(szMsg,USERCOLOR_DEFAULT);
      MQ2TwistDoCommand(pChar,"/stopsong");
      if (i>10) { //item?
         ItemClick[i-10].castdue = 0;
      } else SongNextCast = 0; //nope, song
   } else WriteChatColor("MQ2Twist::Invalid gem specified, ignoring",USERCOLOR_DEFAULT);
}

VOID StopTwistCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   bTwist=false;
   HoldSong=0;
   MQ2TwistDoCommand(pChar,"/stopsong");
   WriteChatColor("MQ2Twist::Stopping Twist",USERCOLOR_DEFAULT);
}

VOID PrepNextSong() {
   if (CurrSong>NumSongs) {
      if (altTwist) {
         NumSongs=AltNumSongs;
         CurrSong=PrevSong=AltCurrSong;
         for (int i=0; i<NumSongs; i++) Song=AltSong;
         altTwist=false;
         if (!quiet) WriteChatColor("MQ2Twist::One-shot twist ended, normal twist will resume next pulse",USERCOLOR_DEFAULT);
      } else CurrSong=1;
   }
}

VOID DisplayTwistHelp() {
   WriteChatColor("MQ2Twist - Twist song or songs",USERCOLOR_DEFAULT);
   WriteChatColor("Usage:   /twist <gem#> - Twists in the order given.",USERCOLOR_DEFAULT);
   WriteChatColor("  Valid options are 1 thru 9 for song gems, and 10 thru 19 for item clicks.",USERCOLOR_DEFAULT);
   WriteChatColor("  These may be mixed in any order, and repeats are allowable.",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist hold <gem #> - Pause twisting and sing only the specified song",USERCOLOR_DEFAULT);
   WriteChatColor("  /sing <gem#> - alias for /twist hold",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist once <gem#> Twists once in the order given, then reverts to original twist",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist or /twist start - Resume the twist after using /twist hold or /twist stop",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist reset - Reset timers for item clicks and long duration songs",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist delay # - 10ths of a second, minimum of 30, default 33",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist adjust # - in ticks, how early to recast long duration songs",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist stop/end/off - stop twisting, does not clear the twist queue",USERCOLOR_DEFAULT);
   WriteChatColor("  /stoptwist - alias for /twist stop",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist reload - reload the INI file to update item clicks",USERCOLOR_DEFAULT);
   WriteChatColor("Usage: /twist slots - List the slots defined in the INI and their #'s",USERCOLOR_DEFAULT);
}

// **************************************************  *************************
// Function:      TwistCommand
// Description:   Our /twist command. sing for me!
// **************************************************  *************************
VOID TwistCommand(PSPAWNINFO pChar, PCHAR szLine)
{
   CHAR szTemp[MAX_STRING]={0};
   CHAR szMsg[MAX_STRING]={0};
   CHAR szChat[MAX_STRING]={0};
   PSPELL pSpell;
   int i;

   GetArg(szTemp,szLine,1);

   if (NumSongs && (!strlen(szTemp) || !strnicmp(szTemp,"start", 5))) {
      WriteChatColor("MQ2Twist::Starting Twist",USERCOLOR_DEFAULT);
      DoSwapOut();
      bTwist=true;
      HoldSong=0;
      CastDue = -1;
      return;
   }

   if (!strnicmp(szTemp,"stop", 4) || !strnicmp(szTemp,"end", 3) || !strnicmp(szTemp,"off", 3)) {
      DoSwapOut();
      StopTwistCommand(pChar, szTemp);
      return;
   }

   if (!strnicmp(szTemp,"slots", 5)) {
      WriteChatColor("MQ2Twist 'Song' Numbers for right click effects:",USERCOLOR_DEFAULT);
      for (i=0;i<10;i++) {
         if (ItemClick.disabled) break;
         if (ItemClick.nousename) {
            sprintf(szMsg, "  %d = %s (slot)", i+10, ItemClick.slot);
         } else {
            sprintf(szMsg, "  %d = %s (name) %s (slot)", i+10, ItemClick.name, ItemClick.slot);
       }
         WriteChatColor(szMsg,USERCOLOR_DEFAULT);
      }
      WriteChatColor("---",USERCOLOR_DEFAULT);
      return;
   }

   if (!strnicmp(szTemp,"reload", 6)) {
      WriteChatColor("MQ2Twist::Re-Loading INI Values",USERCOLOR_DEFAULT);
      Load_MQ2Twist_INI();
      return;
   }

   if (!strnicmp(szTemp,"delay", 5)) {
      GetArg(szTemp,szLine,2);
      if (strlen(szTemp)>0) {
         i=atoi(szTemp);
         if (i<=30) {
            WriteChatColor("MQ2Twist::WARNING delay specified is less than standard song cast time",CONCOLOR_RED);
         }
         CAST_TIME=i;
         Update_INIFileName();
         WritePrivateProfileString("MQ2Twist","Delay",itoa(CAST_TIME, szTemp, 10),INIFileName);
         sprintf(szMsg, "MQ2Twist::Set delay to %d, INI updated", CAST_TIME);
      } else sprintf(szMsg, "MQ2Twist::Delay %d", CAST_TIME);
      WriteChatColor(szMsg,USERCOLOR_DEFAULT);
      return;
   }
   
   if (!strnicmp(szTemp,"quiet", 5)) {
      quiet=!quiet;
      sprintf(szTemp,"%d",quiet);
      WritePrivateProfileString("MQ2Twist","Quiet",szTemp,INIFileName);
      sprintf(szMsg,"MQ2Twist::Now being %s",quiet ? "quiet" : "noisy");
      WriteChatColor(szMsg,USERCOLOR_DEFAULT);
      return;
   }
   
   if (!strnicmp(szTemp,"adjust", 6)) {
      GetArg(szTemp,szLine,2);
      if (strlen(szTemp)>0) {
         i=atoi(szTemp);
         LONGSONG_ADJUST=i;
         Update_INIFileName();
         WritePrivateProfileString("MQ2Twist","Adjust",itoa(LONGSONG_ADJUST, szTemp, 10),INIFileName);
         sprintf(szMsg, "MQ2Twist::Long song adjustment set to %d, INI updated", LONGSONG_ADJUST);
      } else sprintf(szMsg, "MQ2Twist::Long song adjustment: %d", LONGSONG_ADJUST);
      WriteChatColor(szMsg,USERCOLOR_DEFAULT);
      return;
   }

   if (!strnicmp(szTemp,"hold", 4)) {
      GetArg(szTemp,szLine,2);
      SingCommand(pChar, szTemp);
      return;
   }

   if (!strnicmp(szTemp,"reset", 5)) {
      Reset_ItemClick_Timers();
      WriteChatColor("MQ2Twist::Timers reset",CONCOLOR_YELLOW);
      return;
   }

   // check help arg, or display if we have no songs defined and /twist was used
   if (!strlen(szTemp) || !strnicmp(szTemp,"help", 4)) {
      DisplayTwistHelp();
      return;
   }

   // if we are "one-shot twisting", save the current song array and current song
   if (!strnicmp(szTemp,"once", 4)) {
      WriteChatColor("MQ2Twist one-shot twisting:",CONCOLOR_YELLOW);
      if (altTwist) {
         CurrSong=NumSongs+1;
         PrepNextSong(); // If CurrSong > NumSongs relaod the song list
      }
      if (NumSongs) {
         AltNumSongs=NumSongs;
         AltCurrSong=CurrSong;
         for (i=0; i<NumSongs; i++) AltSong=Song;
      }
      altTwist=true;
   } else altTwist=false;

   DoSwapOut();
   DebugSpew("MQ2Twist::TwistCommand Parsing twist order");
   NumSongs=0;
   HoldSong=0;
   if (!altTwist) {
      if (!quiet) {
         WriteChatColor("MQ2Twist Twisting:",CONCOLOR_YELLOW);
      } else WriteChatColor("MQ2Twist::Starting Twist",USERCOLOR_DEFAULT);
   }
   for (i=0 + altTwist ? 1 : 0; i<20; i++)
   {
      GetArg(szTemp,szLine,i+1);
      if (!strlen(szTemp))  break;

      Song[NumSongs]=atoi(szTemp);
      if (Song[NumSongs]>=1 && Song[NumSongs]<=19) {
         if ((Song[NumSongs]>9) && ItemClick[Song[NumSongs]-10].disabled) {
            sprintf(szChat, " Undefined item specified (%s) - ignoring (see INI file)", szTemp);
            WriteChatColor(szChat,CONCOLOR_RED);
         } else {
            sprintf(szMsg, " %s - ", szTemp);

            if (Song[NumSongs]<=9) {
               pSpell=GetSpellByID(GetCharInfo2()->MemorizedSpells[Song[NumSongs]-1]);
               if (altTwist) SongNextCast[NumSongs] = 0;
               if (pSpell) strcat(szMsg, pSpell->Name);
            } else {
               if (ItemClick[Song[NumSongs]-10].nousename) {
                  strcat(szMsg, ItemClick[Song[NumSongs]-10].slot);
               } else {
                  strcat(szMsg, ItemClick[Song[NumSongs]-10].name);
               }
               if (altTwist) ItemClick[NumSongs].castdue = 0;
            }
            if (!quiet) WriteChatColor(szMsg,COLOR_LIGHTGREY);
            NumSongs++;
         }
      } else {
         sprintf(szChat, " Invalid gem specified (%s) - ignoring", szTemp);
         WriteChatColor(szChat,CONCOLOR_RED);
      }
   }

   sprintf(szTemp, "Twisting %d song%s", NumSongs, NumSongs>1 ? "s" : "");
   if (!quiet) WriteChatColor(szTemp,CONCOLOR_YELLOW);

   if (NumSongs>0) bTwist=true;
   CurrSong = 1;
   PrevSong = 1;
   CastDue = -1;
   MQ2TwistDoCommand(pChar,"/stopsong");
   if (!altTwist) Reset_ItemClick_Timers();
}

/*
Checks to see if character is in a fit state to cast next song/item

Note 1: Do not try to correct SIT state, or you will have to stop the
twist before re-memming songs

Note 2: Since the auto-stand-on-cast bullcrap added to EQ a few patches ago,
chars would stand up every time it tried to twist a song.  So now
we stop twisting at sit.
*/
BOOL CheckCharState() {
   if (!bTwist) return FALSE;

   if (GetCharInfo()) {
      if (GetCharInfo()->Stunned==1) return FALSE;
      switch (GetCharInfo()->standstate) {
       case STANDSTATE_SIT:
          WriteChatColor("MQ2Twist::Stopping Twist",USERCOLOR_DEFAULT);
          bTwist = FALSE;
          return FALSE;
          break;
       case STANDSTATE_FEIGN:
          MQ2TwistDoCommand(NULL,"/stand");
          return FALSE;
          break;
       case STANDSTATE_DEAD:
          WriteChatColor("MQ2Twist::Stopping Twist",USERCOLOR_DEFAULT);
          bTwist = FALSE;
          return FALSE;
          break;
       default:
          break;
      }
   }

   if (pCastingWnd) {
      PCSIDLWND pCastingWindow = (PCSIDLWND)pCastingWnd;
      if (pCastingWindow->Show == 1) return FALSE;
      // Don't try to twist if the casting window is up, it implies the previous song
      // is still casting, or the user is manually casting a song between our twists
   }
   return TRUE;
}
class MQ2TwistType *pTwistType=0;

class MQ2TwistType : public MQ2Type
{
public:
   enum TwistMembers
   {
      Twisting=1,
      Next=2,
      Current=3,
      List=4,
   };

   MQ2TwistType():MQ2Type("twist")
   {
      TypeMember(Twisting);
      TypeMember(Next);
      TypeMember(Current);
      TypeMember(List);
   }
   ~MQ2TwistType()
   {
   }

   bool GetMember(MQ2VARPTR VarPtr, PCHAR Member, PCHAR Index, MQ2TYPEVAR &Dest)
   {
      PMQ2TYPEMEMBER pMember=MQ2TwistType::FindMember(Member);
      if (!pMember)
         return false;
      switch((TwistMembers)pMember->ID)
      {
      case Twisting:
         /* Returns: bool
            0 - Not Twisting
            1 - Twisting
         */
         Dest.Int=bTwist;
         Dest.Type=pBoolType;
         return true;
      case Next:
         /* Returns: int
            0 - Not Twisting
            -1 - Casting Item
            1-9 - Current Gem
         */
         Dest.Int=HoldSong ? HoldSong : Song[CurrSong-1];
         if (Dest.Int>9) Dest.Int = -1;
         if (!bTwist) Dest.Int = 0;

         Dest.Type=pIntType;
         return true;
      case Current:
         Dest.Int=HoldSong ? HoldSong : Song[PrevSong-1];
         if (Dest.Int>9) Dest.Int = -1;
         if (!bTwist) Dest.Int = 0;

         Dest.Type=pIntType;
         return true;
      case List:
         /* Returns: string
            Space separated list of gem and item #'s being twisted, in order
         */
         int a;
         CHAR szTemp[MAX_STRING] = {0};

         MQ2TwistTypeTemp[0] = 0;
         for (a=0; a<NumSongs; a++) {
            sprintf(szTemp, "%d ", Song[a]);
            strcat(MQ2TwistTypeTemp, szTemp);
         }

         Dest.Ptr=&MQ2TwistTypeTemp[0];
         Dest.Type=pStringType;
         return true;
      }
      return false;
   }

   bool ToString(MQ2VARPTR VarPtr, PCHAR Destination)
   {
      if (bTwist)
         strcpy(Destination,"TRUE");
      else
         strcpy(Destination,"FALSE");
      return true;
   }

   bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
   {
      return false;
   }
   bool FromString(MQ2VARPTR &VarPtr, PCHAR Source)
   {
      return false;
   }
};

BOOL dataTwist(PCHAR szName, MQ2TYPEVAR &Dest)
{
   Dest.DWord=1;
   Dest.Type=pTwistType;
   return true;
}


// ******************************
// **** MQ2 API Calls Follow ****
// ******************************

PLUGIN_API VOID InitializePlugin(VOID)
{
   DebugSpewAlways("Initializing MQ2Twist");

   AddCommand("/twist",TwistCommand,0,1,1);
   AddCommand("/sing",SingCommand,0,1,1);
   AddCommand("/stoptwist",StopTwistCommand,0,0,1);;
    AddMQ2Data("Twist",dataTwist);

    pTwistType = new MQ2TwistType;

}

PLUGIN_API VOID ShutdownPlugin(VOID)
{
   DebugSpewAlways("MQ2Twist::Shutting down");

   RemoveCommand("/twist");
   RemoveCommand("/sing");
   RemoveCommand("/stoptwist");
    RemoveMQ2Data("Twist");

    delete pTwistType;
}

PLUGIN_API VOID OnPulse(VOID)
{
   CHAR szTemp[MAX_STRING] = {0};
   PSPELL pSpell;
   int a,b;

   if (!MQ2TwistEnabled || !CheckCharState()) return;

   if ((HoldSong>0) || ((NumSongs==1) && !altTwist)) {
      // DebugSpew("MQ2Twist::Pulse - Single Song");
      if ( CastDue<0 || ( ((CastDue-GetTime()) <= 0 ) && (GetCharInfo()->pSpawn->pActorInfo->CastingSpellID == -1) ) ) {
         int SongTodo = HoldSong ? HoldSong : Song[0];
         if (SongTodo <= 9) {
            DebugSpew("MQ2Twist::Pulse - Single Song (Casting Gem %d)", SongTodo);
            sprintf(szTemp,"/multiline ; /stopsong ; /cast %d", SongTodo);
            MQ2TwistDoCommand(NULL,szTemp);
            CastDue = GetTime()+CAST_TIME;
         } else {
            if (ItemClick[SongTodo-10].castdue-GetTime() <= 0) {
               if (ItemClick[SongTodo-10].nousename) {
                  DebugSpew("MQ2Twist::Pulse - Single Song (Casting Item %d - %s)", SongTodo, ItemClick[SongTodo-10].slot);
                  sprintf(szTemp,"/multiline ; /stopsong ; /itemnotify %s rightmouseup", ItemClick[SongTodo-10].slot);
               } else {
                  DebugSpew("MQ2Twist::Pulse - Single Song (Casting Item %d - %s)", SongTodo, ItemClick[SongTodo-10].name);
                  DoSwapIn(SongTodo-10);
                  sprintf(szTemp,"/multiline ; /stopsong ; /itemnotify ${FindItem[%s].InvSlot.Name} rightmouseup", ItemClick[SongTodo-10].name);
               }
               MQ2TwistDoCommand(NULL,szTemp);
               ItemClick[SongTodo-10].castdue = ItemClick[SongTodo-10].recast ? (GetTime()+ItemClick[SongTodo-10].cast_time+ItemClick[SongTodo-10].recast) : (GetTime()+CAST_TIME);
               CastDue = ItemClick[SongTodo-10].castdue;
            }
         }
      }
   } else {
      int SongTodo = Song[CurrSong-1];
      if (NumSongs && ((CastDue-GetTime()) <= 0)) {
         DoSwapOut();
         if (SongTodo <= 9) {
            if (SongNextCast[CurrSong-1]-GetTime() <= 0) {
               DebugSpew("MQ2Twist::OnPulse - Next Song = %s", szTemp);
               sprintf(szTemp,"/multiline ; /stopsong ; /cast %d", SongTodo);
               MQ2TwistDoCommand(NULL,szTemp);
               pSpell=GetSpellByID(GetCharInfo2()->MemorizedSpells[Song[CurrSong-1]-1]);
               if(!pSpell) {
                  WriteChatColor("Songs not present - suspending twist.  /twist to resume",CONCOLOR_RED);
                  bTwist = FALSE;
                  return;
               }
               a = pSpell->RecastTime/1000 * 60;                     // recasttime in 10's of a second
               b = GetSpellDuration(pSpell,GetCharInfo()->pSpawn) * 60;   // duration in 10's of a second
               if (pSpell->DurationType == 5 && !pSpell->DurationValue1) {
                  b = 18;   //FIXME - Remove once GetSpellDuration handles duration type5
               }
               CastDue = GetTime()+CAST_TIME;
               if (a > 0 || b > 180) { // We only care about songs with > 3 tick durations or non-0 recast times
                  SongNextCast[CurrSong-1] = GetTime() + (a > b ? a : b) - CAST_TIME - (LONGSONG_ADJUST*60);   // Cast next after greater of recasttime or duration, minus LONGSONG_ADJUST ticks.
               } else {
                  SongNextCast[CurrSong-1] = CastDue;
               }
               PrevSong=CurrSong;
            } // if it's not time for currsong to be re-sung, skip it in the twist
            CurrSong++;
            PrepNextSong();
         } else {
            if (ItemClick[SongTodo-10].castdue-GetTime() <= 0) {
               if (ItemClick[SongTodo-10].nousename) {
                  DebugSpew("MQ2Twist::Pulse - Next Song (Casting Slot %d - %s)", SongTodo, ItemClick[SongTodo-10].slot);
                  sprintf(szTemp,"/multiline ; /stopsong ; /itemnotify %s rightmouseup", ItemClick[SongTodo-10].slot);
               } else {
                  DebugSpew("MQ2Twist::Pulse - Next Song (Casting Item %d - %s)", SongTodo, ItemClick[SongTodo-10].name);
                  DoSwapIn(SongTodo-10);
                  sprintf(szTemp,"/multiline ; /stopsong ; /itemnotify ${FindItem[%s].InvSlot.Name} rightmouseup", ItemClick[SongTodo-10].name);
               }
               MQ2TwistDoCommand(NULL,szTemp);
               ItemClick[SongTodo-10].castdue = ItemClick[SongTodo-10].recast ? (GetTime()+ItemClick[SongTodo-10].cast_time+ItemClick[SongTodo-10].recast) : (GetTime()+CAST_TIME);
               CastDue = GetTime()+ItemClick[SongTodo-10].cast_time;
            }
            PrevSong=CurrSong;   // Increment twist position even if we didn't do an itemnotify - this might have a long recast
            CurrSong++;         // interval set, and we just skip it until it's time to recast, rather than keep a separate timer.
            PrepNextSong();
         }   
      }
   }     
}

PLUGIN_API DWORD OnIncomingChat(PCHAR Line, DWORD Color)
{
   if (!bTwist || !MQ2TwistEnabled) return 0;
   // DebugSpew("MQ2Twist::OnIncomingChat(%s)",Line);
   
   if ( !strcmp(Line,"You miss a note, bringing your song to a close!") ||
      !strcmp(Line,"You haven't recovered yet...") ||
      !strcmp(Line,"Your spell is interrupted.") ) {
         DebugSpew("MQ2Twist::OnIncomingChat - Song Interrupt Event");
         if (!HoldSong) CurrSong=PrevSong;
         CastDue = -1;
         SongNextCast[CurrSong-1] = -1;
         return 0;
      }

   if (!strcmp(Line,"You can't cast spells while stunned!") ) {
      DebugSpew("MQ2Twist::OnIncomingChat - Song Interrupt Event (stun)");
      if (!HoldSong) CurrSong=PrevSong;
      CastDue = GetTime() + 10;
      // Wait one second before trying again, to avoid spamming the trigger text w/ cast attempts
      return 0;
   }
   return 0;
}

PLUGIN_API VOID SetGameState(DWORD GameState)
{
   DebugSpew("MQ2Twist::SetGameState()");
   if (GameState==GAMESTATE_INGAME)
   {
      MQ2TwistEnabled = true;
      Load_MQ2Twist_INI();
   } else {
      MQ2TwistEnabled = false;
   }
} 
 
Last edited:
MQ2CSum by Cronic

See this thread for comments and the .dll download: MQ2CSum

Rich (BB code):
#include "../MQ2Plugin.h"

#undef PKT_CORPSE_DRAG
#undef PKT_CORPSE_DROP
#undef PKT_UPDATE_POSITION
#undef _UPDATEPOSITIONPKT

#define PKT_CORPSE_DRAG      0x6E8B
#define PKT_CORPSE_DROP      0x4560
#define PKT_UPDATE_POSITION  0x2B94

PreSetup("MQ2CSum");

VOID SumCorpseCmd(PSPAWNINFO pChar, PCHAR szLine)
{
	// check for target
	if (!pTarget || !ppTarget) return;
	
	// make sure it's a corpse
	PSPAWNINFO Target = (PSPAWNINFO)pTarget;
	if (Target->Type != SPAWN_CORPSE) return;

	// setup move packet
	struct _UPDATEPOSITIONPKT {
		unsigned short SpawnID;
		unsigned short Data0x02;
		unsigned short Heading:12;
		unsigned short Data0x04:4;
		unsigned char Data0x06[2];
		float DeltaY;
		float X;
		float DeltaX;
		int DeltaHeading:10;
		int Data0x14:6;
		int Data10x16:6;
		int Data20x16:10;
		float Z;
		float Y;
		float DeltaZ;
	} P;

	// init move packet
	ZeroMemory(&P, sizeof(P));
	P.SpawnID = (unsigned short)pChar->SpawnID;
	P.Heading = (unsigned int)(pChar->Heading * 4);

	// jump to
	P.Z = Target->Z;
	P.Y = Target->Y;
	P.X = Target->X;
	SendEQMessage(PKT_UPDATE_POSITION, &P, sizeof(P));

	// corpse drag
	char szCorpseName[152] = {0};
	strcpy(szCorpseName, Target->Name);
	SendEQMessage(PKT_CORPSE_DRAG, szCorpseName, 152);

	// jump back
	P.Z = pChar->Z;
	P.Y = pChar->Y;
	P.X = pChar->X;
	SendEQMessage(PKT_UPDATE_POSITION, &P, sizeof(P));

	// corpse drop
	SendEQMessage(PKT_CORPSE_DROP, "", 0);
}

PLUGIN_API VOID InitializePlugin(VOID)
{
	AddCommand("/sumcorpse", SumCorpseCmd);
}

PLUGIN_API VOID ShutdownPlugin(VOID)
{
	RemoveCommand("/sumcorpse");
}
 
Last edited:
MQ2Docrack by

Fist version by jaflemming
Maintenance by Kint
CDoCrackWnd class implementation by Koa
Code clean up and DefaultSetting by bootyjuice

This plugin makes use of a list file to keep track of the offsets for ingame hacks, see these post threads for more information and dll downlaods:

http://www.redguides.com/community/showthread.php?t=534

http://www.redguides.com/community/showthread.php?t=1594

Rich (BB code):
/****************************************************************************** 
 MQ2DoCrack.cpp 
  
 Fist version by jaflemming 
 Maintenance by Kint 
 CDoCrackWnd class implementation by Koa 
 Code clean up and DefaultSetting by bootyjuice 

TO DO: (for developers) 
  *********** 
  Add more information in errors (crack app that caused it, iteration of normal/crack) 
  put in window class 
  *********** 


 This plugin facilitates applying memory patches to the eqgame.exe process.  
 It reads from MQ2DoCrack.ini to determine what hacks are available.  For example: 

 [AddFriends] 
 Description="Add Over 100 Friends" 
 Version="2004.05.12" 
 DefaultSetting= 
 address0=45CA07 
 normal0="75 04" 
 crack0="90 90" 


 Values for DefaultSetting are "on", "off", and "" (blank).  "on" will load 
 the crack upon entering the game.  "off" will force the memory to the normal 
 state upon entering the game. "" will toggle the crack's state. 

 Usage: 

 /docrack list 
   Lists all available cracks and their current status. 

 /docrack <crack name> [on|off] [silent] 
   Apply or remove <crack name>.  [silent] does it without printing out 
   anything (used during startup). 
  
 /showmem <address> <bytes to show> shows X amount of bytes of memory at specified address 

 /dooffset <address> <memory> Writes supplied memory to specified address 

******************************************************************************/ 
#pragma warning(disable:4786) 
#include "../MQ2Plugin.h" 
#include <list> 
#include <vector> 
#define CRACKSTATUS_ON 1 
#define CRACKSTATUS_OFF 0 
#define CRACKSTATUS_ERROR 3 


#include "ByteHandler.h" 
#include "MQ2DoCrack.h" 
#include "MQ2Crackwnd.h" 




PreSetup("MQ2DoCrack"); 

PLUGIN_API VOID InitializePlugin(VOID) 
{ 
   DebugSpewAlways("Initializing MQ2DoCrack"); 
   AddCommand("/docrack",DoCrackHandler); 
   AddCommand("/dooffset",DoOffsetHandler); 
   AddCommand("/showmem",ShowMemHandler); 
         AddXMLFile("MQUI_DoCrackWnd.xml"); 
   AddCommand("/docrackwnd",DoCrackWndCommand,0,1); 
    
   DoCrackClass.InitializeCracks(); 

} 

PLUGIN_API VOID ShutdownPlugin(VOID) 
{ 
   DebugSpewAlways("Shutting down MQ2DoCrack"); 
   RemoveCommand("/docrack"); 
   RemoveCommand("/dooffset"); 
   RemoveCommand("/showmem"); 
      DestroyDoCrackWindow(); 
   RemoveCommand("/docrackwnd"); 
   RemoveXMLFile("MQUI_DoCrackWnd.xml"); 
} 

// Called once directly after initialization, and then every time the gamestate changes 
PLUGIN_API VOID SetGameState(DWORD GameState) 
{ 
   // Initialize the cracks if we haven't already. 
   if (GameState!=GAMESTATE_INGAME && GameState!=3) //prep InitializeCracks to fire on zone 
      bInitialized = false; 
   if ( !bInitialized ) DoCrackClass.InitializeCracks(); 
   //added 
      if (GameState==GAMESTATE_INGAME && !MyWnd) 
   { 
      CreateDoCrackWindow(); 
   } 
   //end added 
} 

void DoCrackHandler(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   DoCrackClass.DoCrack(szLine); 
   return; 
} 


void ShowMemHandler(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   DoCrackClass.ShowMemory(szLine); 
   return; 
} 


void DoOffsetHandler(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   DoCrackClass.DoOffset(szLine); 
   return; 
}
 
MQ2Zone Plugin by Machiavelli

See this thread for full instructions and list of short zone names:


http://www.redguides.com/community/showthread.php?t=55&highlight=mq2zone

Rich (BB code):
#include "../MQ2Plugin.h" 

PreSetup("MQ2Zone"); 
#undef GateBind
#undef ZoneShift
#undef ZoneToGoTo
VOID GateBind(PSPAWNINFO, PCHAR); 
VOID ZoneShift(PSPAWNINFO pChar, PCHAR szLine); 

VOID ZoneShift(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   CHAR szMsg[MAX_STRING] = {0};      
   DWORD ZoneToGoTo; 
   ZoneToGoTo = GetZoneID(szLine);
   if (ZoneToGoTo == -1) {
	   WriteChatColor("Wrong Zone.ShortName, aborting!!",CONCOLOR_RED);
	   return;
   }

   sprintf(szMsg,"Going to zone %s, id %d",szLine,ZoneToGoTo); 
   WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
   GetCharInfo()->ZoneBoundId = ZoneToGoTo; 
   pChar->Type = SPAWN_CORPSE; 
} 

VOID GateBind(PSPAWNINFO pChar, PCHAR szLine) 
{       WriteChatColor ("Gating...",CONCOLOR_RED); 
       pChar->Type = SPAWN_CORPSE; 
} 

PLUGIN_API VOID InitializePlugin(VOID) 
{ 
        AddCommand("/zone",ZoneShift); 
   AddCommand("/gate",GateBind); 
} 


PLUGIN_API VOID ShutdownPlugin(VOID) 
{ 
   DebugSpewAlways("Shutting down MQ2Zone"); 
   RemoveCommand("/gate"); 
   RemoveCommand("/zone"); 
}


in eqdata.h replace
Rich (BB code):
/* 0x12e0 */ BYTE Unknown0x12e0[0x14ec-0x12e0];
with
/* 0x */ BYTE Unknown0xfd8[0x1f8];
/* 0x14d8 */ DWORD ZoneBoundId;
/* 0x14dc */ BYTE field_0x14dc[0x10];
 
Last edited:
MQ2Warp by Machiavelli (Updated 4-12-05 Offset)

See this thread for information about this plugin:

http://www.redguides.com/community/showthread.php?t=27&highlight=mq2zone

MQ2Warp.cpp
Rich (BB code):
include "../MQ2Plugin.h" 
#undef CDisplay__MoveLocalPlayerToSafeCoords
#define CDisplay__MoveLocalPlayerToSafeCoords   0x444C21

PreSetup("MQ2Warp"); 
#undef ExactLocation
#undef zWarp
#undef DoWarp
#undef Warp
#undef SafeYLoc
#undef SafeXLoc
#undef SafeZLoc
VOID DoWarp(float y, float x, float z); 
VOID Warp(PSPAWNINFO pChar, PCHAR szLine); 
VOID zWarp(PSPAWNINFO pChar, PCHAR szLine); 
VOID ExactLocation(PSPAWNINFO pChar); 

VOID ExactLocation(PSPAWNINFO pChar, PCHAR szLine) 
{  CHAR LocMsg[MAX_STRING] = {0}; 
   sprintf(LocMsg, "Your location is %3.6f, %3.6f, %3.6f", pChar->Y, pChar->X, pChar->Z); 
   WriteChatColor(LocMsg); 
   return; 
} 

VOID zWarp(PSPAWNINFO pChar, PCHAR szLine) 
{   CHAR Z[MAX_STRING] = {0}; 
        GetArg(Z,szLine,1); 
        float MyY = pChar->Y; 
        float MyX = pChar->X; 


        if (Z[0]==0) { 
      WriteChatColor("Usage: /zwarp <dist>", CONCOLOR_RED); 
      return; 
        } 

        float NewZ = pChar->Z; 
        NewZ = NewZ + (FLOAT)atof(Z); 
        DoWarp(MyY, MyX, NewZ); 
        return; 
} 

VOID Warp(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   static float LastY; 
   static float LastX; 
   static float LastZ; 
   bRunNextCommand = TRUE; 
   PSPAWNINFO psTarget = NULL; 
   PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
    CHAR command[MAX_STRING]; GetArg(command,szLine,1); 
   CHAR Y[MAX_STRING]; GetArg(Y,szLine,2); 
   CHAR X[MAX_STRING]; GetArg(X,szLine,3); 
   CHAR Z[MAX_STRING]; GetArg(Z,szLine,4); 
   if ( 
      stricmp(command, "succor") != 0 && 
      stricmp(command, "loc") != 0 && 
      stricmp(command, "last") != 0 && 
      stricmp(command, "target") != 0 && 
      stricmp(command, "dir") != 0 
   ) { 
      WriteChatColor("Usage: /warp <succor|last|loc <y x z>|dir <dist>| target>", CONCOLOR_RED); 
      return; 
      } else { 
      if (!stricmp(command,"target"))  { 
         if (ppTarget && pTarget) { 
         psTarget = (PSPAWNINFO)pTarget; 
         } 
         if (!psTarget) { 
            WriteChatColor("You must have a target for /warp target.", CONCOLOR_RED); 
            return; 
         } 
         float TargetZ = float (psTarget->Z); 
         float TargetY = float (psTarget->Y); 
         float TargetX = float (psTarget->X); 
                        LastY = TargetY; 
         LastX = TargetX; 
         LastZ = TargetZ; 
         DoWarp(TargetY, TargetX, TargetZ); 
      } else if (!stricmp(command,"succor"))  { 
         static float north = 0; 
         ((PSPAWNINFO)pCharSpawn)->Heading = north; 
         DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
         __asm call dword ptr [MLPTSC]; 
         return; 
      } else if (!stricmp(command,"loc")) { 
      if ((Y[0] == 0) || (X[0] == 0) || (Z[0] == 0)) 
      { 
         WriteChatColor("You must provide <y> <x> <z> if going to a location.", CONCOLOR_RED); 
         return; 
      } 
         LastY = (float)atof(Y); 
         LastX = (float)atof(X); 
         LastZ = (float)atof(Z); 
      DoWarp((float)atof(Y), (float)atof(X), (float)atof(Z)); 
      return; 
      } else if (!stricmp(command,"last")) { 
      if ((LastY==0) || (LastX==0) || (LastZ==0)) 
      { 
         WriteChatColor("You must have warped before to use this command!.", CONCOLOR_RED); 
         return; 
      } 
      DoWarp(LastY, LastX, LastZ); 
      return; 
      } else if (!stricmp(command,"dir")) { 
      if (Y[0]==0) { 
         WriteChatColor("You MUST provide <dist> if going in your current direction.", CONCOLOR_RED); 
         return; 
      } 
      FLOAT angle = (FLOAT)((pChar->Heading)*0.0123); 
      FLOAT dissafegoto = (FLOAT)atof(Y); 
      DoWarp(pChar->Y + (FLOAT)(dissafegoto * cos(angle)), pChar->X + (FLOAT)(dissafegoto * sin(angle)), pChar->Z); 
      return; 
                } 
   } 
} 


VOID DoWarp(float y, float x, float z) 
{ 

        PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
   float SafeY = Zone->SafeYLoc; 
   float SafeX = Zone->SafeXLoc; 
   float SafeZ = Zone->SafeZLoc; 

   Zone->SafeYLoc = y; 
   Zone->SafeXLoc = x; 
   Zone->SafeZLoc = z; 

   CHAR szMsg[MAX_STRING] = {0}; 
   sprintf(szMsg, "Warping to: %3.2f, %3.2f, %3.2f.", Zone->SafeYLoc, Zone->SafeXLoc, Zone->SafeZLoc); 
   WriteChatColor(szMsg, COLOR_PURPLE); 

   DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
   __asm call dword ptr [MLPTSC]; 

   Zone->SafeYLoc = SafeY; 
   Zone->SafeXLoc = SafeX; 
   Zone->SafeZLoc = SafeZ; 
} 

PLUGIN_API VOID InitializePlugin(VOID) 
{ 
   AddCommand("/warp",Warp); 
   AddCommand("/zwarp",zWarp); 
        AddCommand("/exactloc",ExactLocation); 
} 


PLUGIN_API VOID ShutdownPlugin(VOID) 
{ 
   DebugSpewAlways("Shutting down MQ2Warp"); 
   RemoveCommand("/warp"); 
   RemoveCommand("/exactloc"); 
   RemoveCommand("/zwarp"); 
}

Struct Changes

Open up MQ2Main\EQData.h
Go to line 1201 (This is the line as of our latest MQ2 Release), it will look like
Rich (BB code):
/*0x1ec*/   FLOAT   Unknown0x1ec[3];

Delete that line and add these 3 in its place:
Rich (BB code):
/*0x1ec*/ FLOAT SafeYLoc; 
/*0x1f0*/ FLOAT SafeXLoc; 
/*0x1f4*/ FLOAT SafeZLoc;


You will also need to go into mq2pluginhandler.h and remove
Rich (BB code):
if (!stricmp(Filename,"mq2warp")) // ^_^
{
return 0;
}

also you'll need to go into mq2commandapi.h and remove
Rich (BB code):
if (!stricmp(Command,"/warp"))
{
Function=0;
}
 
Last edited:
MQ2FPS plugin

Requires latest version of MQ2, no changes or offsets needed

See this thread for more information: http://www.redguides.com/community/showthread.php?t=54

MQ2FPS.cpp
Rich (BB code):
// MQ2FPS.cpp : Defines the entry point for the DLL application. 
// 

// PLUGIN_API is only to be used for callbacks.  All existing callbacks at this time 
// are shown below. Remove the ones your plugin does not use.  Always use Initialize 
// and Shutdown for setup and cleanup, do NOT do it in DllMain. 

#pragma warning(disable:4786) 
//#define DEBUG_TRY 1 
#include "../MQ2Plugin.h" 

PreSetup("MQ2FPS"); 


VOID MaxFPS(PSPAWNINFO pChar, PCHAR szLine); 
VOID SetForegroundMaxFPS(DWORD MaxFPS); 
VOID SetBackgroundMaxFPS(DWORD MaxFPS); 
VOID FPSCommand(PSPAWNINFO pChar, PCHAR szLine); 

#define FPS_ABSOLUTE  0 
#define FPS_CALCULATE 1 

DWORD MaxFPSMode=FPS_CALCULATE; 

DWORD FPSIndicatorX=5; 
DWORD FPSIndicatorY=25; 
BOOL FPSIndicator=TRUE; 

bool InForeground=false; 

DWORD gFG_Rate=1; 
DWORD gBG_Rate=0; 
BOOL  ReverseFG_Rate=true;// skip every nth frame vs show every nth frame 
BOOL  ReverseBG_Rate=false; 

DWORD CurrentRate=1; 
BOOL CurrentReverse=false; 

DWORD PreDetour=0; 

BOOL InMacro=false; 

char *szFPSModes[]= 
{ 
   "Absolute", 
   "Calculate" 
}; 

HMODULE EQWhMod=0; 
typedef HWND   (__stdcall *fEQW_GetDisplayWindow)(VOID); 
fEQW_GetDisplayWindow EQW_GetDisplayWindow=0; 

BOOL dataFPS(PCHAR szIndex, MQ2TYPEVAR &Ret); 
BOOL dataMaxFPS(PCHAR szIndex, MQ2TYPEVAR &Ret); 
BOOL dataForeground(PCHAR szIndex, MQ2TYPEVAR &Ret); 
VOID RenderCommand(PSPAWNINFO pChar, PCHAR szLine); 

void SetVTable(DWORD index, DWORD value) 
{ 
   DWORD oldperm=0; 
   DWORD Address=(DWORD)&(*((DWORD**)g_pDrawHandler))[index]; 
   DebugSpewAlways("SetVTable writing at address %X to %X",Address,value); 
  VirtualProtectEx(GetCurrentProcess(), (LPVOID)Address, 4,PAGE_EXECUTE_READWRITE, &oldperm); 
 WriteProcessMemory( 
  GetCurrentProcess(), 
  (LPVOID)Address, 
  (LPVOID)&value, 
  4, 
  NULL); 
 VirtualProtectEx(GetCurrentProcess(), (LPVOID)Address, 4, oldperm, &oldperm); 
} 

DWORD GetVTable(DWORD index) 
{ 
   DWORD Ret=(*((DWORD**)g_pDrawHandler))[index]; 
   DebugSpewAlways("GetVTable(%d)=%X",index,Ret); 
   return Ret; 
} 

class CMyDisplay 
{ 
public: 
   VOID Void(VOID) 
   { 
      static DWORD nRender=0; 
      if (++nRender>CurrentRate-1) 
      { 
         nRender=0; 
         if (!CurrentReverse) 
         { 
            Render(); 
         } 
      } 
      else if (CurrentReverse) 
         Render(); 
   } 
   VOID Render(VOID); 
}; 
FUNCTION_AT_VARIABLE_ADDRESS(VOID CMyDisplay::Render(VOID),PreDetour); 

// Called once, when the plugin is to initialize 
PLUGIN_API VOID InitializePlugin(VOID) 
{ 
   DebugSpewAlways("Initializing MQ2FPS"); 
   if (EQWhMod=GetModuleHandle("eqw.dll")) 
   { 
      EQW_GetDisplayWindow=(fEQW_GetDisplayWindow)GetPro  cAddress(EQWhMod,"EQW_GetDisplayWindow"); 
   } 
    
   // Add commands, macro parameters, hooks, etc. 
   // INI Settings 
    DWORD Temp=0; 
    Temp = GetPrivateProfileInt("MQ2FPS","ForegroundMaxFPS",50,INIFileName); 
    SetForegroundMaxFPS(Temp); 
    Temp = GetPrivateProfileInt("MQ2FPS","BackgroundMaxFPS",30,INIFileName); 
    SetBackgroundMaxFPS(Temp); 
    MaxFPSMode = GetPrivateProfileInt("MQ2FPS","Mode",FPS_CALCULATE,INIFileName); 
    FPSIndicatorX = GetPrivateProfileInt("MQ2FPS","IndicatorX",5,INIFileName); 
    FPSIndicatorY = GetPrivateProfileInt("MQ2FPS","IndicatorY",25,INIFileName); 
   FPSIndicator = GetPrivateProfileInt("MQ2FPS","Indicator",TRUE,INIFileName); 

   gBG_Rate = GetPrivateProfileInt("Rendering","BGRate",30,INIFileName); 
   ReverseBG_Rate = GetPrivateProfileInt("Rendering","ReverseBGRate",0,INIFileName); 
   gFG_Rate = GetPrivateProfileInt("Rendering","FGRate",1,INIFileName); 
   ReverseFG_Rate = GetPrivateProfileInt("Rendering","ReverseFGRate",0,INIFileName); 

   // Commands 
   AddCommand("/maxfps",MaxFPS,0,1); 
   AddCommand("/fps",FPSCommand,0,1); 
   AddCommand("/render",RenderCommand,0,1); 

   AddMQ2Data("FPS",dataFPS); 
   AddMQ2Data("MaxFPS",dataMaxFPS); 
   AddMQ2Data("Foreground",dataForeground); 

} 

PLUGIN_API VOID SetGameState(DWORD GameState) 
{ 
   if (GameState==GAMESTATE_INGAME || GameState==GAMESTATE_CHARSELECT) 
   { 
      if (!PreDetour) 
         PreDetour=GetVTable(36); 
      VOID (CMyDisplay::*pfDetour)(VOID) = CMyDisplay::Void; 
      SetVTable(36,*(DWORD*)&pfDetour); 
   } 
} 


// Called once, when the plugin is to shutdown 
PLUGIN_API VOID ShutdownPlugin(VOID) 
{ 
   DebugSpewAlways("Shutting down MQ2FPS"); 
   // Remove commands, macro parameters, hooks, etc. 
   RemoveCommand("/maxfps"); 
   RemoveCommand("/fps"); 
   RemoveCommand("/render"); 
   RemoveMQ2Data("FPS"); 
   RemoveMQ2Data("MaxFPS"); 
   RemoveMQ2Data("Foreground"); 

   if (PreDetour) 
   { 
      SetVTable(36,PreDetour); 
      PreDetour=0; 
   } 
} 

DWORD gFG_MAX=0; 
DWORD gBG_MAX=0; 
DWORD CurMax=0; 
#define FRAME_COUNT 64 
DWORD FrameArray[FRAME_COUNT+1]={0}; 
DWORD CurrentFrame=0; 
DWORD FrameTime=0; 
DWORD LastSleep=0; 
BOOL bFrameArrayFilled=0; 
float FPS=0.0f; 

VOID SetMode(DWORD Mode) 
{ 
   if (Mode<2) 
   { 
      MaxFPSMode=Mode; 
      if (Mode==FPS_ABSOLUTE) // i dont really want to use sprintf here, suck it 
      { 
         WriteChatColor("FPS Limiter mode now absolute"); 
         WritePrivateProfileString("MQ2FPS","Mode","0",INIFileName); 
      } 
      else 
      { 
         WriteChatColor("FPS Limiter mode now calculate"); 
         WritePrivateProfileString("MQ2FPS","Mode","1",INIFileName); 
      } 
   } 
} 

VOID SetForegroundMaxFPS(DWORD MaxFPS) 
{ 
   gFG_MAX=MaxFPS; 
   /* 
    if (MaxFPS==0) 
        gFG_SLEEP=0; 
    else 
        gFG_SLEEP=1000/MaxFPS; 
   /**/ 
} 

VOID SetBackgroundMaxFPS(DWORD MaxFPS) 
{ 
   gBG_MAX=MaxFPS; 
   /* 
    if (MaxFPS==0) 
        gBG_SLEEP=0; 
    else 
        gBG_SLEEP=1000/MaxFPS; 
   /**/ 
} 

VOID ProcessFrame() 
{ 
   // Update frame array 
   DWORD Now=FrameArray[CurrentFrame]=GetTickCount(); 

   DWORD FirstFrame=0; 
   DWORD Frames=CurrentFrame; 
   if (bFrameArrayFilled) 
   { 
      FirstFrame=CurrentFrame+1; 
      if (FirstFrame>FRAME_COUNT) 
      { 
         FirstFrame=FRAME_COUNT; 
      } 
      Frames=FRAME_COUNT; 
   } 
   // Calculate time this frame 
   DWORD LastFrame=CurrentFrame-1; 
   if (LastFrame>FRAME_COUNT) 
   { 
      if (bFrameArrayFilled) 
      { 
         LastFrame=FRAME_COUNT; 
         FrameTime=Now-FrameArray[LastFrame]; 
      } 
      else 
         FrameTime=0; 
   } 
   else 
      FrameTime=Now-FrameArray[LastFrame]; 

   // Calculate FPS 
   // Get amount of time between first frame and now 
   DWORD Elapsed=Now-FrameArray[FirstFrame]; 


   if (Elapsed) 
   { 
      // less than one second? 
      if (Elapsed<1000) 
      { 
         // elapsed 150 ms 
         // extrapolate. how many frame arrays would fit in one second? 
         FPS=(float)(1000.0f/(float)Elapsed); 
         // 6.66667=1000/150 
         // now multiply by the number of frames we've gone through 
         // Frames 10 
         FPS*=(float)Frames; 
         // 66.6667= FPS * 10 
   //      FPS= 
      } 
      else 
      { 
         // Frames = 100 
         // Elapsed = 2000ms 
         // FPS = 100 / (2000/1000) = 50 

         // interpolate. how many seconds did it take for our frame array? 
         FPS=(float)Frames/(float)((float)Elapsed/1000.0f); // Frames / number of seconds 
      } 
   } 
   else 
      FPS=999.0f; 
   // advance frame count 
   if (++CurrentFrame>FRAME_COUNT) 
   { 
      CurrentFrame=0; 
      bFrameArrayFilled=1; 
   } 
} 

// This is called every time MQ pulses 
PLUGIN_API VOID OnPulse(VOID) 
{ 
   // DONT leave in this debugspew, even if you leave in all the others 
//   DebugSpewAlways("MQ2FPS::OnPulse()"); 
   DebugTry(ProcessFrame()); 
   if (IsMouseWaiting()) 
      return; 


//   if (!gDelay && !gMacroPause && (!gMQPauseOnChat || *EQADDR_NOTINCHATMODE) && 
//        gMacroBlock && gMacroStack) { 
//      InMacro=true; 
//      Sleep(0); 
//    } 
//   else 
   { 
      InMacro=false; 
      HWND EQhWnd=*(HWND*)EQADDR_HWND; 
      if (EQW_GetDisplayWindow) 
         EQhWnd=EQW_GetDisplayWindow(); 
       
      if (GetForegroundWindow()==EQhWnd) 
      { 
         InForeground=true; 
         CurMax=gFG_MAX; 
         CurrentRate=gFG_Rate; 
         CurrentReverse=ReverseFG_Rate; 
         if (gFG_MAX) 
         { 
            int SleepTime=(int)(1000.0f/(float)gFG_MAX); 
            if (MaxFPSMode==FPS_CALCULATE) 
            { 
               // assume last frame time is constant, so a 30ms frame = 33 fps 
               // 
                
               SleepTime-=(FrameTime-LastSleep); 
               /**/ 
               if (SleepTime<0) 
                  SleepTime=0; 
               else if (SleepTime>300) 
                  SleepTime=300; 
               Sleep(SleepTime); 
               LastSleep=SleepTime; 
            } 
            else 
            { 
               Sleep(SleepTime); 
               LastSleep=SleepTime; 
            } 
         } 
         else 
            Sleep(0); 
      } 
      else 
      { 
         if (InForeground) 
         { 
            // just switched to background, release ctrl/alt/shift 
            ((PCXWNDMGR)pWndMgr)->KeyboardFlags[0]=0; 
            ((PCXWNDMGR)pWndMgr)->KeyboardFlags[1]=0; 
            ((PCXWNDMGR)pWndMgr)->KeyboardFlags[2]=0; 
         } 
         InForeground=false; 
         CurMax=gBG_MAX; 
         CurrentRate=gBG_Rate; 
         CurrentReverse=ReverseBG_Rate; 
         if (gBG_MAX) 
         { 
            int SleepTime=(int)(1000.0f/(float)gBG_MAX); 
            if (MaxFPSMode==FPS_CALCULATE) 
            { 
               SleepTime-=(FrameTime-LastSleep); 
               /**/ 
               if (SleepTime<0) 
                  SleepTime=0; 
               else if (SleepTime>300) 
                  SleepTime=300; 
               Sleep(SleepTime); 
               LastSleep=SleepTime; 
            } 
            else 
            { 
               Sleep(SleepTime); 
               LastSleep=SleepTime; 
            } 
         } 
         else 
            Sleep(0); 
      } 
   } 

} 



// Called every frame that the "HUD" is drawn -- e.g. net status / packet loss bar 
PLUGIN_API VOID OnDrawHUD(VOID) 
{ 
   if (!pDisplay || !FPSIndicator) 
      return; 
   CHAR szBuffer[MAX_STRING]; 

    
   // Display 
   DWORD SX=0; 
   DWORD SY=0; 
   if (pScreenX && pScreenY) 
   { 
      SX=ScreenX; 
      SY=ScreenY; 
   } 
    
   if (InMacro) 
      sprintf(szBuffer,"%d/MACRO FPS",(DWORD)FPS); 
   else 
   { 
      if (MaxFPSMode==FPS_ABSOLUTE) 
      { 
         sprintf(szBuffer,"%d/%d* FPS",(DWORD)FPS,CurMax); 
      } 
      else 
      { 
         sprintf(szBuffer,"%d/%d FPS",(DWORD)FPS,CurMax); 
      } 
   } 



   DebugTry(pDisplay->WriteTextHD2(szBuffer,SX+FPSIndicatorX,SY+FPSIndic  atorY,0x0d)); 

} 

VOID FPSCommand(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   bRunNextCommand = TRUE; 
   CHAR szCmd[MAX_STRING] = {0}; 
    CHAR Arg1[MAX_STRING] = {0}; 
    GetArg(Arg1,szLine,1); 
   if (Arg1[0]==0) { 
        SyntaxError("Usage: /fps <mode|absolute|calculate|x,y|on|off>"); 
        return; 
   } 

   if (!strnicmp(Arg1,"absolute",strlen(Arg1))) 
   { 
      CurrentFrame=0; 
      bFrameArrayFilled=0; 
      SetMode(FPS_ABSOLUTE); 
      return; 
   } 
   else 
   if (!strnicmp(Arg1,"calculate",strlen(Arg1))) 
   { 
      CurrentFrame=0; 
      bFrameArrayFilled=0; 
      SetMode(FPS_CALCULATE); 
      return; 
   } 
   else 
   if (!strnicmp(Arg1,"mode",strlen(Arg1))) 
   { 
      CurrentFrame=0; 
      bFrameArrayFilled=0; 
      SetMode(MaxFPSMode==0); 
      return; 
   } 
   else 
    if (!strnicmp(Arg1,"on",strlen(Arg1))) 
    { 
       FPSIndicator=TRUE; 
       WritePrivateProfileString("MQ2FPS","Indicator","1",INIFileName); 
       return; 
    } 
    else 
    if (!strnicmp(Arg1,"off",strlen(Arg1))) 
    { 
       FPSIndicator=FALSE; 
       WritePrivateProfileString("MQ2FPS","Indicator","0",INIFileName); 
       return; 
    } 

   if (strchr(szLine,',')) 
   { 
      sscanf(szLine,"%d,%d",&FPSIndicatorX,&FPSIndicatorY); 
//      itoa(FPSIndicatorX,szCmd,10); 
      WritePrivateProfileString("MQ2FPS","IndicatorX",itoa(FPSIndicatorX,szCmd,10),INIFileName); 
      WritePrivateProfileString("MQ2FPS","IndicatorY",itoa(FPSIndicatorY,szCmd,10),INIFileName); 
      return; 
   } 
        SyntaxError("Usage: /fps <mode|absolute|calculate|x,y|on|off>"); 
} 


// **************************************************  ************************* 
// Function:      MaxFPS 
// Description:   Our /MaxFPS command. Sets or displays the max fps setting for 
//                foreground or background 
// 2003-11-01     Lax 
// **************************************************  ************************* 
VOID MaxFPS(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   bRunNextCommand = TRUE; 
   CHAR szCmd[MAX_STRING] = {0}; 
    CHAR Arg1[MAX_STRING] = {0}; 
    CHAR Arg2[MAX_STRING] = {0}; 
    GetArg(Arg1,szLine,1); 
    GetArg(Arg2,szLine,2); 


   if (Arg1[0]==0 || Arg2[0]==0) { 
       sprintf(szCmd,"\aw\ayMaxFPS\ax\a-u:\ax \a-u[\ax\at%d\ax Foreground\a-u]\ax \a-u[\ax\at%d\ax Background\a-u]\ax \a-u[\ax%s Mode\a-u]\ax",gFG_MAX,gBG_MAX,szFPSModes[MaxFPSMode]); 
        WriteChatColor(szCmd,USERCOLOR_DEFAULT); 
        WriteChatColor("Usage: /maxfps <fg|bg> <#>",CONCOLOR_YELLOW); 
        return; 
   } 
   DWORD NewMax=atoi(Arg2); 
   if (NewMax>200) 
   { 
       MacroError("MaxFPS: Please use a number between 0 and 200, 0 being absolute fastest, 1-200 being that many frames per second."); 
       return; 
   } 

   if (!stricmp(Arg1,"fg")) 
   { 
     SetForegroundMaxFPS(NewMax); 
       WritePrivateProfileString("MQ2FPS","ForegroundMaxFPS",Arg2,INIFileName); 
   } 
   else if (!stricmp(Arg1,"bg")) 
   { 
       SetBackgroundMaxFPS(NewMax); 
       WritePrivateProfileString("MQ2FPS","BackgroundMaxFPS",Arg2,INIFileName); 
   } 
    sprintf(szCmd,"\aw\ayMaxFPS\ax\a-u:\ax \a-u[\ax\at%d\ax Foreground\a-u]\ax \a-u[\ax\at%d\ax Background\a-u]\ax \a-u[\ax%s Mode\a-u]\ax",gFG_MAX,gBG_MAX,szFPSModes[MaxFPSMode]); 
    WriteChatColor(szCmd,USERCOLOR_DEFAULT); 
} 

VOID RenderCommand(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   bRunNextCommand = TRUE; 
   CHAR szCmd[MAX_STRING] = {0}; 
    CHAR Arg1[MAX_STRING] = {0}; 
    CHAR Arg2[MAX_STRING] = {0}; 
    GetArg(Arg1,szLine,1); 
    GetArg(Arg2,szLine,2); 
   CHAR szFore[MAX_STRING]={0}; 
   CHAR szBack[MAX_STRING]={0}; 


   if (Arg1[0]==0 || Arg2[0]==0) { 
      if (ReverseFG_Rate) 
         sprintf(szFore,"%d/",gFG_Rate-1); 
      else 
         strcpy(szFore,"1/"); 
      if (ReverseBG_Rate) 
         sprintf(szBack,"%d/",gBG_Rate-1); 
      else 
         strcpy(szBack,"1/"); 
      sprintf(szCmd,"\aw\ayRender Rate\ax\a-u:\ax \a-u[\ax\at%s%d\ax Foreground\a-u]\ax \a-u[\ax\at%s%d\ax Background\a-u]\ax",szFore,gFG_Rate,szBack,gBG_Rate); 
        WriteChatColor(szCmd,USERCOLOR_DEFAULT); 
      WriteChatColor("Usage: /render <fg|bg> <#|~#>",CONCOLOR_YELLOW); 
        return; 
   } 
   DWORD NewRate; 
   BOOL Reverse=false; 
   if (Arg2[0]=='~') 
   { 
      NewRate=atoi(&Arg2[1]); 
      Reverse=true; 
      memcpy(&Arg2[0],&Arg2[1],MAX_STRING-1); 
   } 
   else 
      NewRate=atoi(&Arg2[0]); 
   if (NewRate>200) 
   { 
       MacroError("Render: Please use a number between 0 and 200, 0 being absolute fastest, 1-200 being that many frames per second.",USERCOLOR_DEFAULT); 
       return; 
   } 

   if (!stricmp(Arg1,"fg")) 
   { 
      gFG_Rate=NewRate; 
      ReverseFG_Rate=Reverse; 
       WritePrivateProfileString("Rendering","FGRate",Arg2,INIFileName); 
      WritePrivateProfileString("Rendering","ReverseFGRate",ReverseFG_Rate?"1":"0",INIFileName); 
   } 
   else if (!stricmp(Arg1,"bg")) 
   { 
      gBG_Rate=NewRate; 
      ReverseBG_Rate=Reverse; 
       WritePrivateProfileString("Rendering","BGRate",Arg2,INIFileName); 
       WritePrivateProfileString("Rendering","ReverseBGRate",ReverseBG_Rate?"1":"0",INIFileName); 
   } 

   if (ReverseFG_Rate) 
      sprintf(szFore,"%d/",gFG_Rate-1); 
   else 
      strcpy(szFore,"1/"); 
   if (ReverseBG_Rate) 
      sprintf(szBack,"%d/",gBG_Rate-1); 
   else 
      strcpy(szBack,"1/"); 
   sprintf(szCmd,"\aw\ayRender Rate\ax\a-u:\ax \a-u[\ax\at%s%d\ax Foreground\a-u]\ax \a-u[\ax\at%s%d\ax Background\a-u]\ax",szFore,gFG_Rate,szBack,gBG_Rate); 
    WriteChatColor(szCmd,USERCOLOR_DEFAULT); 
} 

BOOL dataFPS(PCHAR szIndex, MQ2TYPEVAR &Ret) 
{ 
   Ret.Float=FPS; 
   Ret.Type=pFloatType; 
   return true; 
} 

BOOL dataMaxFPS(PCHAR szIndex, MQ2TYPEVAR &Ret) 
{ 
   Ret.DWord=CurMax; 
   Ret.Type=pIntType; 
   return true; 
} 

BOOL dataForeground(PCHAR szIndex, MQ2TYPEVAR &Ret) 
{ 
   Ret.DWord=InForeground; 
   Ret.Type=pBoolType; 
   return true; 
}
 
Last edited:
MQ2 Nomez plugin

Requires latest version of MQ2 no offsets or changes needed.
Recompile each patch.

The thing with this plugin is you need to put it in one thats already running nonstop, so the best place would be in mq2map

See this thread for more info: http://www.redguides.com/community/showthread.php?t=53

Rich (BB code):
#include "../MQ2Plugin.h" 
PreSetup("MQ2NoMez"); 
PLUGIN_API VOID OnDrawHUD(VOID) 
{ 
   BYTE nostun = 00; 
    GetCharInfo()->Stunned = nostun; 
}
 
MQ2NoSummon by cbsro

The NoSummon offset for DoCrack always seems to be a tricky one to find, so to do away with it I made this simple little plugin.

Basically all it does is detect when you move very close to a target very quickly, and warps you back where you were before (code courtesy of mq2warp). You still take one round of damage like with the docrack version but other than that it seems to be working fine. I'm a complete noob when it comes to writing plugins so if you see anything that could be done better or have any criticism please let me know.

Also, one issue, this effectively nullifies /warp target, since there's really no difference. If anyone has any insight on how to make this work let me know. Likewise, if what you're being summoned by is not your target, it won't warp back...hmm... I wasn't thinking of that really, usually wouldn't be the case but definitely a possibility... I'll think about that one.

http://www.redguides.com/community/showthread.php?t=2340


Rich (BB code):
// MQ2NoSummon.cpp : Defines the entry point for the DLL application

// Same offset as MQ2Warp

#define CDisplay__MoveLocalPlayerToSafeCoords   0x444C21
#include "../MQ2Plugin.h"
float UnSummonY, UnSummonX, UnSummonZ;

PreSetup("MQ2NoSummon");
VOID UnSummonMe(PSPAWNINFO pChar);

PLUGIN_API VOID InitializePlugin(VOID)
{
	DebugSpewAlways("Initializing MQ2NoSummon");
}

PLUGIN_API VOID ShutdownPlugin(VOID)
{
	DebugSpewAlways("Shutting down MQ2NoSummon");
}


PLUGIN_API VOID OnPulse(VOID)
{
	CHAR ABuffer[MAX_STRING] = {0};
	PSPAWNINFO pChar = (PSPAWNINFO)pCharSpawn;
	PSPAWNINFO Target = (PSPAWNINFO)pTarget;

	
	if ( (pTarget) && (ppTarget) ) {
			if ( ( (abs(Target->Y - pChar->Y)<2) && (abs(UnSummonY - pChar->Y)>4) ) || ( (abs(Target->X - pChar->X)<2) && (abs(UnSummonX - pChar->X)>4) ) ) {
				if (pChar->SpawnID != Target->SpawnID) {
					UnSummonMe(pChar);
				}
			} else {
				UnSummonY = pChar->Y;
				UnSummonX = pChar->X;
				UnSummonZ = pChar->Z;
			}
	} else {
	UnSummonY = pChar->Y;
	UnSummonX = pChar->X;
	UnSummonZ = pChar->Z;
	}
       

}




VOID UnSummonMe(PSPAWNINFO pChar)
{
	CHAR ABuffer[MAX_STRING] = {0};
    PZONEINFO Zone = (PZONEINFO)pZoneInfo; 

   float SafeY = Zone->SafeYLoc; 
   float SafeX = Zone->SafeXLoc; 
   float SafeZ = Zone->SafeZLoc; 

   Zone->SafeYLoc = UnSummonY; 
   Zone->SafeXLoc = UnSummonX;
   Zone->SafeZLoc = UnSummonZ;

   DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
   __asm call dword ptr [MLPTSC]; 

   Zone->SafeYLoc = SafeY; 
   Zone->SafeXLoc = SafeX; 
   Zone->SafeZLoc = SafeZ; 
}
 
Last edited:
MQ2RWarp By Riddlerr from Siddin's code and INcorperated with Cosmic's Update From PiggyZone

Rich (BB code):
 //MQ2RWarp.cpp
//Created By Riddlerr 7/1/05
//Teachers Pet ChainShift 10/1
//Teachers Pet Ghost 10/6
//Updated Code By Cosmic 10/8

#include "../MQ2Plugin.h"

PreSetup("MQ2RWarp");
#undef ExactLocation
#undef zWarp
#undef DoWarp
#undef Warp
#undef SafeYLoc
#undef SafeXLoc
#undef SafeZLoc
#undef GateBind
#undef ZoneShift
#undef ZoneToGoTo
#define LocalCEverQuest__DoTheZone		   0x4AB5A1
#define INFINITY ((int) pow(2, sizeof(int)*8-2)-1)

#ifdef PKT_UPDATE_POSITION
#undef PKT_UPDATE_POSITION
#endif
#define PKT_UPDATE_POSITION 0x14CB
#define PKT_CHANNEL_MESSAGE 0x1004

typedef struct
{
	int connections[100]; // An array of edges which has this as the starting node
	int numconnect;
} FWVertice;

typedef struct
{
	int Zone;
	char Name[50];
	char Phrase[20][50];
	int Destination[20];
	float X,Y,Z;
	int DestCnt;
} NPCTeleporter;

FWVertice *V=NULL;
NPCTeleporter NPCs[100];
int NPCCnt;
int* distances=NULL;
int* predecessor=NULL;

class LocalCEverQuest;
class LocalCEverQuest
{
public:
	__declspec(dllexport) char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int);
};

#ifdef LocalCEverQuest__DoTheZone
FUNCTION_AT_ADDRESS(char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int),LocalCEverQuest__  DoTheZone);
#endif

LocalCEverQuest **ppLEQ;
#define pLEQ (*ppLEQ)

void Setup();
bool UseNPC(PSPAWNINFO pChar, int dest);
PLUGIN_API VOID OnZoned(PSPAWNINFO pChar, PCHAR szLine);
PLUGIN_API VOID OnPulse(VOID);
DWORD ListSimilarZones(PCHAR ZoneShortName);
VOID ChangeZones(PSPAWNINFO pChar, PCHAR szLine); 
void FloydWarshall(FWVertice* vertices, int nodecount);
VOID FindPath(PSPAWNINFO pChar, PCHAR szLine); 
VOID SimFade(PSPAWNINFO pChar, PCHAR szLine); 
VOID SimGate(PSPAWNINFO pChar, PCHAR szLine); 
VOID DoWarp(float y, float x, float z); 
VOID Warp(PSPAWNINFO pChar, PCHAR szLine); 
VOID zWarp(PSPAWNINFO pChar, PCHAR szLine); 
VOID ExactLocation(PSPAWNINFO pChar);
VOID waypoint(PSPAWNINFO pChar, PCHAR szLine); 
VOID Ghost(PSPAWNINFO pChar, PCHAR szLine);

bool ZoneChange=false;  
float X,Y,Z;
int Heading;
int DestZone;
int ChainZone[100];
int ChainZoneCnt=0;
int DestType; // 0=use supplied coords 1=succorpoint
int ChainZoneType; // 0=use supplied coords 1=succorpoint
int ZoneReason;

int LastKnownZone=-1; //don't fire MyOnZoned when you first log in

void MyOnZoned(PSPAWNINFO pChar)
{
	if (ChainZoneCnt>0)
	{
		if (pChar->Zone != ChainZone[ChainZoneCnt])
		{
			ChainZoneCnt=0;
			return;
		}
		ChainZoneCnt--;
		DestZone=ChainZone[ChainZoneCnt];
		if (ChainZoneCnt==0) DestType=ChainZoneType;
		WriteChatColor("Attempting ChainZone...", USERCOLOR_DEFAULT); 
		if ( UseNPC(pChar,DestZone) == false)
		{
			ZoneChange=true;
		}
	}
	return;
}

PLUGIN_API VOID OnPulse(VOID)
{
	PSPAWNINFO pChar = NULL;
	if (ppCharSpawn && pCharSpawn) {
		pChar = (PSPAWNINFO)pCharSpawn;
		if ((pChar) && (!gZoning))
		{
			if (LastKnownZone == -1)	LastKnownZone=pChar->Zone;
			if (pChar->Zone != LastKnownZone)
			{
				LastKnownZone=pChar->Zone;
				MyOnZoned(pChar);
			}
		}
	}

	char aa[100]="test";
	if(ZoneChange)
	{
		ZoneChange=false;
		pLEQ->DoTheZone(DestZone,aa,DestType,ZoneReason,Y,X,Z,He  ading);
	}
	return;
}

DWORD ListSimilarZones(PCHAR PartialName)
{
	CHAR szMsg[MAX_STRING] = "Bad Zone.ShortName. Suggest: ";
	CHAR szName[MAX_STRING] = {0};
	char *partial,*longname;

    PZONELIST pZone = NULL;

	partial=_strlwr(_strdup(PartialName));
    if (!ppWorldData | !pWorldData) return -1;
    for (int nIndex=0; nIndex < MAX_ZONES+1; nIndex++) {
      pZone = ((PWORLDDATA)pWorldData)->ZoneArray[nIndex];
        if(pZone )
		{
			longname=_strlwr(_strdup(pZone->LongName));
            if (strstr(longname,partial)) {
				sprintf(szName,"%s(%s) ",pZone->LongName,pZone->ShortName);
				if ((strlen(szMsg)+strlen(szName))>=300)
				{
					WriteChatColor(szMsg,USERCOLOR_DEFAULT);
					szMsg[0]=0;
				}
                strcat(szMsg,szName);
            }
			free(longname);
		}
    }
	WriteChatColor(szMsg,USERCOLOR_DEFAULT);
	free(partial);
    return -1; 
}

VOID Zone(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	CHAR szMsg[MAX_STRING] = {0};
	CHAR szParam[MAX_STRING] = {0};
	CHAR sZoneName[MAX_STRING] ={0};
	CHAR sWPName[MAX_STRING] ={0};
	CHAR sKeyData[MAX_STRING]={0};
	DWORD ZoneToGoTo; 
	int rLen;
	int i,j,cnt=0;
	bool IgnoreChain=false;
	int Param=1;

	GetArg(szParam,szLine,Param);
	if (_stricmp(szParam,"setwp")==0)
	{
		Param++;
		GetArg(sWPName,szLine,Param);
		if (sWPName[0]==0)
		{
			WriteChatColor("Usage: /zone setwp <WayPointName>", CONCOLOR_RED); 
			return;
		}
		sprintf(sKeyData,"%.2f %.2f %2.f %d",pChar->Y,pChar->X,pChar->Z,(int)pChar->Heading);
		WritePrivateProfileString(GetShortZone(pChar->Zone), sWPName, sKeyData, INIFileName); 
		WriteChatColor("Waypoint recorded", USERCOLOR_DEFAULT); 
		return;
	}
	if (_stricmp(szParam,"clearwp")==0)
	{
		Param++;
		GetArg(sWPName,szLine,Param);
		if (sWPName[0]==0)
		{
			WriteChatColor("Usage: /zone clearwp <WayPointName>", CONCOLOR_RED); 
			return;
		}
		WritePrivateProfileString(GetShortZone(pChar->Zone), sWPName, NULL, INIFileName); 
		WriteChatColor("Waypoint cleared", USERCOLOR_DEFAULT); 
		return;
	}
	if (_stricmp(szParam,"force")==0)
	{
		IgnoreChain=true;
		Param++;
	}
	GetArg(sZoneName,szLine,Param++);

	ZoneToGoTo = GetZoneID(sZoneName);

	if (ZoneToGoTo == -1) {
		ListSimilarZones(sZoneName);
		return;
	}

	Setup();

	if (IgnoreChain==false)
	{
		i=pChar->Zone;
		j=ZoneToGoTo;

		if (distances[i*MAX_ZONES+j]==0)
		{
			WriteChatColor("Poof! You are already there.", CONCOLOR_RED); 
			return;
		}

		if (distances[i*MAX_ZONES+j]==INFINITY)
		{
			WriteChatColor("I don't know a route to that zone.", CONCOLOR_RED); 
			return;
		}
	}
	GetArg(sWPName,szLine,Param++);
	if (sWPName[0]!=0)
	{
		CHAR sDefault[MAX_STRING]="none";
		GetPrivateProfileString(sZoneName,sWPName, sDefault, sKeyData, MAX_STRING, INIFileName); 
		if (_stricmp(sKeyData,"none")==0)
		{
			rLen=GetPrivateProfileString(sZoneName,NULL, sDefault, sKeyData, MAX_STRING, INIFileName); 
			for (int i=0;i<rLen-1;i++) if (sKeyData==0) sKeyData=',';
			sprintf(szMsg,"Bad Waypoint. Suggest: %s",sKeyData); 
			WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
			return;
		}
		sscanf(sKeyData,"%f %f %f %d",&Y,&X,&Z,&Heading);
		DestType=0;
	}
	else
	{
		sprintf(sWPName,"default");
		CHAR sDefault[MAX_STRING]="none";
		GetPrivateProfileString(sZoneName,sWPName, sDefault, sKeyData, MAX_STRING, INIFileName); 
		if (_stricmp(sKeyData,"none")!=0)
		{
			sscanf(sKeyData,"%f %f %f %d",&Y,&X,&Z,&Heading);
			DestType=0;
		}
		else
		{
			Y=pChar->Y;
			X=pChar->X;
			Z=pChar->Z;
			Heading = (int)pChar->Heading;
			DestType=1;
		}
	}

	ChainZoneCnt=0;	//reset in case we failed to finish previous chain-zone attempt
	if (IgnoreChain==false)
	{
		while (i!=j)
		{
			ChainZone[ChainZoneCnt++]=j;
			j=predecessor[i*MAX_ZONES+j];
		}

		if (ChainZoneCnt>1) 
		{
			ChainZoneType=DestType;
			DestType=1;
		}
		DestZone = ChainZone[--ChainZoneCnt];
	}
	else
	{
		DestZone=ZoneToGoTo;
	}

	sprintf(szMsg,"Zoneing..."); 
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	ZoneReason=0;
	if (UseNPC(pChar,DestZone) == false) ZoneChange=true;
	return;
} 

VOID FindPath(PSPAWNINFO pChar, PCHAR szLine)
{
	CHAR sDest[MAX_STRING]={0};
	int ZoneToGoTo;
	int i,j,cnt=0,stops[100];

	GetArg(sDest,szLine,1);
	if (sDest[0]==0)
	{
		WriteChatColor("Usage: /FindPath <ShortZoneName>", CONCOLOR_RED); 
		return;
	}
	ZoneToGoTo = GetZoneID(sDest);

	if (ZoneToGoTo == -1) {
		ListSimilarZones(sDest);
		return;
	}

	Setup();

	i=pChar->Zone;
	j=ZoneToGoTo;

	if (distances[i*MAX_ZONES+j]==0)
	{
		WriteChatColor("Poof! You are already there.", CONCOLOR_RED); 
		return;
	}
	if (distances[i*MAX_ZONES+j]==INFINITY)
	{
		WriteChatColor("I don't know a route to that zone.", CONCOLOR_RED); 
		return;
	}

	WriteChatColor("My path:", CONCOLOR_RED); 
	while (i!=j)
	{
		stops[cnt++]=j;
		j=predecessor[i*MAX_ZONES+j];
	}

	while (cnt>0)
	{
		cnt--;
		WriteChatColor(GetShortZone(stops[cnt]),USERCOLOR_DEFAULT);
	}

}

void Setup()
{
	char sKey[300];
	char sKeyData[300];
	char *p;
	int i;
	if (distances!=NULL) free(distances);
    if (predecessor!=NULL) free(predecessor);
	if (V!=NULL) free(V);
	V = (FWVertice *)malloc(MAX_ZONES*sizeof(FWVertice));
	int tmp[100],cnt;
	for (i=0;i<MAX_ZONES;i++)
	{
		sprintf(sKey,"%d",i);
		V.numconnect=0;
		GetPrivateProfileString("ZoneConnections",sKey,"none",sKeyData,300,INIFileName);
		if (_stricmp(sKeyData,"none")!=0)
		{
			strtok(sKeyData,"\"");
			strtok(NULL,"\"");
			cnt=0;
			while ( (p=strtok(NULL,",")) != NULL)
			{
				tmp[cnt++]=atoi(p);
			}
			V.numconnect=cnt+1;
			for (int j=0;j<cnt;j++) V.connections[j]=tmp[j];
		}
		V.connections[V.numconnect++]=GetCharInfo2()->ZoneBoundID; //always connected to my bind point
	}

	//NPCTeleporter support
	NPCCnt=0;
	for (i=0;i<100;i++)
	{
		sprintf(sKey,"%d",(i+1));
		GetPrivateProfileString("NPCTeleporters",sKey,"none",sKeyData,300,INIFileName);
		if (_stricmp(sKeyData,"none")==0) break;
		NPCCnt++;
		NPCs.Zone=atoi(strtok(sKeyData," \""));
		strcpy(NPCs.Name,strtok(NULL,"\""));
		NPCs.Y=(float)atof(strtok(NULL," "));
		NPCs.X=(float)atof(strtok(NULL," "));
		NPCs.Z=(float)atof(strtok(NULL," "));
		NPCs.DestCnt=0;
		p=strtok(NULL," \"");
		while (p!=NULL)
		{
			NPCs.Destination[NPCs.DestCnt]=atoi(p);
			strcpy(NPCs.Phrase[NPCs.DestCnt],strtok(NULL,"\""));
			V[NPCs.Zone].connections[V[NPCs.Zone].numconnect++]=NPCs.Destination[NPCs.DestCnt];
			NPCs.DestCnt++;
			p=strtok(NULL," \"");
		}
	}

	FloydWarshall(V,MAX_ZONES);
}

bool UseNPC(PSPAWNINFO pChar,int dest)
{
	for (int i=0;i<NPCCnt;i++)
	{
		if (NPCs.Zone != pChar->Zone) continue;
		for (int j=0;j<NPCs.DestCnt;j++)
		{
			if (NPCs.Destination[j]==dest)
			{
				//Code borrowed directly from MQ2CSum
				// setup move packet
				struct _MOVEPKT {
				/*0000*/ unsigned short SpawnID;
				/*0002*/ unsigned short TimeStamp;
				/*0004*/ float Y;
				/*0008*/ float DeltaZ;
				/*0012*/ float DeltaY;
				/*0016*/ float DeltaX;
				/*0020*/ int Animation:10;
				/*0020*/ int DeltaHeading:10;
				/*0020*/ int padding0020:12;
				/*0024*/ float X;
				/*0028*/ float Z;
				/*0032*/ int Heading:12;
				/*0032*/ int padding1_0032:10;
				/*0032*/ int padding2_0032:10;
				} P; // 36
				struct _MSGPACKET {
				/*0000*/ char target[64];
				/*0064*/ char sender[64];
				/*0128*/ unsigned int language;
				/*0132*/ unsigned int channel;
				/*0136*/ char padding136[8];
				/*0144*/ unsigned int languageskill;
				/*0148*/ char message[100];
				} M;

				// init packets
				ZeroMemory(&P, sizeof(P));
				ZeroMemory(&M, sizeof(M));
				P.SpawnID = (unsigned short)pChar->SpawnID;
				P.Heading = (unsigned int)(pChar->Heading * 4);

				PSPAWNINFO psTarget = NULL; 
				Target(pChar,NPCs.Name);
				if (ppTarget && pTarget) { 
					psTarget = (PSPAWNINFO)pTarget; 
				} 
				if (psTarget) 
				{
					strcpy(M.target,psTarget->Name);
				}
				strcpy(M.sender,pChar->Name);
				M.channel=8;
				M.languageskill=100;

				// jump to
				P.Z = NPCs.Z;
				P.Y = NPCs.Y;
				P.X = NPCs.X;
				SendEQMessage(PKT_UPDATE_POSITION, &P, sizeof(P));

				sprintf(M.message,"%s",NPCs.Phrase[j]);
				SendEQMessage(PKT_CHANNEL_MESSAGE,&M,sizeof(M));
				return true;
			}
		}
	}
	return false;
}

void FloydWarshall(FWVertice* vertices, int nodecount) // Vertices numbered from 0 to nodecount-1
{
    distances = (int*) malloc(nodecount*nodecount*sizeof(int)*8);
    predecessor = (int*) malloc(nodecount*nodecount*sizeof(int)*8);
	int i,j,k;

    for(i = 0; i < nodecount; i++)
    {
        for(j = 0; j < nodecount; j++)
        {
            distances[i*nodecount+j] = 0;
            predecessor[i*nodecount+j] = i;
        }
    }
    for(i = 0; i < nodecount; i++)
    {
        for(j = 0; j < vertices.numconnect; j++)
        {
            distances[i*nodecount + vertices.connections[j]] =1; 
//                            vertices.connections[j].weight;
        }
        for(j = 0; j < nodecount; j++)
        {
            if(!distances[i*nodecount+j] && (i^j)) 
                // i ^ j returns 0 if they are equal
            {
				distances[i*nodecount+j] = INFINITY;
            }
        }
    }
    for(k = 0; k < nodecount; k++)
    {
        for(i = 0; i < nodecount; i++)
        {
            for(j = 0; j < nodecount; j++)
            {
                if(distances[i*nodecount+j] > distances[i*nodecount+k] + distances[k*nodecount+j])
                {
                    distances[i*nodecount+j] = distances[i*nodecount+k] + distances[k*nodecount+j];
                    predecessor[i*nodecount+j] = predecessor[k*nodecount+j];
                }
            }
        }
    }
}

VOID Gate(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	CHAR szMsg[MAX_STRING] = {0};
	PCHARINFO2 pChar2 = GetCharInfo2();

	sprintf(szMsg,"Gating...");
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	DestZone=pChar2->ZoneBoundID;
	DestType=0;
	ZoneReason=11;
	Y=pChar2->ZoneBoundX;
	X=pChar2->ZoneBoundY;
	Z=pChar2->ZoneBoundZ;
	Heading=0;
	ZoneChange=true;
	return;
} 

VOID Fade(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	CHAR szMsg[MAX_STRING] = {0};
	if (pChar->Instance != 0)
	{
		DestZone = *((int *)(&(pChar->Instance)-1));
	}
	else
	{
		DestZone = pChar->Zone;
	}
	sprintf(szMsg,"Fading..."); 
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	DestType=0;
	ZoneReason=0;
	Y=pChar->Y;
	X=pChar->X;
	Z=pChar->Z;
	Heading =(int)pChar->Heading;
	ZoneChange=true;
	return;
}

VOID ExactLocation(PSPAWNINFO pChar, PCHAR szLine) 
{  CHAR LocMsg[MAX_STRING] = {0}; 
   sprintf(LocMsg, "Your location is %3.6f, %3.6f, %3.6f", pChar->Y, pChar->X, pChar->Z); 
   WriteChatColor(LocMsg); 
   return; 
} 

VOID zWarp(PSPAWNINFO pChar, PCHAR szLine) 
{   CHAR Z[MAX_STRING] = {0}; 
        GetArg(Z,szLine,1); 
        float MyY = pChar->Y; 
        float MyX = pChar->X; 


        if (Z[0]==0) { 
      WriteChatColor("Usage: /zwarp <dist>", CONCOLOR_RED); 
      return; 
        } 

        float NewZ = pChar->Z; 
        NewZ = NewZ + (FLOAT)atof(Z); 
        DoWarp(MyY, MyX, NewZ); 
        return; 
} 

VOID Warp(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   static float LastY; 
   static float LastX; 
   static float LastZ; 
   bRunNextCommand = TRUE; 
   PSPAWNINFO psTarget = NULL; 
   PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
    CHAR command[MAX_STRING]; GetArg(command,szLine,1); 
   CHAR Y[MAX_STRING]; GetArg(Y,szLine,2); 
   CHAR X[MAX_STRING]; GetArg(X,szLine,3); 
   CHAR Z[MAX_STRING]; GetArg(Z,szLine,4); 
   if ( 
      stricmp(command, "succor") != 0 && 
      stricmp(command, "loc") != 0 && 
      stricmp(command, "last") != 0 && 
      stricmp(command, "target") != 0 && 
      stricmp(command, "dir") != 0 &&
      stricmp(command, "wp") != 0
   ) { 
      WriteChatColor("Usage: /warp <succor|last|loc <y x z>|dir <dist>|target|wp name>", CONCOLOR_RED); 
      return; 
      } else { 
      if (!stricmp(command,"target"))  { 
         if (ppTarget && pTarget) { 
         psTarget = (PSPAWNINFO)pTarget; 
         } 
         if (!psTarget) { 
            WriteChatColor("You must have a target for /warp target.", CONCOLOR_RED); 
            return; 
         } 
         float TargetZ = float (psTarget->Z); 
         float TargetY = float (psTarget->Y); 
         float TargetX = float (psTarget->X); 
                        LastY = TargetY; 
         LastX = TargetX; 
         LastZ = TargetZ; 
         DoWarp(TargetY, TargetX, TargetZ); 
      } else if (!stricmp(command,"succor"))  { 
         static float north = 0; 
         ((PSPAWNINFO)pCharSpawn)->Heading = north; 
         DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
         __asm call dword ptr [MLPTSC]; 
         return; 
      } else if (!stricmp(command,"loc")) { 
      if ((Y[0] == 0) || (X[0] == 0) || (Z[0] == 0)) 
      { 
         WriteChatColor("You must provide <y> <x> <z> if going to a location.", CONCOLOR_RED); 
         return; 
      } 
         LastY = (float)atof(Y); 
         LastX = (float)atof(X); 
         LastZ = (float)atof(Z); 
      DoWarp((float)atof(Y), (float)atof(X), (float)atof(Z)); 
      return; 
      } else if (!stricmp(command,"last")) { 
      if ((LastY==0) || (LastX==0) || (LastZ==0)) 
      { 
         WriteChatColor("You must have warped before to use this command!.", CONCOLOR_RED); 
         return; 
      } 
      DoWarp(LastY, LastX, LastZ); 
      return; 
      } else if (!stricmp(command,"dir")) { 
      if (Y[0]==0) { 
         WriteChatColor("You MUST provide <dist> if going in your current direction.", CONCOLOR_RED); 
         return; 
      } 
      FLOAT angle = (FLOAT)((pChar->Heading)*0.0123); 
      FLOAT dissafegoto = (FLOAT)atof(Y); 
      DoWarp(pChar->Y + (FLOAT)(dissafegoto * cos(angle)), pChar->X + (FLOAT)(dissafegoto * sin(angle)), pChar->Z); 
      return; 
                } 
   { 
      char szLoc[MAX_STRING] = {0}; 
      char szName[MAX_STRING] = {0}; 
      char WaypointsINI[MAX_STRING] = {0}; 
      char szBuf[MAX_STRING] = {0};
      char szHeading[MAX_STRING] = {0};
      char szDestWarpX[MAX_STRING] = {0}; 
      char szDestWarpY[MAX_STRING] = {0}; 
      char szDestWarpZ[MAX_STRING] = {0}; 
      char szMsg[MAX_STRING] = {0}; 


      sprintf(WaypointsINI,"%s\\waypoints.ini",gszINIPath); 
      GetArg(szName, szLine, 2); 

      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a waypoint.", COLOR_LIGHTGREY); 
      } 
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szLoc,MAX_STRING,WaypointsINI); 
          
         if (!strnicmp(szLoc, "", 1)) 
         { 
            sprintf(szMsg, "Waypoint \'%s\' does not exist.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            // get destination locs 
            GetArg(szDestWarpX, szLoc, 2); 
            GetArg(szDestWarpY, szLoc, 1); 
            GetArg(szDestWarpZ, szLoc, 3); 
             
            // get heading 
            GetArg(szBuf, szLoc, 4); 
            GetArg(szHeading,szBuf,1,0,0,0,':'); 
			DoWarp((float)atof(szDestWarpY), (float)atof(szDestWarpX), (float)atof(szDestWarpZ));
            } 
			}
         } 
   } 
} 


VOID DoWarp(float y, float x, float z) 
{ 

        PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
   float SafeY = Zone->SafeYLoc; 
   float SafeX = Zone->SafeXLoc; 
   float SafeZ = Zone->SafeZLoc; 

   Zone->SafeYLoc = y; 
   Zone->SafeXLoc = x; 
   Zone->SafeZLoc = z; 

   CHAR szMsg[MAX_STRING] = {0}; 
   sprintf(szMsg, "Warping to: %3.2f, %3.2f, %3.2f.", Zone->SafeYLoc, Zone->SafeXLoc, Zone->SafeZLoc); 
   WriteChatColor(szMsg, COLOR_PURPLE); 

   DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
   __asm call dword ptr [MLPTSC]; 

   Zone->SafeYLoc = SafeY; 
   Zone->SafeXLoc = SafeX; 
   Zone->SafeZLoc = SafeZ; 
} 

VOID waypoint(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
   CHAR WaypointsINI[MAX_STRING] = {0}; 
   CHAR szTemp[10] = {0}; 
   CHAR szData[MAX_STRING] = {0}; 
   CHAR szDesc[MAX_STRING] = {0}; 
   CHAR szName[MAX_STRING] = {0}; 
   CHAR szCommand[MAX_STRING] = {0}; 
   CHAR szBuffer[MAX_STRING] = {0}; 
   CHAR szMsg[MAX_STRING] = {0}; 
   CHAR WaypointList[MAX_STRING*10] = {0}; 
   PCHAR pWaypointList = WaypointList; 
   CHAR szKey[MAX_STRING] = {0}; 
   CHAR szValue[MAX_STRING] = {0}; 

   sprintf(WaypointsINI,"%s\\waypoints.ini",gszINIPath); 
    
   GetArg(szCommand, szLine, 1); 

   if (!strnicmp(szCommand, "add", 3)) 
   { 
      GetArg(szName, szLine, 2); 
       
      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a name for the waypoint.", COLOR_LIGHTGREY); 
      }          
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szBuffer,MAX_STRING,WaypointsINI); 

         if (!strnicmp(szBuffer, "", 1)) 
         { 
            GetArg(szDesc, szLine, 3); 
             
            sprintf(szData, "%1.2f %1.2f %1.2f %1.2f:%s", pChar->Y, pChar->X, pChar->Z, (float)pChar->Heading*0.703125f, szDesc); 
            WritePrivateProfileString(Zone->ShortName,szName,szData,WaypointsINI); 
            sprintf(szMsg, "Waypoint \'%s\' added.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            sprintf(szMsg, "Waypoint \'%s\' already exists.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
      } 
   } 
   else if (!strnicmp(szCommand, "delete", 6)) 
   { 
      GetArg(szName, szLine, 2); 
       
      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a waypoint to delete.", COLOR_LIGHTGREY); 
      }          
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szBuffer,MAX_STRING,WaypointsINI); 

         if (!strnicmp(szBuffer, "", 1)) 
         { 
            sprintf(szMsg, "Waypoint \'%s\' does not exist.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            WritePrivateProfileString(Zone->ShortName,szName,"",WaypointsINI); 
          
            // rewrite the section minus the deleted waypoint 
            GetPrivateProfileSection(Zone->ShortName,WaypointList,MAX_STRING*10,WaypointsINI)      ; 
            WritePrivateProfileSection(Zone->ShortName,"",WaypointsINI); 
            pWaypointList = WaypointList; 
                         
            while (pWaypointList[0]!=0) 
            { 
               GetArg(szKey,pWaypointList,1,0,0,0,'='); 
               GetArg(szValue,pWaypointList,2,0,0,0,'='); 
               if (strnicmp(szValue, "", 1)) 
               { 
                  WritePrivateProfileString(Zone->ShortName,szKey,szValue,WaypointsINI); 
               } 
               pWaypointList+=strlen(pWaypointList)+1; 
            } 

            sprintf(szMsg, "Waypoint \'%s\' deleted.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
      } 
   } 
   else if (!strnicmp(szCommand, "list", 4)) 
   { 
      GetPrivateProfileSection(Zone->ShortName,WaypointList,MAX_STRING*10,WaypointsINI)      ; 
      pWaypointList = WaypointList; 

      sprintf(szMsg, "Waypoints for %s", Zone->LongName); 
      WriteChatColor(szMsg, CONCOLOR_YELLOW); 
       
      while (pWaypointList[0]!=0) 
      { 
         GetArg(szName,pWaypointList,1,0,0,0,'='); 
         GetArg(szData,pWaypointList,2,0,0,0,'='); 
         GetArg(szDesc,szData,2,0,0,0,':'); 
          
         if (strnicmp(szDesc,"",1)) 
         { 
            sprintf(szMsg, "- %s   ( %s )", szName, szDesc); 
         } 
         else 
         { 
            sprintf(szMsg, "- %s", szName); 
         } 
         WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         pWaypointList+=strlen(pWaypointList)+1; 
      } 
   } 
   else 
   { 
      WriteChatColor("Invalid syntax.  Usage:", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint add name", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint delete name", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint list", COLOR_LIGHTGREY); 
   } 
} 

VOID Ghost(PSPAWNINFO pChar, PCHAR szLine)
{
	DWORD SpawnID;
	if((!strcmp(szLine,"on")) && (GetCharInfo()->pSpawn->SpawnID != 0))
	{
		pTarget = NULL;
		SpawnID = GetCharInfo()->pSpawn->SpawnID;
		GetCharInfo()->pSpawn->SpawnID = 0;
		WriteChatColor("You are now ghosting.",USERCOLOR_DEFAULT);
	}
	if(!strcmp(szLine,"off"))
	{
		pTarget = NULL;
		GetCharInfo()->pSpawn->SpawnID = SpawnID;
		WriteChatColor("You are no longer ghosting.",USERCOLOR_DEFAULT);
	}
}

PLUGIN_API VOID InitializePlugin(VOID)
{
	DebugSpewAlways("Initializing MQ2RWarp");
  	AddCommand("/warp",Warp); 
 	AddCommand("/zwarp",zWarp); 
  	AddCommand("/exactloc",ExactLocation);
 	AddCommand("/waypoint", waypoint);
   	AddCommand("/ghost",Ghost);
	ppLEQ=(LocalCEverQuest**)pinstCEverQuest;
	AddCommand("/zone",Zone); 
	AddCommand("/gate",Gate); 
	AddCommand("/fade",Fade); 
	AddCommand("/findpath",FindPath); 
}

PLUGIN_API VOID ShutdownPlugin(VOID)
{
	DebugSpewAlways("Shutting down MQ2RWarp");
   	RemoveCommand("/warp"); 
   	RemoveCommand("/exactloc"); 
   	RemoveCommand("/zwarp");
   	RemoveCommand("/waypoint");
	RemoveCommand("/zone");
	RemoveCommand("/gate");
	RemoveCommand("/fade");
   	RemoveCommand("/ghost");
} 



Find in MQ2Main.h and change

Rich (BB code):
 ave to remove/replace the following part in the MQ2 Source
//////////////////////////////////////////////
eqdata.h and replace 
/*0x1ec*/   FLOAT   Unknown0x1ec[3];

with 

/*0x1ec*/   FLOAT SafeYLoc; 
/*0x1f0*/   FLOAT SafeXLoc; 
/*0x1f4*/   FLOAT SafeZLoc;
//////////////////////////////////////////////
MQ2Main.h
#define CDisplay__MoveLocalPlayerToSafeCoords 0
replace 0 with offset
0x043B0FA
(9/21 offset)
//////////////////////////////////////////////
mq2commandapi.cpp and remove

if (!stricmp(Command,"/warp"))
{
Function=0;
}
////////////////////////////////////////////////
MAX_ZONES in EQData.h to 0x171 
or you won't be able to get to DoD zones.

See This POST FOR FURTHER



 
Last edited:
[MQ2] - Size Plugin Posted by Redbot and code found by ()===D====>

See HERE for the original post

This plugin requires an offset just like the warp plugins

This is a client side only plugin (ie no one else sees it)

Usage:
/size 1
(microscopic)
/size 4
(gnome size)
/size 10
(pretty big)
/size 30
(SMASH HUMANS)

/size 0
(return character to normal size)

The sizes go from 1 to 98. 1 Being the smallet, 98 being the largest.
0 is to reset.

Do not go higher than /size 98. If you do, you'll have to delete your character file and do a complete file check with the EQ patcher.


Offset for 8/11 0x47EC91

Rich (BB code):
#include "../MQ2Plugin.h" 

/* 06-27-05 OFFSET */ 

PreSetup("MQ2Size"); 

class SizeClass { 
public: 
void SizeFunc(float); 
}; 

FUNCTION_AT_ADDRESS(void SizeClass::SizeFunc(float), 0x004875ac ); 

VOID Size(PSPAWNINFO pChar, PCHAR szLine) 
{ 
CHAR szArg[MAX_STRING]={0}; 
GetArg(szArg,szLine,1); 

if(szArg[0]!=0) 
if (ppTarget && pTarget) 
{ 
PSPAWNINFO Target = (PSPAWNINFO)pTarget; 
{ 
((SizeClass*)Target)->SizeFunc((float)atof(szArg)); 
} 
} 
} 

PLUGIN_API VOID InitializePlugin(VOID) 
{ 
AddCommand("/size",Size); 
} 

PLUGIN_API VOID ShutdownPlugin(VOID) 
{ 
RemoveCommand("/size"); 
}
 
MQ2PiggyZone by Cosmic

See THIS THREAD FOR MORE INFO

Here is a plugin version that might be easier for folks to use.

updated 10/08/2005: Got sick of people complaining about cut/paste errors, so i'm just distributing the .zip from now on. Its still just got the .cpp and .ini in it. Just watch the date to see if you have the latest and greatest version.

updated 10/08/2005: There has been some confusion with DoN zones because MAX_ZONES in EQData.h is wrong in many people's compiles. This value should be 0x171 at the moment. I had hardcoded this at one point, but really people need to fix the value in the EQData.h. So I took my hardcode out. If you get a message that says you can't get to corathus, you probably have an old MAX_ZONES value. Updated the ini with a couple fixes as well.

updated 10/07/2005(again): No longer uses MQ2 OnZoned (which was failing to fire reliably. Should reduce stalling greatly. Now targets NPC to whom the magic phrases are uttered (fixes PoDiscord issue). Updated .ini thanks again to Tone. Added a .zip with the .cpp and .ini file in it for folks having problems cutting and pasting.

updated 10/07/2005: Now with NPC support! (Magus,Translocator) Extra section in .ini defines where the NPCs are and where they can go. Also updated .ini with Tone's expansion info. Thanks Tone!

updated 10/02/2005: Now takes bind point into consideration for chain-zone path determination. Updated .ini zonemap. Now includes OldWorld, Kunark, Luclin, Velious, and PoK.

updated 9/30/2005: Added automatic chain zoning with Floyd-Warshall shortest path logic!
/zone <ShortZoneName> - attempts to take you through all the adjacent zones required to get you to that zone.
/zone force <ShortZoneName> - just trys to go to that zone directly (will crash if not adjacent)
/findpath <ShortZoneName> - display what I think the shortest path will be without actually zoning anywhere
All of these commands still supports the fuzzy matching on long zone names in case you can't remember the short zone name.
This REQUIRES a special section in your .INI file. Its attached below

I will update the INI file over time. Right now it ONLY contain the old world zones. Feel free to complete it yourself or wait. I will try get through at least an expansion per day. Feel free to post errors/omissions. The syntax should be obvious. DO NOT RENUMBER ANYTHING ON THE LEFT HAND SIDE.

updated 9/28/2005: Added waypoint support
/zone setwp <waypointname> - marks your current position in the zone you are in as a waypoint
/zone clearwp <waypointname> - removes waypoint
/zone setwp default - marks your current position as the new default (instead of the succor point) position.
/zone <zoneshortname> <waypointname> -zones you to an adjacent zone at the loc specified by the waypoint.
/zone <zoneshortname> <garbage> - lists all of the waypoints you have set for that zone.

updated 9/27/2005:
Uses Pulse to get around re-entry issues. Might help the peeps who still crash.
Now supports /fade in instanced zones!
/zone with no parameters will list all of the zone names.
/zone with a partial name lists all similar zone names

updated (again) 9/24/2005. bug fixed. now compiles under VS6 properly.

updated 9/24/2005 to *hopefully* fix crash bug

Updated 9/23/2005 to include /fade and /gate

http://www.redguides.com/community/attachment.php?attachmentid=594

Above is the link to get the current download below is the current code

MQ2PiggyZone.cpp

Rich (BB code):
 // MQ2PiggyZone.cpp : Defines the entry point for the DLL application.
 //
 // updated to work with VC6 (previously only worked in VS.NET)
 
 #include "../MQ2Plugin.h"
 
 PreSetup("MQ2PiggyZone");
 
 #undef ZoneToGoTo
 #define LocalCEverQuest__DoTheZone		   0x4AB5A1
 #define INFINITY ((int) pow(2, sizeof(int)*8-2)-1)
 
 #ifdef PKT_UPDATE_POSITION
 #undef PKT_UPDATE_POSITION
 #endif
 #define PKT_UPDATE_POSITION 0x14CB
 #define PKT_CHANNEL_MESSAGE 0x1004
 
 typedef struct
 {
 	int connections[100]; // An array of edges which has this as the starting node
 	int numconnect;
 } FWVertice;
 
 typedef struct
 {
 	int Zone;
 	char Name[50];
 	char Phrase[20][50];
 	int Destination[20];
 	float X,Y,Z;
 	int DestCnt;
 } NPCTeleporter;
 
 FWVertice *V=NULL;
 NPCTeleporter NPCs[100];
 int NPCCnt;
 int* distances=NULL;
 int* predecessor=NULL;
 
 class LocalCEverQuest;
 class LocalCEverQuest
 {
 public:
 	__declspec(dllexport) char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int);
 };
 
 #ifdef LocalCEverQuest__DoTheZone
 FUNCTION_AT_ADDRESS(char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int),LocalCEverQuest__DoTheZone);
 #endif
 
 LocalCEverQuest **ppLEQ;
 #define pLEQ (*ppLEQ)
 
 void Setup();
 bool UseNPC(PSPAWNINFO pChar, int dest);
 PLUGIN_API VOID OnZoned(PSPAWNINFO pChar, PCHAR szLine);
 PLUGIN_API VOID OnPulse(VOID);
 DWORD ListSimilarZones(PCHAR ZoneShortName);
 VOID ChangeZones(PSPAWNINFO pChar, PCHAR szLine); 
 void FloydWarshall(FWVertice* vertices, int nodecount);
 VOID FindPath(PSPAWNINFO pChar, PCHAR szLine); 
 VOID SimFade(PSPAWNINFO pChar, PCHAR szLine); 
 VOID SimGate(PSPAWNINFO pChar, PCHAR szLine); 
 
 bool ZoneChange=false;  
 float X,Y,Z;
 int Heading;
 int DestZone;
 int ChainZone[100];
 int ChainZoneCnt=0;
 int DestType; // 0=use supplied coords 1=succorpoint
 int ChainZoneType; // 0=use supplied coords 1=succorpoint
 int ZoneReason;
 
 int LastKnownZone=-1; //don't fire MyOnZoned when you first log in
 
 void MyOnZoned(PSPAWNINFO pChar)
 {
 	if (ChainZoneCnt>0)
 	{
 		if (pChar->Zone != ChainZone[ChainZoneCnt])
 		{
 			ChainZoneCnt=0;
 			return;
 		}
 		ChainZoneCnt--;
 		DestZone=ChainZone[ChainZoneCnt];
 		if (ChainZoneCnt==0) DestType=ChainZoneType;
 		WriteChatColor("Attempting ChainZone...", USERCOLOR_DEFAULT); 
 		if ( UseNPC(pChar,DestZone) == false)
 		{
 			ZoneChange=true;
 		}
 	}
 	return;
 }
 
 PLUGIN_API VOID OnPulse(VOID)
 {
 	PSPAWNINFO pChar = NULL;
 	if (ppCharSpawn && pCharSpawn) {
 		pChar = (PSPAWNINFO)pCharSpawn;
 		if ((pChar) && (!gZoning))
 		{
 			if (LastKnownZone == -1)	LastKnownZone=pChar->Zone;
 			if (pChar->Zone != LastKnownZone)
 			{
 				LastKnownZone=pChar->Zone;
 				MyOnZoned(pChar);
 			}
 		}
 	}
 
 	char aa[100]="test";
 	if(ZoneChange)
 	{
 		ZoneChange=false;
 		pLEQ->DoTheZone(DestZone,aa,DestType,ZoneReason,Y,X,Z,Heading);
 	}
 	return;
 }
 
 DWORD ListSimilarZones(PCHAR PartialName)
 {
 	CHAR szMsg[MAX_STRING] = "Bad Zone.ShortName. Suggest: ";
 	CHAR szName[MAX_STRING] = {0};
 	char *partial,*longname;
 
 	PZONELIST pZone = NULL;
 
 	partial=_strlwr(_strdup(PartialName));
 	if (!ppWorldData | !pWorldData) return -1;
 	for (int nIndex=0; nIndex < MAX_ZONES+1; nIndex++) {
 	  pZone = ((PWORLDDATA)pWorldData)->ZoneArray[nIndex];
 		if(pZone )
 		{
 			longname=_strlwr(_strdup(pZone->LongName));
 			if (strstr(longname,partial)) {
 		    	sprintf(szName,"%s(%s) ",pZone->LongName,pZone->ShortName);
 				if ((strlen(szMsg)+strlen(szName))>=300)
 				{
 		    	    WriteChatColor(szMsg,USERCOLOR_DEFAULT);
 					szMsg[0]=0;
 				}
 				strcat(szMsg,szName);
 			}
 			free(longname);
 		}
 	}
 	WriteChatColor(szMsg,USERCOLOR_DEFAULT);
 	free(partial);
 	return -1; 
 }
 
 VOID ChangeZones(PSPAWNINFO pChar, PCHAR szLine) 
 { 
 	CHAR szMsg[MAX_STRING] = {0};
 	CHAR szParam[MAX_STRING] = {0};
 	CHAR sZoneName[MAX_STRING] ={0};
 	CHAR sWPName[MAX_STRING] ={0};
 	CHAR sKeyData[MAX_STRING]={0};
 	DWORD ZoneToGoTo; 
 	int rLen;
 	int i,j,cnt=0;
 	bool IgnoreChain=false;
 	int Param=1;
 
 	GetArg(szParam,szLine,Param);
 	if (_stricmp(szParam,"setwp")==0)
 	{
 		Param++;
 		GetArg(sWPName,szLine,Param);
 		if (sWPName[0]==0)
 		{
 		    WriteChatColor("Usage: /zone setwp <WayPointName>", CONCOLOR_RED); 
 			return;
 		}
 		sprintf(sKeyData,"%.2f %.2f %2.f %d",pChar->Y,pChar->X,pChar->Z,(int)pChar->Heading);
 		WritePrivateProfileString(GetShortZone(pChar->Zone), sWPName, sKeyData, INIFileName); 
 		WriteChatColor("Waypoint recorded", USERCOLOR_DEFAULT); 
 		return;
 	}
 	if (_stricmp(szParam,"clearwp")==0)
 	{
 		Param++;
 		GetArg(sWPName,szLine,Param);
 		if (sWPName[0]==0)
 		{
 		    WriteChatColor("Usage: /zone clearwp <WayPointName>", CONCOLOR_RED); 
 			return;
 		}
 		WritePrivateProfileString(GetShortZone(pChar->Zone), sWPName, NULL, INIFileName); 
 		WriteChatColor("Waypoint cleared", USERCOLOR_DEFAULT); 
 		return;
 	}
 	if (_stricmp(szParam,"force")==0)
 	{
 		IgnoreChain=true;
 		Param++;
 	}
 	GetArg(sZoneName,szLine,Param++);
 
 	ZoneToGoTo = GetZoneID(sZoneName);
 
 	if (ZoneToGoTo == -1) {
 		ListSimilarZones(sZoneName);
 		return;
 	}
 
 	Setup();
 
 	if (IgnoreChain==false)
 	{
 		i=pChar->Zone;
 		j=ZoneToGoTo;
 
 		if (distances[i*MAX_ZONES+j]==0)
 		{
 			WriteChatColor("Poof! You are already there.", CONCOLOR_RED); 
 			return;
 		}
 
 		if (distances[i*MAX_ZONES+j]==INFINITY)
 		{
 			WriteChatColor("I don't know a route to that zone.", CONCOLOR_RED); 
 			return;
 		}
 	}
 	GetArg(sWPName,szLine,Param++);
 	if (sWPName[0]!=0)
 	{
 		CHAR sDefault[MAX_STRING]="none";
 		GetPrivateProfileString(sZoneName,sWPName, sDefault, sKeyData, MAX_STRING, INIFileName); 
 		if (_stricmp(sKeyData,"none")==0)
 		{
 		    rLen=GetPrivateProfileString(sZoneName,NULL, sDefault, sKeyData, MAX_STRING, INIFileName); 
 			for (int i=0;i<rLen-1;i++) if (sKeyData==0) sKeyData=',';
 			sprintf(szMsg,"Bad Waypoint. Suggest: %s",sKeyData); 
 			WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
 			return;
 		}
 		sscanf(sKeyData,"%f %f %f %d",&Y,&X,&Z,&Heading);
 		DestType=0;
 	}
 	else
 	{
 		sprintf(sWPName,"default");
 		CHAR sDefault[MAX_STRING]="none";
 		GetPrivateProfileString(sZoneName,sWPName, sDefault, sKeyData, MAX_STRING, INIFileName); 
 		if (_stricmp(sKeyData,"none")!=0)
 		{
 			sscanf(sKeyData,"%f %f %f %d",&Y,&X,&Z,&Heading);
 			DestType=0;
 		}
 		else
 		{
 			Y=pChar->Y;
 			X=pChar->X;
 			Z=pChar->Z;
 			Heading = (int)pChar->Heading;
 			DestType=1;
 		}
 	}
 
 	ChainZoneCnt=0;	//reset in case we failed to finish previous chain-zone attempt
 	if (IgnoreChain==false)
 	{
 		while (i!=j)
 		{
 			ChainZone[ChainZoneCnt++]=j;
 			j=predecessor[i*MAX_ZONES+j];
 		}
 
 		if (ChainZoneCnt>1) 
 		{
 			ChainZoneType=DestType;
 			DestType=1;
 		}
 		DestZone = ChainZone[--ChainZoneCnt];
 	}
 	else
 	{
 		DestZone=ZoneToGoTo;
 	}
 
 	sprintf(szMsg,"Zoneing..."); 
 	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
 	ZoneReason=0;
 	if (UseNPC(pChar,DestZone) == false) ZoneChange=true;
 	return;
 } 
 
 VOID FindPath(PSPAWNINFO pChar, PCHAR szLine)
 {
 	CHAR sDest[MAX_STRING]={0};
 	int ZoneToGoTo;
 	int i,j,cnt=0,stops[100];
 
 	GetArg(sDest,szLine,1);
 	if (sDest[0]==0)
 	{
 		WriteChatColor("Usage: /FindPath <ShortZoneName>", CONCOLOR_RED); 
 		return;
 	}
 	ZoneToGoTo = GetZoneID(sDest);
 
 	if (ZoneToGoTo == -1) {
 		ListSimilarZones(sDest);
 		return;
 	}
 
 	Setup();
 
 	i=pChar->Zone;
 	j=ZoneToGoTo;
 
 	if (distances[i*MAX_ZONES+j]==0)
 	{
 		WriteChatColor("Poof! You are already there.", CONCOLOR_RED); 
 		return;
 	}
 	if (distances[i*MAX_ZONES+j]==INFINITY)
 	{
 		WriteChatColor("I don't know a route to that zone.", CONCOLOR_RED); 
 		return;
 	}
 
 	WriteChatColor("My path:", CONCOLOR_RED); 
 	while (i!=j)
 	{
 		stops[cnt++]=j;
 		j=predecessor[i*MAX_ZONES+j];
 	}
 
 	while (cnt>0)
 	{
 		cnt--;
 		WriteChatColor(GetShortZone(stops[cnt]),USERCOLOR_DEFAULT);
 	}
 
 }
 
 void Setup()
 {
 	char sKey[300];
 	char sKeyData[300];
 	char *p;
 	int i;
 	if (distances!=NULL) free(distances);
 	if (predecessor!=NULL) free(predecessor);
 	if (V!=NULL) free(V);
 	V = (FWVertice *)malloc(MAX_ZONES*sizeof(FWVertice));
 	int tmp[100],cnt;
 	for (i=0;i<MAX_ZONES;i++)
 	{
 		sprintf(sKey,"%d",i);
 		V.numconnect=0;
 		GetPrivateProfileString("ZoneConnections",sKey,"none",sKeyData,300,INIFileName);
 		if (_stricmp(sKeyData,"none")!=0)
 		{
 			strtok(sKeyData,"\"");
 			strtok(NULL,"\"");
 			cnt=0;
 			while ( (p=strtok(NULL,",")) != NULL)
 			{
 				tmp[cnt++]=atoi(p);
 			}
 			V.numconnect=cnt+1;
 			for (int j=0;j<cnt;j++) V.connections[j]=tmp[j];
 		}
 	    V.connections[V.numconnect++]=GetCharInfo2()->ZoneBoundID; //always connected to my bind point
 	}
 
 	//NPCTeleporter support
 	NPCCnt=0;
 	for (i=0;i<100;i++)
 	{
 		sprintf(sKey,"%d",(i+1));
 		GetPrivateProfileString("NPCTeleporters",sKey,"none",sKeyData,300,INIFileName);
 		if (_stricmp(sKeyData,"none")==0) break;
 		NPCCnt++;
 		NPCs.Zone=atoi(strtok(sKeyData," \""));
 		strcpy(NPCs.Name,strtok(NULL,"\""));
 		NPCs.Y=(float)atof(strtok(NULL," "));
 		NPCs.X=(float)atof(strtok(NULL," "));
 		NPCs.Z=(float)atof(strtok(NULL," "));
 		NPCs.DestCnt=0;
 		p=strtok(NULL," \"");
 		while (p!=NULL)
 		{
 			NPCs.Destination[NPCs.DestCnt]=atoi(p);
 			strcpy(NPCs.Phrase[NPCs.DestCnt],strtok(NULL,"\""));
 		    V[NPCs.Zone].connections[V[NPCs.Zone].numconnect++]=NPCs.Destination[NPCs.DestCnt];
 			NPCs.DestCnt++;
 			p=strtok(NULL," \"");
 		}
 	}
 
 	FloydWarshall(V,MAX_ZONES);
 }
 
 bool UseNPC(PSPAWNINFO pChar,int dest)
 {
 	for (int i=0;i<NPCCnt;i++)
 	{
 		if (NPCs.Zone != pChar->Zone) continue;
 		for (int j=0;j<NPCs.DestCnt;j++)
 		{
 			if (NPCs.Destination[j]==dest)
 			{
 				//Code borrowed directly from MQ2CSum
 				// setup move packet
 				struct _MOVEPKT {
 				/*0000*/ unsigned short SpawnID;
 				/*0002*/ unsigned short TimeStamp;
 				/*0004*/ float Y;
 				/*0008*/ float DeltaZ;
 				/*0012*/ float DeltaY;
 				/*0016*/ float DeltaX;
 				/*0020*/ int Animation:10;
 				/*0020*/ int DeltaHeading:10;
 				/*0020*/ int padding0020:12;
 				/*0024*/ float X;
 				/*0028*/ float Z;
 				/*0032*/ int Heading:12;
 				/*0032*/ int padding1_0032:10;
 				/*0032*/ int padding2_0032:10;
 				} P; // 36
 				struct _MSGPACKET {
 				/*0000*/ char target[64];
 				/*0064*/ char sender[64];
 				/*0128*/ unsigned int language;
 				/*0132*/ unsigned int channel;
 				/*0136*/ char padding136[8];
 				/*0144*/ unsigned int languageskill;
 				/*0148*/ char message[100];
 				} M;
 
 				// init packets
 				ZeroMemory(&P, sizeof(P));
 				ZeroMemory(&M, sizeof(M));
 				P.SpawnID = (unsigned short)pChar->SpawnID;
 				P.Heading = (unsigned int)(pChar->Heading * 4);
 
 				PSPAWNINFO psTarget = NULL; 
 				Target(pChar,NPCs.Name);
 				if (ppTarget && pTarget) { 
 					psTarget = (PSPAWNINFO)pTarget; 
 				} 
 				if (psTarget) 
 				{
 		    	    strcpy(M.target,psTarget->Name);
 				}
 				strcpy(M.sender,pChar->Name);
 				M.channel=8;
 				M.languageskill=100;
 
 				// jump to
 				P.Z = NPCs.Z;
 				P.Y = NPCs.Y;
 				P.X = NPCs.X;
 		    	SendEQMessage(PKT_UPDATE_POSITION, &P, sizeof(P));
 
 				sprintf(M.message,"%s",NPCs.Phrase[j]);
 				SendEQMessage(PKT_CHANNEL_MESSAGE,&M,sizeof(M));
 				return true;
 			}
 		}
 	}
 	return false;
 }
 
 void FloydWarshall(FWVertice* vertices, int nodecount) // Vertices numbered from 0 to nodecount-1
 {
 	distances = (int*) malloc(nodecount*nodecount*sizeof(int)*8);
 	predecessor = (int*) malloc(nodecount*nodecount*sizeof(int)*8);
 	int i,j,k;
 
 	for(i = 0; i < nodecount; i++)
 	{
 		for(j = 0; j < nodecount; j++)
 		{
 			distances[i*nodecount+j] = 0;
 			predecessor[i*nodecount+j] = i;
 		}
 	}
 	for(i = 0; i < nodecount; i++)
 	{
 		for(j = 0; j < vertices.numconnect; j++)
 		{
 			distances[i*nodecount + vertices.connections[j]] =1; 
 //						    vertices.connections[j].weight;
 		}
 		for(j = 0; j < nodecount; j++)
 		{
 			if(!distances[i*nodecount+j] && (i^j)) 
 				// i ^ j returns 0 if they are equal
 			{
 				distances[i*nodecount+j] = INFINITY;
 			}
 		}
 	}
 	for(k = 0; k < nodecount; k++)
 	{
 		for(i = 0; i < nodecount; i++)
 		{
 			for(j = 0; j < nodecount; j++)
 			{
 			    if(distances[i*nodecount+j] > distances[i*nodecount+k] + distances[k*nodecount+j])
 				{
 				    distances[i*nodecount+j] = distances[i*nodecount+k] + distances[k*nodecount+j];
 				    predecessor[i*nodecount+j] = predecessor[k*nodecount+j];
 				}
 			}
 		}
 	}
 }
 
 VOID SimGate(PSPAWNINFO pChar, PCHAR szLine) 
 { 
 	CHAR szMsg[MAX_STRING] = {0};
 	PCHARINFO2 pChar2 = GetCharInfo2();
 
 	sprintf(szMsg,"Gating...");
 	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
 	DestZone=pChar2->ZoneBoundID;
 	DestType=0;
 	ZoneReason=11;
 	Y=pChar2->ZoneBoundX;
 	X=pChar2->ZoneBoundY;
 	Z=pChar2->ZoneBoundZ;
 	Heading=0;
 	ZoneChange=true;
 	return;
 } 
 
 VOID SimFade(PSPAWNINFO pChar, PCHAR szLine) 
 { 
 	CHAR szMsg[MAX_STRING] = {0};
 	if (pChar->Instance != 0)
 	{
 		DestZone = *((int *)(&(pChar->Instance)-1));
 	}
 	else
 	{
 		DestZone = pChar->Zone;
 	}
 	sprintf(szMsg,"Fading..."); 
 	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
 	DestType=0;
 	ZoneReason=0;
 	Y=pChar->Y;
 	X=pChar->X;
 	Z=pChar->Z;
 	Heading =(int)pChar->Heading;
 	ZoneChange=true;
 	return;
 }
 
 // Called once, when the plugin is to initialize
 PLUGIN_API VOID InitializePlugin(VOID)
 {
 	DebugSpewAlways("Initializing MQ2PiggyZone");
 
 	ppLEQ=(LocalCEverQuest**)pinstCEverQuest;
 	AddCommand("/zone",ChangeZones); 
 	AddCommand("/gate",SimGate); 
 	AddCommand("/fade",SimFade); 
 	AddCommand("/findpath",FindPath); 
 }
 
 // Called once, when the plugin is to shutdown
 PLUGIN_API VOID ShutdownPlugin(VOID)
 {
 	DebugSpewAlways("Shutting down MQ2PiggyZone");
 
 	RemoveCommand("/zone");
 	RemoveCommand("/gate");
 	RemoveCommand("/fade");
 }
 
 



MQ2PiggyZone.ini

Rich (BB code):
 [qeytoqrg]
 south=230.70 106.47 -3 505
 
 [qeynos2]
 default=203.61 484.94  4 257
 alt2=306.74 533.17  4 484
 
 [NPCTeleporters]
 1=344 "Magus Alaria" 601 -7 2 68 "Butcherblock" 22 "East Commonlands" 30 "Everfrost" 34 "North Ro" 35 "South Ro" 182 "Nedaria"
 2=182 "Magus Wenla" 1023 1525 82 68 "Butcherblock" 22 "East Commonlands" 30 "Everfrost" 34 "North Ro" 35 "South Ro" 280 "Natimbi" 279 "Abysmal Sea"
 3=279 "Magus Pellen" -150 48 140 280 "Natimbi" 182 "Nedaria"
 4=280 "Magus Releua" -693 -1585 246 182 "Nedaria" 279 "Abysmal Sea"
 5=68 "Magus Tira" -1084 -2450 0  22 "East Commonlands" 30 "Everfrost" 34 "North Ro" 35 "South Ro" 182 "Nedaria"
 6=30 "Magus Delin" 1802 -5041 -60 22 "East Commonlands" 68 "Butcherblock" 34 "North Ro" 35 "South Ro" 182 "Nedaria"
 7=22 "Magus Zeir" -1626 -178 4 30 "Everfrost" 68 "Butcherblock" 34 "North Ro" 35 "South Ro" 182 "Nedaria"
 8=34 "Magus Arindri" 2678 917 -25 30 "Everfrost" 68 "Butcherblock" 22 "East Commonlands" 35 "South Ro" 182 "Nedaria"
 9=35 "Magus Jerira" -1468 1066 -23 30 "Everfrost" 68 "Butcherblock" 22 "East Commonlands" 34 "North Ro" 182 "Nedaria"
 10=37 "Translocator Tradil" 881 -831 0 96 "Travel to Timorous Deep"
 11=96 "Translocator Jorbin" 5862 3623 2 37 "travel to Oasis" 93 "travel to overthere"
 12=93 "Translocator Breya" 3435 2747 -158 96 "Travel to Timorous Deep"
 13=34 "Translocator Ionie" 781 -843 0 110 "travel to Iceclad"
 14=110 "Translocator Kurione" 5341 360 -16 34 "travel to North Ro"
 15=68 "Translocator Gethia" 854 3167 12 96 "Travel to Timorous Deep"
 16=68 "Translocator Fithop" 1351 3253 12 69 "Travel to Ocean of Tears"
 17=96 "Translocator Deela" -4545 -3253 19 68 "Travel to Butcherblock" 84 "Travel to Firiona Vie"
 18=84 "Translocator Drabilt" -4388 1386 -103 96 "Travel to Timorous Deep"
 19=69 "Translocator Narrik" 273 -9200 4  68 "Travel to Butcherblock" 10 "Travel to Freeport"
 20=10 "Translocator Setikan" -20 -1020 -52 69 "Travel to Ocean of Tears"
 21=1 "Translocator Sedina" 14 221 4 98 "Travel to Crossing"
 22=98 "Translocator Jempar" -1768 670 4 1 "Travel to Qeynos" 24 "Travel to Erudin"
 23=24 "Translocator Eniela" 96 -354 24 98 "Travel to Crossing"
 24=202 "Priest of Discord" 49 577 4 302 "Wish to go"
 [ZoneConnections]
 1=qeynos "South Qeynos",2,45
 2=qeynos2 "North Qeynos",45,4,1,202
 3=qrg "Surefall Glade",4,181
 4=qeytoqrg "Qeynos Hills",17,3,2,12
 5=highpass "Highpass Hold",6,15,20
 6=highkeep "HighKeep",5
 8=freportn "North Freeport",9
 9=freportw "West Freeport",8,10,22,202
 10=freporte "East Freeport",9,69,34
 11=runnyeye "Clan RunnyEye",33,16
 12=qey2hh1 "West Karana",4,13
 13=northkarana "North Karana",12,15,14
 14=southkarana "South Karana",13,18,51
 15=eastkarana "East Karana",13,5,16
 16=beholder "Gorge of King Xorbb",15,11
 17=blackburrow "BlackBurrow",4,30
 18=paw "Infected Paw",14
 19=rivervale "Rivervale",20,33,202
 20=kithicor "Kithicor Forest",19,5,21
 21=commons "West Commonlands",20,22,36
 22=ecommons "East Commonlands",21,25,9,34
 23=erudnint "Erudin Palace",24
 24=erudnext "Erudin",23,38
 25=nektulos "Nektulos Forest",27,40,22,202,365
 26=cshome "Sunset Home"
 27=lavastorm "Lavastorm Mountains",80,44,25,31,32,337,341
 28=nektropos "Nektropos"
 29=halas "Halas",30
 30=everfrost "Everfrost Peaks",29,73,17,202
 31=soldunga "Solusek's Eye",32,27,278
 32=soldungb "Nagafen's Lair",31,27,278
 33=misty "Misty Thicket",11,19,202
 34=nro "North Ro",10,22,37
 35=sro "South Ro",37,46
 36=befallen "Befallen",21
 37=oasis "Oasis of Marr",34,35
 38=tox "Toxxulia Forest",24,75,74,202
 39=hole "The Ruins of Old Paineel",75
 40=neriaka "Neriak Foreign Quarter",25,41
 41=neriakb "Neriak Commons",40,42
 42=neriakc "Neriak Third Gate",41
 43=neriakd "Neriak Palace"
 44=najena "Najena",44
 45=qcat "Qeynos Catacombs",1,2
 46=innothule "Innothule Swamp",35,65,52,47,202
 47=feerrott "The Feerrott",49,46,48,50,202
 48=cazicthule "Cazic-Thule",47
 49=oggok "Oggok",47
 50=rathemtn "Mountains of Rathe",47,51
 51=lakerathe "Lake Rathetear",14,50,77
 52=grobb "Grobb",46
 53=aviak "Aviak Village"
 54=gfaydark "Greater Faydark",58,61,57,68,202
 55=akanon "Ak'Anon",56
 56=steamfont "Steamfont Mountains",55,57,202
 57=lfaydark "Lesser Faydark",54,56,59
 58=crushbone "Clan Crushbone",54
 59=mistmoore "Castle Mistmoore",57
 60=kaladima "Kaladim",67,68
 61=felwithea "Felwithe",62,54
 62=felwitheb "Felwithe",61
 63=unrest "Estate of Unrest",70
 64=kedge "Kedge Keep",70
 65=guktop "Upper Guk",46,66
 66=gukbottom "Lower Guk",66
 67=kaladimb "Kaladim",60
 68=butcher "Butcherblock Mountains",60,54,70,69,202
 69=oot "Ocean of Tears",10,68
 70=cauldron "Dagnor's Cauldron",68,63,64
 71=airplane "Plane of Sky"
 72=fearplane "Plane of Fear"
 73=permafrost "Permafrost Keep",30
 74=kerraridge "Kerra Isle",38
 75=paineel "Paineel",38,39,101
 76=hateplane "The Plane of Hate"
 77=arena "The Arena",51
 78=fieldofbone "The Field of Bone",97,94,88,83,106,79,202
 79=warslikswood "Warsliks Wood",104,78,82,85,93
 80=soltemple "Temple of Solusek Ro",27
 81=droga "Temple of Droga",92,107
 82=cabwest "West Cabilis",106,85,79
 83=swampofnohope "Swamp of No Hope",78,95,84,106
 84=firiona "Firiona Vie",83,86,85,202
 85=lakeofillomen "Lake of Ill Omen",79,82,84,92,109
 86=dreadlands "Dreadlands",92,84,102,87
 87=burningwood "Burning Woods",91,103,92,86
 88=kaesora "Kaesora",78
 89=sebilis "Old Sebilis",95
 90=citymist "City of Mist",94
 91=skyfire "Skyfire Mountains",108,93,87
 92=frontiermtns "Frontier Mountains",93,85,86,81,107,87
 93=overthere "The Overthere",105,79,92,91,202
 94=emeraldjungle "The Emerald Jungle",90,95,78
 95=trakanon "Trakanon's Teeth",94,89,83
 96=timorous "Timorous Deep"
 97=kurn "Kurn's Tower",78
 98=erudsxing "Erud's Crossing"
 100=stonebrunt "Stonebrunt Mountains"
 101=warrens "The Warrens"
 102=karnor "Karnor's Castle",86
 103=chardok "Chardok",87
 104=dalnir "Dalnir",79
 105=charasis "Howling Stones",93
 106=cabeast "East Cabilis",78,83,82
 107=nurga "Mines of Nurga",81,92
 108=veeshan "Veeshan's Peak"
 109=veksar "Veksar",85
 110=iceclad "Iceclad Ocean",111,116
 111=frozenshadow "Tower of Frozen Shadow",110
 112=velketor "Velketor's Labyrinth",118
 113=kael "Kael Drakkal",116,119
 114=skyshrine "Skyshrine",117,119
 115=thurgadina "Thurgadin",129,118
 116=eastwastes "Eastern Wastes",110,121,118,113,128
 117=cobaltscar "Cobalt Scar",125,114
 118=greatdivide "Great Divide",116,115,112,202
 119=wakening "The Wakening Land",113,127,114
 120=westwastes "Western Wastes",124,125,123
 121=crystal "Crystal Caverns",116
 123=necropolis "Dragon Necropolis",120
 124=templeveeshan "Temple of Veeshan",126,120
 125=sirens "Siren's Grotto",117,120
 126=mischiefplane "Plane of Mischief"
 127=growthplane "Plane of Growth"
 128=sleeper "Sleeper's Tomb"
 129=thurgadinb "Icewell Keep",115,118
 130=erudsxing2 "Marauder's Mire"
 150=shadowhaven "Shadow Haven",151,156,153,152
 151=bazaar "The Bazaar",150,152,202
 152=nexus "The Nexus",161,150,151,202
 153=echo "Echo Caverns",150,164,157
 154=acrylia "Acrylia Caverns",167
 155=sharvahl "Shar Vahl",166,165
 156=paludal "Paludal Caverns",166,165,150
 157=fungusgrove "Fungus Grove",170,153
 158=vexthal "Vex Thal",176
 159=sseru "Sanctus Seru",168,174
 160=katta "Katta Castellum",172,170
 161=netherbian "Netherbian Lair",152,174,168
 162=ssratemple "Ssraeshza Temple",171
 163=griegsend "Grieg's End",175,174
 164=thedeep "The Deep",153
 165=shadeweaver "Shadeweaver's Thicket",156,155,202
 166=hollowshade "Hollowshade Moor",167,155
 167=grimling "Grimling Forest",172,166,154
 168=mseru "Marus Seru",169,161,159
 169=letalis "Mons Letalis",171,168
 170=twilight "The Twilight Sea",160,157,175
 171=thegrey "The Grey",162,175,169
 172=tenebrous "The Tenebrous Mountains",167,160
 173=maiden "The Maiden's Eye",176,179,174
 174=dawnshroud "Dawnshroud Peaks",161,173,163,159
 175=scarlet "The Scarlet Desert",163,170,171
 176=umbral "The Umbral Plains",158,173
 179=akheva "Akheva Ruins",173
 180=arena2 "The Arena"
 181=jaggedpine "The Jaggedpine Forest",3,182
 182=nedaria "Nedaria's Landing",181
 183=tutorial "Tutorial Zone"
 184=load "Loading"
 185=load2 "Loading"
 186=hateplaneb "The Plane of Hate"
 187=shadowrest "Shadowrest"
 188=tutoriala "The Mines of Gloomingdeep"
 189=tutorialb "The Mines of Gloomingdeep"
 190=clz "Loading"
 200=codecay "Ruins of Lxanvom",203
 201=pojustice "Plane of Justice",203
 202=poknowledge "Plane of Knowledge",19,54,68,30,38,152,118,165,2,203,84,9,56,78,46,25,47,93,224,151,344,33
 203=potranquility "Plane of Tranquility",202,200,201,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219
 204=ponightmare "Plane of Nightmare",203,221
 205=podisease "Plane of Disease",203,200
 206=poinnovation "Plane of Innovation",203
 207=potorment "Plane of Torment",203
 208=povalor "Plane of Valor",203,211
 209=bothunder "Torden, The Bastion of Thunder",203
 210=postorms "Plane of Storms",203,209
 211=hohonora "Halls of Honor",203,220,
 212=solrotower "Solusek Ro's Tower",203,217
 213=powar "Plane of War",203
 214=potactics "Drunder, Fortress of Zek",203
 215=poair "Eryslai, the Kingdom of Wind",203
 216=powater "Reef of Coirnav",203
 217=pofire "Doomfire, The Burning Lands",203
 218=poeartha "Vegarlson, The Earthen Badlands",203,222
 219=potimea "Plane of Time",203
 220=hohonorb "Temple of Marr",211
 221=nightmareb "Lair of Terris Thule",204
 222=poearthb "Stronghold of the Twelve",218
 223=potimeb "Plane of Time",219
 224=gunthak "Gulf of Gunthak",202,225,227
 225=dulak "Dulak's Harbor",224,226
 226=torgiran "Torgiran Mines",225
 227=nadox "Crypt of Nadox",224,228
 228=hatesfury "Hate's Fury, The Scorned Maiden",227
 229=guka "The Cauldron of Lost Souls"
 230=ruja "The Bloodied Quarries"
 231=taka "The Sunken Library"
 232=mira "The Silent Gallery"
 233=mmca "The Forlorn Caverns"
 234=gukb "The Drowning Crypt"
 235=rujb "The Halls of War"
 236=takb "The Shifting Tower"
 237=mirb "The Maw of the Menagerie"
 238=mmcb "The Dreary Grotto"
 239=gukc "The Ancient Aqueducts"
 240=rujc "The Wind Bridges"
 241=takc "The Fading Temple"
 242=mirc "The Spider Den"
 243=mmcc "The Asylum of Invoked Stone"
 244=gukd "The Mushroom Grove"
 245=rujd "The Gladiator Pits"
 246=takd "The Royal Observatory"
 247=mird "The Hushed Banquet"
 248=mmcd "The Chambers of Eternal Affliction"
 249=guke "The Foreboding Prison"
 250=ruje "The Drudge Hollows"
 251=take "The River of Recollection"
 252=mire "The Frosted Halls"
 253=mmce "The Sepulcher of the Damned"
 254=gukf "The Chapel of the Witnesses"
 255=rujf "The Fortified Lair of the Taskmasters"
 256=takf "The Sandfall Corridors"
 257=mirf "The Forgotten Wastes"
 258=mmcf "The Ritualistic Summoning Grounds"
 259=gukg "The Root Garden"
 260=rujg "The Hidden Vale"
 261=takg "The Balancing Chamber"
 262=mirg "The Heart of the Menagerie"
 263=mmcg "The Cesspits of Putrescence"
 264=gukh "The Accursed Sanctuary"
 265=rujh "The Blazing Forge"
 266=takh "The Sweeping Tides"
 267=mirh "The Morbid Laboratory"
 268=mmch "The Aisles of Blood"
 269=ruji "The Arena of Chance"
 270=taki "The Antiquated Palace"
 271=miri "The Theater of Imprisoned Horrors"
 272=mmci "The Halls of Sanguinary Rites"
 273=rujj "The Barracks of War"
 274=takj "The Prismatic Corridors"
 275=mirj "The Grand Library"
 276=mmcj "The Infernal Sanctuary"
 277=chardokb "The Halls of Betrayal",103
 278=soldungc "The Caverns of Exile",32
 279=abysmal "Abysmal Sea"
 280=natimbi "Natimbi, The Broken Shores",281,293
 281=qinimi "Qinimi, Court of Nihilia",280,282,284,283
 282=riwwi "Riwwi, Coliseum of Games",283,284,281
 283=barindu "Barindu, Hanging Gardens",282,281,290,289,284,285,286,287,288
 284=ferubi "Ferubi, Forgotten Temple of Taelosia",283,281,282
 285=snpool "Sewers of Nihilia, Pool of Sludge",283
 286=snlair "Sewers of Nihilia, Lair of Trapped Ones",283
 287=snplant "Sewers of Nihilia, Purifying Plant",283
 288=sncrematory "Sewers of Nihilia, the Crematory",283
 289=tipt "Tipt, Treacherous Crags",283
 290=vxed "Vxed, The Crumbling Caverns",283
 291=yxtta "Yxtta, Pulpit of Exiles",294,292
 292=uqua "Uqua, The Ocean God Chantry",291
 293=kodtaz "Kod'Taz, Broken Trial Grounds",280,294,295,291
 294=ikkinz "Ikkinz, Chambers of Destruction",293
 295=qvic "Qvic, Prayer Grounds of Calling",293,297,295
 296=inktuta "Inktu`Ta, The Unmasked Chapel",295
 297=txevu "Txevu, Lair of the Elite",295,298
 298=tacvi "Tacvi, Seat of the Slaver",295
 299=qvicb "Qvic, the Hidden Vault"
 300=wallofslaughter "Wall of Slaughter",303,316,317
 301=bloodfields "The Bloodfields",302,336
 302=draniksscar "Dranik's Scar",202,301,335,303
 303=causeway "Nobles' Causeway",302,300
 304=chambersa "Muramite Proving Grounds"
 305=chambersb "Muramite Proving Grounds"
 306=chambersc "Muramite Proving Grounds"
 307=chambersd "Muramite Proving Grounds"
 308=chamberse "Muramite Proving Grounds"
 309=chambersf "Muramite Proving Grounds"
 316=provinggrounds "Muramite Proving Grounds",300,334
 317=anguish "Asylum of Anguish",300
 318=dranikhollowsa "Dranik's Hollows"
 319=dranikhollowsb "Dranik's Hollows"
 320=dranikhollowsc "Dranik's Hollows"
 321=dranikhollowsd "Dranik's Hollows"
 322=dranikhollowse "Dranik's Hollows"
 323=dranikhollowsf "Dranik's Hollows"
 324=dranikhollowsg "Dranik's Hollows"
 325=dranikhollowsh "Dranik's Hollows"
 326=dranikhollowsi "Dranik's Hollows"
 327=dranikhollowsj "Dranik's Hollows"
 328=dranikcatacombsa "Catacombs of Dranik"
 329=dranikcatacombsb "Catacombs of Dranik"
 330=dranikcatacombsc "Catacombs of Dranik"
 331=draniksewersa "Sewers of Dranik"
 332=draniksewersb "Sewers of Dranik"
 333=draniksewersc "Sewers of Dranik"
 334=riftseekers "Riftseekers' Sanctum",316
 335=harbingers "Harbingers' Spire",302
 336=dranik "The Ruined City of Dranik",301
 337=broodlands "The Broodlands",27,338,340,343	
 338=stillmoona "Stillmoon Temple",337
 339=stillmoonb "The Ascent",338
 340=thundercrest "Thundercrest Isles",337
 341=delvea "Lavaspinner's Lair",337,27,342
 342=delveb "Tirranun's Delve",341
 343=thenest "The Accursed Nest",337
 344=guildlobby "The Guild Lobby",202
 345=guildhall "Guild Hall"
 346=barter "The Barter Hall"
 347=illsalin "Ruins of Illsalin",362
 348=illsalina "Imperial Bazaar"
 349=illsalinb "Temple of the Korlach"
 350=illsalinc "The Nargilor Pits"
 351=dreadspire "Dreadspire Keep",358
 354=drachnidhive "The Hive",358
 355=drachnidhivea "Living Larder"
 356=drachnidhiveb "Coven of the Skinwalkers"
 357=drachnidhivec "Queen Sendaii's Lair"
 358=westkorlach "Stoneroot Falls",362,354,351
 359=westkorlacha "Chambers of Xill"
 360=westkorlachb "Caverns of the Lost"
 361=westkorlachc "Lair of the Korlach"
 362=eastkorlach "Undershore",365,347,358
 363=eastkorlacha "Snarlstone Dens"
 364=shadowspine "Shadowspine"
 365=corathus "Corathus Creep",25,362
 366=corathusa "Sporali Caverns"
 367=corathusb "Corathus Lair"
 368=nektulosa "Shadowed Grove"
 
MQ2ALLWARP by Noobhaxor See THIS POST FOR MORE

MQ2AllWarp.cpp

Rich (BB code):
 // MQ2Allwarp.cpp : Compilation of /zone made by Cosmic and /warp made by Riddler/Siddin
// Directions for usage:
//////////////1///////////////////
// eqdata.h and replace
// /*0x1ec*/ FLOAT Unknown0x1ec[3];
// 
// with
// 
// /*0x1ec*/ FLOAT SafeYLoc;
// /*0x1f0*/ FLOAT SafeXLoc;
// /*0x1f4*/ FLOAT SafeZLoc;
//////////////2////////////////////
// MQ2Main.h
// #define CDisplay__MoveLocalPlayerToSafeCoords 0
// replace 0 with offset
// 0x0043B0FA 9/27
//////////////3////////////////////
// mq2commandapi.cpp and remove
// 
// if (!stricmp(Command,"/warp"))
// {
// Function=0;
// }
///////////////////////////////////
#include "../MQ2Plugin.h"

PreSetup("MQ2Allwarp");

#undef ExactLocation
#undef DoWarp
#undef Warp
#undef SafeYLoc
#undef SafeXLoc
#undef SafeZLoc
#undef ZoneToGoTo
#define LocalCEverQuest__DoTheZone		   0x4AB5A1

class LocalCEverQuest;
class LocalCEverQuest
{
public:
	__declspec(dllexport) char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int);
};

#ifdef LocalCEverQuest__DoTheZone
FUNCTION_AT_ADDRESS(char * LocalCEverQuest::DoTheZone(int,char *,int,int,float,float,float,int),LocalCEverQuest__  DoTheZone);
#endif

LocalCEverQuest **ppLEQ;
#define pLEQ (*ppLEQ)

VOID ChainShift(PSPAWNINFO pChar, PCHAR szLine); 
VOID ChangeZones(PSPAWNINFO pChar, PCHAR szLine); 
VOID SimGate(PSPAWNINFO pChar, PCHAR szLine); 
VOID SimFade(PSPAWNINFO pChar, PCHAR szLine); 
VOID DoWarp(float y, float x, float z); 
VOID Warp(PSPAWNINFO pChar, PCHAR szLine); 
VOID ExactLocation(PSPAWNINFO pChar);
VOID waypoint(PSPAWNINFO pChar, PCHAR szLine); 
    int ChainShiftZone[100] = {0};
    int ChainShiftStatus = 0;
	int DestZone = 0;
	int DestType = 0;
	int ZoneReason = 0;
	float X = 0;
	float Y = 0;
	float Z = 0;
	int Heading = 0;
	bool ZoneChange = false;

VOID ChainShift(PSPAWNINFO pChar, PCHAR szLine)
{
	char szMsg[MAX_STRING] = {0};
	bool ZoneDetected = true;
	char ZoneCheckName[MAX_STRING] = {0};
	int ZoneFound = 0;
	ChainShiftStatus = 0;
        
	GetArg(ZoneCheckName,szLine,1);
	ZoneFound = GetZoneID(ZoneCheckName);

	while(ZoneDetected == true) {
		if(ZoneFound > 0) {
			ChainShiftZone[0]++;
			ChainShiftZone[ChainShiftZone[0]] = ZoneFound;
			GetArg(ZoneCheckName,szLine,(ChainShiftZone[0] + 1));
			ZoneFound = GetZoneID(ZoneCheckName);
		} else {
			ZoneDetected = false;
		}
	}

	if(ChainShiftZone[0] > 0) {
		ChainShiftStatus++;
		DestZone=ChainShiftZone[1];
		DestType=1;
		ZoneReason=0;
		Y=pChar->Y;
		X=pChar->X;
		Z=pChar->Z;
		Heading =(int)pChar->Heading;
		ZoneChange=true;
		return;
	}
}

VOID ChangeZones(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	static int once=0;
	if (once==1)
	{
		once=0;
		return;
	}
	once=1;
	CHAR szMsg[MAX_STRING] = {0};
	DWORD ZoneToGoTo; 
	ZoneToGoTo = GetZoneID(szLine);

	if (ZoneToGoTo == -1) {
		WriteChatColor("Wrong Zone.ShortName, aborting!!",CONCOLOR_RED);
		once=0;
		return;
	}

	sprintf(szMsg,"Going to zone %s, id %d",szLine,ZoneToGoTo); 
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	char aa[100]="test";
	int heading = (int)pChar->Heading;
	pLEQ->DoTheZone(ZoneToGoTo,aa,1,0,pChar->Y,pChar->X,pChar->Z,heading);
	return;
} 

VOID SimGate(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	static int once=0;
	if (once==1)
	{
		once=0;
		return;
	}
	once=1;

	CHAR szMsg[MAX_STRING] = {0};
	PCHARINFO2 pChar2 = GetCharInfo2();

	sprintf(szMsg,"Gating...");
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	char aa[100]="test";
	pLEQ->DoTheZone(pChar2->ZoneBoundID,aa,0,11,pChar2->ZoneBoundX,pChar2->ZoneBoundY,pChar2->ZoneBoundZ,0);
	return;
} 

VOID SimFade(PSPAWNINFO pChar, PCHAR szLine) 
{ 
	static int once=0;
	if (once==1)
	{
		once=0;
		return;
	}
	once=1;

	CHAR szMsg[MAX_STRING] = {0};

	sprintf(szMsg,"Fading..."); 
	WriteChatColor(szMsg,USERCOLOR_DEFAULT); 
	char aa[100]="test";
	int heading = (int)pChar->Heading;
	pLEQ->DoTheZone(pChar->Zone,aa,0,0,pChar->Y,pChar->X,pChar->Z,heading);
	return;
} 

VOID ExactLocation(PSPAWNINFO pChar, PCHAR szLine) 
{  CHAR LocMsg[MAX_STRING] = {0}; 
   sprintf(LocMsg, "Your location is %3.6f, %3.6f, %3.6f", pChar->Y, pChar->X, pChar->Z); 
   WriteChatColor(LocMsg); 
   return; 
} 

VOID Warp(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   static float LastY; 
   static float LastX; 
   static float LastZ; 
   bRunNextCommand = TRUE; 
   PSPAWNINFO psTarget = NULL; 
   PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
    CHAR command[MAX_STRING]; GetArg(command,szLine,1); 
   CHAR Y[MAX_STRING]; GetArg(Y,szLine,2); 
   CHAR X[MAX_STRING]; GetArg(X,szLine,3); 
   CHAR Z[MAX_STRING]; GetArg(Z,szLine,4); 
   if ( 
      stricmp(command, "succor") != 0 && 
      stricmp(command, "loc") != 0 && 
      stricmp(command, "last") != 0 && 
      stricmp(command, "target") != 0 && 
      stricmp(command, "dir") != 0 &&
      stricmp(command, "wp") != 0
   ) { 
      WriteChatColor("Usage: /warp <succor|last|loc <y x z>|dir <dist>| target|wp name>", CONCOLOR_RED); 
      return; 
      } else { 
      if (!stricmp(command,"target"))  { 
         if (ppTarget && pTarget) { 
         psTarget = (PSPAWNINFO)pTarget; 
         } 
         if (!psTarget) { 
            WriteChatColor("You must have a target for /warp target.", CONCOLOR_RED); 
            return; 
         } 
         float TargetZ = float (psTarget->Z); 
         float TargetY = float (psTarget->Y); 
         float TargetX = float (psTarget->X); 
                        LastY = TargetY; 
         LastX = TargetX; 
         LastZ = TargetZ; 
         DoWarp(TargetY, TargetX, TargetZ); 
      } else if (!stricmp(command,"succor"))  { 
         static float north = 0; 
         ((PSPAWNINFO)pCharSpawn)->Heading = north; 
         DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
         __asm call dword ptr [MLPTSC]; 
         return; 
      } else if (!stricmp(command,"loc")) { 
      if ((Y[0] == 0) || (X[0] == 0) || (Z[0] == 0)) 
      { 
         WriteChatColor("You must provide <y> <x> <z> if going to a location.", CONCOLOR_RED); 
         return; 
      } 
         LastY = (float)atof(Y); 
         LastX = (float)atof(X); 
         LastZ = (float)atof(Z); 
      DoWarp((float)atof(Y), (float)atof(X), (float)atof(Z)); 
      return; 
      } else if (!stricmp(command,"last")) { 
      if ((LastY==0) || (LastX==0) || (LastZ==0)) 
      { 
         WriteChatColor("You must have warped before to use this command!.", CONCOLOR_RED); 
         return; 
      } 
      DoWarp(LastY, LastX, LastZ); 
      return; 
      } else if (!stricmp(command,"dir")) { 
      if (Y[0]==0) { 
         WriteChatColor("You MUST provide <dist> if going in your current direction.", CONCOLOR_RED); 
         return; 
      } 
      FLOAT angle = (FLOAT)((pChar->Heading)*0.0123); 
      FLOAT dissafegoto = (FLOAT)atof(Y); 
      DoWarp(pChar->Y + (FLOAT)(dissafegoto * cos(angle)), pChar->X + (FLOAT)(dissafegoto * sin(angle)), pChar->Z); 
      return; 
                } 
//////Waypoint//////////
   { 
      char szLoc[MAX_STRING] = {0}; 
      char szName[MAX_STRING] = {0}; 
      char WaypointsINI[MAX_STRING] = {0}; 
      char szBuf[MAX_STRING] = {0};
      char szHeading[MAX_STRING] = {0};
      char szDestWarpX[MAX_STRING] = {0}; 
      char szDestWarpY[MAX_STRING] = {0}; 
      char szDestWarpZ[MAX_STRING] = {0}; 
      char szMsg[MAX_STRING] = {0}; 


      sprintf(WaypointsINI,"%s\\waypoints.ini",gszINIPath); 
      GetArg(szName, szLine, 2); 

      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a waypoint.", COLOR_LIGHTGREY); 
      } 
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szLoc,MAX_STRING,WaypointsINI); 
          
         if (!strnicmp(szLoc, "", 1)) 
         { 
            sprintf(szMsg, "Waypoint \'%s\' does not exist.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            // get destination locs 
            GetArg(szDestWarpX, szLoc, 2); 
            GetArg(szDestWarpY, szLoc, 1); 
            GetArg(szDestWarpZ, szLoc, 3); 
             
            // get heading 
            GetArg(szBuf, szLoc, 4); 
            GetArg(szHeading,szBuf,1,0,0,0,':'); 
			DoWarp((float)atof(szDestWarpY), (float)atof(szDestWarpX), (float)atof(szDestWarpZ));
            } 
			}
         } 
//////Waypoint end/////////
   } 
} 


VOID DoWarp(float y, float x, float z) 
{ 

        PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
   float SafeY = Zone->SafeYLoc; 
   float SafeX = Zone->SafeXLoc; 
   float SafeZ = Zone->SafeZLoc; 

   Zone->SafeYLoc = y; 
   Zone->SafeXLoc = x; 
   Zone->SafeZLoc = z; 

   CHAR szMsg[MAX_STRING] = {0}; 
   sprintf(szMsg, "Warping to: %3.2f, %3.2f, %3.2f.", Zone->SafeYLoc, Zone->SafeXLoc, Zone->SafeZLoc); 
   WriteChatColor(szMsg, COLOR_PURPLE); 

   DWORD MLPTSC = CDisplay__MoveLocalPlayerToSafeCoords; 
   __asm call dword ptr [MLPTSC]; 

   Zone->SafeYLoc = SafeY; 
   Zone->SafeXLoc = SafeX; 
   Zone->SafeZLoc = SafeZ; 
} 

VOID waypoint(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   PZONEINFO Zone = (PZONEINFO)pZoneInfo; 
   CHAR WaypointsINI[MAX_STRING] = {0}; 
   CHAR szTemp[10] = {0}; 
   CHAR szData[MAX_STRING] = {0}; 
   CHAR szDesc[MAX_STRING] = {0}; 
   CHAR szName[MAX_STRING] = {0}; 
   CHAR szCommand[MAX_STRING] = {0}; 
   CHAR szBuffer[MAX_STRING] = {0}; 
   CHAR szMsg[MAX_STRING] = {0}; 
   CHAR WaypointList[MAX_STRING*10] = {0}; 
   PCHAR pWaypointList = WaypointList; 
   CHAR szKey[MAX_STRING] = {0}; 
   CHAR szValue[MAX_STRING] = {0}; 

   sprintf(WaypointsINI,"%s\\waypoints.ini",gszINIPath); 
    
   GetArg(szCommand, szLine, 1); 

   if (!strnicmp(szCommand, "add", 3)) 
   { 
      GetArg(szName, szLine, 2); 
       
      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a name for the waypoint.", COLOR_LIGHTGREY); 
      }          
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szBuffer,MAX_STRING,WaypointsINI); 

         if (!strnicmp(szBuffer, "", 1)) 
         { 
            GetArg(szDesc, szLine, 3); 
             
            sprintf(szData, "%1.2f %1.2f %1.2f %1.2f:%s", pChar->Y, pChar->X, pChar->Z, (float)pChar->Heading*0.703125f, szDesc); 
            WritePrivateProfileString(Zone->ShortName,szName,szData,WaypointsINI); 
            sprintf(szMsg, "Waypoint \'%s\' added.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            sprintf(szMsg, "Waypoint \'%s\' already exists.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
      } 
   } 
   else if (!strnicmp(szCommand, "delete", 6)) 
   { 
      GetArg(szName, szLine, 2); 
       
      if(!strnicmp(szName, "", 1)) 
      { 
         WriteChatColor("You didn't specify a waypoint to delete.", COLOR_LIGHTGREY); 
      }          
      else 
      { 
         GetPrivateProfileString(Zone->ShortName,szName,"",szBuffer,MAX_STRING,WaypointsINI); 

         if (!strnicmp(szBuffer, "", 1)) 
         { 
            sprintf(szMsg, "Waypoint \'%s\' does not exist.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
         else 
         { 
            WritePrivateProfileString(Zone->ShortName,szName,"",WaypointsINI); 
          
            // rewrite the section minus the deleted waypoint 
            GetPrivateProfileSection(Zone->ShortName,WaypointList,MAX_STRING*10,WaypointsINI)          ; 
            WritePrivateProfileSection(Zone->ShortName,"",WaypointsINI); 
            pWaypointList = WaypointList; 
                         
            while (pWaypointList[0]!=0) 
            { 
               GetArg(szKey,pWaypointList,1,0,0,0,'='); 
               GetArg(szValue,pWaypointList,2,0,0,0,'='); 
               if (strnicmp(szValue, "", 1)) 
               { 
                  WritePrivateProfileString(Zone->ShortName,szKey,szValue,WaypointsINI); 
               } 
               pWaypointList+=strlen(pWaypointList)+1; 
            } 

            sprintf(szMsg, "Waypoint \'%s\' deleted.", szName); 
            WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         } 
      } 
   } 
   else if (!strnicmp(szCommand, "list", 4)) 
   { 
      GetPrivateProfileSection(Zone->ShortName,WaypointList,MAX_STRING*10,WaypointsINI)          ; 
      pWaypointList = WaypointList; 

      sprintf(szMsg, "Waypoints for %s", Zone->LongName); 
      WriteChatColor(szMsg, CONCOLOR_YELLOW); 
       
      while (pWaypointList[0]!=0) 
      { 
         GetArg(szName,pWaypointList,1,0,0,0,'='); 
         GetArg(szData,pWaypointList,2,0,0,0,'='); 
         GetArg(szDesc,szData,2,0,0,0,':'); 
          
         if (strnicmp(szDesc,"",1)) 
         { 
            sprintf(szMsg, "- %s   ( %s )", szName, szDesc); 
         } 
         else 
         { 
            sprintf(szMsg, "- %s", szName); 
         } 
         WriteChatColor(szMsg, COLOR_LIGHTGREY); 
         pWaypointList+=strlen(pWaypointList)+1; 
      } 
   } 
   else 
   { 
      WriteChatColor("Invalid syntax.  Usage:", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint add name", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint delete name", COLOR_LIGHTGREY); 
      WriteChatColor("/waypoint list", COLOR_LIGHTGREY); 
   } 
}

PLUGIN_API VOID OnZoned(PSPAWNINFO pChar, PCHAR szLine)
{
	CHAR szMsg[MAX_STRING] = {0};
	if(ChainShiftZone[0] > 0) {
		ChainShiftStatus++;
		if(ChainShiftStatus > ChainShiftZone[0]) {
			ChainShiftZone[0] = 0;
		}
		DestZone=ChainShiftZone[ChainShiftStatus];
		DestType=1;
		ZoneReason=0;
		Y=pChar->Y;
		X=pChar->X;
		Z=pChar->Z;
		Heading =(int)pChar->Heading;
		ZoneChange=true;
		return;
	}
}

// Called once, when the plugin is to initialize
PLUGIN_API VOID InitializePlugin(VOID)
{
	DebugSpewAlways("Initializing MQ2Allwarp");

	ppLEQ=(LocalCEverQuest**)pinstCEverQuest;
    AddCommand("/warp",Warp); 
    AddCommand("/exactloc",ExactLocation);
    AddCommand("/waypoint", waypoint);
	AddCommand("/zone",ChangeZones); 
	AddCommand("/gate",SimGate); 
	AddCommand("/fade",SimFade); 
    AddCommand("/chainshift",ChainShift);
}

// Called once, when the plugin is to shutdown
PLUGIN_API VOID ShutdownPlugin(VOID)
{
	DebugSpewAlways("Shutting down MQ2Allwarp");
    RemoveCommand("/warp"); 
    RemoveCommand("/exactloc"); 
    RemoveCommand("/waypoint");
	RemoveCommand("/zone");
	RemoveCommand("/gate");
	RemoveCommand("/fade");
    RemoveCommand("/chainshift");
}
 
MQ2Ventriloquist by TeachersPet See THIS THREAD FOR MORE INFO

Commands:
/throwvoice <text goes here>
- does a /say at your target
/throwvoice -hail
- does a /hail at your targe

Rich (BB code):
 // MQ2Ventriloquist
// Type /throwvoice <your /say goes here> or /throwvoice -hail to "throw" a /say or a /hail safely to your target without any risk of dying.
// By: TeachersPet

#include "../MQ2Plugin.h"
PreSetup("MQ2Ventriloquist");

#define WarpOffset 0x43B0FA

int ThrowBack = 0;
float ThrowSafeLocY = 0;
float ThrowSafeLocX = 0;
float ThrowSafeLocZ = 0;
float ThrowOrigLocY = 0;
float ThrowOrigLocX = 0;
float ThrowOrigLocZ = 0;
char ThrowCmd[MAX_STRING] = {0};

VOID ThrowVoice(PSPAWNINFO pChar, PCHAR szLine)
{
	DWORD MLPTSC = WarpOffset;

	PZONEINFO Zone = (PZONEINFO)pZoneInfo;
	ThrowSafeLocY = Zone->Unknown0x1ec[0];
	ThrowSafeLocX = Zone->Unknown0x1ec[1];
	ThrowSafeLocZ = Zone->Unknown0x1ec[2];

	ThrowOrigLocX = pChar->X;
	ThrowOrigLocY = pChar->Y;
	ThrowOrigLocZ = pChar->Z;

	if (!pTarget || !ppTarget) return;

	PSPAWNINFO Target = (PSPAWNINFO)pTarget;
	if (Target->Type != SPAWN_NPC) return;

	if(!strnicmp(szLine, "-hail", 5)) {
		sprintf(ThrowCmd,"/hail");
	} else {
		sprintf(ThrowCmd,"/say %s",szLine);
	}

	Zone->Unknown0x1ec[1] = Target->X;
	Zone->Unknown0x1ec[0] = Target->Y;
	Zone->Unknown0x1ec[2] = Target->Z;

	__asm call dword ptr [MLPTSC];

	ThrowBack = 1;
}

PLUGIN_API VOID OnPulse(PSPAWNINFO pChar)
{
	PZONEINFO Zone = (PZONEINFO)pZoneInfo;
	DWORD MLPTSC = WarpOffset;
	if(ThrowBack == 1) {	
		DoCommand(pChar,"/keypress left");
		DoCommand(pChar,ThrowCmd);
		ThrowBack = 2;
	} else if(ThrowBack == 2) {
		Zone->Unknown0x1ec[0] = ThrowOrigLocY;
		Zone->Unknown0x1ec[1] = ThrowOrigLocX;
		Zone->Unknown0x1ec[2] = ThrowOrigLocZ;
		__asm call dword ptr [MLPTSC];
		Zone->Unknown0x1ec[0] = ThrowSafeLocY;
		Zone->Unknown0x1ec[1] = ThrowSafeLocX;
		Zone->Unknown0x1ec[2] = ThrowSafeLocZ;
		DoCommand(pChar,"/keypress left");
		ThrowBack = 0;
	}
	return;
}

PLUGIN_API VOID InitializePlugin(VOID)
{
	AddCommand("/throwvoice",ThrowVoice);
}

PLUGIN_API VOID ShutdownPlugin(VOID)
{
	RemoveCommand("/throwvoice");
}
 
MQ2NormalGhost by TeachersPet See THIS THREAD FOR MORE INFO

Rich (BB code):
Rich (BB code):
 OID Ghost(PSPAWNINFO pChar, PCHAR szLine)
{
	static DWORD SpawnID;
	if((!strcmp(szLine,"on")) && (GetCharInfo()->pSpawn->SpawnID != 0))
	{
		pTarget = NULL;
		SpawnID = GetCharInfo()->pSpawn->SpawnID;
		GetCharInfo()->pSpawn->SpawnID = 0;
		WriteChatColor("You are now ghosting.",USERCOLOR_DEFAULT);
	}
	if(!strcmp(szLine,"off"))
	{
		pTarget = NULL;
		GetCharInfo()->pSpawn->SpawnID = SpawnID;
		WriteChatColor("You are no longer ghosting.",USERCOLOR_DEFAULT);
	}
}

 
Addon to PiggyZone, CHAINSHIFT by TeachersPet

See THIS THREAD FOR MORE INFO

Add this into PiggyZone. This is sort of a beta so you HAVE to use exact zone names (you can't use his full zone names thing etc...), but it works!

Just type /chainshift <zone1> <zone2> <zone3> all the way up to <zone 99> and it will zone you in order to each zone.


Rich (BB code):
 // ChainShift Data
int ChainShiftZone[100] = {0};
int ChainShiftStatus = 0;
PLUGIN_API VOID OnZoned(PSPAWNINFO pChar, PCHAR szLine)
{
	CHAR szMsg[MAX_STRING] = {0};
	if(ChainShiftZone[0] > 0) {
		ChainShiftStatus++;
		if(ChainShiftStatus > ChainShiftZone[0]) {
			ChainShiftZone[0] = 0;
		}
		DestZone=ChainShiftZone[ChainShiftStatus];
		DestType=1;
		ZoneReason=0;
		Y=pChar->Y;
		X=pChar->X;
		Z=pChar->Z;
		Heading =(int)pChar->Heading;
		ZoneChange=true;
		return;
	}
}

VOID ChainShift(PSPAWNINFO pChar, PCHAR szLine);

VOID ChainShift(PSPAWNINFO pChar, PCHAR szLine)
{
	char szMsg[MAX_STRING] = {0};
	bool ZoneDetected = true;
	char ZoneCheckName[MAX_STRING] = {0};
	int ZoneFound = 0;
	ChainShiftStatus = 0;

	GetArg(ZoneCheckName,szLine,1);
	ZoneFound = GetZoneID(ZoneCheckName);

	while(ZoneDetected == true) {
		if(ZoneFound > 0) {
			ChainShiftZone[0]++;
			ChainShiftZone[ChainShiftZone[0]] = ZoneFound;
			GetArg(ZoneCheckName,szLine,(ChainShiftZone[0] + 1));
			ZoneFound = GetZoneID(ZoneCheckName);
		} else {
			ZoneDetected = false;
		}
	}

	if(ChainShiftZone[0] > 0) {
		ChainShiftStatus++;
		DestZone=ChainShiftZone[1];
		DestType=1;
		ZoneReason=0;
		Y=pChar->Y;
		X=pChar->X;
		Z=pChar->Z;
		Heading =(int)pChar->Heading;
		ZoneChange=true;
		return;
	}
}


Add THIS to IntializePlugin
Rich (BB code):
 	
AddCommand("/chainshift",ChainShift);​

Add THIS to ShutDownPlugin
Rich (BB code):
  	
RemoveCommand("/chainshift");​
 
Plugin Creation
Status
Not open for further replies.

Users who are viewing this thread

Back
Top
Cart