This is for the Titanium (Project1999 Build) Source. Enjoy!
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
- Updated 2005.09.19 by Outlander
- Updated 2005.09.21 by Outlander
- Updated 2005.09.26 by Outlander
- Updated 2005.09.28 by Outlander
* Corrections 2005.09.28
Corrected problem with IsBardClass function, thanks BardOMatic and DKAA
* Addition 2005.09.28
Added HoTT check to stick, if sticking to a MOB or PC and you are their target
then if you are doing stick !front, behind, or pin you just do a a normal stick until
you are not the HoTT target then you go back to what ever option you had before.
* Addition 2005.09.26
Added new option:
/stick !front
This option will keep you not in front of the mob, so off to the side or behind.
This option should reduce the amount your toon moves around during a fight with a mob when you are not the
target as your will only adjust your position if you you are in the front 180 degrees of the mob, as long as you are
in the behind 180 degrees you will not move around just because the mob shifts.
* Corrections 2005.09.21
Changed movestuck logic for underwater to not kick in till you are not moving at all; pulse average = 0.
* Corrections 2005.09.19
Changed IsBardClass function to use GetCharInfo2() instead of the old GetCharInfo() function.
* 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 20050921";
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 moveNotFront=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 !front - Keeps you out from in front of the mob");
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;
moveNotFront=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,"!front",6) ) {
stickOn=true;
moveNotFront=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) || 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 == 0 && 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;
bool mounted;
mounted = pChSpawn->pActorInfo && pChSpawn->pActorInfo->Mount ? true : false;
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 == 0 && pChSpawn->pActorInfo->UnderWater) || (pulseAvg < (stuckDist + SpeedModifier)/3 && mounted )) &&
((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) && pChSpawn!=pChSpawn->pActorInfo->pTargetOfTarget ) {
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 && pChSpawn!=pChSpawn->pActorInfo->pTargetOfTarget ) {
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);
}
} else if (moveNotFront && pChSpawn!=pChSpawn->pActorInfo->pTargetOfTarget ) {
FLOAT angDist = angularDistance(psTarget->Heading,pChSpawn->Heading);
if( fabs(angDist) > 135.0 ) {
if(angDist < 0.0) {
// strafe left
DoLft(true);
} else {
// strage right
DoRgt(true);
}
} else {
// moveBehindOnce = false;
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(GetCharInfo()->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 & 0xff),"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 == 0 && 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);
}

