• 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

moveutils

Try this...

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

Currently contains three commands:
/stick -- /follow-like command, works for any pc/npc, default distance is melee range
/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");


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

bool bCircling=FALSE;
bool bDrunken=false;
double CircleX=0.0f;
double CircleY=0.0f;
double 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;

VOID MoveToCommand(PSPAWNINFO pChar, PCHAR szLine);
void HandleMoveTo();
bool bMoveToOn=false;
double LocX=0.0f;
double 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("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)
{
   CHAR szTemp[MAX_STRING]={0};
   CHAR szMsg[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 = atof(szTemp);
      }

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

      GetArg(szTemp,szLine,4);
      if (!strlen(szTemp)) {
         CircleX = pChSpawn->X - CircleRadius * cos(pChSpawn->Heading * PI / 256.0);
      } else {
         CircleX = 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("Usage: /stick [on|hold|off|pause|unpause|reload] [<dist>] [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");
}

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

   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;
   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,"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,stickHold?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 ) {
         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;
   double distance;
   double heading;
   PSPAWNINFO pChSpawn = (PSPAWNINFO) pCharSpawn;

   if (!GetCharInfo() || !bCircling) return;
   double X = pChSpawn->X - CircleX;
   double Y = pChSpawn->Y - CircleY;
   distance = sqrt(X*X + Y*Y);

   if (distance>(CircleRadius*(2.0/3.0))) {
      heading=atan2(pChSpawn->Y - CircleY, CircleX - pChSpawn->X) * 180.0f / 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;
      }
   }
}

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 || !psTarget || !pLPlayer || !GetCharInfo()) {
      WriteChatColor("Null pointer, breaking stick");
      breakStick();
      return;
   }
   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->CastingSpellID)) >= 0 && !(IsBardClass()) ) || pChSpawn->StandState != STANDSTATE_STAND || GetCharInfo()->Stunned==1 || psTarget->SpawnID == pChSpawn->SpawnID ) {
      if( !casting ) {
         casting = true;
         ReleaseKeys();
      }
   } else if( casting ) {
      casting = false;
   }
   if( (!stickPaused && !casting) || !autoPauseEnabled ) {
      float newHeading = (float) (atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * 256.0 / 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 = atan2(psTarget->Z + psTarget->AvatarHeight*StateHeightMultiplier(psTarget->StandState) -
         pChSpawn->Z - pChSpawn->AvatarHeight*StateHeightMultiplier(pChSpawn->StandState),
         currentDist) * 256.0f / 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) { //blahblah
            DoLft(true);
         } else if ((angDist < 0 && angDist > -112) || angDist > 144) {
            DoRgt(true);
         } else {
            DoLft(false);
            DoRgt(false);
         }
      }
      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(GetCharInfo()->Name,"Verbosity",stickVerbosity,INIFileName);
}

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

PLUGIN_API VOID OnPulse(VOID)
{

   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) {
//   if (!(pLocalPlayer)) {
//      WriteChatColor("pLocalPlayer is null");
//      return;
//   }
//   if (!(((PSPAWNINFO) pLocalPlayer)->pActorInfo)) {
//      WriteChatColor("pLocalPlayer->pActorInfo is null");
//      return;
//   }
   bool state_walking = (*EQADDR_RUNWALKSTATE) ? false : true;
//   float SpeedMultiplier = *((float*) &(((PSPAWNINFO) pLocalPlayer)->Unknown0x0af[25]));
  float SpeedMultiplier = ((PSPAWNINFO) pLocalPlayer)->SpeedMultiplier;
   if (SpeedMultiplier < 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;
   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("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)
{
   CHAR szTemp[MAX_STRING]={0};
   CHAR szMsg[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 = atof(szTemp);
      }

      GetArg(szTemp,szLine,3);
      if (!strlen(szTemp)) {
         MoveToHelp();
         return;
      } else {
         LocX = 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;
   if ( ( ((long) (pChSpawn->CastingSpellID)) >= 0 && !(IsBardClass()) )) {
      if( !casting ) {
         casting = true;
         DoFwd(false);
      }
   } else if( casting ){
      casting = false;
   }

   float newHeading = (float) (atan2(LocX - pChSpawn->X, LocY - pChSpawn->Y) * 256.0 / 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);
}
 
Last edited:
Does anyone have a moveutils.dll already developed for EQemu that they might be willing to share with me via PM or however you please? I noticed its not in the compiles given by Unknown, but I do thank you for the ones you have put out there for us.
 
moveutils

Users who are viewing this thread

Back
Top
Cart