Advertisement
gSe7eN

MoveUtils.cpp

Dec 9th, 2013
134
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 327.53 KB | None | 0 0
  1. /***** NOTICE ******
  2. Many functions included in this source code are not copyrighted to the developer and are used with permissions
  3. restricting their release to VIP board members of MacroQuest2.com. These functions have comments above them stating
  4. to whom the copyright belongs to. If you intend to redistribute this source or binaries compiled from this source
  5. outside of a direct link to the forum post in which it is released, you must get permission from these authors. Otherwise
  6. link to the forum post directly to encourage any users of this plugin to donate to the developers at MacroQuest2.com
  7. as required by the copyright holders of these functions, and desired by the developer. Please show your support!
  8. ****************/
  9.  
  10. #include "../MQ2Plugin.h"
  11. #include "math.h"
  12. #include <vector>
  13.  
  14. // uncomment these lines to enable debugspew spam
  15. //#define DEBUGMAIN
  16. // debugspew for stucklogic
  17. //#define DEBUGSTUCK
  18. // debugspew for trivial messages
  19. //#define DEBUGMISC
  20.  
  21. // uncomment this line if you use VC6
  22. //#define OLD_COMPILER_USER 1
  23. #if defined(_MSC_VER) && _MSC_VER <=1200
  24. #define OLD_COMPILER_USER 1
  25. #endif
  26.  
  27. #ifdef OLD_COMPILER_USER
  28.  #define A_TIME_TYPE  time_t
  29. #else
  30.  #define A_TIME_TYPE  __time64_t
  31. #endif
  32.  
  33. // version information
  34. const char*  MODULE_NAME    = "MQ2MoveUtils";
  35. const double MODULE_VERSION = 11.0411;
  36. PreSetup(MODULE_NAME);
  37. PLUGIN_VERSION(MODULE_VERSION); // will truncate, hence we use our own TLO
  38.  
  39. // ------------------------------------------------------------------------------
  40. // constants - the unsigned chars are aesthetics but we use different values
  41. // so that nothing can be called incorrectly and erroneously match a switch case
  42. // ------------------------------------------------------------------------------
  43. // check calling command
  44. const unsigned char CMD_STICK       = 1;
  45. const unsigned char CMD_MOVETO      = 2;
  46. const unsigned char CMD_CIRCLE      = 3;
  47. const unsigned char CMD_MAKECAMP    = 4;
  48. // walk handling
  49. const unsigned char MU_WALKON       = 10;
  50. const unsigned char MU_WALKOFF      = 11;
  51. const unsigned char MU_WALKIGNORE   = 12;
  52. // reset altcamp or make new altcamp
  53. const unsigned char SET_ALT         = 20;
  54. const unsigned char RESET_ALT       = 21;
  55. // direction to move
  56. const unsigned char GO_FORWARD      = 30;
  57. const unsigned char GO_BACKWARD     = 31;
  58. const unsigned char GO_LEFT         = 32;
  59. const unsigned char GO_RIGHT        = 33;
  60. const unsigned char KILL_STRAFE     = 34;
  61. const unsigned char KILL_FB         = 35;
  62. const unsigned char APPLY_TO_ALL    = 36;
  63. // help output
  64. const unsigned char HELP_SETTINGS   = 50;
  65. // error messages
  66. const unsigned char ERR_STICKSELF   = 60;
  67. const unsigned char ERR_STICKNONE   = 61;
  68. const unsigned char ERR_BADMOVETO   = 62;
  69. const unsigned char ERR_BADMAKECAMP = 63;
  70. const unsigned char ERR_BADCIRCLE   = 64;
  71. const unsigned char ERR_BADSPAWN    = 65;
  72. const unsigned char ERR_BADDELAY    = 66;
  73. // debug output
  74. const unsigned char DBG_MAIN        = 200;
  75. const unsigned char DBG_STUCK       = 201;
  76. const unsigned char DBG_MISC        = 202;
  77. const unsigned char DBG_DISABLE     = 203;
  78.  
  79. // ------------------------------------------
  80. // formulas & randomization
  81. const float CIRCLE_QUARTER          = 90.0f;
  82. const float CIRCLE_HALF             = 180.0f;
  83. const float CIRCLE_MAX              = 360.0f;
  84. const float HEADING_QUARTER         = 128.0f;
  85. const float HEADING_HALF            = 256.0f;
  86. const float HEADING_MAX             = 512.0f;
  87. const int   BEHIND_ARC              = 45;
  88. const int   FRONT_ARC               = 240;
  89. const int   NOT_FRONT_ARC           = 135;
  90. const int   PIN_ARC_MIN             = 112;
  91. const int   PIN_ARC_MAX             = 144;
  92. // initialization
  93. const float H_INACTIVE              = 10000.0f;
  94. const char  H_FAST                  = 0;
  95. const char  H_LOOSE                 = 1;
  96. const char  H_TRUE                  = 2;
  97. const char  T_INACTIVE              = 0;
  98. const char  T_WAITING               = 1;
  99. const char  T_READY                 = 2;
  100. // stucklogic ring size
  101. const int   MAXRINGSIZE             = 32; // MovingAvg max pulses to average
  102.  
  103. // ------------------------------------------
  104. // class instances
  105. class CMUSettings*     SET      = NULL;
  106. class CMUActive*       pMU      = NULL;
  107. class CMUCharacter*    ME       = NULL;
  108. class CMUWndHandler*   WINDOW   = NULL;
  109. class CMUMovement*     MOVE     = NULL;
  110. class CStickCmd*       STICK    = NULL;
  111. class CMoveToCmd*      MOVETO   = NULL;
  112. class CCircleCmd*      CIRCLE   = NULL;
  113. class CStuckLogic*     STUCK    = NULL;
  114. class CCampHandler*    CAMP     = NULL;
  115. class CAltCamp*        ALTCAMP  = NULL;
  116. class CCampCmd*        CURCAMP  = NULL;
  117. class CPauseHandler*   PAUSE    = NULL;
  118. class CMULoc*          SUMMON   = NULL;
  119. class CCircleSettings* SET_C    = NULL;
  120. class CMoveToSettings* SET_M    = NULL;
  121. class CCampSettings*   SET_CAMP = NULL;
  122. class CStickSettings*  SET_S    = NULL;
  123.  
  124. // ---------------------------------
  125. // verbosity bit flags
  126. enum VERBLEVEL {
  127.     V_SILENCE       = 0,
  128.     V_AUTOPAUSE     = 1,
  129.     V_MOVEPAUSE     = 2,
  130.     V_MOUSEPAUSE    = 4,
  131.     V_FEIGN         = 8,
  132.     V_HIDEHELP      = 16,
  133.     V_STICKV        = 32,
  134.     V_STICKFV       = 64,
  135.     V_MOVETOV       = 128,
  136.     V_MOVETOFV      = 256,
  137.     V_MAKECAMPV     = 512,
  138.     V_MAKECAMPFV    = 1024,
  139.     V_CIRCLEV       = 2048,
  140.     V_CIRCLEFV      = 4096,
  141.     V_SETTINGS      = 8192,
  142.     V_SAVED         = 16384,
  143.     V_BREAKONWARP   = 32768,
  144.     V_BREAKONAGGRO  = 65536,
  145.     V_BREAKONHIT    = 131072,
  146.     V_BREAKONSUMMON = 262144,
  147.     V_BREAKONGM     = 524288,
  148.     V_BREAKONGATE   = 1048576,
  149.     V_STICKALWAYS   = 2097152,
  150.     V_ERRORS        = 4194304,
  151.     V_RANDOMIZE     = 8388608,
  152.     V_PAUSED        = 16777216,
  153.     V_VERBOSITY     = 2720, // normal verbosity msgs
  154.     V_FULLVERBOSITY = 11736390, // full verbosity msgs
  155.     V_EVERYTHING    = 33554431, // all messages on (dont add verb + fullverb in)
  156. };
  157. unsigned int uiVerbLevel   = V_EVERYTHING;
  158. unsigned int uiRetainFlags = V_EVERYTHING; // stores flags for when totalsilence toggle
  159.  
  160. // -----------------------
  161. // import / export
  162.  
  163. PLUGIN_API bool bStickOn = false; // stick active or off, exported for other plugins to have a sure way of always knowing
  164. PLUGIN_API void StickCommand(PSPAWNINFO pLPlayer, char* szLine); // exported wrapper for MQ2Melee support
  165. // note to any developers: if you intend to use these exports and want to shut off stick, do not flip STICK->On directly,
  166. // instead, call StickCommand(pLPlayer, "off")
  167. bool* pbMULoaded = NULL; // imported from mq2melee in InitializePlugin()
  168. bool bWrapped = false; // hi htw!
  169.  
  170. // -----------------------
  171. // strings
  172.  
  173. char szMsg[MAX_STRING]         = {0};                // use for generic msg output
  174. char szDebugName[MAX_STRING]   = {0};                // debug file name
  175. char szCharName[MAX_STRING]    = {0};                // stores char name for INI read/write
  176. const char szOn[10]            = "\agON\ax";         // used in outputs
  177. const char szOff[10]           = "\arOFF\ax";        // used in outputs
  178. const char szArriveMove[50]    = "/moveto location"; // output moveto arrival
  179. const char szArriveCamp[50]    = "camp from /makecamp return"; // output camp return arrival
  180. const char szArriveAlt[50]     = "camp from /makecamp altreturn"; // output altcamp return arrival
  181.  
  182. // ----------------------------------------
  183. // events
  184.  
  185. unsigned int Event_AggroNorm   = NULL;
  186. unsigned int Event_MissNorm    = NULL;
  187. unsigned int Event_AggroAbbrev = NULL;
  188. unsigned int Event_MissAbbrev  = NULL;
  189. unsigned int Event_MissNumOnly = NULL;
  190. unsigned int Event_Gates       = NULL;
  191.  
  192. // ----------------------------------------
  193. // key IDs & pointers
  194.  
  195. int iAutoRun     = NULL;
  196. unsigned long* pulAutoRun     = NULL;
  197. int iForward     = NULL;
  198. unsigned long* pulForward     = NULL;
  199. int iBackward    = NULL;
  200. unsigned long* pulBackward    = NULL;
  201. int iTurnLeft    = NULL;
  202. unsigned long* pulTurnLeft    = NULL;
  203. int iTurnRight   = NULL;
  204. unsigned long* pulTurnRight   = NULL;
  205. int iStrafeLeft  = NULL;
  206. unsigned long* pulStrafeLeft  = NULL;
  207. int iStrafeRight = NULL;
  208. unsigned long* pulStrafeRight = NULL;
  209.  
  210. int iJumpKey     = NULL;
  211. int iRunWalk     = NULL;
  212. int iDuckKey     = NULL;
  213.  
  214. char* szFailedLoad[] = {
  215.     "No Error",            // 0
  216.     "TurnRight Address",   // 1
  217.     "TurnRight",           // 2
  218.     "StafeLeft",           // 3
  219.     "StrafeRight",         // 4
  220.     "AutoRun",             // 5
  221.     "TurnLeft",            // 6
  222.     "MoveForward Address", // 7
  223.     "Forward",             // 8
  224.     "AutoRun Mismatch",    // 9
  225.     "Backward"             // 10
  226. };
  227. unsigned long addrTurnRight     = NULL;
  228. PBYTE patternTurnRight          = (PBYTE)"\xA3\x00\x00\x00\x00\x89\x1D\x00\x00\x00\x00\x89\x1D\x00\x00\x00"
  229.    "\x00\x3B\x00\x0F\x84\x00\x00\x00\x00\xF6\x05\x00\x00\x00\x00\x00\x74\x00"
  230.    "\x89\x1D\x00\x00\x00\x00\x89\x1D";
  231. char maskTurnRight[]            = "x????xx????xx????x?xx????xx?????x?xx????xx";
  232. // A3 ? ? ? ? 89 1D ? ? ? ? 89 1D ? ? ? ? 3B ? 0F 84 ? ? ? ? F6 05 ? ? ? ? ? 74 ? 89 1D ? ? ? ? 89 1D
  233. unsigned long addrMoveForward   = NULL;
  234. PBYTE patternMoveForward        = (PBYTE)"\xA3\x00\x00\x00\x00\x3B\x00\x0F\x84\x00\x00\x00\x00\xF6\x05\x00\x00\x00"
  235.    "\x00\x00\x74\x00\x89\x1D";
  236. char maskMoveForward[]          = "x????x?xx????xx?????x?xx";
  237. // A3 ? ? ? ? 3B ? 0F 84 ? ? ? ? F6 05 ? ? ? ? ? 74 ? 89 1D
  238. bool bOffsetOverride            = false;
  239.  
  240. // ----------------------------------------
  241. // function prototypes
  242.  
  243. void SpewMUError(unsigned char ucErrorNum);
  244. void SpewDebug(unsigned char ucDbgType, char* szOuput, ...);
  245. void OutputHelp(unsigned char ucCmdUsed, bool bOnlyCmdHelp = false);
  246. void WriteLine(char szOutput[MAX_STRING], VERBLEVEL V_COMPARE);
  247. void HandleOurCmd(unsigned char ucCmdUsed, char* szInput);
  248. void EndPreviousCmd(bool bKillMovement, unsigned char ucCmdUsed = APPLY_TO_ALL, bool bPreserveSelf = false);
  249. void ChangeSetting(unsigned char ucCmdUsed, bool bToggle, char szSetting[MAX_STRING]);
  250. void SaveConfig();
  251. void LoadConfig();
  252. void DebugToWnd(unsigned char ucCmdUsed);
  253. void DebugToINI(unsigned char ucCmdUsed);
  254. void DebugToDebugger(char* szFormat, ...);
  255. void SetupEvents(bool bAddEvent, bool bForceRemove = false);
  256. inline bool ValidIngame(bool bCheckDead = true);
  257.  
  258. // ----------------------------------------
  259. // ************* CLASSES *****************
  260. // ----------------------------------------
  261.  
  262. // ----------------------
  263. // inherit-only classes
  264.  
  265. class CMULoc
  266. {
  267. // locations & dist comparisons
  268. public:
  269.     float Y;
  270.     float X;
  271.     float Z;
  272.     float CurDist;
  273.     float DifDist;
  274.  
  275.     CMULoc()
  276.     {
  277.         Y       = 0.0f;
  278.         X       = 0.0f;
  279.         Z       = 0.0f;
  280.         CurDist = 0.0f;
  281.         DifDist = 0.0f;
  282.     };
  283. };
  284.  
  285. class CMUDelay
  286. {
  287. // delay & time calculations
  288. public:
  289.     int Min;
  290.     int Max;
  291.  
  292.     void TimeStop()
  293.     {
  294.         Resume = T_INACTIVE;
  295.     };
  296.  
  297.     void TimeStart()
  298.     {
  299.         GetSystemTime(&Began);
  300.         Resume = rand() % (Max - Min + 1) + Min;
  301.     };
  302.  
  303.     char TimeStatus()
  304.     {
  305.         if (Resume == T_INACTIVE)
  306.         {
  307.             return T_INACTIVE;
  308.         }
  309.         if (ElapsedMS() >= Resume)
  310.         {
  311.             return T_READY;
  312.         }
  313.         return T_WAITING;
  314.     };
  315.  
  316.     void Validate()
  317.     {
  318.         MinDelay(Min);
  319.         MaxDelay(Max);
  320.     };
  321.  
  322.     void MinDelay(int iNew)
  323.     {
  324.         Min = iNew;
  325.         if (Min < 125) Min = 125;
  326.     };
  327.  
  328.     void MaxDelay(int iNew)
  329.     {
  330.         Max = iNew;
  331.         if (Max < Min + 125) Max = Min + 125;
  332.     };
  333.  
  334.     CMUDelay()
  335.     {
  336.         Min    = 0;
  337.         Max    = 0;
  338.         Resume = T_INACTIVE;
  339.     };
  340.  
  341. protected:
  342.     int        Resume; // calculated resume time
  343.     SYSTEMTIME Began;  // timer start
  344.  
  345.     int ElapsedMS()
  346.     {
  347.         SYSTEMTIME     stCurr, stResult;
  348.         FILETIME       ftPrev, ftCurr, ftResult;
  349.         ULARGE_INTEGER prev,   curr,   result;
  350.  
  351.         GetSystemTime(&stCurr);
  352.         SystemTimeToFileTime(&Began, &ftPrev);
  353.         SystemTimeToFileTime(&stCurr, &ftCurr);
  354.         prev.HighPart           = ftPrev.dwHighDateTime;
  355.         prev.LowPart            = ftPrev.dwLowDateTime;
  356.         curr.HighPart           = ftCurr.dwHighDateTime;
  357.         curr.LowPart            = ftCurr.dwLowDateTime;
  358.         result.QuadPart         = curr.QuadPart - prev.QuadPart;
  359.         ftResult.dwHighDateTime = result.HighPart;
  360.         ftResult.dwLowDateTime  = result.LowPart;
  361.         FileTimeToSystemTime(&ftResult, &stResult);
  362.         return ((int)(stResult.wSecond * 1000 + stResult.wMilliseconds));
  363.     };
  364. };
  365.  
  366. // ----------------------------------------
  367. // character functions
  368. class CMUCharacter
  369. {
  370. public:
  371.     bool IsBard()
  372.     {
  373.         if (GetCharInfo()->pSpawn->Class == Bard)
  374.         {
  375.             return true;
  376.         }
  377.         return false;
  378.     };
  379.  
  380.     bool InCombat()
  381.     {
  382.         if (ValidIngame() && ((PCPLAYERWND)pPlayerWnd)->CombatState == 0 && ((CXWnd*)pPlayerWnd)->GetChildItem("PW_CombatStateAnim"))
  383.         {
  384.             return true;
  385.         }
  386.         return false;
  387.     };
  388.  
  389.     bool IsMe(PSPAWNINFO pCheck)
  390.     {
  391.         if (!pCheck || !pLocalPlayer) return false;
  392.         if (pCheck->SpawnID == ((PSPAWNINFO)pCharSpawn)->SpawnID || pCheck->SpawnID == ((PSPAWNINFO)pLocalPlayer)->SpawnID)
  393.         {
  394.             return true;
  395.         }
  396.         return false;
  397.     };
  398. };
  399.  
  400. // ----------------------------------------------------------
  401. // configuration classes - store default & INI-saved settings
  402.  
  403. class CStuckLogic : public CMULoc
  404. {
  405. public:
  406.     bool         On;       // INI: stucklogic active or off
  407.     bool         Jump;     // INI: if true, try to jump when stuck
  408.     bool         TurnHalf; // INI: if true, reset heading and try other dir if gone halfway without freeing
  409.     unsigned int Check;    // INI: # of pulses to average distance for stuck awareness
  410.     unsigned int Unstuck;  // INI: if StuckDec == this, consider unstuck
  411.     float        Dist;     // INI: dist needed to move else considered stuck, compared against pulse average
  412.     float        TurnSize; // Turn increment value for left/right (sign flipped by TurnHalf)
  413.     unsigned int StuckInc; // increments each pulse we haven't moved beyond Dist until we reach Check value which == we are stuck
  414.     unsigned int StuckDec; // increments each pulse we've moved again after being stuck, when Unstuck = StuckDec, we force unstuck
  415.  
  416.     void Reset()
  417.     {
  418.         Y = X = Z = 0.0f;
  419.         DifDist   = 0.0f;
  420.         CurDist   = 1.0f;
  421.         StuckInc  = 0;
  422.         StuckDec  = 0;
  423.     };
  424.  
  425.     CStuckLogic()
  426.     {
  427.         // plugin defaults established here
  428.         On       = true;
  429.         Jump     = false;
  430.         TurnHalf = true;
  431.         TurnSize = 10.0f;
  432.         Dist     = 0.1f;
  433.         Check    = 6;
  434.         Unstuck  = 10;
  435.         StuckInc = 0;
  436.         StuckDec = 0;
  437.         CurDist  = 1.0f; // baseline to not trigger when first starting movement
  438.         // Y X Z DifDist already initialized by CMULoc() inherit
  439.     };
  440. };
  441.  
  442. class CStickSettings : public CMUDelay
  443. {
  444. public:
  445.     bool  BreakGate;    // INI: stick breaks if "mob_name Gates." message
  446.     bool  BreakHit;     // INI: stick breaks if npc is attacking
  447.     bool  BreakTarget;  // INI: stick breaks if target switched
  448.     bool  BreakWarp;    // INI: stick breaks if target warps out of DistBreak
  449.     bool  Flex;         // INI: stick flexibility when close
  450.     bool  PauseWarp;    // INI: stick pauses if target warps out of DistBreak
  451.     bool  Randomize;    // INI: randomize strafe arcs during stick
  452.     bool  DelayStrafe;  // INI: strafe sticks use a delay timer with TimedStrafe()
  453.     bool  UseBack;      // INI: use backwards walking when close to target
  454.     bool  UseFleeing;   // INI: 'front' will not strafe if target is fleeing
  455.     bool  Walk;         // INI: stick walks when strafing
  456.     bool  UW;           // look angle up or down at target (/stick uw)
  457.     float ArcBehind;    // INI: arc size for stick behind
  458.     float ArcNotFront;  // INI: arc size for stick !front
  459.     float DistBack;     // INI: within this dist UseBack handles positioning if enabled
  460.     float DistBreak;    // INI: target warps this distance, BreakWarp triggers if enabled
  461.     float DistFlex;     // INI: distance for flexibility
  462.     float DistMod;      // INI: raw modifier to Dist (CStickCmd) (best used if plugin is auto-setting dist)
  463.     float DistModP;     // INI: % modifier to Dist (CStickCmd) (best used if plugin is auto-setting dist)
  464.     float DistSnap;     // INI: default distance from target to snaproll
  465.  
  466.     CStickSettings()
  467.     {
  468.         // plugin defaults, established here
  469.         Min         = 1500; // inherit: CMUDelay (for strafe)
  470.         Max         = 3000; // inherit: CMUDelay (for strafe)
  471.         BreakGate   = true;
  472.         BreakHit    = false;
  473.         BreakTarget = false;
  474.         BreakWarp   = true;
  475.         PauseWarp   = false;
  476.         Flex        = false;
  477.         Randomize   = false;
  478.         DelayStrafe = true;
  479.         UseBack     = true;
  480.         UseFleeing  = true;
  481.         Walk        = false;
  482.         UW          = false;
  483.         ArcBehind   = BEHIND_ARC;
  484.         ArcNotFront = NOT_FRONT_ARC;
  485.         DistBack    = 10.0f;
  486.         DistBreak   = 250.0f;
  487.         DistFlex    = 7.0f;
  488.         DistMod     = 0.0f;
  489.         DistModP    = 1.0f;
  490.         DistSnap    = 10.0f;
  491.     };
  492. };
  493.  
  494. class CCampSettings : public CMUDelay
  495. {
  496. public:
  497.     bool  HaveTarget; // INI: if true, auto camp return even with a target
  498.     bool  NoAggro;    // INI: if true, auto camp return only if not aggro
  499.     bool  NotLoot;    // INI: if true, auto camp return only if not looting
  500.     bool  Scatter;    // INI: camp return scattering active or off
  501.     bool  Realtime;   // INI: makecamp player updates pc anchor Y/X while returning
  502.     bool  Leash;      // INI: camp leashing active or off
  503.     float Bearing;    // INI: bearing for camp return scattering
  504.     float Length;     // INI: length of leash checked against anchor
  505.     float Radius;     // INI: default camp radius size
  506.     float ScatSize;   // INI: camp return scatter radius size
  507.     float ScatDist;   // INI: dist from anchor for camp return scattering
  508.  
  509.     CCampSettings()
  510.     {
  511.         Min        = 500;  // inherit: CMUDelay
  512.         Max        = 1500; // inherit: CMUDelay
  513.         HaveTarget = false;
  514.         NoAggro    = false;
  515.         NotLoot    = false;
  516.         Scatter    = false;
  517.         Realtime   = false;
  518.         Leash      = false;
  519.         Bearing    = 0.0f;
  520.         Length     = 50.0f;
  521.         Radius     = 40.0f;
  522.         ScatSize   = 10.0f;
  523.         ScatDist   = 10.0f;
  524.     };
  525.  
  526.     void SetRadius(float fNew)
  527.     {
  528.         Radius = fNew;
  529.         ValidateSizes();
  530.     };
  531.  
  532.     void SetLeash(float fNew)
  533.     {
  534.         Length = fNew;
  535.         ValidateSizes();
  536.     };
  537.  
  538. protected:
  539.     void ValidateSizes()
  540.     {
  541.         if (Radius < 5.0f)  Radius = 5.0f;  // enforce min Radius size 5.0f
  542.         float fTemp = Radius + 5.0f;
  543.         if (Length < fTemp) Length = fTemp; // enforce min leash size 5.0f >= Radius
  544.     };
  545. };
  546.  
  547. class CMoveToSettings
  548. {
  549. public:
  550.     bool  BreakAggro; // INI: break moveto if aggro gained
  551.     bool  BreakHit;   // INI: break moveto if attacked (blech event)
  552.     bool  UseBack;    // INI: use backwards walking when initially close to destination
  553.     bool  UW;         // INI: moveto uses UW face angle adjustments
  554.     bool  Walk;       // INI: moveto walks if close to arrivaldist
  555.     float Dist;       // INI: how close to moveto location is considered acceptable
  556.     float DistBack;   // INI: within this dist UseBack handles positioning if enabled
  557.     float DistY;      // INI: how close to moveto Y location is acceptable for precisey
  558.     float DistX;      // INI: how close to moveto X location is acceptable for precisex
  559.     float Mod;        // INI: Dist percent modifier
  560.  
  561.     CMoveToSettings()
  562.     {
  563.         BreakAggro = false;
  564.         BreakHit   = false;
  565.         UseBack    = false;
  566.         UW         = false;
  567.         Walk       = true;
  568.         Dist       = 10.0f;
  569.         DistBack   = 30.0f;
  570.         DistY      = 10.0f;
  571.         DistX      = 10.0f;
  572.         Mod        = 0.0f;
  573.     };
  574. };
  575.  
  576. class CCircleSettings
  577. {
  578. public:
  579.     bool  Backward; // INI: always backwards
  580.     bool  CCW;      // INI: always counter-clockwise
  581.     bool  Drunk;    // INI: always drunken
  582.     float CMod;     // INI: default radius percent modifer
  583.     float Radius;   // INI: default radius size
  584.  
  585.     CCircleSettings()
  586.     {
  587.         Backward = false;
  588.         CCW      = false;
  589.         Drunk    = false;
  590.         CMod     = 0.0f;
  591.         Radius   = 30.0f;
  592.     };
  593.  
  594.     void SetRadius(float fNew)
  595.     {
  596.         // enforce min radius size 5.0f
  597.         Radius = fNew;
  598.         if (Radius < 5.0f) Radius = 5.0f;
  599.     };
  600. };
  601.  
  602. class CMUSettings
  603. {
  604. public:
  605.     bool  AutoSave;    // INI: autosave ini file when using 'toggle' or 'set'
  606.     bool  AutoPause;   // INI: pause automatically when casting/stunned/self targeted/sitting
  607.     bool  AutoUW;      // INI: automatically use 'uw' when underwater
  608.     bool  BreakGM;     // INI: command breaks if visible GM enters zone
  609.     bool  BreakSummon; // INI: command breaks if you move too far in a single pulse (summoned)
  610.     bool  BreakKB;     // INI: break command if movement key pressed
  611.     bool  PauseKB;     // INI: pause command if movement key pressed
  612.     bool  BreakMouse;  // INI: break command if mouselook active
  613.     bool  PauseMouse;  // INI: pause command if mouselook active
  614.     bool  Feign;       // INI: do not stand if currently FD
  615.     bool  LockPause;   // INI: pause will not reset until unpaused
  616.     bool  SaveByChar;  // INI: save some settings for individual characters
  617.     bool  Spin;        // INI: if true, stick front ignores requiring being on HoTT
  618.     bool  Window;      // INI: use dedicated UI window
  619.     bool  WinEQ;       // INI: use old-style movement
  620.     float AllowMove;   // INI: distance to allow forward movement while turning, CanLooseMove()
  621.     float DistSummon;  // INI: distance your character moves in a single pulse to trigger BreakSummon
  622.     float TurnRate;    // INI: rate at which to turn using loose heading (14 is default)
  623.     int   Head;        // INI: heading adjustment type (0 = fast [H_FAST], 1 = loose [H_LOOSE], 2 = true [H_TRUE])
  624.  
  625.     CMUSettings()
  626.     {
  627.         SET_CAMP = new CCampSettings();
  628.         SET_S    = new CStickSettings();
  629.         SET_M    = new CMoveToSettings();
  630.         SET_C    = new CCircleSettings();
  631.  
  632.         AutoSave    = true;
  633.         AutoPause   = true;
  634.         AutoUW      = false;
  635.         BreakGM     = true;
  636.         BreakSummon = false;
  637.         BreakKB     = true;
  638.         PauseKB     = false;
  639.         BreakMouse  = false;
  640.         PauseMouse  = false;
  641.         Feign       = false;
  642.         LockPause   = false;
  643.         SaveByChar  = true;
  644.         Spin        = false;
  645.         Window      = false;
  646.         WinEQ       = false;
  647.         AllowMove   = 32.0f;
  648.         DistSummon  = 8.0f;
  649.         TurnRate    = 14.0f;
  650.         Head        = H_TRUE;
  651.     };
  652.  
  653.     ~CMUSettings()
  654.     {
  655.         delete SET_CAMP;
  656.         SET_CAMP = NULL;
  657.         delete SET_S;
  658.         SET_S    = NULL;
  659.         delete SET_M;
  660.         SET_M    = NULL;
  661.         delete SET_C;
  662.         SET_C    = NULL;
  663.     };
  664. };
  665.  
  666. // ---------------------------------------------------
  667. // command classes - instanced for individual cmd use
  668.  
  669. class CCircleCmd : public CMULoc, public CMUDelay, public CCircleSettings
  670. {
  671. public:
  672.     bool On; // circling active or off
  673.  
  674.     bool Wait()
  675.     {
  676.         // drunken circling uses this formula
  677.         if (ElapsedMS() > Max + GetDrunk(Min))
  678.         {
  679.             TimeStart();
  680.             return false;
  681.         }
  682.         return true;
  683.     };
  684.  
  685.     void AtMe()
  686.     {
  687.         // HandleOurCmd calls this to establish '/circle on' without loc supplied
  688.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  689.         Y = pChSpawn->Y + Radius * sin(pChSpawn->Heading * (float)PI / HEADING_HALF);
  690.         X = pChSpawn->X + Radius * cos(pChSpawn->Heading * (float)PI / HEADING_HALF);
  691.         On = true;
  692.     };
  693.  
  694.     void AtLoc(float fY, float fX)
  695.     {
  696.         // HandleOurCmd calls this with desired Y X supplied
  697.         Y  = fY;
  698.         X  = fX;
  699.         On = true;
  700.     };
  701.  
  702.     CCircleCmd() // ooo: CMULoc(), CMUDelay(), CCircleSettings(), CCircleCmd()
  703.     {
  704.         Min = 600;      // inherit: CMUDelay
  705.         Max = 900;      // inherit: CMUDelay
  706.         On  = false;
  707.         UserDefaults(); // copy defaults from INI settings
  708.         TimeStart();
  709.     };
  710.  
  711. protected:
  712.     void UserDefaults()
  713.     {
  714.         Backward = SET_C->Backward;
  715.         CCW      = SET_C->CCW;
  716.         Drunk    = SET_C->Drunk;
  717.         CMod     = SET_C->CMod;
  718.         Radius   = SET_C->Radius;
  719.     };
  720.  
  721.     int GetDrunk(int iNum)
  722.     {
  723.         return (iNum * rand() / (RAND_MAX + 1));
  724.     };
  725. };
  726.  
  727. class CMoveToCmd : public CMULoc, public CMoveToSettings
  728. {
  729. public:
  730.     bool  On;       // moveto active or off (MOVETO->On)
  731.     bool  PreciseY; // moveto arrivaldist is only checked against Y
  732.     bool  PreciseX; // moveto arrivaldist is only checked against X
  733.  
  734.     bool DidAggro();
  735.  
  736.     CMoveToCmd()
  737.     {
  738.         On       = false;
  739.         PreciseY = false;
  740.         PreciseX = false;
  741.         UserDefaults();
  742.     };
  743.  
  744.     void Activate(float fY, float fX, float fZ)
  745.     {
  746.         Y  = fY;
  747.         X  = fX;
  748.         Z  = fZ;
  749.         On = true;
  750.     };
  751.  
  752. protected:
  753.     void UserDefaults()
  754.     {
  755.         BreakAggro = SET_M->BreakAggro;
  756.         BreakHit   = SET_M->BreakHit;
  757.         UseBack    = SET_M->UseBack;
  758.         UW         = SET_M->UW;
  759.         Walk       = SET_M->Walk;
  760.         Dist       = SET_M->Dist;
  761.         DistBack   = SET_M->DistBack;
  762.         DistY      = SET_M->DistY;
  763.         DistX      = SET_M->DistX;
  764.         Mod        = SET_M->Mod;
  765.     };
  766. };
  767.  
  768. class CCampCmd : public CMULoc, public CCampSettings
  769. {
  770. public:
  771.     bool          On;                  // camp active or off
  772.     bool          Pc;                  // makecamp player on or off
  773.     bool          RedoStick;           // set during camp return
  774.     bool          RedoCircle;          // set during camp return
  775.     unsigned long PcID;                // stores id of makecamp player
  776.     eSpawnType    PcType;              // stores spawn type of makecamp player
  777.     char          PcName[MAX_STRING];  // stores makecamp player displayedname
  778.  
  779.     CCampCmd()
  780.     {
  781.         On         = false;
  782.         Pc         = false;
  783.         RedoStick  = false;
  784.         RedoCircle = false;
  785.         PcID       = 0;
  786.         PcType     = NONE;
  787.         memset(&PcName, 0, MAX_STRING);
  788.         UserDefaults();
  789.     };
  790.  
  791. protected:
  792.     void UserDefaults()
  793.     {
  794.         Min        = SET_CAMP->Min;
  795.         Max        = SET_CAMP->Max;
  796.         HaveTarget = SET_CAMP->HaveTarget;
  797.         NoAggro    = SET_CAMP->NoAggro;
  798.         NotLoot    = SET_CAMP->NotLoot;
  799.         Scatter    = SET_CAMP->Scatter;
  800.         Realtime   = SET_CAMP->Realtime;
  801.         Leash      = SET_CAMP->Leash;
  802.         Bearing    = SET_CAMP->Bearing;
  803.         Length     = SET_CAMP->Length;
  804.         Radius     = SET_CAMP->Radius;
  805.         ScatSize   = SET_CAMP->ScatSize;
  806.         ScatDist   = SET_CAMP->ScatDist;
  807.     };
  808. };
  809.  
  810. class CAltCamp : public CMULoc
  811. {
  812. public:
  813.     bool  On;
  814.     float Radius;
  815.  
  816.     void Update(CCampCmd* Cur)
  817.     {
  818.         Y      = Cur->Y;
  819.         X      = Cur->X;
  820.         Radius = Cur->Radius;
  821.         On     = true;
  822.     };
  823.  
  824.     CAltCamp()
  825.     {
  826.         On     = false;
  827.         Radius = 0.0f;
  828.     };
  829. };
  830.  
  831. class CCampHandler : public CMUDelay, public CMULoc
  832. {
  833. public:
  834.     bool Auto;      // state awareness (is camp return auto or manual)
  835.     bool DoAlt;     // true when manually forcing a return to altcamp
  836.     bool DoReturn;  // true when manually forcing a return to curcamp
  837.     bool Returning; // true when any return is active (both auto and manual)
  838.  
  839.     void ResetBoth()
  840.     {
  841.         delete ALTCAMP;
  842.         ALTCAMP = new CAltCamp();
  843.         delete CURCAMP;
  844.         CURCAMP = new CCampCmd();
  845.     };
  846.  
  847.     void ResetCamp(bool bOutput)
  848.     {
  849.         ALTCAMP->Update(CURCAMP);
  850.         NewCamp(bOutput);
  851.     };
  852.  
  853.     void ResetPlayer(bool bOutput)
  854.     {
  855.         NewCamp(false);
  856.         if (bOutput) OutputPC();
  857.     };
  858.  
  859.     void NewCamp(bool bOutput)
  860.     {
  861.         if (ValidIngame() && MOVETO->On && Returning)
  862.         {
  863.             // kill active camp return
  864.             EndPreviousCmd(true);
  865.         }
  866.         delete CURCAMP;
  867.         CURCAMP   = new CCampCmd();
  868.         VarReset();
  869.         if (bOutput) Output();
  870.     };
  871.  
  872.     void Activate(float fY, float fX)
  873.     {
  874.         if (CURCAMP->On && !CURCAMP->Pc)
  875.         {
  876.             ResetCamp(false);
  877.         }
  878.         else
  879.         {
  880.             NewCamp(false);
  881.         }
  882.         CURCAMP->On = true;
  883.         CURCAMP->Y  = fY;
  884.         CURCAMP->X  = fX;
  885.         Validate(); // CMUDelay
  886.     };
  887.  
  888.     void ActivatePC(PSPAWNINFO pCPlayer)
  889.     {
  890.         Activate(pCPlayer->Y, pCPlayer->X);
  891.         sprintf(CURCAMP->PcName, "%s", pCPlayer->DisplayedName);
  892.         CURCAMP->Pc     = true;
  893.         CURCAMP->PcID   = pCPlayer->SpawnID;
  894.         CURCAMP->PcType = GetSpawnType(pCPlayer);
  895.     }
  896.  
  897.     void VarReset()
  898.     {
  899.         Auto      = false;
  900.         DoAlt     = false;
  901.         DoReturn  = false;
  902.         Returning = false;
  903.     };
  904.  
  905.     CCampHandler()
  906.     {
  907.         ALTCAMP   = new CAltCamp();
  908.         CURCAMP   = new CCampCmd();
  909.         Min       = SET_CAMP->Min;
  910.         Max       = SET_CAMP->Max;
  911.         VarReset();
  912.     };
  913.  
  914.     ~CCampHandler()
  915.     {
  916.         delete ALTCAMP;
  917.         ALTCAMP = NULL;
  918.         delete CURCAMP;
  919.         CURCAMP = NULL;
  920.     };
  921.  
  922. protected:
  923.     void Output()
  924.     {
  925.         sprintf(szMsg, "\ay%s\aw:: MakeCamp off.", MODULE_NAME);
  926.         WriteLine(szMsg, V_MAKECAMPV);
  927.     };
  928.  
  929.     void OutputPC()
  930.     {
  931.         sprintf(szMsg, "\ay%s\aw:: MakeCamp player off.", MODULE_NAME);
  932.         WriteLine(szMsg, V_MAKECAMPV);
  933.     };
  934. };
  935.  
  936. class CSnaproll : public CMULoc
  937. {
  938. public:
  939.     float Head;    // heading to snaproll
  940.     float Bearing; // bearing of target to snaproll to
  941.  
  942.     CSnaproll()
  943.     {
  944.         Head    = 0.0f;
  945.         Bearing = HEADING_HALF;
  946.     };
  947. };
  948.  
  949. class CStickCmd : public CMULoc, public CStickSettings
  950. {
  951. public:
  952.     CSnaproll* Snap;  // instance a snaproll
  953.     // active stick settings
  954.     bool  SetDist;    // has dist to mob has been set
  955.     float Dist;       // defaults to melee range or set to 10 by /stick 10 for example
  956.     float RandMin;    // min arc for strafe (if randomize enabled)
  957.     float RandMax;    // max arc for strafe (if randomize enabled)
  958.     bool  RandFlag;   // flag to randomly randomize min or max
  959.     // active stick type
  960.     bool  MoveBack;   // maintains distance (if too close, back up)
  961.     bool  Behind;     // uses rear arc of target
  962.     bool  BehindOnce; // moves to rear arc of target then position is ignored
  963.     bool  Front;      // uses front arc of target
  964.     bool  NotFront;   // uses anywhere but the front arc of target (/stick !front)
  965.     bool  Pin;        // uses left or right arc of the target
  966.     bool  Snaproll;   // snaprolls to a fixed loc (polarmath) instead of strafing
  967.     bool  Hold;       // maintains sticking to previous target if it changes
  968.     bool  Healer;     // healer type (non-constant facing)
  969.     bool  Always;     // restick when new target acquired (wont work with hold) (/stick __ always)
  970.     bool  HaveTarget; // true when Always true and have a target
  971.     bool  Strafe;     // true when using a cmd that will strafe other than 'front'
  972.     bool  On;         // stick active or off, set this only through TurnOn()
  973.     // spawn information
  974.     unsigned long LastID;    // compare target change OnPulse
  975.     unsigned long HoldID;    // spawn id for stick hold
  976.     eSpawnType    LastType;  // if target changes to a corpse, stop sticking
  977.     eSpawnType    HoldType;  // if stick hold changes to a corpse, stop sticking
  978.  
  979.     void TurnOn()
  980.     {
  981.         On       = true;
  982.         bStickOn = true; // mq2melee support until setup valid/updated pointer to the class member
  983.     };
  984.  
  985.     void StopHold()
  986.     {
  987.         HoldID   = NULL;
  988.         HoldType = NONE;
  989.         Hold     = false;
  990.     };
  991.  
  992.     void FirstAlways()
  993.     {
  994.         // reset hold values, dont allow 'hold' or 'id' with 'always'
  995.         StopHold();
  996.         Always = true;
  997.         TurnOn();
  998.         if (pTarget)
  999.         {
  1000.             HaveTarget = true;
  1001.             return;
  1002.         }
  1003.         HaveTarget = false;
  1004.     };
  1005.  
  1006.     void NewSnaproll()
  1007.     {
  1008.         delete Snap;
  1009.         Snap = new CSnaproll();
  1010.     };
  1011.  
  1012.     void ResetLoc()
  1013.     {
  1014.         Y = X = Z = 0.0f;
  1015.         CurDist = DifDist = 0.0f;
  1016.     };
  1017.  
  1018.     bool Ready()
  1019.     {
  1020.         if (Always)
  1021.         {
  1022.             return AlwaysStatus();
  1023.         }
  1024.         return On;
  1025.     };
  1026.  
  1027.     void DoRandomize()
  1028.     {
  1029.         if (!Randomize) return;
  1030.         if (NotFront)
  1031.         {
  1032.             SetRandArc(NOT_FRONT_ARC);
  1033.         }
  1034.         else if (Behind)
  1035.         {
  1036.             SetRandArc(BEHIND_ARC);
  1037.         }
  1038.         else if (Pin)
  1039.         {
  1040.             SetRandArc(PIN_ARC_MIN);
  1041.         }
  1042.     };
  1043.  
  1044.     CStickCmd()
  1045.     {
  1046.         Snap        = new CSnaproll();
  1047.         SetDist     = false;
  1048.         Dist        = 0.0f;
  1049.         RandMin     = 0.0f;
  1050.         RandMax     = 0.0f;
  1051.         RandFlag    = true;
  1052.         MoveBack    = false;
  1053.         Behind      = false;
  1054.         BehindOnce  = false;
  1055.         Front       = false;
  1056.         NotFront    = false;
  1057.         Pin         = false;
  1058.         Snaproll    = false;
  1059.         Hold        = false;
  1060.         Healer      = false;
  1061.         Always      = false;
  1062.         HaveTarget  = false;
  1063.         Strafe      = false;
  1064.         On          = false;
  1065.         LastID      = 0;
  1066.         HoldID      = 0;
  1067.         LastType    = NONE;
  1068.         HoldType    = NONE;
  1069.  
  1070.         AlwaysReady = true;
  1071.         UserDefaults();
  1072.     };
  1073.  
  1074.     ~CStickCmd()
  1075.     {
  1076.         delete Snap;
  1077.         Snap = NULL;
  1078.     };
  1079.  
  1080. protected:
  1081.     void UserDefaults()
  1082.     {
  1083.         Min         = SET_S->Min;
  1084.         Max         = SET_S->Max;
  1085.         BreakGate   = SET_S->BreakGate;
  1086.         BreakHit    = SET_S->BreakHit;
  1087.         BreakTarget = SET_S->BreakTarget;
  1088.         BreakWarp   = SET_S->BreakWarp;
  1089.         PauseWarp   = SET_S->PauseWarp;
  1090.         Randomize   = SET_S->Randomize;
  1091.         DelayStrafe = SET_S->DelayStrafe;
  1092.         UseBack     = SET_S->UseBack;
  1093.         UseFleeing  = SET_S->UseFleeing;
  1094.         UW          = SET_S->UW;
  1095.         Walk        = SET_S->Walk;
  1096.         ArcBehind   = SET_S->ArcBehind;
  1097.         ArcNotFront = SET_S->ArcNotFront;
  1098.         DistBack    = SET_S->DistBack;
  1099.         DistBreak   = SET_S->DistBreak;
  1100.         DistMod     = SET_S->DistMod;
  1101.         DistModP    = SET_S->DistModP;
  1102.         DistSnap    = SET_S->DistSnap;
  1103.     };
  1104.  
  1105.     void SetRandArc(int iArcType)
  1106.     {
  1107.         float  fTempArc    = 0.0f;
  1108.         float  fArcSize    = 0.0f;
  1109.         float* pfRandomArc = NULL;
  1110.         float* pfStableArc = NULL;
  1111.  
  1112.         RandFlag = !RandFlag;
  1113.         if (RandFlag)
  1114.         {
  1115.             pfRandomArc = &RandMin;
  1116.             pfStableArc = &RandMax;
  1117.         }
  1118.         else
  1119.         {
  1120.             pfRandomArc = &RandMax;
  1121.             pfStableArc = &RandMin;
  1122.         }
  1123.  
  1124.         switch (iArcType)
  1125.         {
  1126.         case PIN_ARC_MIN: // 112 to 144  ---  144 - 112 = 32 total size
  1127.             fTempArc = (float)(rand() % 32 + 5);
  1128.             fArcSize = (float)(rand() % 32 + 16);
  1129.             break;
  1130.         case BEHIND_ARC:
  1131.             fTempArc = (float)(rand() % 45 + 5);
  1132.             fArcSize = (float)(rand() % 90 + 40);
  1133.             break;
  1134.         case NOT_FRONT_ARC:
  1135.             fTempArc = (float)(rand() % 135 + 5);
  1136.             fArcSize = (float)(rand() % 270 + 80);
  1137.             break;
  1138.         }
  1139.  
  1140.         *pfRandomArc = fTempArc;
  1141.         *pfStableArc = fArcSize;
  1142.  
  1143.         sprintf(szMsg, "\ay%s\aw:: Arcs Randomized! Max: %.2f  Min: %.2f", MODULE_NAME, RandMax, RandMin);
  1144.         WriteLine(szMsg, V_RANDOMIZE);
  1145.     };
  1146.  
  1147.     bool AlwaysStatus();
  1148.     bool AlwaysReady;
  1149. };
  1150.  
  1151. // ------------------------------------------
  1152. class CPauseHandler : public CMUDelay
  1153. {
  1154. public:
  1155.     bool PausedCmd; // pauses via command (not overwritten until 'unpause' or off/new cmd)
  1156.     bool PausedMU;  // pauses all operations (used by many operations)
  1157.     bool UserKB;    // true while movement keybinds are pressed
  1158.     bool UserMouse; // true while mouselook held
  1159.  
  1160.     bool Waiting()
  1161.     {
  1162.         if (PausedCmd || PausedMU) return true;
  1163.         return false;
  1164.     };
  1165.  
  1166.     void HandlePause()
  1167.     {
  1168.         if (PausedCmd) return;
  1169.         if (MouseCheck()) return;
  1170.         MouseFree();
  1171.         PauseTimers();
  1172.     };
  1173.  
  1174.     void PauseTimers()
  1175.     {
  1176.         if (PausedMU && !UserKB)
  1177.         {
  1178.             // verify we didnt ditch our stick target
  1179.             if (STICK->On && (!STICK->Always || (STICK->Always && STICK->HaveTarget)))
  1180.             {
  1181.                 PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget);
  1182.                 if (!psTarget || (STICK->Hold && STICK->HoldType != GetSpawnType(psTarget)))
  1183.                 {
  1184.                     Reset();
  1185.                     EndPreviousCmd(true);
  1186.                     sprintf(szMsg, "\ay%s\aw:: You are no longer sticking to anything.", MODULE_NAME);
  1187.                     WriteLine(szMsg, V_STICKV);
  1188.                     return;
  1189.                 }
  1190.             }
  1191.             switch(TimeStatus())
  1192.             {
  1193.             case T_INACTIVE:
  1194.             case T_WAITING:
  1195.                 break;
  1196.             case T_READY:
  1197.             default:
  1198.                 PausedMU = false;
  1199.                 if (!CAMP->Auto)
  1200.                 {
  1201.                     sprintf(szMsg, "\ay%s\aw:: Resuming previous command from movement pause.", MODULE_NAME);
  1202.                     WriteLine(szMsg, V_MOVEPAUSE);
  1203.                 }
  1204.                 Reset();
  1205.                 break;
  1206.             }
  1207.         }
  1208.     };
  1209.  
  1210.     void MouseFree()
  1211.     {
  1212.         if (HandleMouse)
  1213.         {
  1214.             HandleMouse = false;
  1215.             if (PauseNeeded())
  1216.             {
  1217.                 TimeStart();
  1218.             }
  1219.         }
  1220.     };
  1221.  
  1222.     bool PauseNeeded()
  1223.     {
  1224.         if (CIRCLE->On || STICK->On || MOVETO->On || CAMP->Auto)
  1225.         {
  1226.             if (STICK->On && (!STICK->Always || (STICK->Always && STICK->HaveTarget)))
  1227.             {
  1228.                 PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget);
  1229.                 if (!psTarget || (STICK->Hold && STICK->HoldType != GetSpawnType(psTarget)))
  1230.                 {
  1231.                     Reset();
  1232.                     if (!UserKB) PausedMU = false;
  1233.                     EndPreviousCmd(true);
  1234.                     sprintf(szMsg, "\ay%s\aw:: You are no longer sticking to anything.", MODULE_NAME);
  1235.                     WriteLine(szMsg, V_STICKV);
  1236.                     return false;
  1237.                 }
  1238.             }
  1239.             return true;
  1240.         }
  1241.         return false;
  1242.     };
  1243.  
  1244.     bool MouseCheck();
  1245.     void Reset();
  1246.  
  1247.     CPauseHandler()
  1248.     {
  1249.         Min         = 500;
  1250.         Max         = 5000;
  1251.         PausedCmd   = PausedMU  = false;
  1252.         UserKB      = UserMouse = false;
  1253.         HandleMouse = HandleKB  = false;
  1254.     };
  1255. protected:
  1256.     bool HandleMouse;
  1257.     bool HandleKB;
  1258. };
  1259.  
  1260. class CMUActive
  1261. {
  1262.     // this class instances everything to be used during plugin
  1263.     // runtime under pMU. cmd instances are deleted and reinstanced
  1264.     // per use, copying their defaults from SET, inline params applied after
  1265. public:
  1266.     bool  Aggro;         // ${MoveUtils.Aggro}
  1267.     bool  Bard;          // true if a bard (used by autopause)
  1268.     bool  BrokeGM;       // true if BreakOnGM fired
  1269.     bool  BrokeSummon;   // true if BreakOnSummon fired
  1270.     bool  CmdFwd;        // awareness if plugin has attempted to move forward
  1271.     bool  CmdStrafe;     // awareness if plugin has attempted to strafe
  1272.     bool  FixWalk;       // true if we are dead, unwalk in the event we rez
  1273.     bool  Keybinds;      // loaded keybinds or not
  1274.     bool  KeyKilled;     // keybind has stopped movement
  1275.     bool  Loaded;        // auto ini load
  1276.     bool  LockPause;     // pause locked until unpause
  1277.     bool  MovetoBroke;   // Moveto BreakOnHit or BreakOnAggro fired
  1278.     bool  StickBroke;    // Stick BreakOnHit fired
  1279.     bool  Rooted;        // rootme command active
  1280.     bool  StoppedMoveto; // MoveTo.Stopped, last cmd arrived success
  1281.     int   Head;          // current heading type (0=fast, 1=loose, 2=true)
  1282.  
  1283.     void NewStick()
  1284.     {
  1285.         CURCAMP->RedoStick = false;
  1286.         bStickOn = false;
  1287.         delete STICK;
  1288.         STICK = new CStickCmd();
  1289.     };
  1290.  
  1291.     void NewMoveTo()
  1292.     {
  1293.         CAMP->VarReset();
  1294.         delete MOVETO;
  1295.         MOVETO = new CMoveToCmd();
  1296.     };
  1297.  
  1298.     void NewCircle()
  1299.     {
  1300.         CURCAMP->RedoCircle = false;
  1301.         delete CIRCLE;
  1302.         CIRCLE = new CCircleCmd();
  1303.     };
  1304.  
  1305.     void NewCmds()
  1306.     {
  1307.         NewStick();
  1308.         NewMoveTo();
  1309.         NewCircle();
  1310.     };
  1311.  
  1312.     void NewSummon()
  1313.     {
  1314.         delete SUMMON;
  1315.         SUMMON = new CMULoc();
  1316.     };
  1317.  
  1318.     void NewDefaults()
  1319.     {
  1320.         NewCmds();
  1321.         NewSummon();
  1322.         STUCK->Reset();
  1323.         CAMP->ResetBoth();
  1324.         Defaults();
  1325.     };
  1326.  
  1327.     bool Active()
  1328.     {
  1329.         if (STICK->On || MOVETO->On || CIRCLE->On || CAMP->Returning)
  1330.         {
  1331.             return true;
  1332.         }
  1333.         return false;
  1334.     };
  1335.  
  1336.     void AggroTLO();
  1337.  
  1338.     bool Broken()
  1339.     {
  1340.         if (BrokeGM || BrokeSummon) return true;
  1341.         return false;
  1342.     };
  1343.  
  1344.     CMUActive()
  1345.     {
  1346.         STICK  = new CStickCmd();
  1347.         MOVETO = new CMoveToCmd();
  1348.         CIRCLE = new CCircleCmd();
  1349.         CAMP   = new CCampHandler();
  1350.         PAUSE  = new CPauseHandler();
  1351.         STUCK  = new CStuckLogic();
  1352.         SUMMON = new CMULoc();
  1353.  
  1354.         Aggro         = false;
  1355.         Bard          = false;
  1356.         BrokeGM       = false;
  1357.         BrokeSummon   = false;
  1358.         CmdFwd        = false;
  1359.         CmdStrafe     = false;
  1360.         FixWalk       = false;
  1361.         Keybinds      = false;
  1362.         KeyKilled     = false;
  1363.         Loaded        = false;
  1364.         LockPause     = false;
  1365.         MovetoBroke   = false;
  1366.         Rooted        = false;
  1367.         StickBroke    = false;
  1368.         StoppedMoveto = false;
  1369.         Head          = H_TRUE;
  1370.         Defaults();
  1371.     };
  1372.  
  1373.     ~CMUActive()
  1374.     {
  1375.         delete STICK;
  1376.         STICK  = NULL;
  1377.         delete MOVETO;
  1378.         MOVETO = NULL;
  1379.         delete CIRCLE;
  1380.         CIRCLE = NULL;
  1381.         delete CAMP;
  1382.         CAMP   = NULL;
  1383.         delete PAUSE;
  1384.         PAUSE  = NULL;
  1385.         delete STUCK;
  1386.         STUCK  = NULL;
  1387.         delete SUMMON;
  1388.         SUMMON = NULL;
  1389.     };
  1390.  
  1391.     void Defaults()
  1392.     {
  1393.         Head      = SET->Head;
  1394.         LockPause = SET->LockPause;
  1395.     };
  1396. };
  1397.  
  1398. // ----------------------------------------
  1399. // movement & heading handling class
  1400. class CMUMovement
  1401. {
  1402. public:
  1403.     float ChangeHead; // heading changes set to this
  1404.     float RootHead;   // lock rooted head to this
  1405.  
  1406.     void AutoHead()   // called OnPulse to adjust heading for loose/true
  1407.     {
  1408.         if (ChangeHead == H_INACTIVE) return;
  1409.         TurnHead(ChangeHead);
  1410.     };
  1411.  
  1412.     void NewHead(float fNewHead)
  1413.     {
  1414.         // this is called to apply new heading changes
  1415.         // if loose/true, set ChangeHead to be adjusted appropriately OnPulse
  1416.         // if fast, apply change immediately
  1417.         if (!ValidIngame()) return;
  1418.         switch (pMU->Head)
  1419.         {
  1420.         case H_LOOSE:
  1421.         case H_TRUE:
  1422.             ChangeHead = fNewHead;
  1423.             break;
  1424.         case H_FAST:
  1425.         default:
  1426.             FastTurn(fNewHead);
  1427.             break;
  1428.         }
  1429.     };
  1430.  
  1431.     void NewFace(double dNewFace)
  1432.     {
  1433.         // set look angle adjustments (uw param & autouw)
  1434.         // loose/true: let mq2's gLookAngle auto-adjust for us
  1435.         // fast: apply change immediately
  1436.         if (!ValidIngame()) return;
  1437.         switch (pMU->Head)
  1438.         {
  1439.         case H_LOOSE:
  1440.         case H_TRUE:
  1441.             gLookAngle = dNewFace;
  1442.             break;
  1443.         case H_FAST:
  1444.         default:
  1445.             ((PSPAWNINFO)pCharSpawn)->CameraAngle = (float)dNewFace;
  1446.             break;
  1447.         }
  1448.     };
  1449.  
  1450.     void StopHeading()
  1451.     {
  1452.         // if loose/true is currently trying to adjust head
  1453.         // set adjustment to current heading to halt it
  1454.         // we do it this way because true heading holds down the turn keys
  1455.         if (ChangeHead != H_INACTIVE)
  1456.         {
  1457.             TurnHead(((PSPAWNINFO)pCharSpawn)->Heading);
  1458.         }
  1459.     };
  1460.  
  1461.     float SaneHead(float fHeading)
  1462.     {
  1463.         // places new heading adjustments within bounds
  1464.         if (fHeading >= HEADING_MAX) fHeading -= HEADING_MAX;
  1465.         if (fHeading < 0.0f)         fHeading += HEADING_MAX;
  1466.         return fHeading;
  1467.     };
  1468.  
  1469.     void DoRoot()
  1470.     {
  1471.         // turns '/rootme' on
  1472.         if (!pMU->Rooted || !ValidIngame()) return;
  1473.  
  1474.         if (SET->WinEQ || bOffsetOverride)
  1475.         {
  1476.             StopRoot();
  1477.             return;
  1478.         }
  1479.         ChangeHead = H_INACTIVE;
  1480.         ((PSPAWNINFO)pCharSpawn)->Heading          = RootHead;
  1481.         ((PSPAWNINFO)pCharSpawn)->SpeedHeading     = 0.0f;
  1482.         pKeypressHandler->CommandState[iTurnLeft]  = 0;
  1483.         *pulTurnLeft                               = 0;
  1484.         pKeypressHandler->CommandState[iTurnRight] = 0;
  1485.         *pulTurnRight                              = 0;
  1486.         TrueMoveOff(APPLY_TO_ALL);
  1487.     };
  1488.  
  1489.     void StopRoot()
  1490.     {
  1491.         if (!pMU->Rooted) return;
  1492.         // turns '/rootme' off
  1493.         pMU->Rooted = false;
  1494.         RootHead    = 0.0f;
  1495.         char szTempOut[MAX_STRING] = {0};
  1496.         sprintf(szTempOut, "\ay%s\aw:: You are no longer rooted.", MODULE_NAME);
  1497.         WriteLine(szTempOut, V_SILENCE);
  1498.     };
  1499.  
  1500.     float AngDist(float fH1, float fH2)
  1501.     {
  1502.         // calculates current angular heading distance between two headings
  1503.         // used primarily by strafing stick cmds
  1504.         if(fabs(fH1 - fH2) > HEADING_HALF)
  1505.         {
  1506.             (fH1 < fH2 ? fH1 : fH2) += HEADING_MAX;
  1507.         }
  1508.         return (fabs(fH1 - fH2) > HEADING_HALF) ? (fH2 - fH1) : (fH1 - fH2);
  1509.     };
  1510.  
  1511.     bool CanMove(float fHead, float fY, float fX)
  1512.     {
  1513.         // anti-orbit formula credit: deadchicken
  1514.         // should always return true for fast heading
  1515.         // loose/true heading will not allow movement until
  1516.         // within a close enough turn to prevent orbiting around
  1517.         // a destination or running away from a close destination
  1518.         if (!ValidIngame()) return false;
  1519.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  1520.         float fHeadDiff = fabs(pChSpawn->Heading - fHead);
  1521.  
  1522.         if (fHeadDiff > SET->AllowMove)
  1523.         {
  1524.             // if we are more than an 1/8th turn
  1525.             return false;
  1526.         }
  1527.  
  1528.         if ((fHeadDiff / 2.0f) > fabs(GetDistance(pChSpawn->Y, pChSpawn->X, fY, fX)))
  1529.         {
  1530.             // if half our needed adjustment is > distance between us and destination
  1531.             return false;
  1532.         }
  1533.         // else safe to move
  1534.         return true;
  1535.     };
  1536.  
  1537.     void SetWalk(bool bWalkOn)
  1538.     {
  1539.         // turns walking on or off when desired (if appropriate)
  1540.         if (!ValidIngame()) return; // ExecuteCmd in any other state = CTD
  1541.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  1542.  
  1543.         bool bWalking = (*EQADDR_RUNWALKSTATE) ? false : true;
  1544.         if (pChSpawn->SpeedMultiplier < 0.0f || pChSpawn->RunSpeed < 0.0f)
  1545.         {
  1546.             //if negative speed, we are snared, and do not want walk on
  1547.             bWalkOn = false;
  1548.         }
  1549.         if (bWalkOn != bWalking)
  1550.         {
  1551.             MQ2Globals::ExecuteCmd(iRunWalk, 1, 0);
  1552.             MQ2Globals::ExecuteCmd(iRunWalk, 0, 0);
  1553.         }
  1554.     };
  1555.  
  1556.     void DoStand()
  1557.     {
  1558.         // stand up when desired (if appropriate)
  1559.         // feignsupport is handled *here only*
  1560.         if (!ValidIngame()) return;
  1561.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  1562.  
  1563.         switch (pChSpawn->StandState)
  1564.         {
  1565.         case STANDSTATE_SIT:
  1566.             EzCommand("/stand"); // fix for preventing sit/stand bug
  1567.             break;
  1568.         case STANDSTATE_FEIGN:
  1569.             if (SET->Feign)
  1570.             {
  1571.                 sprintf(szMsg, "\ay%s\aw:: Not standing as you are currently Feign Death", MODULE_NAME);
  1572.                 WriteLine(szMsg, V_FEIGN);
  1573.                 break;
  1574.             }
  1575.             EzCommand("/stand");
  1576.             break;
  1577.         case STANDSTATE_DUCK:
  1578.             /*MQ2Globals::ExecuteCmd(iDuckKey, 1, 0);
  1579.             MQ2Globals::ExecuteCmd(iDuckKey, 0, 0);*/ // rare server desync can happen from doing it this way
  1580.             EzCommand("/stand");
  1581.             break;
  1582.         case STANDSTATE_STAND:
  1583.         case STANDSTATE_DEAD:
  1584.         case STANDSTATE_BIND:
  1585.         case STANDSTATE_CASTING:
  1586.             break;
  1587.         default:
  1588.             SpewDebug(DBG_MAIN, "StandIfNeeded():: no StandState matches for %d", pChSpawn->StandState);
  1589.             break;
  1590.         }
  1591.     };
  1592.  
  1593.     void Walk(unsigned char ucDirection)
  1594.     {
  1595.         // wrapper for calling movement with walking on
  1596.         DoMove(ucDirection, true, MU_WALKON);
  1597.     };
  1598.  
  1599.     void TryMove(unsigned char ucDirection, unsigned char ucWalk, float fHead, float fY, float fX)
  1600.     {
  1601.         // wrapper for calling movement with anti-orbit formula calculated
  1602.         DoMove(ucDirection, CanMove(fHead, fY, fX), ucWalk);
  1603.     };
  1604.  
  1605.     void DoMove(unsigned char ucDirection, bool bTurnOn = true, unsigned char ucWalk = MU_WALKOFF); // main movement function
  1606.  
  1607.     void StopMove(unsigned char ucDirection)
  1608.     {
  1609.         // wrapper for stopping movement
  1610.         // old or new style support handled by the class instead of function
  1611.         if (SET->WinEQ || bOffsetOverride)
  1612.         {
  1613.             SimMoveOff(ucDirection);
  1614.             return;
  1615.         }
  1616.         TrueMoveOff(ucDirection);
  1617.     };
  1618.  
  1619.     void StickStrafe(unsigned char ucDirection)
  1620.     {
  1621.         if (STICK->DelayStrafe)
  1622.         {
  1623.             TimedStrafe(ucDirection);
  1624.             return;
  1625.         }
  1626.         DoMove(ucDirection, true, STICK->Walk ? MU_WALKON : MU_WALKIGNORE);
  1627.     };
  1628.  
  1629.     CMUMovement()
  1630.     {
  1631.         ChangeHead = H_INACTIVE;
  1632.         RootHead   = 0.0f;
  1633.     };
  1634.  
  1635. private:
  1636.     void TimedStrafe(unsigned char ucDirection)
  1637.     {
  1638.         // function to determine if we can begin strafing based on
  1639.         // called if delaystrafe is on, calculates values via
  1640.         // CMUDelay inherit functions using Min/Max
  1641.         unsigned char ucResult = STICK->TimeStatus();
  1642.         if (!pMU->CmdStrafe && ucResult == T_INACTIVE)
  1643.         {
  1644.             StopMove(KILL_STRAFE);
  1645.             STICK->TimeStart();
  1646.             return; // return if we are start moving, not continue moving
  1647.         }
  1648.         if (ucResult == T_READY)
  1649.         {
  1650.             DoMove(ucDirection, true, STICK->Walk ? MU_WALKON : MU_WALKIGNORE);
  1651.         }
  1652.     };
  1653.  
  1654.     void TurnHead(float fHeading)
  1655.     {
  1656.         // this is called by AutoHead if ChangeHead has a value
  1657.         // do a loose or true heading adjustment determined here
  1658.         if (!ValidIngame()) return;
  1659.         switch(pMU->Head)
  1660.         {
  1661.         case H_LOOSE:
  1662.             LooseTurn(fHeading);
  1663.             break;
  1664.         case H_TRUE:
  1665.             if (bOffsetOverride || SET->WinEQ)
  1666.             {
  1667.                 LooseTurn(fHeading);
  1668.                 break;
  1669.             }
  1670.             TrueTurn(fHeading);
  1671.             break;
  1672.         default:
  1673.             break;
  1674.         }
  1675.     };
  1676.  
  1677.     void FastTurn(float fNewHead)
  1678.     {
  1679.         if (!ValidIngame()) return;
  1680.         gFaceAngle = H_INACTIVE;
  1681.         ((PSPAWNINFO)pCharSpawn)->Heading = fNewHead;
  1682.     };
  1683.  
  1684.     void LooseTurn(float fNewHead)
  1685.     {
  1686.         if (!ValidIngame()) return;
  1687.         gFaceAngle = H_INACTIVE;
  1688.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  1689.         if (fabs(pChSpawn->Heading - fNewHead) < SET->TurnRate)
  1690.         {
  1691.             // if we are within one turn away, set heading to desired heading
  1692.             pChSpawn->Heading      = fNewHead;
  1693.             pChSpawn->SpeedHeading = 0.0f;
  1694.             ChangeHead             = H_INACTIVE;
  1695.         }
  1696.         else
  1697.         {
  1698.             float fCompHead = pChSpawn->Heading + HEADING_HALF;
  1699.  
  1700.             if (fNewHead < pChSpawn->Heading) fNewHead += HEADING_MAX;
  1701.             if (fNewHead < fCompHead)
  1702.             {
  1703.                 pChSpawn->Heading      = SaneHead(pChSpawn->Heading + SET->TurnRate);
  1704.                 pChSpawn->SpeedHeading = 12.0f;
  1705.             }
  1706.             else
  1707.             {
  1708.                 pChSpawn->Heading      = SaneHead(pChSpawn->Heading - SET->TurnRate);
  1709.                 pChSpawn->SpeedHeading = -12.0f;
  1710.             }
  1711.         }
  1712.     };
  1713.  
  1714.     void TrueTurn(float fNewHead)
  1715.     {
  1716.         if (!ValidIngame()) return;
  1717.         gFaceAngle = H_INACTIVE;
  1718.         PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  1719.         if (fabs(pChSpawn->Heading - fNewHead) < 14.0f)
  1720.         {
  1721.             pKeypressHandler->CommandState[iTurnLeft]  = 0;
  1722.             *pulTurnLeft                               = 0;
  1723.             pKeypressHandler->CommandState[iTurnRight] = 0;
  1724.             *pulTurnRight                              = 0;
  1725.             pChSpawn->Heading                          = fNewHead;
  1726.             pChSpawn->SpeedHeading                     = 0.0f;
  1727.             ChangeHead                                 = H_INACTIVE;
  1728.         }
  1729.         else
  1730.         {
  1731.             float fCompHead = pChSpawn->Heading + HEADING_HALF;
  1732.  
  1733.             if (fNewHead < pChSpawn->Heading) fNewHead += HEADING_MAX;
  1734.             if (fNewHead < fCompHead)
  1735.             {
  1736.                 pKeypressHandler->CommandState[iTurnRight] = 0;
  1737.                 *pulTurnRight                              = 0;
  1738.                 pKeypressHandler->CommandState[iTurnLeft]  = 1;
  1739.                 *pulTurnLeft                               = 1;
  1740.             }
  1741.             else
  1742.             {
  1743.                 pKeypressHandler->CommandState[iTurnLeft]  = 0;
  1744.                 *pulTurnLeft                               = 0;
  1745.                 pKeypressHandler->CommandState[iTurnRight] = 1;
  1746.                 *pulTurnRight                              = 1;
  1747.             }
  1748.         }
  1749.     };
  1750.  
  1751.     void TrueMoveOn(unsigned char ucDirection)
  1752.     {
  1753.         switch(ucDirection)
  1754.         {
  1755.         case GO_FORWARD:
  1756.             pMU->CmdFwd                               = true;
  1757.             pKeypressHandler->CommandState[iAutoRun]  = 0;
  1758.             *pulAutoRun                               = 0;
  1759.             pKeypressHandler->CommandState[iBackward] = 0;
  1760.             *pulBackward                              = 0;
  1761.             pKeypressHandler->CommandState[iForward]  = 1;
  1762.             *pulForward                               = 1;
  1763.             break;
  1764.         case GO_BACKWARD:
  1765.             pMU->CmdFwd                               = false;
  1766.             pKeypressHandler->CommandState[iAutoRun]  = 0;
  1767.             *pulAutoRun                               = 0;
  1768.             pKeypressHandler->CommandState[iForward]  = 0;
  1769.             *pulForward                               = 0;
  1770.             pKeypressHandler->CommandState[iBackward] = 1;
  1771.             *pulBackward                              = 1;
  1772.             break;
  1773.         case GO_LEFT:
  1774.             pMU->CmdStrafe                               = true;
  1775.             pKeypressHandler->CommandState[iAutoRun]     = 0;
  1776.             *pulAutoRun                                  = 0;
  1777.             pKeypressHandler->CommandState[iStrafeRight] = 0;
  1778.             *pulStrafeRight                              = 0;
  1779.             pKeypressHandler->CommandState[iStrafeLeft]  = 1;
  1780.             *pulStrafeLeft                               = 1;
  1781.             break;
  1782.         case GO_RIGHT:
  1783.             pMU->CmdStrafe                               = true;
  1784.             pKeypressHandler->CommandState[iAutoRun]     = 0;
  1785.             *pulAutoRun                                  = 0;
  1786.             pKeypressHandler->CommandState[iStrafeLeft]  = 0;
  1787.             *pulStrafeLeft                               = 0;
  1788.             pKeypressHandler->CommandState[iStrafeRight] = 1;
  1789.             *pulStrafeRight                              = 1;
  1790.             break;
  1791.         }
  1792.     };
  1793.  
  1794.     void TrueMoveOff(unsigned char ucDirection)
  1795.     {
  1796.         switch(ucDirection)
  1797.         {
  1798.         case APPLY_TO_ALL:
  1799.             pKeypressHandler->CommandState[iAutoRun]     = 0;
  1800.             *pulAutoRun                                  = 0;
  1801.             pKeypressHandler->CommandState[iStrafeLeft]  = 0;
  1802.             *pulStrafeLeft                               = 0;
  1803.             pKeypressHandler->CommandState[iStrafeRight] = 0;
  1804.             *pulStrafeRight                              = 0;
  1805.             pKeypressHandler->CommandState[iForward]     = 0;
  1806.             *pulForward                                  = 0;
  1807.             pKeypressHandler->CommandState[iBackward]    = 0;
  1808.             *pulBackward                                 = 0;
  1809.             pMU->CmdFwd = pMU->CmdStrafe                 = false;
  1810.             STICK->TimeStop();
  1811.             break;
  1812.         case GO_FORWARD:
  1813.             pKeypressHandler->CommandState[iAutoRun] = 0;
  1814.             *pulAutoRun                              = 0;
  1815.             pKeypressHandler->CommandState[iForward] = 0;
  1816.             *pulForward                              = 0;
  1817.             pMU->CmdFwd                              = false;
  1818.             break;
  1819.         case GO_BACKWARD:
  1820.             pKeypressHandler->CommandState[iAutoRun]  = 0;
  1821.             *pulAutoRun                               = 0;
  1822.             pKeypressHandler->CommandState[iBackward] = 0;
  1823.             *pulBackward                              = 0;
  1824.             pMU->CmdFwd                               = false;
  1825.             break;
  1826.         case GO_LEFT:
  1827.             pKeypressHandler->CommandState[iAutoRun]    = 0;
  1828.             *pulAutoRun                                 = 0;
  1829.             pKeypressHandler->CommandState[iStrafeLeft] = 0;
  1830.             *pulStrafeLeft                              = 0;
  1831.             pMU->CmdStrafe                              = false;
  1832.             STICK->TimeStop();
  1833.             break;
  1834.         case GO_RIGHT:
  1835.             pKeypressHandler->CommandState[iAutoRun]     = 0;
  1836.             *pulAutoRun                                  = 0;
  1837.             pKeypressHandler->CommandState[iStrafeRight] = 0;
  1838.             *pulStrafeRight                              = 0;
  1839.             pMU->CmdStrafe                               = false;
  1840.             STICK->TimeStop();
  1841.             break;
  1842.         case KILL_STRAFE:
  1843.             pKeypressHandler->CommandState[iStrafeLeft]  = 0;
  1844.             *pulStrafeLeft                               = 0;
  1845.             pKeypressHandler->CommandState[iStrafeRight] = 0;
  1846.             *pulStrafeRight                              = 0;
  1847.             pMU->CmdStrafe                               = false;
  1848.             STICK->TimeStop();
  1849.             break;
  1850.         case KILL_FB:
  1851.             pKeypressHandler->CommandState[iAutoRun]  = 0;
  1852.             *pulAutoRun                               = 0;
  1853.             pKeypressHandler->CommandState[iForward]  = 0;
  1854.             *pulForward                               = 0;
  1855.             pKeypressHandler->CommandState[iBackward] = 0;
  1856.             *pulBackward                              = 0;
  1857.             pMU->CmdFwd                               = false;
  1858.             break;
  1859.         }
  1860.     };
  1861.  
  1862.     void SimMoveOn(unsigned char ucDirection)
  1863.     {
  1864.         switch (ucDirection)
  1865.         {
  1866.         case GO_FORWARD:
  1867.             pMU->CmdFwd = true;
  1868.             MQ2Globals::ExecuteCmd(iBackward, 0, 0);
  1869.             MQ2Globals::ExecuteCmd(iForward,  1, 0);
  1870.             break;
  1871.         case GO_BACKWARD:
  1872.             pMU->CmdFwd = false;
  1873.             MQ2Globals::ExecuteCmd(iForward,  0, 0);
  1874.             MQ2Globals::ExecuteCmd(iBackward, 1, 0);
  1875.             break;
  1876.         case GO_LEFT:
  1877.             pMU->CmdStrafe = true;
  1878.             MQ2Globals::ExecuteCmd(iStrafeRight, 0, 0);
  1879.             MQ2Globals::ExecuteCmd(iStrafeLeft,  1, 0);
  1880.             break;
  1881.         case GO_RIGHT:
  1882.             pMU->CmdStrafe = true;
  1883.             MQ2Globals::ExecuteCmd(iStrafeLeft,  0, 0);
  1884.             MQ2Globals::ExecuteCmd(iStrafeRight, 1, 0);
  1885.             break;
  1886.         }
  1887.     };
  1888.  
  1889.     void SimMoveOff(unsigned char ucDirection)
  1890.     {
  1891.         switch (ucDirection)
  1892.         {
  1893.         case APPLY_TO_ALL:
  1894.             MQ2Globals::ExecuteCmd(iForward,     0, 0);
  1895.             MQ2Globals::ExecuteCmd(iBackward,    1, 0);
  1896.             MQ2Globals::ExecuteCmd(iBackward,    0, 0);
  1897.             MQ2Globals::ExecuteCmd(iStrafeLeft,  0, 0);
  1898.             MQ2Globals::ExecuteCmd(iStrafeRight, 1, 0);
  1899.             MQ2Globals::ExecuteCmd(iStrafeRight, 0, 0);
  1900.             pMU->CmdFwd = pMU->CmdStrafe = false;
  1901.             break;
  1902.         case KILL_FB:
  1903.         case GO_FORWARD:
  1904.         case GO_BACKWARD:
  1905.             MQ2Globals::ExecuteCmd(iForward,     1, 0);
  1906.             MQ2Globals::ExecuteCmd(iForward,     0, 0);
  1907.             MQ2Globals::ExecuteCmd(iBackward,    1, 0);
  1908.             MQ2Globals::ExecuteCmd(iBackward,    0, 0);
  1909.             pMU->CmdFwd = false;
  1910.             break;
  1911.         case KILL_STRAFE:
  1912.         case GO_LEFT:
  1913.         case GO_RIGHT:
  1914.             MQ2Globals::ExecuteCmd(iStrafeRight, 1, 0);
  1915.             MQ2Globals::ExecuteCmd(iStrafeRight, 0, 0);
  1916.             MQ2Globals::ExecuteCmd(iStrafeLeft,  1, 0);
  1917.             MQ2Globals::ExecuteCmd(iStrafeLeft,  0, 0);
  1918.             pMU->CmdStrafe = false;
  1919.             break;
  1920.         }
  1921.     };
  1922. };
  1923.  
  1924. //--------------------------------------------------------------
  1925. // class methods that are gayed because of declaration placement
  1926.  
  1927. void CMUMovement::DoMove(unsigned char ucDirection, bool bTurnOn, unsigned char ucWalk)
  1928. {
  1929.     // this one due to prototype
  1930.  
  1931.     switch(ucWalk)
  1932.     {
  1933.     case MU_WALKON:
  1934.         SetWalk(true);
  1935.         break;
  1936.     case MU_WALKOFF:
  1937.         SetWalk(false);
  1938.         break;
  1939.     case MU_WALKIGNORE:
  1940.         break;
  1941.     }
  1942.  
  1943.     if (SET->WinEQ || bOffsetOverride)
  1944.     {
  1945.         if (bTurnOn)
  1946.         {
  1947.             SimMoveOn(ucDirection);
  1948.             return;
  1949.         }
  1950.         SimMoveOff(ucDirection);
  1951.         return;
  1952.     }
  1953.     if (bTurnOn)
  1954.     {
  1955.         TrueMoveOn(ucDirection);
  1956.         return;
  1957.     }
  1958.     TrueMoveOff(ucDirection);
  1959. };
  1960.  
  1961. bool CMoveToCmd::DidAggro()
  1962. {
  1963.     if (!CURCAMP->On && On && ME->InCombat())
  1964.     {
  1965.         pMU->MovetoBroke = true;
  1966.         EndPreviousCmd(true);
  1967.         sprintf(szMsg, "\ay%s\aw:: Aggro gained during /moveto, Halting command...", MODULE_NAME);
  1968.         WriteLine(szMsg, V_BREAKONAGGRO);
  1969.         return true;
  1970.     }
  1971.     return false;
  1972. };
  1973.  
  1974. bool CStickCmd::AlwaysStatus()
  1975. {
  1976.     if (!pTarget || ((PSPAWNINFO)pTarget)->Type != SPAWN_NPC)
  1977.     {
  1978.         if (AlwaysReady)
  1979.         {
  1980.             sprintf(szMsg, "\ay%s\aw:: Stick awaiting next valid NPC target...", MODULE_NAME);
  1981.             WriteLine(szMsg, V_STICKALWAYS);
  1982.             MOVE->StopMove(APPLY_TO_ALL);
  1983.             DoRandomize();
  1984.             AlwaysReady = false;
  1985.         }
  1986.         HaveTarget = false;
  1987.         return false;
  1988.     }
  1989.  
  1990.     if (!AlwaysReady)
  1991.     {
  1992.         EndPreviousCmd(true, CMD_STICK, true);
  1993.         PAUSE->Reset();
  1994.         MOVE->DoStand();
  1995.         MOVE->StopHeading();
  1996.         AlwaysReady = true;
  1997.     }
  1998.     HaveTarget = true;
  1999.     return true;
  2000. };
  2001.  
  2002. bool CPauseHandler::MouseCheck()
  2003. {
  2004.     if (*pMouseLook)
  2005.     {
  2006.         UserMouse = true;
  2007.         if ((SET->PauseMouse || SET->BreakMouse) && PauseNeeded())
  2008.         {
  2009.             CAMP->TimeStop();
  2010.             TimeStop();
  2011.             MOVE->StopHeading();
  2012.             if (SET->BreakMouse)
  2013.             {
  2014.                 EndPreviousCmd(true);
  2015.                 if (!CAMP->Auto)
  2016.                 {
  2017.                     sprintf(szMsg, "\ay%s\aw:: Current command ended from mouse movement.", MODULE_NAME);
  2018.                     WriteLine(szMsg, V_MOUSEPAUSE);
  2019.                 }
  2020.                 return false;
  2021.             }
  2022.             PausedMU = true;
  2023.             MOVE->DoMove(APPLY_TO_ALL, false, MU_WALKOFF);
  2024.             HandleMouse = true;
  2025.             return true;
  2026.         }
  2027.         return false;
  2028.     }
  2029.     UserMouse = false;
  2030.     return false;
  2031. };
  2032.  
  2033. void CPauseHandler::Reset()
  2034. {
  2035.     CAMP->TimeStop();
  2036.     STUCK->Reset();
  2037.     pMU->CmdFwd    = false;
  2038.     pMU->CmdStrafe = false;
  2039.     pMU->NewSummon();
  2040.     STICK->NewSnaproll();
  2041.     STICK->TimeStop();
  2042.     STICK->ResetLoc();
  2043. };
  2044.  
  2045. void CMUActive::AggroTLO()
  2046. {
  2047.     if (pTarget)
  2048.     {
  2049.         if (fabs(MOVE->AngDist(((PSPAWNINFO)pTarget)->Heading, ((PSPAWNINFO)pCharSpawn)->Heading)) > 190.0f)
  2050.         {
  2051.             Aggro = true;
  2052.             return;
  2053.         }
  2054.     }
  2055.     Aggro = false;
  2056. };
  2057.  
  2058. // ----------------------------------------
  2059. // custom UI window
  2060. class CMoveUtilsWnd : public CCustomWnd
  2061. {
  2062. public:
  2063.     CStmlWnd*         StmlOut;
  2064.     CXWnd*            OutWnd;
  2065.     struct _CSIDLWND* OutStruct;
  2066.  
  2067.     CMoveUtilsWnd(CXStr* Template) : CCustomWnd(Template)
  2068.     {
  2069.         SetWndNotification(CMoveUtilsWnd);
  2070.         StmlOut                                     = (CStmlWnd*)GetChildItem("CWChatOutput");
  2071.         OutWnd                                      = (CXWnd*)StmlOut;
  2072.         OutWnd->Clickable                           = 1;
  2073.         OutStruct                                   = (_CSIDLWND*)GetChildItem("CWChatOutput");
  2074.         CloseOnESC                                  = 0;
  2075.         *(unsigned long*)&(((char*)StmlOut)[EQ_CHAT_HISTORY_OFFSET]) = 400;
  2076.         BitOff(WindowStyle, CWS_CLOSE);
  2077.     };
  2078.  
  2079.     int WndNotification(CXWnd* pWnd, unsigned int uiMessage, void* pData)
  2080.     {
  2081.         if (pWnd == NULL && uiMessage == XWM_CLOSE)
  2082.         {
  2083.             dShow = 1;
  2084.             return 0;
  2085.         }
  2086.         return CSidlScreenWnd::WndNotification(pWnd, uiMessage, pData);
  2087.     };
  2088. };
  2089.  
  2090. class CMUWndHandler
  2091. {
  2092. public:
  2093.     bool Active()
  2094.     {
  2095.         if (OurWnd) return true;
  2096.         return false;
  2097.     };
  2098.  
  2099.     void Create()
  2100.     {
  2101.         if (!ValidIngame() || !SET->Window || OurWnd) return;
  2102.         NewWnd();
  2103.     };
  2104.  
  2105.     void Destroy(bool bSave)
  2106.     {
  2107.         if (!OurWnd) return;
  2108.         if (bSave) SaveWnd();
  2109.         delete OurWnd;
  2110.         OurWnd = NULL;
  2111.     };
  2112.  
  2113.     void Clear()
  2114.     {
  2115.         if (!OurWnd) return;
  2116.         ((CChatWindow*)OurWnd)->Clear();
  2117.     };
  2118.  
  2119.     void Hover()
  2120.     {
  2121.         if (!OurWnd) return;
  2122.         ((CXWnd*)OurWnd)->DoAllDrawing();
  2123.     };
  2124.  
  2125.     void Min()
  2126.     {
  2127.         if (!OurWnd) return;
  2128.         ((CXWnd*)OurWnd)->OnMinimizeBox();
  2129.     };
  2130.  
  2131.     void Save()
  2132.     {
  2133.         if (!OurWnd) return;
  2134.         SaveWnd();
  2135.     };
  2136.  
  2137.     void Write(char* szText)
  2138.     {
  2139.         if (!OurWnd) return;
  2140.         Output(szText);
  2141.     };
  2142.  
  2143.     void NewFont(int iSize)
  2144.     {
  2145.         if (!OurWnd || iSize < 0) return;
  2146.         SetFontSize(iSize);
  2147.     };
  2148.  
  2149.     CMUWndHandler()
  2150.     {
  2151.         OurWnd   = NULL;
  2152.         FontSize = 2;
  2153.     };
  2154.  
  2155. protected:
  2156.     void NewWnd()
  2157.     {
  2158.         char szWindowText[MAX_STRING] = {0};
  2159.         class CXStr ChatWnd("ChatWindow");
  2160.         OurWnd = new CMoveUtilsWnd(&ChatWnd);
  2161.  
  2162.         OurWnd->Location.top    = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "ChatTop",      10,   INIFileName);
  2163.         OurWnd->Location.bottom = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "ChatBottom",   210,  INIFileName);
  2164.         OurWnd->Location.left   = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "ChatLeft",     10,   INIFileName);
  2165.         OurWnd->Location.right  = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "ChatRight",    410,  INIFileName);
  2166.         OurWnd->Fades           = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "Fades",        0,    INIFileName);
  2167.         OurWnd->Alpha           = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "Alpha",        255,  INIFileName);
  2168.         OurWnd->FadeToAlpha     = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "FadeToAlpha",  255,  INIFileName);
  2169.         OurWnd->FadeDuration    = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "Duration",     500,  INIFileName);
  2170.         OurWnd->Locked          = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "Locked",       0,    INIFileName);
  2171.         OurWnd->TimeMouseOver   = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "Delay",        2000, INIFileName);
  2172.         OurWnd->BGType          = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "BGType",       1,    INIFileName);
  2173.         OurWnd->BGColor.R       = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "BGTint.red",   255,  INIFileName);
  2174.         OurWnd->BGColor.G       = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "BGTint.green", 255,  INIFileName);
  2175.         OurWnd->BGColor.B       = GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "BGTint.blue",  255,  INIFileName);
  2176.  
  2177.  
  2178.         NewFont(GetPrivateProfileInt(SET->SaveByChar ? szCharName : "Window", "FontSize", 2, INIFileName));
  2179.         GetPrivateProfileString(SET->SaveByChar ? szCharName : "Window", "WindowTitle", "MoveUtils", szWindowText, MAX_STRING, INIFileName);
  2180.         SetCXStr(&OurWnd->WindowText, szWindowText);
  2181.         ((CXWnd*)OurWnd)->Show(1, 1);
  2182.         BitOff(OurWnd->OutStruct->WindowStyle, CWS_CLOSE);
  2183.     };
  2184.  
  2185.     void SaveWnd()
  2186.     {
  2187.         PCSIDLWND UseWnd = (PCSIDLWND)OurWnd;
  2188.         char szTemp[20]                = {0};
  2189.  
  2190.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "ChatTop",      itoa(UseWnd->Location.top,    szTemp, 10), INIFileName);
  2191.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "ChatBottom",   itoa(UseWnd->Location.bottom, szTemp, 10), INIFileName);
  2192.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "ChatLeft",     itoa(UseWnd->Location.left,   szTemp, 10), INIFileName);
  2193.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "ChatRight",    itoa(UseWnd->Location.right,  szTemp, 10), INIFileName);
  2194.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "Fades",        itoa(UseWnd->Fades,           szTemp, 10), INIFileName);
  2195.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "Alpha",        itoa(UseWnd->Alpha,           szTemp, 10), INIFileName);
  2196.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "FadeToAlpha",  itoa(UseWnd->FadeToAlpha,     szTemp, 10), INIFileName);
  2197.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "Duration",     itoa(UseWnd->FadeDuration,    szTemp, 10), INIFileName);
  2198.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "Locked",       itoa(UseWnd->Locked,          szTemp, 10), INIFileName);
  2199.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "Delay",        itoa(UseWnd->TimeMouseOver,   szTemp, 10), INIFileName);
  2200.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "BGType",       itoa(UseWnd->BGType,          szTemp, 10), INIFileName);
  2201.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "BGTint.red",   itoa(UseWnd->BGColor.R,       szTemp, 10), INIFileName);
  2202.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "BGTint.green", itoa(UseWnd->BGColor.G,       szTemp, 10), INIFileName);
  2203.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "BGTint.blue",  itoa(UseWnd->BGColor.B,       szTemp, 10), INIFileName);
  2204.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "FontSize",     itoa(FontSize,                szTemp, 10), INIFileName);
  2205.  
  2206.         GetCXStr(UseWnd->WindowText, szTemp);
  2207.         WritePrivateProfileString(SET->SaveByChar ? szCharName : "Window", "WindowTitle", szTemp, INIFileName);
  2208.     };
  2209.  
  2210.     void Output(char* szText)
  2211.     {
  2212.         ((CXWnd*)OurWnd)->Show(1, 1);
  2213.         char szProcessed[MAX_STRING] = {0};
  2214.         StripMQChat(szText, szProcessed);
  2215.         CheckChatForEvent(szProcessed);
  2216.         MQToSTML(szText, szProcessed, MAX_STRING);
  2217.         strcat(szProcessed, "<br>");
  2218.         CXStr NewText(szProcessed);
  2219.         (OurWnd->StmlOut)->AppendSTML(NewText);
  2220.         (OurWnd->OutWnd)->SetVScrollPos(OurWnd->OutStruct->VScrollMax);
  2221.     };
  2222.  
  2223.     void SetFontSize(unsigned int uiSize)
  2224.     {
  2225.         struct FONTDATA
  2226.         {
  2227.             unsigned long ulNumFonts;
  2228.             char**        ppFonts;
  2229.         };
  2230.         FONTDATA*      pFonts;       // font array structure
  2231.         unsigned long* pulSelFont;   // selected font
  2232.         pFonts = (FONTDATA*)&(((char*)pWndMgr)[EQ_CHAT_FONT_OFFSET]);
  2233.         if (!pFonts->ppFonts || uiSize >= (int)pFonts->ulNumFonts)
  2234.         {
  2235.             return;
  2236.         }
  2237.         pulSelFont = (unsigned long*)pFonts->ppFonts[uiSize];
  2238.  
  2239.         CXStr ContStr(((CStmlWnd*)OurWnd->StmlOut)->GetSTMLText());
  2240.         ((CXWnd*)OurWnd->StmlOut)->SetFont(pulSelFont);
  2241.         ((CStmlWnd*)OurWnd->StmlOut)->SetSTMLText(ContStr, 1, 0);
  2242.         ((CStmlWnd*)OurWnd->StmlOut)->ForceParseNow();
  2243.         ((CXWnd*)OurWnd->StmlOut)->SetVScrollPos(OurWnd->StmlOut->VScrollMax);
  2244.  
  2245.         FontSize = uiSize;
  2246.     };
  2247.  
  2248.     CMoveUtilsWnd* OurWnd;
  2249.     unsigned long FontSize;
  2250. };
  2251.  
  2252. // --------------------------------
  2253. // Begin Custom Top-Level Objects
  2254.  
  2255. class MQ2MakeCampType*   pMakeCampType   = NULL;
  2256. class MQ2StickType*      pStickType      = NULL;
  2257. class MQ2MoveToType*     pMoveToType     = NULL;
  2258. class MQ2CircleType*     pCircleType     = NULL;
  2259. class MQ2MoveUtilsType*  pMoveUtilsType  = NULL;
  2260.  
  2261. class MQ2MakeCampType : public MQ2Type
  2262. {
  2263. public:
  2264.     enum MakeCampMembers
  2265.     {
  2266.         Status           = 1,
  2267.         Leash            = 2,
  2268.         AnchorY          = 3,
  2269.         AnchorX          = 4,
  2270.         LeashLength      = 5,
  2271.         CampRadius       = 6,
  2272.         MinDelay         = 7,
  2273.         MaxDelay         = 8,
  2274.         Returning        = 9,
  2275.         AltAnchorY       = 10,
  2276.         AltAnchorX       = 11,
  2277.         CampDist         = 12,
  2278.         AltCampDist      = 13,
  2279.         AltRadius        = 14,
  2280.         Scatter          = 15,
  2281.         ReturnNoAggro    = 16,
  2282.         ReturnNotLooting = 17,
  2283.         ReturnHaveTarget = 18,
  2284.         Bearing          = 19,
  2285.         ScatDist         = 20,
  2286.         ScatSize         = 21,
  2287.     };
  2288.  
  2289.     MQ2MakeCampType():MQ2Type("makecamp")
  2290.     {
  2291.         TypeMember(Status);
  2292.         TypeMember(Leash);
  2293.         TypeMember(AnchorY);
  2294.         TypeMember(AnchorX);
  2295.         TypeMember(LeashLength);
  2296.         TypeMember(CampRadius);
  2297.         TypeMember(MinDelay);
  2298.         TypeMember(MaxDelay);
  2299.         TypeMember(Returning);
  2300.         TypeMember(AltAnchorY);
  2301.         TypeMember(AltAnchorX);
  2302.         TypeMember(CampDist);
  2303.         TypeMember(AltCampDist);
  2304.         TypeMember(AltRadius);
  2305.         TypeMember(Scatter);
  2306.         TypeMember(ReturnNoAggro);
  2307.         TypeMember(ReturnNotLooting);
  2308.         TypeMember(ReturnHaveTarget);
  2309.         TypeMember(Bearing);
  2310.         TypeMember(ScatDist);
  2311.         TypeMember(ScatSize);
  2312.     }
  2313.  
  2314.     bool GetMember(MQ2VARPTR VarPtr, char* Member, char* Index, MQ2TYPEVAR &Dest)
  2315.     {
  2316.         PMQ2TYPEMEMBER pMember = MQ2MakeCampType::FindMember(Member);
  2317.         if (!pMember || !ValidIngame(false)) return false;
  2318.         switch((MakeCampMembers)pMember->ID)
  2319.         {
  2320.         case Status:
  2321.             strcpy(DataTypeTemp, "OFF");
  2322.             if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2323.             {
  2324.                 strcpy(DataTypeTemp, "PAUSED");
  2325.             }
  2326.             else if (CURCAMP->On)
  2327.             {
  2328.                 strcpy(DataTypeTemp, "ON");
  2329.             }
  2330.             Dest.Ptr  = DataTypeTemp;
  2331.             Dest.Type = pStringType;
  2332.             return true;
  2333.         case Leash:
  2334.             Dest.DWord = CURCAMP->Leash;
  2335.             Dest.Type  = pBoolType;
  2336.             return true;
  2337.         case AnchorY:
  2338.             Dest.Float = CURCAMP->Y;
  2339.             Dest.Type  = pFloatType;
  2340.             return true;
  2341.         case AnchorX:
  2342.             Dest.Float = CURCAMP->X;
  2343.             Dest.Type  = pFloatType;
  2344.             return true;
  2345.         case LeashLength:
  2346.             Dest.Float = CURCAMP->Length;
  2347.             Dest.Type  = pFloatType;
  2348.             return true;
  2349.         case CampRadius:
  2350.             Dest.Float = CURCAMP->Radius;
  2351.             Dest.Type  = pFloatType;
  2352.             return true;
  2353.         case MinDelay:
  2354.             Dest.DWord = CAMP->Min;
  2355.             Dest.Type  = pIntType;
  2356.             return true;
  2357.         case MaxDelay:
  2358.             Dest.DWord = CAMP->Max;
  2359.             Dest.Type  = pIntType;
  2360.             return true;
  2361.         case Returning:
  2362.             Dest.DWord = CAMP->DoReturn;
  2363.             Dest.Type  = pBoolType;
  2364.             return true;
  2365.         case AltAnchorY:
  2366.             Dest.Float = ALTCAMP->Y;
  2367.             Dest.Type  = pFloatType;
  2368.             return true;
  2369.         case AltAnchorX:
  2370.             Dest.Float = ALTCAMP->X;
  2371.             Dest.Type  = pFloatType;
  2372.             return true;
  2373.         case CampDist:
  2374.             Dest.Float = 0.0f;
  2375.             if (CURCAMP->On)
  2376.             {
  2377.                 PSPAWNINFO pLPlayer = (PSPAWNINFO)pLocalPlayer;
  2378.                 Dest.Float = GetDistance(pLPlayer->Y, pLPlayer->X, CURCAMP->Y, CURCAMP->X);
  2379.             }
  2380.             Dest.Type = pFloatType;
  2381.             return true;
  2382.         case AltCampDist:
  2383.             Dest.Float = 0.0f;
  2384.             if (ALTCAMP->On)
  2385.             {
  2386.                 PSPAWNINFO pLPlayer = (PSPAWNINFO)pLocalPlayer;
  2387.                 Dest.Float = GetDistance(pLPlayer->Y, pLPlayer->X, ALTCAMP->Y, ALTCAMP->X);
  2388.             }
  2389.             Dest.Type = pFloatType;
  2390.             return true;
  2391.         case AltRadius:
  2392.             Dest.Float = ALTCAMP->Radius;
  2393.             Dest.Type  = pFloatType;
  2394.             return true;
  2395.         case Scatter:
  2396.             Dest.DWord = CURCAMP->Scatter;
  2397.             Dest.Type  = pBoolType;
  2398.             return true;
  2399.         case ReturnNoAggro:
  2400.             Dest.DWord = CURCAMP->NoAggro;
  2401.             Dest.Type  = pBoolType;
  2402.             return true;
  2403.         case ReturnNotLooting:
  2404.             Dest.DWord = CURCAMP->NotLoot;
  2405.             Dest.Type  = pBoolType;
  2406.             return true;
  2407.         case ReturnHaveTarget:
  2408.             Dest.DWord = CURCAMP->HaveTarget;
  2409.             Dest.Type  = pBoolType;
  2410.             return true;
  2411.         case Bearing:
  2412.             Dest.Float = CURCAMP->Bearing;
  2413.             Dest.Type  = pFloatType;
  2414.             return true;
  2415.         case ScatDist:
  2416.             Dest.Float = CURCAMP->ScatDist;
  2417.             Dest.Type  = pFloatType;
  2418.             return true;
  2419.         case ScatSize:
  2420.             Dest.Float = CURCAMP->ScatSize;
  2421.             Dest.Type  = pFloatType;
  2422.             return true;
  2423.         }
  2424.         return false;
  2425.     }
  2426.  
  2427.     bool ToString(MQ2VARPTR VarPtr, char* Destination)
  2428.     {
  2429.         strcpy(Destination, "OFF");
  2430.         if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2431.         {
  2432.             strcpy(Destination, "PAUSED");
  2433.         }
  2434.         else if (CURCAMP->On)
  2435.         {
  2436.             strcpy(Destination, "ON");
  2437.         }
  2438.         return true;
  2439.     }
  2440.  
  2441.     bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
  2442.     {
  2443.         return false;
  2444.     }
  2445.     bool FromString(MQ2VARPTR &VarPtr, char* Source)
  2446.     {
  2447.         return false;
  2448.     }
  2449. };
  2450.  
  2451. int dataMakeCamp(char* szName, MQ2TYPEVAR &Ret)
  2452. {
  2453.     Ret.DWord = 1;
  2454.     Ret.Type  = pMakeCampType;
  2455.     return true;
  2456. }
  2457.  
  2458. class MQ2StickType : public MQ2Type
  2459. {
  2460. public:
  2461.     enum StickMembers
  2462.     {
  2463.         Status          = 1,
  2464.         Active          = 2,
  2465.         Distance        = 3,
  2466.         MoveBehind      = 4,
  2467.         MoveBack        = 5,
  2468.         Loose           = 6,
  2469.         Paused          = 7,
  2470.         Behind          = 8,
  2471.         Stopped         = 9,
  2472.         Pin             = 10,
  2473.         StickTarget     = 11,
  2474.         StickTargetName = 12,
  2475.         DistMod         = 13,
  2476.         DistModPercent  = 14,
  2477.         Always          = 15,
  2478.         Broken          = 16,
  2479.     };
  2480.  
  2481.     MQ2StickType():MQ2Type("stick")
  2482.     {
  2483.         TypeMember(Status);
  2484.         TypeMember(Active);
  2485.         TypeMember(Distance);
  2486.         TypeMember(MoveBehind);
  2487.         TypeMember(MoveBack);
  2488.         TypeMember(Loose);
  2489.         TypeMember(Paused);
  2490.         TypeMember(Behind);
  2491.         TypeMember(Stopped);
  2492.         TypeMember(Pin);
  2493.         TypeMember(StickTarget);
  2494.         TypeMember(StickTargetName);
  2495.         TypeMember(DistMod);
  2496.         TypeMember(DistModPercent);
  2497.         TypeMember(Always);
  2498.         TypeMember(Broken);
  2499.     }
  2500.  
  2501.     bool GetMember(MQ2VARPTR VarPtr, char* Member, char* Index, MQ2TYPEVAR &Dest)
  2502.     {
  2503.         PMQ2TYPEMEMBER pMember = MQ2StickType::FindMember(Member);
  2504.         if (!pMember || !ValidIngame(false)) return false;
  2505.         switch((StickMembers)pMember->ID)
  2506.         {
  2507.         case Status:
  2508.             strcpy(DataTypeTemp, "OFF");
  2509.             if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2510.             {
  2511.                 strcpy(DataTypeTemp, "PAUSED");
  2512.             }
  2513.             else if (STICK->On)
  2514.             {
  2515.                 strcpy(DataTypeTemp, "ON");
  2516.             }
  2517.             Dest.Ptr  = DataTypeTemp;
  2518.             Dest.Type = pStringType;
  2519.             return true;
  2520.         case Active:
  2521.             Dest.DWord = STICK->On;
  2522.             Dest.Type  = pBoolType;
  2523.             return true;
  2524.         case Distance:
  2525.             Dest.Float = STICK->Dist;
  2526.             Dest.Type  = pFloatType;
  2527.             return true;
  2528.         case MoveBehind:
  2529.             Dest.DWord = STICK->Behind;
  2530.             Dest.Type  = pBoolType;
  2531.             return true;
  2532.         case MoveBack:
  2533.             Dest.DWord = STICK->MoveBack;
  2534.             Dest.Type  = pBoolType;
  2535.             return true;
  2536.         case Loose:
  2537.             Dest.DWord = (pMU->Head == H_LOOSE) ? true : false;
  2538.             Dest.Type  = pBoolType;
  2539.             return true;
  2540.         case Paused:
  2541.             Dest.DWord = PAUSE->PausedMU;
  2542.             Dest.Type  = pBoolType;
  2543.             return true;
  2544.         case Behind:
  2545.             Dest.DWord = false;
  2546.             if (PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget))
  2547.             {
  2548.                 PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  2549.                 Dest.DWord = (fabs(GetDistance(pChSpawn, psTarget)) <= ((STICK->Dist > 0.0f ? STICK->Dist : (psTarget->StandState ? get_melee_range(pLocalPlayer, (EQPlayer *)psTarget) : 15.0f)) * STICK->DistModP + STICK->DistMod) && fabs(MOVE->AngDist(psTarget->Heading, pChSpawn->Heading)) <= STICK->ArcBehind) ? true : false;
  2550.             }
  2551.             Dest.Type = pBoolType;
  2552.             return true;
  2553.         case Stopped:
  2554.             Dest.DWord = false;
  2555.             if (PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget))
  2556.             {
  2557.                 Dest.DWord = (fabs(GetDistance((PSPAWNINFO)pCharSpawn, psTarget)) <= STICK->Dist) ? true : false;
  2558.             }
  2559.             Dest.Type = pBoolType;
  2560.             return true;
  2561.         case Pin:
  2562.             Dest.DWord = STICK->Pin;
  2563.             Dest.Type  = pBoolType;
  2564.             return true;
  2565.         case StickTarget:
  2566.             Dest.Int = 0;
  2567.             if (PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget))
  2568.             {
  2569.                 Dest.Int = psTarget->SpawnID;
  2570.             }
  2571.             Dest.Type = pIntType;
  2572.             return true;
  2573.         case StickTargetName:
  2574.             strcpy(DataTypeTemp, "NONE");
  2575.             if (PSPAWNINFO psTarget = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget))
  2576.             {
  2577.                 strcpy(DataTypeTemp, psTarget->DisplayedName);
  2578.             }
  2579.             Dest.Ptr  = DataTypeTemp;
  2580.             Dest.Type = pStringType;
  2581.             return true;
  2582.         case DistMod:
  2583.             Dest.Float = STICK->DistMod;
  2584.             Dest.Type  = pFloatType;
  2585.             return true;
  2586.         case DistModPercent:
  2587.             Dest.Float = STICK->DistModP;
  2588.             Dest.Type  = pFloatType;
  2589.             return true;
  2590.         case Always:
  2591.             Dest.DWord = STICK->Always;
  2592.             Dest.Type  = pBoolType;
  2593.             return true;
  2594.         case Broken:
  2595.             Dest.DWord = pMU->StickBroke;
  2596.             Dest.Type  = pBoolType;
  2597.             return true;
  2598.         }
  2599.         return false;
  2600.     }
  2601.  
  2602.     bool ToString(MQ2VARPTR VarPtr, char* Destination)
  2603.     {
  2604.         strcpy(Destination, "OFF");
  2605.         if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2606.         {
  2607.             strcpy(Destination, "PAUSED");
  2608.         }
  2609.         else if (STICK->On)
  2610.         {
  2611.             strcpy(Destination, "ON");
  2612.         }
  2613.  
  2614.         return true;
  2615.     }
  2616.  
  2617.     bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
  2618.     {
  2619.         return false;
  2620.     }
  2621.     bool FromString(MQ2VARPTR &VarPtr, char* Source)
  2622.     {
  2623.         return false;
  2624.     }
  2625. };
  2626.  
  2627. int dataStick(char* szName, MQ2TYPEVAR &Ret)
  2628. {
  2629.     Ret.DWord = 1;
  2630.     Ret.Type  = pStickType;
  2631.     return true;
  2632. }
  2633.  
  2634. class MQ2MoveToType : public MQ2Type
  2635. {
  2636. public:
  2637.     enum MoveToMembers
  2638.     {
  2639.         Moving       = 1,
  2640.         Stopped      = 2,
  2641.         CampStopped  = 3,
  2642.         UseWalk      = 4,
  2643.         ArrivalDist  = 5,
  2644.         ArrivalDistY = 6,
  2645.         ArrivalDistX = 7,
  2646.         Broken       = 8,
  2647.     };
  2648.  
  2649.     MQ2MoveToType():MQ2Type("moveto")
  2650.     {
  2651.         TypeMember(Moving);
  2652.         TypeMember(Stopped);
  2653.         TypeMember(CampStopped);
  2654.         TypeMember(UseWalk);
  2655.         TypeMember(ArrivalDist);
  2656.         TypeMember(ArrivalDistY);
  2657.         TypeMember(ArrivalDistX);
  2658.         TypeMember(Broken);
  2659.     }
  2660.  
  2661.     bool GetMember(MQ2VARPTR VarPtr, char* Member, char* Index, MQ2TYPEVAR &Dest)
  2662.     {
  2663.         PMQ2TYPEMEMBER pMember = MQ2MoveToType::FindMember(Member);
  2664.         if (!pMember || !ValidIngame(false)) return false;
  2665.         switch((MoveToMembers)pMember->ID)
  2666.         {
  2667.         case Moving:
  2668.             Dest.DWord = MOVETO->On;
  2669.             Dest.Type  = pBoolType;
  2670.             return true;
  2671.         case Stopped:
  2672.             /*if (pLocalPlayer)
  2673.             {
  2674.                 Dest.DWord = (fabs(GetDistance(((PSPAWNINFO)pCharSpawn)->Y, ((PSPAWNINFO)pCharSpawn)->X, MOVETO->Y, MOVETO->X)) <= MOVETO->Dist) ? true : false;
  2675.             }*/
  2676.             Dest.DWord = pMU->StoppedMoveto;
  2677.             Dest.Type  = pBoolType;
  2678.             return true;
  2679.         case CampStopped:
  2680.             Dest.DWord = false;
  2681.             if (pLocalPlayer)
  2682.             {
  2683.                 Dest.DWord = (fabs(GetDistance(((PSPAWNINFO)pCharSpawn)->Y, ((PSPAWNINFO)pCharSpawn)->X, CAMP->Y, CAMP->X)) <= MOVETO->Dist) ? true : false;
  2684.             }
  2685.             Dest.Type  = pBoolType;
  2686.             return true;
  2687.         case UseWalk:
  2688.             Dest.DWord = MOVETO->Walk;
  2689.             Dest.Type  = pBoolType;
  2690.             return true;
  2691.         case ArrivalDist:
  2692.             Dest.Float = MOVETO->Dist;
  2693.             Dest.Type  = pFloatType;
  2694.             return true;
  2695.         case ArrivalDistY:
  2696.             Dest.Float = MOVETO->DistY;
  2697.             Dest.Type  = pFloatType;
  2698.             return true;
  2699.         case ArrivalDistX:
  2700.             Dest.Float = MOVETO->DistX;
  2701.             Dest.Type  = pFloatType;
  2702.             return true;
  2703.         case Broken:
  2704.             Dest.DWord = pMU->MovetoBroke;
  2705.             Dest.Type  = pBoolType;
  2706.             return true;
  2707.         }
  2708.         return false;
  2709.     }
  2710.  
  2711.     bool ToString(MQ2VARPTR VarPtr, char* Destination)
  2712.     {
  2713.         strcpy(Destination, "OFF");
  2714.         if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2715.         {
  2716.             strcpy(Destination, "PAUSED");
  2717.         }
  2718.         else if (MOVETO->On)
  2719.         {
  2720.             strcpy(Destination, "ON");
  2721.         }
  2722.  
  2723.         return true;
  2724.     }
  2725.  
  2726.     bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
  2727.     {
  2728.         return false;
  2729.     }
  2730.     bool FromString(MQ2VARPTR &VarPtr, char* Source)
  2731.     {
  2732.         return false;
  2733.     }
  2734. };
  2735.  
  2736. int dataMoveTo(char* szName, MQ2TYPEVAR &Ret)
  2737. {
  2738.     Ret.DWord = 1;
  2739.     Ret.Type  = pMoveToType;
  2740.     return true;
  2741. }
  2742.  
  2743. class MQ2CircleType : public MQ2Type
  2744. {
  2745. public:
  2746.     enum CircleMembers
  2747.     {
  2748.         Status    = 1,
  2749.         CircleY   = 2,
  2750.         CircleX   = 3,
  2751.         Drunken   = 4,
  2752.         Rotation  = 5,
  2753.         Direction = 6,
  2754.         Clockwise = 7,
  2755.         Backwards = 8,
  2756.         Radius    = 9,
  2757.     };
  2758.  
  2759.     MQ2CircleType():MQ2Type("circle")
  2760.     {
  2761.         TypeMember(Status);
  2762.         TypeMember(CircleY);
  2763.         TypeMember(CircleX);
  2764.         TypeMember(Drunken);
  2765.         TypeMember(Rotation);
  2766.         TypeMember(Direction);
  2767.         TypeMember(Clockwise);
  2768.         TypeMember(Backwards);
  2769.         TypeMember(Radius);
  2770.     }
  2771.  
  2772.     bool GetMember(MQ2VARPTR VarPtr, char* Member, char* Index, MQ2TYPEVAR &Dest)
  2773.     {
  2774.         PMQ2TYPEMEMBER pMember = MQ2CircleType::FindMember(Member);
  2775.         if (!pMember || !ValidIngame(false)) return false;
  2776.         switch((CircleMembers)pMember->ID)
  2777.         {
  2778.         case Status:
  2779.             strcpy(DataTypeTemp, "OFF");
  2780.             if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2781.             {
  2782.                 strcpy(DataTypeTemp, "PAUSED");
  2783.             }
  2784.             else if (CIRCLE->On)
  2785.             {
  2786.                 strcpy(DataTypeTemp, "ON");
  2787.             }
  2788.             Dest.Ptr  = DataTypeTemp;
  2789.             Dest.Type = pStringType;
  2790.             return true;
  2791.         case CircleY:
  2792.             Dest.Float = CIRCLE->Y;
  2793.             Dest.Type  = pFloatType;
  2794.             return true;
  2795.         case CircleX:
  2796.             Dest.Float = CIRCLE->X;
  2797.             Dest.Type = pFloatType;
  2798.             return true;
  2799.         case Drunken:
  2800.             Dest.DWord = CIRCLE->Drunk;
  2801.             Dest.Type  = pBoolType;
  2802.             return true;
  2803.         case Rotation:
  2804.             strcpy(DataTypeTemp, "CW");
  2805.             if (CIRCLE->CCW)
  2806.             {
  2807.                 strcpy(DataTypeTemp, "CCW");
  2808.             }
  2809.             Dest.Ptr = DataTypeTemp;
  2810.             Dest.Type = pStringType;
  2811.             return true;
  2812.         case Direction:
  2813.             strcpy(DataTypeTemp, "FORWARDS");
  2814.             if (CIRCLE->Backward)
  2815.             {
  2816.                 strcpy(DataTypeTemp, "BACKWARDS");
  2817.             }
  2818.             Dest.Ptr  = DataTypeTemp;
  2819.             Dest.Type = pStringType;
  2820.             return true;
  2821.         case Clockwise:
  2822.             Dest.DWord = !CIRCLE->CCW;
  2823.             Dest.Type  = pBoolType;
  2824.             return true;
  2825.         case Backwards:
  2826.             Dest.DWord = CIRCLE->Backward;
  2827.             Dest.Type  = pBoolType;
  2828.             return true;
  2829.         case Radius:
  2830.             Dest.Float = CIRCLE->Radius;
  2831.             Dest.Type  = pFloatType;
  2832.             return true;
  2833.         }
  2834.         return false;
  2835.     }
  2836.  
  2837.     bool ToString(MQ2VARPTR VarPtr, char* Destination)
  2838.     {
  2839.         strcpy(Destination, "OFF");
  2840.         if (PAUSE->PausedMU || PAUSE->PausedCmd)
  2841.         {
  2842.             strcpy(Destination, "PAUSED");
  2843.         }
  2844.         else if (CIRCLE->On)
  2845.         {
  2846.             strcpy(Destination, "ON");
  2847.         }
  2848.         return true;
  2849.     }
  2850.  
  2851.     bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
  2852.     {
  2853.         return false;
  2854.     }
  2855.     bool FromString(MQ2VARPTR &VarPtr, char* Source)
  2856.     {
  2857.         return false;
  2858.     }
  2859. };
  2860.  
  2861. int dataCircling(char* szName, MQ2TYPEVAR &Ret)
  2862. {
  2863.     Ret.DWord = 1;
  2864.     Ret.Type  = pCircleType;
  2865.     return true;
  2866. }
  2867.  
  2868. class MQ2MoveUtilsType : public MQ2Type
  2869. {
  2870. public:
  2871.     enum MoveUtilsMembers
  2872.     {
  2873.         Command       = 1,
  2874.         Stuck         = 2,
  2875.         Summoned      = 3,
  2876.         StuckLogic    = 4,
  2877.         Verbosity     = 5,
  2878.         FullVerbosity = 6,
  2879.         TotalSilence  = 7,
  2880.         Aggro         = 8,
  2881.         PauseMinDelay = 9,
  2882.         PauseMaxDelay = 10,
  2883.         PulseCheck    = 11,
  2884.         PulseUnstuck  = 12,
  2885.         TryToJump     = 13,
  2886.         DistStuck     = 14,
  2887.         Version       = 15,
  2888.         MovePause     = 16,
  2889.         GM            = 17,
  2890.     };
  2891.  
  2892.     MQ2MoveUtilsType():MQ2Type("MoveUtils")
  2893.     {
  2894.         TypeMember(Command);
  2895.         TypeMember(Stuck);
  2896.         TypeMember(Summoned);
  2897.         TypeMember(StuckLogic);
  2898.         TypeMember(Verbosity);
  2899.         TypeMember(FullVerbosity);
  2900.         TypeMember(TotalSilence);
  2901.         TypeMember(Aggro);
  2902.         TypeMember(PauseMinDelay);
  2903.         TypeMember(PauseMaxDelay);
  2904.         TypeMember(PulseCheck);
  2905.         TypeMember(PulseUnstuck);
  2906.         TypeMember(TryToJump);
  2907.         TypeMember(DistStuck);
  2908.         TypeMember(Version);
  2909.         TypeMember(MovePause);
  2910.         TypeMember(GM);
  2911.     }
  2912.  
  2913.     bool GetMember(MQ2VARPTR VarPtr, char* Member, char* Index, MQ2TYPEVAR &Dest)
  2914.     {
  2915.         PMQ2TYPEMEMBER pMember = MQ2MoveUtilsType::FindMember(Member);
  2916.         if (!pMember || !ValidIngame(false)) return false;
  2917.         switch((MoveUtilsMembers)pMember->ID)
  2918.         {
  2919.         case Command:
  2920.             strcpy(DataTypeTemp, "NONE");
  2921.             if (STICK->On)
  2922.             {
  2923.                 strcpy(DataTypeTemp, "STICK");
  2924.             }
  2925.             else if (CIRCLE->On)
  2926.             {
  2927.                 strcpy(DataTypeTemp, "CIRCLE");
  2928.             }
  2929.             else if (MOVETO->On)
  2930.             {
  2931.                 strcpy(DataTypeTemp, "MOVETO");
  2932.             }
  2933.             else if (CURCAMP->On)
  2934.             {
  2935.                 strcpy(DataTypeTemp, "MAKECAMP");
  2936.             }
  2937.             Dest.Ptr  = DataTypeTemp;
  2938.             Dest.Type = pStringType;
  2939.             return true;
  2940.         case Stuck:
  2941.             Dest.DWord = false;
  2942.             if (STUCK->StuckInc)
  2943.             {
  2944.                 Dest.DWord = true;
  2945.             }
  2946.             Dest.Type = pBoolType;
  2947.             return true;
  2948.         case Summoned:
  2949.             Dest.DWord = pMU->BrokeSummon;
  2950.             Dest.Type  = pBoolType;
  2951.             return true;
  2952.         case StuckLogic:
  2953.             Dest.DWord = STUCK->On;
  2954.             Dest.Type  = pBoolType;
  2955.             return true;
  2956.         case Verbosity:
  2957.             Dest.DWord = (uiVerbLevel & V_VERBOSITY) == V_VERBOSITY ? true : false;
  2958.             Dest.Type  = pBoolType;
  2959.             return true;
  2960.         case FullVerbosity:
  2961.             Dest.DWord = (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY ? true : false;
  2962.             Dest.Type  = pBoolType;
  2963.             return true;
  2964.         case TotalSilence:
  2965.             Dest.DWord = (uiVerbLevel == V_SILENCE) ? true : false;
  2966.             Dest.Type  = pBoolType;
  2967.             return true;
  2968.         case Aggro:
  2969.             Dest.DWord = pMU->Aggro;
  2970.             Dest.Type  = pBoolType;
  2971.             return true;
  2972.         case PauseMinDelay:
  2973.             Dest.Int  = PAUSE->Min;
  2974.             Dest.Type = pIntType;
  2975.             return true;
  2976.         case PauseMaxDelay:
  2977.             Dest.Int  = PAUSE->Max;
  2978.             Dest.Type = pIntType;
  2979.             return true;
  2980.         case PulseCheck:
  2981.             Dest.Int  = STUCK->Check;
  2982.             Dest.Type = pIntType;
  2983.             return true;
  2984.         case PulseUnstuck:
  2985.             Dest.Int  = STUCK->Unstuck;
  2986.             Dest.Type = pIntType;
  2987.             return true;
  2988.         case TryToJump:
  2989.             Dest.DWord = STUCK->Jump;
  2990.             Dest.Type  = pBoolType;
  2991.             return true;
  2992.         case DistStuck:
  2993.             Dest.Float = STUCK->Dist;
  2994.             Dest.Type  = pFloatType;
  2995.             return true;
  2996.         case Version:
  2997.             sprintf(DataTypeTemp, "%1.4f", MODULE_VERSION);
  2998.             Dest.Ptr  = DataTypeTemp;
  2999.             Dest.Type = pStringType;
  3000.             return true;
  3001.         case MovePause:
  3002.             Dest.DWord = SET->PauseKB;
  3003.             Dest.Type  = pBoolType;
  3004.             return true;
  3005.         case GM:
  3006.             Dest.DWord = pMU->BrokeGM;
  3007.             Dest.Type  = pBoolType;
  3008.             return true;
  3009.         }
  3010.         return false;
  3011.     }
  3012.  
  3013.     bool ToString(MQ2VARPTR VarPtr, char* Destination)
  3014.     {
  3015.         strcpy(Destination, "NONE");
  3016.         if (STICK->On)
  3017.         {
  3018.             strcpy(Destination, "STICK");
  3019.         }
  3020.         else if (CIRCLE->On)
  3021.         {
  3022.             strcpy(Destination, "CIRCLE");
  3023.         }
  3024.         else if (MOVETO->On)
  3025.         {
  3026.             strcpy(Destination, "MOVETO");
  3027.         }
  3028.         else if (CURCAMP->On)
  3029.         {
  3030.             strcpy(Destination, "MAKECAMP");
  3031.         }
  3032.         return true;
  3033.     }
  3034.  
  3035.     bool FromData(MQ2VARPTR &VarPtr, MQ2TYPEVAR &Source)
  3036.     {
  3037.         return false;
  3038.     }
  3039.     bool FromString(MQ2VARPTR &VarPtr, char* Source)
  3040.     {
  3041.         return false;
  3042.     }
  3043. };
  3044.  
  3045. int dataMoveUtils(char* szName, MQ2TYPEVAR &Ret)
  3046. {
  3047.     Ret.DWord = 1;
  3048.     Ret.Type  = pMoveUtilsType;
  3049.     return true;
  3050. }
  3051.  
  3052. // End Custom Top-Level Objects
  3053. // -----------------------------
  3054. // Blech Events
  3055.  
  3056. void __stdcall CheckAggro_Event(unsigned int ID, void *pData, PBLECHVALUE pValues)
  3057. {
  3058.     // do not process if makecamp is on, as that would interfere with camp returns
  3059.     if (!ValidIngame() || CURCAMP->On) return;
  3060.     if (MOVETO->On && MOVETO->BreakHit)
  3061.     {
  3062.         pMU->MovetoBroke = true;
  3063.         sprintf(szMsg, "\ay%s\aw:: Aggro gained during /moveto, Halting command...", MODULE_NAME);
  3064.     }
  3065.     else if (STICK->On && STICK->BreakHit)
  3066.     {
  3067.         pMU->StickBroke = true;
  3068.         sprintf(szMsg, "\ay%s\aw:: Aggro gained during /stick, Halting command...", MODULE_NAME);
  3069.     }
  3070.     else
  3071.     {
  3072.         return;
  3073.     }
  3074.     EndPreviousCmd(true);
  3075.     WriteLine(szMsg, V_BREAKONHIT);
  3076. }
  3077.  
  3078. void __stdcall CheckGates_Event(unsigned int ID, void *pData, PBLECHVALUE pValues)
  3079. {
  3080.     if (!ValidIngame() || !STICK->On || !STICK->BreakGate) return;
  3081.     PSPAWNINFO psTarget = (PSPAWNINFO)((STICK->Hold && STICK->HoldID) ? GetSpawnByID(STICK->HoldID) : pTarget);
  3082.     if (psTarget && pValues)
  3083.     {
  3084.         if (!strcmp(pValues->Value, psTarget->DisplayedName))
  3085.         {
  3086.             EndPreviousCmd(true);
  3087.             sprintf(szMsg, "\ay%s\aw:: Mob gating ended previous command.", MODULE_NAME);
  3088.             WriteLine(szMsg, V_BREAKONGATE);
  3089.         }
  3090.     }
  3091. }
  3092.  
  3093. void SetupEvents(bool bAddEvent, bool bForceRemove)
  3094. {
  3095.     if (bAddEvent)
  3096.     {
  3097.         if (SET_M->BreakHit || MOVETO->BreakHit || SET_S->BreakHit || STICK->BreakHit)
  3098.         {
  3099.             if (!Event_AggroNorm)    Event_AggroNorm    = pMQ2Blech->AddEvent("#Name# #Hurts# YOU for #Damage#",          CheckAggro_Event);
  3100.             if (!Event_MissNorm)     Event_MissNorm     = pMQ2Blech->AddEvent("#Name# tries to #Hit# YOU, but #YouRock#", CheckAggro_Event);
  3101.             if (!Event_AggroAbbrev)  Event_AggroAbbrev  = pMQ2Blech->AddEvent("#Name# #Hurt#s for #Damage#",              CheckAggro_Event);
  3102.             if (!Event_MissAbbrev)   Event_MissAbbrev   = pMQ2Blech->AddEvent("#Name# missed",                            CheckAggro_Event);
  3103.             if (!Event_MissNumOnly)  Event_MissNumOnly  = pMQ2Blech->AddEvent("miss",                                     CheckAggro_Event);
  3104.             // not going to parse for just numbers as that would require parsing every line
  3105.             // and evaluating if its only numerical - this would be a bit over the top
  3106.         }
  3107.         if (SET_S->BreakGate || STICK->BreakGate)
  3108.         {
  3109.             if (!Event_Gates)        Event_Gates        = pMQ2Blech->AddEvent("#Name# Gates.",                            CheckGates_Event);
  3110.         }
  3111.     }
  3112.     else
  3113.     {
  3114.         if (bForceRemove || (!SET_M->BreakHit && !SET_S->BreakHit))
  3115.         {
  3116.             if (Event_AggroNorm)    pMQ2Blech->RemoveEvent(Event_AggroNorm);
  3117.             Event_AggroNorm = NULL;
  3118.  
  3119.             if (Event_MissNorm)     pMQ2Blech->RemoveEvent(Event_MissNorm);
  3120.             Event_MissNorm = NULL;
  3121.  
  3122.             if (Event_AggroAbbrev)  pMQ2Blech->RemoveEvent(Event_AggroAbbrev);
  3123.             Event_AggroAbbrev = NULL;
  3124.  
  3125.             if (Event_MissAbbrev)   pMQ2Blech->RemoveEvent(Event_MissAbbrev);
  3126.             Event_MissAbbrev = NULL;
  3127.  
  3128.             if (Event_MissNumOnly)  pMQ2Blech->RemoveEvent(Event_MissNumOnly);
  3129.             Event_MissNumOnly = NULL;
  3130.         }
  3131.         if (bForceRemove || !SET_S->BreakGate)
  3132.         {
  3133.             if (Event_Gates) pMQ2Blech->RemoveEvent(Event_Gates);
  3134.             Event_Gates = NULL;
  3135.         }
  3136.     }
  3137. }
  3138.  
  3139. // ----------------------------------------
  3140. // deadchicken formula functions
  3141.  
  3142.  
  3143. // CampReturn copyright: deadchicken
  3144. // not to be released outside of VIP without permission
  3145. inline void CampReturn(float fY, float fX, float fUseRadius, float* fUseY, float* fUseX)
  3146. {
  3147.     float fRandHead = rand() / RAND_MAX * CIRCLE_MAX;
  3148.     float fRandDist = rand() / RAND_MAX * fUseRadius;
  3149.  
  3150.     SpewDebug(DBG_MISC, "MoveUtils::CampReturn() fRandHead = %.2f, fRandDist = %.2f", fRandHead, fRandDist);
  3151.  
  3152.     *fUseY = fY + (fRandDist * cos(fRandHead));
  3153.     *fUseX = fX + (fRandDist * sin(fRandHead));
  3154. }
  3155.  
  3156. // PolarSpot copyright: deadchicken
  3157. // not to be released outside of VIP without permission
  3158. // MOB:  PolarSpot(targetX, targetY, targetHeading, desiredHeading, distanceAway, scatter);
  3159. // CAMP: PolarSpot(anchorX, anchorY, heading doesnt matter, bearing = which dir from center, dist = how far from center, scatter=size of scatter);
  3160. inline void PolarSpot(float fY, float fX, float fPHeading, float fPBearing, float fPDist, float fPScatter, float* fUseY, float* fUseX)
  3161. {
  3162.     // if camp returning
  3163.     if (fPScatter != 0.0f)
  3164.     {
  3165.         float fRandHead = MOVE->SaneHead(rand() / RAND_MAX * HEADING_MAX);
  3166.         float fRandDist = rand() / RAND_MAX * fPScatter;
  3167.  
  3168.         *fUseY = fY + (fRandDist * cos(fRandHead));
  3169.         *fUseX = fX + (fRandDist * sin(fRandHead));
  3170.  
  3171.         // 0.0175f converts degrees to radians which sinf/cosf expect
  3172.         /*fUseX = fOurGotoX + fRandDist * sinf(fRandHead*0.0175f));
  3173.         fUseY = fOurGotoY + fRandDist * cosf(fRandHead*0.0175f));*/
  3174.  
  3175.         return;
  3176.     }
  3177.     // else snaproll
  3178.  
  3179.     //float fRelHead = (fPHeading / fPBearing) * -(float)PI;
  3180.     //STICK->Snap->Y = fY  - (float)cos(fRelHead)* fPDist;
  3181.     //STICK->Snap->X = fX  + (float)sin(fRelHead)* fPDist;
  3182.     float fRelHead = MOVE->SaneHead(fPHeading - fPBearing);
  3183.     fRelHead       = ((fRelHead / HEADING_MAX) * CIRCLE_MAX) * 0.0175f;
  3184.     *fUseY         = fY + (fPDist * cos(fRelHead));
  3185.     *fUseX         = fX + (fPDist * sin(fRelHead));
  3186. }
  3187.  
  3188. // MovingAvg copyright: deadchicken
  3189. // not to be released outside of VIP without permission
  3190. // returns a moving average of size iEntries by adding fNew to the ring and computing
  3191. // fNew = New value to add to the ring
  3192. // iEntries = number of entries in ring, used for divisior and to re-init ring on change/init.
  3193. // Returns the moving average based on said values
  3194. // Notes: MaxRing size is 32 by #define up top and not checked, should be
  3195. float MovingAvg(float fNew, int iEntries)
  3196. {
  3197.     static float fRing[MAXRINGSIZE] = {0.0f};
  3198.     static int            iOldStuck = 0;
  3199.     static int              iRinger = 0;
  3200.     static int            iRingFull = 0;
  3201.            int                    i = 0;
  3202.          float                 fAvg = 0.0f;
  3203.  
  3204.     // Bounds checking
  3205.     if (iEntries > MAXRINGSIZE || iEntries < 2 ) return fNew;
  3206.     // Do we have a new ring size?
  3207.     if (iOldStuck != iEntries)
  3208.     {
  3209.         // Do some shit to make us right
  3210.         SpewDebug(DBG_MISC, "MoveUtils::MovingAvg() Entry # changed, filling ring with %3.2f!  %d != %d", fNew, iOldStuck, iEntries);
  3211.         // Fill the array with this latest value
  3212.         // maybe this should be our default preload value of 2.0f?
  3213.         for(i = 0; i < iEntries; i++) fRing[i] = fNew;
  3214.         // update iOldStuck and reset counter to 0
  3215.         iRinger   = 0;
  3216.         iOldStuck = iEntries;
  3217.         return fNew;
  3218.     }
  3219.     else
  3220.     {
  3221.         // Plain old ring buffer
  3222.         fRing[iRinger] = fNew;
  3223.         SpewDebug(DBG_MISC, "MoveUtils::MovingAvg() Added %3.2f to fRing[%d]", fNew, iRinger);
  3224.         // Increment iRinger and wrap if needed, if we wrap then it's full
  3225.         iRinger++;
  3226.         if (iRinger >= iEntries)
  3227.         {
  3228.             iRinger   = 0;
  3229.             iRingFull = 1;
  3230.         }
  3231.         // Get the sum of the ring
  3232.         //for( i=0; i<(iRingFull?iEntries:iRinger); i++) {  <-- this was a bad idea
  3233.         for(i = 0; i < iEntries; i++)
  3234.         {
  3235.             SpewDebug(DBG_MISC, "MoveUtils::MovingAvg() i=%d and fRing[%d]=%3.2f", i, i, fRing[i]);
  3236.             fAvg += fRing[i];
  3237.         }
  3238.     }
  3239.     return (fAvg / (float)iEntries);
  3240. }
  3241.  
  3242. // ----------------------------------------
  3243. // Utility
  3244. inline bool ValidIngame(bool bCheckDead)
  3245. {
  3246.     // CTD prevention function
  3247.     PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  3248.     if (GetGameState() != GAMESTATE_INGAME || !pLocalPlayer || !pChSpawn->SpawnID || !pMU || (bCheckDead && pChSpawn->RespawnTimer > 0))
  3249.     {
  3250.         return false;
  3251.     }
  3252.     return true;
  3253. }
  3254.  
  3255. char* ftoa(float fNum, char* szText)
  3256. {
  3257.     sprintf(szText, "%.2f", fNum);
  3258.     return szText;
  3259. }
  3260.  
  3261. // ----------------------------------------
  3262. // Begin user command handling
  3263.  
  3264. // ends active commands
  3265. void EndPreviousCmd(bool bStopMove, unsigned char ucCmdUsed, bool bPreserveSelf)
  3266. {
  3267.     //reset pause
  3268.     PAUSE->PausedMU = PAUSE->PausedCmd = false;
  3269.     PAUSE->TimeStop();
  3270.     PAUSE->Reset();
  3271.  
  3272.     // break any active commands
  3273.     if (ucCmdUsed != CMD_CIRCLE || !bPreserveSelf)
  3274.     {
  3275.         pMU->NewCircle();
  3276.     }
  3277.     if (ucCmdUsed != CMD_MOVETO || !bPreserveSelf)
  3278.     {
  3279.         pMU->NewMoveTo();
  3280.     }
  3281.     if (ucCmdUsed != CMD_STICK || !bPreserveSelf)
  3282.     {
  3283.         pMU->NewStick();
  3284.     }
  3285.  
  3286.     pMU->Defaults();
  3287.     MOVE->SetWalk(false);
  3288.     SetupEvents(false);
  3289.     if (bStopMove)
  3290.     {
  3291.         MOVE->StopHeading();
  3292.         MOVE->StopMove(APPLY_TO_ALL);
  3293.     }
  3294. }
  3295.  
  3296. // main MU command handler, called by wrappers
  3297. void HandleOurCmd(unsigned char ucCmdUsed, char* szInput)
  3298. {
  3299.     // don't allow commands from char select or cfg files that load before entering world
  3300.     if (!ValidIngame(false)) return;
  3301.  
  3302.     char szCurrentArg[MAX_STRING]       = {0};  // stores current argument from szInput
  3303.     char szTempID[MAX_STRING]           = {0};  // stores output msg for stick
  3304.     unsigned int uiArgNum               = 1;    // argument number to evaluate
  3305.     float fTempY                        = 0.0f; // store cmd input to temp var before setting to prevent inconsistency on failed input
  3306.  
  3307.     PSPAWNINFO pTargetUsed = NULL; // stick id, moveto id
  3308.     PSPAWNINFO pCampPlayer = NULL; // makecamp player
  3309.     PSPAWNINFO psTarget    = (PSPAWNINFO)pTarget;
  3310.     PSPAWNINFO pLPlayer    = (PSPAWNINFO)pLocalPlayer;
  3311.     PSPAWNINFO pChSpawn    = (PSPAWNINFO)pCharSpawn;
  3312.  
  3313.     // switch direction of turnhalf randomly
  3314.     if (rand() % 100 > 50) STUCK->TurnSize *= -1.0f;
  3315.     // call bardcheck function upon command usage instead of onpulse
  3316.     pMU->Bard = ME->IsBard();
  3317.     // reset state of ${MoveTo.Broken} upon next '/moveto' command
  3318.     if (ucCmdUsed == CMD_MOVETO)
  3319.     {
  3320.         // added moveto.stopped here as well
  3321.         pMU->StoppedMoveto = false;
  3322.         pMU->MovetoBroke   = false;
  3323.     }
  3324.     // reset state of ${Stick.Broken} upon next '/stick' command
  3325.     if (ucCmdUsed == CMD_STICK)
  3326.     {
  3327.         pMU->StickBroke = false;
  3328.     }
  3329.  
  3330.     // get first argument
  3331.     GetArg(szCurrentArg, szInput, uiArgNum++);
  3332.     // if no argument supplied
  3333.     if (!*szCurrentArg)
  3334.     {
  3335.         // halt all other commands due to BreakOnGM/BreakOnSummon
  3336.         if (pMU->BrokeGM || pMU->BrokeSummon)
  3337.         {
  3338.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to \ay%s\ax triggering.", MODULE_NAME, pMU->BrokeGM ? "BreakOnGM" : "BreakOnSummon");
  3339.             WriteLine(szMsg, V_SILENCE);
  3340.             return;
  3341.         }
  3342.         // halt all other commands due to rootme being on
  3343.         if (pMU->Rooted)
  3344.         {
  3345.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to \ayrootme\ax active.", MODULE_NAME);
  3346.             WriteLine(szMsg, V_SILENCE);
  3347.             return;
  3348.         }
  3349.         // halt new commands if plugin is paused & lockpause is on
  3350.         if (PAUSE->PausedCmd && pMU->LockPause)
  3351.         {
  3352.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to plugin paused with lockpause.", MODULE_NAME);
  3353.             WriteLine(szMsg, V_PAUSED);
  3354.             return;
  3355.         }
  3356.         PAUSE->PausedMU = false;
  3357.         switch(ucCmdUsed)
  3358.         {
  3359.         case CMD_MAKECAMP:
  3360.             if (!CURCAMP->On)
  3361.             {
  3362.                 PAUSE->TimeStop();
  3363.                 CAMP->Activate(pChSpawn->Y, pChSpawn->X);
  3364.                 sprintf(szMsg, "\ay%s\aw:: MakeCamp actived. Y(\ag%.2f\ax) X(\ag%.2f\ax) Radius(\ag%.2f\ax) Leash(%s) LeashLen(\ag%.2f\ax) Min(\ag%d\ax) Max(\ag%d\ax)", MODULE_NAME, CURCAMP->Y, CURCAMP->X, CURCAMP->Radius, CURCAMP->Leash ? "\agon\ax" : "\aroff\ax", CURCAMP->Length, CAMP->Min, CAMP->Max);
  3365.                 WriteLine(szMsg, V_MAKECAMPV);
  3366.                 break;
  3367.             }
  3368.             CAMP->ResetCamp(true);
  3369.             break;
  3370.         case CMD_STICK:
  3371.             EndPreviousCmd(true);
  3372.             if (psTarget)
  3373.             {
  3374.                 // prevent sticking to self/mount
  3375.                 if (ME->IsMe(psTarget))
  3376.                 {
  3377.                     SpewMUError(ERR_STICKSELF);
  3378.                     break;
  3379.                 }
  3380.                 STICK->TurnOn();
  3381.                 MOVE->DoStand();
  3382.                 sprintf(szMsg, "\ay%s\aw:: You are now sticking to \ag%s\ax.", MODULE_NAME, psTarget->DisplayedName);
  3383.                 WriteLine(szMsg, V_STICKV);
  3384.                 break;
  3385.             }
  3386.             SpewMUError(ERR_STICKNONE);
  3387.             break;
  3388.         case CMD_MOVETO:
  3389.         case CMD_CIRCLE:
  3390.         default:
  3391.             EndPreviousCmd(true);
  3392.             // possible future use, currently '/circle' and '/moveto' designed to fail
  3393.             sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) /moveto or /circle command used with no parameter.", MODULE_NAME);
  3394.             WriteLine(szMsg, V_ERRORS);
  3395.             break;
  3396.         }
  3397.         return;
  3398.     }
  3399.  
  3400.     if (*szCurrentArg)
  3401.     {
  3402.         // generic parameters that we want to enforce first-parameter syntax
  3403.         if (!strnicmp(szCurrentArg, "help", 5))
  3404.         {
  3405.             unsigned char ucCaller = ucCmdUsed;
  3406.             GetArg(szCurrentArg, szInput, uiArgNum);
  3407.             if (!strnicmp(szCurrentArg, "settings", 9))
  3408.             {
  3409.                 ucCaller = HELP_SETTINGS;
  3410.             }
  3411.             OutputHelp(ucCaller);
  3412.             return;
  3413.         }
  3414.         else if (!strnicmp(szCurrentArg, "debug", 6))
  3415.         {
  3416.             DebugToINI(ucCmdUsed);
  3417.             sprintf(szMsg, "\ay%s\aw:: Debug file created.", MODULE_NAME);
  3418.             WriteLine(szMsg, V_SAVED);
  3419.             return;
  3420.         }
  3421.         else if (!strnicmp(szCurrentArg, "status", 7))
  3422.         {
  3423.             GetArg(szCurrentArg, szInput, uiArgNum);
  3424.             if (!strnicmp(szCurrentArg, "all", 4))
  3425.             {
  3426.                 DebugToWnd(APPLY_TO_ALL);
  3427.                 return;
  3428.             }
  3429.             DebugToWnd(ucCmdUsed);
  3430.             return;
  3431.         }
  3432.         else if (!strnicmp(szCurrentArg, "pause", 6))
  3433.         {
  3434.             bool bDisplayLock = false;
  3435.             GetArg(szCurrentArg, szInput, uiArgNum);
  3436.             if (!strnicmp(szCurrentArg, "lock", 5))
  3437.             {
  3438.                 pMU->LockPause = true;
  3439.                 bDisplayLock = true;
  3440.             }
  3441.             if (!PAUSE->PausedCmd)
  3442.             {
  3443.                 PAUSE->PausedCmd = true;
  3444.                 PAUSE->TimeStop();
  3445.                 MOVE->StopHeading();
  3446.                 MOVE->StopMove(APPLY_TO_ALL);
  3447.                 sprintf(szMsg, "\ay%s\aw:: \arPAUSED\ax%s", MODULE_NAME, pMU->LockPause ? " \ayLOCKED" : "");
  3448.                 WriteLine(szMsg, V_PAUSED);
  3449.                 return;
  3450.             }
  3451.             if (!bDisplayLock)
  3452.             {
  3453.                 sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Plugin was already paused.", MODULE_NAME);
  3454.                 WriteLine(szMsg, V_ERRORS);
  3455.             }
  3456.             else
  3457.             {
  3458.                 sprintf(szMsg, "\ay%s\aw:: Pause \ayLOCKED", MODULE_NAME);
  3459.                 WriteLine(szMsg, V_PAUSED);
  3460.             }
  3461.             return;
  3462.         }
  3463.         else if (!strnicmp(szCurrentArg, "unpause", 8))
  3464.         {
  3465.             if (PAUSE->PausedMU || PAUSE->PausedCmd)
  3466.             {
  3467.                 PAUSE->PausedMU = PAUSE->PausedCmd = false;
  3468.                 pMU->LockPause = SET->LockPause; // reset one-time usage if non-default
  3469.                 PAUSE->TimeStop();
  3470.                 PAUSE->Reset();
  3471.                 sprintf(szMsg, "\ay%s\aw:: \agRESUMED", MODULE_NAME);
  3472.                 WriteLine(szMsg, V_PAUSED);
  3473.                 return;
  3474.             }
  3475.             if (!bWrapped)
  3476.             {
  3477.                 sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Plugin was not paused.", MODULE_NAME);
  3478.                 WriteLine(szMsg, V_ERRORS);
  3479.             }
  3480.             bWrapped = false; // cheap fix
  3481.             return;
  3482.         }
  3483.         else if (!strnicmp(szCurrentArg, "save", 5))
  3484.         {
  3485.             SaveConfig();
  3486.             sprintf(szMsg, "\ay%s\aw:: Saved settings to %s", MODULE_NAME, INIFileName);
  3487.             WriteLine(szMsg, V_SAVED);
  3488.             return;
  3489.         }
  3490.         else if (!strnicmp(szCurrentArg, "load", 5))
  3491.         {
  3492.             EndPreviousCmd(true);
  3493.             LoadConfig();
  3494.             sprintf(szMsg, "\ay%s\aw:: Loaded settings from %s", MODULE_NAME, INIFileName);
  3495.             WriteLine(szMsg, V_SAVED);
  3496.             return;
  3497.         }
  3498.         else if (!strnicmp(szCurrentArg, "imsafe", 7))
  3499.         {
  3500.             pMU->BrokeSummon = pMU->BrokeGM = false;
  3501.             EndPreviousCmd(true);
  3502.             sprintf(szMsg, "\ay%s\aw:: Command usage allowed once again.", MODULE_NAME);
  3503.             WriteLine(szMsg, V_SILENCE);
  3504.             return;
  3505.         }
  3506.         else if (!strnicmp(szCurrentArg, "set", 4))
  3507.         {
  3508.             char szTempSet[MAX_STRING] = {0};
  3509.             sprintf(szTempSet, "%s", GetNextArg(szInput, 1, FALSE, 0));
  3510.             ChangeSetting(ucCmdUsed, false, szTempSet);
  3511.             return;
  3512.         }
  3513.         else if (!strnicmp(szCurrentArg, "toggle", 7))
  3514.         {
  3515.             char szTempSet[MAX_STRING] = {0};
  3516.             sprintf(szTempSet, "%s", GetNextArg(szInput, 1, FALSE, 0));
  3517.             ChangeSetting(ucCmdUsed, true, szTempSet);
  3518.             return;
  3519.         }
  3520.         else if (!strnicmp(szCurrentArg, "min", 4))
  3521.         {
  3522.             WINDOW->Min();
  3523.             return;
  3524.         }
  3525.         else if (!strnicmp(szCurrentArg, "clear", 6))
  3526.         {
  3527.             WINDOW->Clear();
  3528.             return;
  3529.         }
  3530.         else if (!strnicmp(szCurrentArg, "verbflags", 10))
  3531.         {
  3532.             sprintf(szMsg, "\ay%s\aw:: Current verbosity flags \ag%d", MODULE_NAME, uiVerbLevel);
  3533.             WriteLine(szMsg, V_SILENCE);
  3534.             return;
  3535.         }
  3536.  
  3537.         // halt all other commands due to BreakOnGM/BreakOnSummon
  3538.         if (pMU->BrokeGM || pMU->BrokeSummon)
  3539.         {
  3540.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to \ay%s\ax triggering.", MODULE_NAME, pMU->BrokeGM ? "BreakOnGM" : "BreakOnSummon");
  3541.             WriteLine(szMsg, V_SILENCE);
  3542.             return;
  3543.         }
  3544.         // halt all other commands due to rootme being on
  3545.         if (pMU->Rooted)
  3546.         {
  3547.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to \ayrootme\ax active.", MODULE_NAME);
  3548.             WriteLine(szMsg, V_SILENCE);
  3549.             return;
  3550.         }
  3551.         // halt new commands if plugin is paused & lockpause is on
  3552.         if (PAUSE->PausedCmd && pMU->LockPause)
  3553.         {
  3554.             sprintf(szMsg, "\ay%s\aw:: \arCommand failed due to plugin paused with lockpause.", MODULE_NAME);
  3555.             WriteLine(szMsg, V_PAUSED);
  3556.             return;
  3557.         }
  3558.  
  3559.         // non-generic parameters that we want to enforce first-parameter syntax
  3560.         if (!strnicmp(szCurrentArg, "on", 3) && (ucCmdUsed == CMD_MAKECAMP || ucCmdUsed == CMD_CIRCLE))
  3561.         {
  3562.             switch (ucCmdUsed)
  3563.             {
  3564.             case CMD_MAKECAMP:
  3565.                 PAUSE->PausedMU = false;
  3566.                 PAUSE->TimeStop();
  3567.                 CAMP->Activate(pChSpawn->Y, pChSpawn->X);
  3568.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  3569.                 if (isdigit(szCurrentArg[0]))
  3570.                 {
  3571.                     CURCAMP->SetRadius((float)atof(szCurrentArg));
  3572.                     GetArg(szCurrentArg, szInput, uiArgNum); // because when we break from this we enter 'while' for NEW args
  3573.                 }
  3574.                 break;
  3575.             case CMD_CIRCLE:
  3576.                 EndPreviousCmd(true);
  3577.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  3578.                 if (isdigit(szCurrentArg[0]))
  3579.                 {
  3580.                     CIRCLE->SetRadius((float)atof(szCurrentArg));
  3581.                     GetArg(szCurrentArg, szInput, uiArgNum); // because when we break from this we enter 'while' for NEW args
  3582.                 }
  3583.                 CIRCLE->AtMe();
  3584.                 break;
  3585.             }
  3586.         }
  3587.         else if (!strnicmp(szCurrentArg, "mod", 4) && ucCmdUsed == CMD_STICK)
  3588.         {
  3589.             GetArg(szCurrentArg, szInput, uiArgNum++);
  3590.             if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3591.             {
  3592.                 STICK->DistMod = (float)atof(szCurrentArg);
  3593.                 sprintf(szMsg, "\ay%s\aw:: Stick modifier changed to Mod(\ag%.2f\ax) Mod%%(\ag%.2f%%\ax)", MODULE_NAME, STICK->DistMod, STICK->DistModP);
  3594.                 WriteLine(szMsg, V_SETTINGS);
  3595.                 return;
  3596.             }
  3597.             sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) \ay/stick mod [#]\ax supplied incorrectly.", MODULE_NAME);
  3598.             WriteLine(szMsg, V_ERRORS);
  3599.             return;
  3600.         }
  3601.         else if(!strnicmp(szCurrentArg, "loc", 4) && ucCmdUsed != CMD_STICK)
  3602.         {
  3603.             GetArg(szCurrentArg, szInput, uiArgNum++);
  3604.             switch (ucCmdUsed)
  3605.             {
  3606.             case CMD_MOVETO:
  3607.                 EndPreviousCmd(true);
  3608.                 if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3609.                 {
  3610.                     fTempY = (float)atof(szCurrentArg);
  3611.                     GetArg(szCurrentArg, szInput, uiArgNum++);
  3612.                     if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3613.                     {
  3614.                         float fTempX = (float)atof(szCurrentArg);
  3615.                         GetArg(szCurrentArg, szInput, uiArgNum++);
  3616.                         if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3617.                         {
  3618.                             MOVETO->Activate(fTempY, fTempX, (float)atof(szCurrentArg));
  3619.                             GetArg(szCurrentArg, szInput, uiArgNum);
  3620.                             break;
  3621.                         }
  3622.                         MOVETO->Activate(fTempY, fTempX, 0.0f);
  3623.                         break;
  3624.                     }
  3625.                 }
  3626.                 SpewMUError(ERR_BADMOVETO);
  3627.                 return;
  3628.             case CMD_MAKECAMP:
  3629.                 PAUSE->PausedMU = false;
  3630.                 PAUSE->TimeStop();
  3631.                 if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3632.                 {
  3633.                     fTempY = (float)atof(szCurrentArg);
  3634.                     GetArg(szCurrentArg, szInput, uiArgNum++);
  3635.                     if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3636.                     {
  3637.                         CAMP->Activate(fTempY, (float)atof(szCurrentArg));
  3638.                         GetArg(szCurrentArg, szInput, uiArgNum);
  3639.                         break;
  3640.                     }
  3641.                 }
  3642.                 SpewMUError(ERR_BADMAKECAMP);
  3643.                 return;
  3644.             case CMD_CIRCLE:
  3645.                 EndPreviousCmd(true, ucCmdUsed, true); // dont reset circle variables
  3646.                 if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3647.                 {
  3648.                     fTempY = (float)atof(szCurrentArg);
  3649.                     GetArg(szCurrentArg, szInput, uiArgNum++);
  3650.                     if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.')
  3651.                     {
  3652.                         CIRCLE->AtLoc(fTempY, (float)atof(szCurrentArg));
  3653.                         GetArg(szCurrentArg, szInput, uiArgNum);
  3654.                         break;
  3655.                     }
  3656.                 }
  3657.                 SpewMUError(ERR_BADCIRCLE);
  3658.                 return;
  3659.             }
  3660.         }
  3661.         else if((!strnicmp(szCurrentArg, "yloc", 5) || !strnicmp(szCurrentArg, "xloc", 5)) && ucCmdUsed == CMD_MOVETO)
  3662.         {
  3663.             bool bUsingY = (!strnicmp(szCurrentArg, "yloc", 5)) ? true : false;
  3664.             EndPreviousCmd(true);
  3665.             GetArg(szCurrentArg, szInput, uiArgNum++);
  3666.             if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '-' || szCurrentArg[0] == '.' )
  3667.             {
  3668.                 if (bUsingY)
  3669.                 {
  3670.                     MOVETO->Activate((float)atof(szCurrentArg), pChSpawn->X, 0.0f);
  3671.                 }
  3672.                 else
  3673.                 {
  3674.                     MOVETO->Activate(pChSpawn->Y, (float)atof(szCurrentArg), 0.0f);
  3675.                 }
  3676.                 GetArg(szCurrentArg, szInput, uiArgNum);
  3677.             }
  3678.             else
  3679.             {
  3680.                 sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) \ay/moveto %s\ax was supplied incorrectly.", MODULE_NAME, bUsingY ? "yloc [Y]" : "xloc [X]");
  3681.                 WriteLine(szMsg, V_ERRORS);
  3682.                 return;
  3683.             }
  3684.         }
  3685.  
  3686.         // reset stick vars one time
  3687.         if (ucCmdUsed == CMD_STICK)
  3688.         {
  3689.             EndPreviousCmd(true);
  3690.         }
  3691.     }
  3692.  
  3693.     while (*szCurrentArg)
  3694.     {
  3695.         if (!strnicmp(szCurrentArg, "off", 4))
  3696.         {
  3697.             switch(ucCmdUsed)
  3698.             {
  3699.             case CMD_MAKECAMP:
  3700.                 CAMP->ResetCamp(true);
  3701.                 MOVE->StopHeading();
  3702.                 return;
  3703.             case CMD_STICK:
  3704.                 sprintf(szMsg, "\ay%s\aw:: You are no longer sticking to anything.", MODULE_NAME);
  3705.                 WriteLine(szMsg, V_STICKV);
  3706.                 break;
  3707.             case CMD_CIRCLE:
  3708.                 sprintf(szMsg, " \ay%s\aw:: Circling radius (\ag%.2f\ax), center (\ag%.2f\ax, \ag%.2f\ax) : \arOFF", MODULE_NAME, CIRCLE->Radius, CIRCLE->Y, CIRCLE->X);
  3709.                 WriteLine(szMsg, V_CIRCLEV);
  3710.                 break;
  3711.             case CMD_MOVETO:
  3712.                 sprintf(szMsg, "\ay%s\aw:: Moveto off.", MODULE_NAME);
  3713.                 WriteLine(szMsg, V_MOVETOV);
  3714.                 break;
  3715.             }
  3716.             EndPreviousCmd(true);
  3717.             return;
  3718.         }
  3719.         else if (!strnicmp(szCurrentArg, "id", 3) && ucCmdUsed != CMD_MAKECAMP)
  3720.         {
  3721.             EndPreviousCmd(true, ucCmdUsed, true);
  3722.             PSPAWNINFO pByID = NULL;
  3723.             GetArg(szCurrentArg, szInput, uiArgNum);
  3724.             if (*szCurrentArg)
  3725.             {
  3726.                 char* pNotNum = NULL;
  3727.                 int iValid = strtoul(szCurrentArg, &pNotNum, 10);
  3728.                 // strtoul verifies the arg is 100% numerical, atoi/atof do not
  3729.                 if (iValid < 1 || *pNotNum)
  3730.                 {
  3731.                     EndPreviousCmd(true);
  3732.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) SpawnID must be a positive numerical value.", MODULE_NAME);
  3733.                     WriteLine(szMsg, V_ERRORS);
  3734.                     return;
  3735.                 }
  3736.                 pByID = (PSPAWNINFO)GetSpawnByID((unsigned long)iValid);
  3737.                 if (pByID)
  3738.                 {
  3739.                     if (ME->IsMe(pByID))
  3740.                     {
  3741.                         EndPreviousCmd(true);
  3742.                         sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You cannot use yourself or your mount.", MODULE_NAME);
  3743.                         WriteLine(szMsg, V_ERRORS);
  3744.                         return;
  3745.                     }
  3746.                     pTargetUsed = (PSPAWNINFO)pByID;
  3747.                     uiArgNum++; // incremeted if # is valid, but not otherwise so that someone can use '/stick id behind' to use target. bad form but nonetheless
  3748.                 }
  3749.                 else
  3750.                 {
  3751.                     pTargetUsed = NULL;
  3752.                 }
  3753.             }
  3754.             else if (psTarget)
  3755.             {
  3756.                 if (ME->IsMe(psTarget))
  3757.                 {
  3758.                     SpewMUError(ERR_BADSPAWN);
  3759.                     return;
  3760.                 }
  3761.                 pTargetUsed = psTarget; // only use target if its not ourself
  3762.             }
  3763.             if (!pTargetUsed)
  3764.             {
  3765.                 SpewMUError(ERR_BADSPAWN);
  3766.                 return;
  3767.             }
  3768.             //if we've made it this far, pTargetUsed is valid
  3769.             switch (ucCmdUsed)
  3770.             {
  3771.             case CMD_STICK:
  3772.                 STICK->Always   = false; // turns off 'always' when using 'id'
  3773.                 STICK->HoldID   = pTargetUsed->SpawnID;
  3774.                 STICK->HoldType = GetSpawnType(pTargetUsed);
  3775.                 STICK->Hold     = true;
  3776.                 STICK->TurnOn();
  3777.                 break;
  3778.             case CMD_MOVETO:
  3779.                 // moveto id with GetDistance3D is causing some users issues
  3780.                 MOVETO->Activate(pTargetUsed->Y, pTargetUsed->X, 0.0f);
  3781.                 break;
  3782.             case CMD_CIRCLE:
  3783.                 CIRCLE->AtLoc(pTargetUsed->Y, pTargetUsed->X);
  3784.                 break;
  3785.             }
  3786.         }
  3787.         // stick specific parameters
  3788.         else if (ucCmdUsed == CMD_STICK)
  3789.         {
  3790.             if (strstr(szCurrentArg, "%"))
  3791.             {
  3792.                 STICK->DistModP = (float)atof(szCurrentArg) / 100.0f;
  3793.                 // shouldnt do this here, need logic to output this only if used by itself
  3794.                 // cant do it on an 'else' for the pTarget 'if' because of 'always' param
  3795.                 sprintf(szMsg, "\ay%s\aw:: Stick mod changed Mod(\ag%.2f\ax) ModPercent(\ag%.2f%%\ax)", MODULE_NAME, STICK->DistMod, STICK->DistModP);
  3796.                 WriteLine(szMsg, V_SETTINGS);
  3797.                 if (STICK->SetDist && STICK->Dist * STICK->DistModP > 0.0f) STICK->Dist *= STICK->DistModP; // possible float math error here?
  3798.                 STICK->TurnOn();
  3799.             }
  3800.             else if (szCurrentArg[0] == '-')
  3801.             {
  3802.                 STICK->DistMod = (float)atof(szCurrentArg);
  3803.                 sprintf(szMsg, "\ay%s\aw:: Stick mod changed Mod(\ag%.2f\ax) ModPercent(\ag%.2f%%\ax)", MODULE_NAME, STICK->DistMod, STICK->DistModP);
  3804.                 WriteLine(szMsg, V_SETTINGS);
  3805.                 if (STICK->SetDist && STICK->Dist + STICK->DistMod >= 0.0f) STICK->Dist += STICK->DistMod; // possible float math error here?
  3806.                 STICK->TurnOn();
  3807.             }
  3808.             else if (isdigit(szCurrentArg[0]) || szCurrentArg[0] == '.' )
  3809.             {
  3810.                 if ((float)atof(szCurrentArg) * STICK->DistModP + STICK->DistMod > 0.0f)
  3811.                 {
  3812.                     STICK->Dist = (float)atof(szCurrentArg) * STICK->DistModP + STICK->DistMod;
  3813.                 }
  3814.                 STICK->SetDist = true;
  3815.                 STICK->TurnOn();
  3816.             }
  3817.             else if (!strnicmp(szCurrentArg, "moveback", 9))
  3818.             {
  3819.                 STICK->MoveBack = true;
  3820.                 STICK->TurnOn();
  3821.             }
  3822.             else if (!strnicmp(szCurrentArg, "loose", 6))
  3823.             {
  3824.                 pMU->Head = H_LOOSE;
  3825.                 STICK->TurnOn();
  3826.             }
  3827.             else if (!strnicmp(szCurrentArg, "truehead", 9))
  3828.             {
  3829.                 pMU->Head = H_TRUE;
  3830.                 STICK->TurnOn();
  3831.             }
  3832.             else if (!strnicmp(szCurrentArg, "healer", 7))
  3833.             {
  3834.                 STICK->Healer = true;
  3835.                 STICK->Behind = STICK->BehindOnce = STICK->Front = STICK->Snaproll = false;
  3836.                 STICK->NotFront = STICK->Pin = false;
  3837.                 STICK->TurnOn();
  3838.             }
  3839.             else if (!strnicmp(szCurrentArg, "uw", 3) || !strnicmp(szCurrentArg, "underwater", 11))
  3840.             {
  3841.                 STICK->UW = true;
  3842.                 STICK->TurnOn();
  3843.             }
  3844.             else if (!strnicmp(szCurrentArg, "hold", 5))
  3845.             {
  3846.                 if (psTarget)
  3847.                 {
  3848.                     if (ME->IsMe(psTarget))
  3849.                     {
  3850.                         sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You cannot stick hold to yourself.", MODULE_NAME);
  3851.                         WriteLine(szMsg, V_ERRORS);
  3852.                         EndPreviousCmd(true);
  3853.                         return;
  3854.                     }
  3855.                     pTargetUsed     = (PSPAWNINFO)psTarget;
  3856.                     STICK->HoldID   = pTargetUsed->SpawnID;
  3857.                     STICK->HoldType = GetSpawnType(pTargetUsed);
  3858.                     STICK->Hold     = true;
  3859.                     STICK->TurnOn();
  3860.                 }
  3861.                 else
  3862.                 {
  3863.                     EndPreviousCmd(true);
  3864.                     SpewMUError(ERR_STICKNONE);
  3865.                     return;
  3866.                 }
  3867.             }
  3868.             else if (!strnicmp(szCurrentArg, "on", 3))
  3869.             {
  3870.                 // useless param, but removing it breaks popular macros
  3871.                 STICK->TurnOn();
  3872.             }
  3873.             else if (!strnicmp(szCurrentArg, "behind", 7))
  3874.             {
  3875.                 STICK->Behind = true;
  3876.                 STICK->Healer = STICK->Snaproll = STICK->BehindOnce = STICK->Pin = STICK->NotFront = STICK->Front = false;
  3877.                 STICK->TurnOn();
  3878.             }
  3879.             else if (!strnicmp(szCurrentArg, "behindonce", 11))
  3880.             {
  3881.                 STICK->BehindOnce = true;
  3882.                 STICK->Healer = STICK->Snaproll = STICK->Behind = STICK->Pin = STICK->NotFront = STICK->Front = false;
  3883.                 STICK->TurnOn();
  3884.             }
  3885.             else if (!strnicmp(szCurrentArg, "!front", 7))
  3886.             {
  3887.                 STICK->NotFront = true;
  3888.                 STICK->Healer = STICK->Snaproll = STICK->Behind = STICK->Pin = STICK->BehindOnce = STICK->Front = false;
  3889.                 STICK->TurnOn();
  3890.             }
  3891.             else if (!strnicmp(szCurrentArg, "front", 6))
  3892.             {
  3893.                 STICK->Front = true;
  3894.                 STICK->Healer = STICK->Snaproll = STICK->Behind = STICK->Pin = STICK->BehindOnce = STICK->NotFront = false;
  3895.                 STICK->TurnOn();
  3896.             }
  3897.             else if (!strnicmp(szCurrentArg, "pin", 4))
  3898.             {
  3899.                 STICK->Pin = true;
  3900.                 STICK->Healer = STICK->Snaproll = STICK->Behind = STICK->BehindOnce = STICK->NotFront = STICK->Front = false;
  3901.                 STICK->TurnOn();
  3902.             }
  3903.             else if (!strnicmp(szCurrentArg, "snaproll", 9))
  3904.             {
  3905.                 STICK->Snaproll = true;
  3906.                 STICK->Healer = STICK->Behind = STICK->BehindOnce = STICK->NotFront = STICK->Front = STICK->Pin = false;
  3907.                 STICK->Snap->Bearing = HEADING_HALF;
  3908.                 GetArg(szCurrentArg, szInput, uiArgNum);
  3909.                 if (!strnicmp(szCurrentArg, "face", 6))
  3910.                 {
  3911.                     uiArgNum++;
  3912.                     STICK->Snap->Bearing = 1.0f;
  3913.                 }
  3914.                 else if (!strnicmp(szCurrentArg, "left", 5))
  3915.                 {
  3916.                     uiArgNum++;
  3917.                     STICK->Snap->Bearing = HEADING_QUARTER;
  3918.                 }
  3919.                 else if (!strnicmp(szCurrentArg, "right", 6))
  3920.                 {
  3921.                     uiArgNum++;
  3922.                     STICK->Snap->Bearing = (HEADING_HALF + HEADING_QUARTER);
  3923.                 }
  3924.                 else if (!strnicmp(szCurrentArg, "rear", 5))
  3925.                 {
  3926.                     uiArgNum++; // uses HEADING_HALF (set above)
  3927.                 }
  3928.                 STICK->TurnOn();
  3929.             }
  3930.             else if (!strnicmp(szCurrentArg, "breakontarget", 14))
  3931.             {
  3932.                 STICK->BreakTarget = true;
  3933.                 STICK->TurnOn();
  3934.             }
  3935.             else if (!strnicmp(szCurrentArg, "breakongate", 12))
  3936.             {
  3937.                 STICK->BreakGate = true;
  3938.                 SetupEvents(true);
  3939.                 STICK->TurnOn();
  3940.             }
  3941.             else if (!strnicmp(szCurrentArg, "breakonwarp", 12))
  3942.             {
  3943.                 STICK->BreakWarp = true;
  3944.                 STICK->PauseWarp = false;
  3945.                 STICK->TurnOn();
  3946.             }
  3947.             else if (!strnicmp(szCurrentArg, "breakonhit", 11))
  3948.             {
  3949.                 STICK->BreakHit = true;
  3950.                 SetupEvents(true);
  3951.                 STICK->TurnOn();
  3952.             }
  3953.             else if (!strnicmp(szCurrentArg, "pauseonwarp", 12))
  3954.             {
  3955.                 STICK->PauseWarp = true;
  3956.                 STICK->BreakWarp = false;
  3957.                 STICK->TurnOn();
  3958.             }
  3959.             else if (!strnicmp(szCurrentArg, "randomize", 10))
  3960.             {
  3961.                 STICK->Randomize = true;
  3962.                 STICK->TurnOn();
  3963.             }
  3964.             else if (!strnicmp(szCurrentArg, "delaystrafe", 12))
  3965.             {
  3966.                 STICK->DelayStrafe = true;
  3967.                 STICK->TurnOn();
  3968.             }
  3969.             else if (!strnicmp(szCurrentArg, "useback", 8))
  3970.             {
  3971.                 STICK->UseBack = true;
  3972.                 STICK->TurnOn();
  3973.             }
  3974.             else if (!strnicmp(szCurrentArg, "usefleeing", 11))
  3975.             {
  3976.                 STICK->UseFleeing = true;
  3977.                 STICK->TurnOn();
  3978.             }
  3979.             else if (!strnicmp(szCurrentArg, "useflex", 8))
  3980.             {
  3981.                 STICK->Flex = true;
  3982.                 STICK->TurnOn();
  3983.             }
  3984.             else if (!strnicmp(szCurrentArg, "strafewalk", 11))
  3985.             {
  3986.                 STICK->Walk = true;
  3987.                 STICK->TurnOn();
  3988.             }
  3989.             else if (!strnicmp(szCurrentArg, "mindelay", 9) || !strnicmp(szCurrentArg, "maxdelay", 9))
  3990.             {
  3991.                 bool bDoMax = !strnicmp(szCurrentArg, "maxdelay", 9) ? true : false;
  3992.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  3993.                 if (isdigit(szCurrentArg[0]))
  3994.                 {
  3995.                     if (bDoMax)
  3996.                     {
  3997.                         STICK->MaxDelay(atoi(szCurrentArg));
  3998.                     }
  3999.                     else
  4000.                     {
  4001.                         STICK->MinDelay(atoi(szCurrentArg));
  4002.                     }
  4003.                     STICK->TurnOn();
  4004.                 }
  4005.                 else
  4006.                 {
  4007.                     EndPreviousCmd(true);
  4008.                     SpewMUError(ERR_BADDELAY);
  4009.                     return;
  4010.                 }
  4011.             }
  4012.             else if (!strnicmp(szCurrentArg, "backupdist", 11))
  4013.             {
  4014.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4015.                 if ((float)atof(szCurrentArg) > 1.0f)
  4016.                 {
  4017.                     STICK->DistBack = (float)atof(szCurrentArg);
  4018.                     STICK->TurnOn();
  4019.                 }
  4020.                 else
  4021.                 {
  4022.                     EndPreviousCmd(true);
  4023.                     sprintf(szMsg, "\ay%s\aw:: \arbackupdist must be 1.0 or larger.", MODULE_NAME);
  4024.                     WriteLine(szMsg, V_ERRORS);
  4025.                     return;
  4026.                 }
  4027.             }
  4028.             else if (!strnicmp(szCurrentArg, "breakdist", 10))
  4029.             {
  4030.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4031.                 if ((float)atof(szCurrentArg) > 1.0f)
  4032.                 {
  4033.                     STICK->DistBreak = (float)atof(szCurrentArg);
  4034.                     STICK->TurnOn();
  4035.                 }
  4036.                 else
  4037.                 {
  4038.                     sprintf(szMsg, "\ay%s\aw:: \arbreakdist must be 1.0 or larger.", MODULE_NAME);
  4039.                     WriteLine(szMsg, V_ERRORS);
  4040.                     return;
  4041.                 }
  4042.             }
  4043.             else if (!strnicmp(szCurrentArg, "snapdist", 9))
  4044.             {
  4045.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4046.                 if ((float)atof(szCurrentArg) > 1.0f)
  4047.                 {
  4048.                     STICK->DistSnap = (float)atof(szCurrentArg);
  4049.                     STICK->TurnOn();
  4050.                 }
  4051.                 else
  4052.                 {
  4053.                     EndPreviousCmd(true);
  4054.                     sprintf(szMsg, "\ay%s\aw:: \arsnapdist must be 1.0 or larger.", MODULE_NAME);
  4055.                     WriteLine(szMsg, V_ERRORS);
  4056.                     return;
  4057.                 }
  4058.             }
  4059.             else if (!strnicmp(szCurrentArg, "flexdist", 9))
  4060.             {
  4061.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4062.                 if ((float)atof(szCurrentArg) >= 2.0f && (float)atof(szCurrentArg) <= 20.0f)
  4063.                 {
  4064.                     STICK->DistFlex = (float)atof(szCurrentArg);
  4065.                     STICK->TurnOn();
  4066.                 }
  4067.                 else
  4068.                 {
  4069.                     EndPreviousCmd(true);
  4070.                     sprintf(szMsg, "\ay%s\aw:: \arflexdist must be between 2.0 and 20.0.", MODULE_NAME);
  4071.                     WriteLine(szMsg, V_ERRORS);
  4072.                     return;
  4073.                 }
  4074.             }
  4075.             else if (!strnicmp(szCurrentArg, "!frontarc", 10))
  4076.             {
  4077.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4078.                 if ((float)atof(szCurrentArg) > 1.0f && (float)atof(szCurrentArg) <= 260.0f)
  4079.                 {
  4080.                     STICK->ArcNotFront = (float)atof(szCurrentArg);
  4081.                     STICK->TurnOn();
  4082.                 }
  4083.                 else
  4084.                 {
  4085.                     EndPreviousCmd(true);
  4086.                     sprintf(szMsg, "\ay%s\aw:: \ar!frontarc must be between 1.0 and 260.0", MODULE_NAME);
  4087.                     WriteLine(szMsg, V_ERRORS);
  4088.                     return;
  4089.                 }
  4090.             }
  4091.             else if (!strnicmp(szCurrentArg, "behindarc", 10))
  4092.             {
  4093.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4094.                 if ((float)atof(szCurrentArg) > 1.0f && (float)atof(szCurrentArg) <= 260.0f)
  4095.                 {
  4096.                     STICK->ArcBehind = (float)atof(szCurrentArg);
  4097.                     STICK->TurnOn();
  4098.                 }
  4099.                 else
  4100.                 {
  4101.                     EndPreviousCmd(true);
  4102.                     sprintf(szMsg, "\ay%s\aw:: \arbehindarc must be between 1.0 and 260.0", MODULE_NAME);
  4103.                     WriteLine(szMsg, V_ERRORS);
  4104.                     return;
  4105.                 }
  4106.             }
  4107.             else if (!strnicmp(szCurrentArg, "always", 7))
  4108.             {
  4109.                 STICK->FirstAlways();
  4110.                 sprintf(szMsg, "\ay%s\aw:: You will now stick to every valid NPC target supplied.", MODULE_NAME);
  4111.                 WriteLine(szMsg, V_STICKV);
  4112.                 MOVE->DoStand();
  4113.                 return; // 'always' must be the last parameter
  4114.             }
  4115.             else
  4116.             {
  4117.                 EndPreviousCmd(true);
  4118.                 if (uiVerbLevel != 0 && (uiVerbLevel & V_HIDEHELP) != V_HIDEHELP) OutputHelp(ucCmdUsed, true);
  4119.                 return;
  4120.             }
  4121.         }
  4122.         // moveto specific parameters
  4123.         else if (ucCmdUsed == CMD_MOVETO)
  4124.         {
  4125.             if (!strnicmp(szCurrentArg, "loose", 6))
  4126.             {
  4127.                 pMU->Head = H_LOOSE;
  4128.             }
  4129.             else if (!strnicmp(szCurrentArg, "truehead", 9))
  4130.             {
  4131.                 pMU->Head = H_TRUE;
  4132.             }
  4133.             else if (!strnicmp(szCurrentArg, "dist", 5))
  4134.             {
  4135.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4136.                 if (szCurrentArg[0] == '-')
  4137.                 {
  4138.                     MOVETO->Mod = (float)atof(szCurrentArg);
  4139.                     MOVETO->Dist += MOVETO->Mod;
  4140.                 }
  4141.                 else if (isdigit(szCurrentArg[0]))
  4142.                 {
  4143.                     MOVETO->Dist = ((float)atof(szCurrentArg) >= 1.0f) ? (float)atof(szCurrentArg) : MOVETO->Dist;
  4144.                 }
  4145.                 else
  4146.                 {
  4147.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Incorrectly used \ay/moveto dist [#]\ax", MODULE_NAME);
  4148.                     WriteLine(szMsg, V_ERRORS);
  4149.                     return;
  4150.                 }
  4151.                 SET_M->Dist = MOVETO->Dist;
  4152.                 SET_M->Mod  = MOVETO->Mod;
  4153.                 sprintf(szMsg, "\ay%s\aw:: Moveto distance mod changed to \ag%.2f\ax.", MODULE_NAME, MOVETO->Dist);
  4154.                 WriteLine(szMsg, V_SETTINGS);
  4155.                 return;
  4156.             }
  4157.             else if (!strnicmp(szCurrentArg, "mdist", 6))
  4158.             {
  4159.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4160.                 if (szCurrentArg[0] == '-')
  4161.                 {
  4162.                     MOVETO->Mod = (float)atof(szCurrentArg);
  4163.                     MOVETO->Dist += MOVETO->Mod;
  4164.                 }
  4165.                 else if (isdigit(szCurrentArg[0]))
  4166.                 {
  4167.                     MOVETO->Dist = ((float)atof(szCurrentArg) >= 1.0f) ? (float)atof(szCurrentArg) : MOVETO->Dist;
  4168.                 }
  4169.                 else
  4170.                 {
  4171.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Incorrectly used \ay/moveto mdist [#]\ax", MODULE_NAME);
  4172.                     WriteLine(szMsg, V_ERRORS);
  4173.                     return;
  4174.                 }
  4175.                 SET_M->Dist = MOVETO->Dist;
  4176.                 SET_M->Mod  = MOVETO->Mod;
  4177.             }
  4178.             else if (!strnicmp(szCurrentArg, "precisey", 9))
  4179.             {
  4180.                 MOVETO->PreciseY = true;
  4181.                 MOVETO->PreciseX = false;
  4182.             }
  4183.             else if (!strnicmp(szCurrentArg, "precisex", 9))
  4184.             {
  4185.                 MOVETO->PreciseX = true;
  4186.                 MOVETO->PreciseY = false;
  4187.             }
  4188.             else if (!strnicmp(szCurrentArg, "uw", 3) || !strnicmp(szCurrentArg, "underwater", 11))
  4189.             {
  4190.                 MOVETO->UW = true;
  4191.             }
  4192.             else if (!strnicmp(szCurrentArg, "breakonaggro", 13))
  4193.             {
  4194.                 MOVETO->BreakAggro = true;
  4195.                 SetupEvents(true);
  4196.             }
  4197.             else if (!strnicmp(szCurrentArg, "breakonhit", 11))
  4198.             {
  4199.                 MOVETO->BreakHit = true;
  4200.                 SetupEvents(true);
  4201.             }
  4202.             else if (!strnicmp(szCurrentArg, "usewalk", 8))
  4203.             {
  4204.                 MOVETO->Walk = true;
  4205.             }
  4206.             else if (!strnicmp(szCurrentArg, "useback", 8))
  4207.             {
  4208.                 MOVETO->UseBack = true;
  4209.             }
  4210.             else if (!strnicmp(szCurrentArg, "backupdist", 11))
  4211.             {
  4212.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4213.                 if ((float)atof(szCurrentArg) > 1.0f)
  4214.                 {
  4215.                     MOVETO->DistBack = (float)atof(szCurrentArg);
  4216.                 }
  4217.                 else
  4218.                 {
  4219.                     sprintf(szMsg, "\ay%s\aw:: \armoveto backup must be 1.0 or larger.", MODULE_NAME);
  4220.                     WriteLine(szMsg, V_ERRORS);
  4221.                     return;
  4222.                 }
  4223.             }
  4224.             else if (!strnicmp(szCurrentArg, "ydist", 6))
  4225.             {
  4226.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4227.                 if ((float)atof(szCurrentArg) > 1.0f)
  4228.                 {
  4229.                     MOVETO->DistY = (float)atof(szCurrentArg);
  4230.                 }
  4231.                 else
  4232.                 {
  4233.                     sprintf(szMsg, "\ay%s\aw:: \armoveto ydist must be 1.0 or larger.", MODULE_NAME);
  4234.                     WriteLine(szMsg, V_ERRORS);
  4235.                     return;
  4236.                 }
  4237.             }
  4238.             else if (!strnicmp(szCurrentArg, "xdist", 6))
  4239.             {
  4240.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4241.                 if ((float)atof(szCurrentArg) > 1.0f)
  4242.                 {
  4243.                     MOVETO->DistX = (float)atof(szCurrentArg);
  4244.                 }
  4245.                 else
  4246.                 {
  4247.                     sprintf(szMsg, "\ay%s\aw:: \armoveto xdist must be 1.0 or larger.", MODULE_NAME);
  4248.                     WriteLine(szMsg, V_ERRORS);
  4249.                     return;
  4250.                 }
  4251.             }
  4252.             else
  4253.             {
  4254.                 EndPreviousCmd(true);
  4255.                 if (uiVerbLevel != 0 && (uiVerbLevel & V_HIDEHELP) != V_HIDEHELP) OutputHelp(ucCmdUsed, true);
  4256.                 return;
  4257.             }
  4258.         }
  4259.         // makecamp specific parameters
  4260.         else if (ucCmdUsed == CMD_MAKECAMP)
  4261.         {
  4262.             if (!strnicmp(szCurrentArg, "leash", 6))
  4263.             {
  4264.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4265.                 if (isdigit(szCurrentArg[0]))
  4266.                 {
  4267.                     CURCAMP->SetLeash((float)atof(szCurrentArg));
  4268.                     CURCAMP->Leash = true;
  4269.                 }
  4270.                 else
  4271.                 {
  4272.                     CURCAMP->Leash = !CURCAMP->Leash;
  4273.                 }
  4274.             }
  4275.             else if (!strnicmp(szCurrentArg, "radius", 7))
  4276.             {
  4277.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4278.                 if (isdigit(szCurrentArg[0]))
  4279.                 {
  4280.                     CURCAMP->SetRadius((float)atof(szCurrentArg));
  4281.                 }
  4282.                 else
  4283.                 {
  4284.                     CAMP->NewCamp(false);
  4285.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) \ay/makecamp [radius <dist>]\ax was supplied incorrectly.", MODULE_NAME);
  4286.                     WriteLine(szMsg, V_ERRORS);
  4287.                     return;
  4288.                 }
  4289.             }
  4290.             else if (!strnicmp(szCurrentArg, "mindelay", 9) || !strnicmp(szCurrentArg, "maxdelay", 9))
  4291.             {
  4292.                 bool bDoMax = !strnicmp(szCurrentArg, "maxdelay", 9) ? true : false;
  4293.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4294.                 if (isdigit(szCurrentArg[0]))
  4295.                 {
  4296.                     if (bDoMax)
  4297.                     {
  4298.                         CAMP->MaxDelay(atoi(szCurrentArg));
  4299.                     }
  4300.                     else
  4301.                     {
  4302.                         CAMP->MinDelay(atoi(szCurrentArg));
  4303.                     }
  4304.                 }
  4305.                 else
  4306.                 {
  4307.                     CAMP->NewCamp(false);
  4308.                     SpewMUError(ERR_BADDELAY);
  4309.                     return;
  4310.                 }
  4311.             }
  4312.             else if (!strnicmp(szCurrentArg, "return", 7))
  4313.             {
  4314.                 if (!CURCAMP->On)
  4315.                 {
  4316.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You do not have an active camp.", MODULE_NAME);
  4317.                     WriteLine(szMsg, V_ERRORS);
  4318.                     return;
  4319.                 }
  4320.                 CAMP->DoReturn = true;
  4321.                 MOVE->DoStand();
  4322.                 sprintf(szMsg, "\ay%s\aw:: MakeCamp returning to within camp radius immediately.", MODULE_NAME);
  4323.                 WriteLine(szMsg, V_MAKECAMPV);
  4324.                 return;
  4325.             }
  4326.             else if (!strnicmp(szCurrentArg, "altreturn", 10))
  4327.             {
  4328.                 if (CURCAMP->Pc)
  4329.                 {
  4330.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You cannot use this command with a player-camp active.", MODULE_NAME);
  4331.                     WriteLine(szMsg, V_ERRORS);
  4332.                     return;
  4333.                 }
  4334.                 if (!ALTCAMP->On || (ALTCAMP->X == 0.0f && ALTCAMP->Y == 0.0f))
  4335.                 {
  4336.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You cannot use this command until you've established an altcamp location.", MODULE_NAME);
  4337.                     WriteLine(szMsg, V_ERRORS);
  4338.                     return;
  4339.                 }
  4340.                 sprintf(szMsg, "\ay%s\aw:: MakeCamp returning to altcamp immediately.%s", MODULE_NAME, CURCAMP->On ? " Current camp now \arOFF\ax." : "");
  4341.                 CAMP->NewCamp(false);
  4342.                 CAMP->DoAlt = true;
  4343.                 MOVE->DoStand();
  4344.                 WriteLine(szMsg, V_MAKECAMPV);
  4345.                 return;
  4346.             }
  4347.             else if (!strnicmp(szCurrentArg, "player", 7))
  4348.             {
  4349.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4350.                 if (*szCurrentArg)
  4351.                 {
  4352.                     pCampPlayer = (PSPAWNINFO)GetSpawnByName(szCurrentArg);
  4353.                 }
  4354.                 else if (psTarget && psTarget->Type == SPAWN_PLAYER)
  4355.                 {
  4356.                     pCampPlayer = (PSPAWNINFO)GetSpawnByID(psTarget->SpawnID);
  4357.                 }
  4358.                 if (!pCampPlayer)
  4359.                 {
  4360.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Invalid player name and do not have a valid player target.", MODULE_NAME);
  4361.                     WriteLine(szMsg, V_ERRORS);
  4362.                     return;
  4363.                 }
  4364.                 if (ME->IsMe(pCampPlayer))
  4365.                 {
  4366.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) You cannot makecamp yourself.", MODULE_NAME);
  4367.                     WriteLine(szMsg, V_ERRORS);
  4368.                     return;
  4369.                 }
  4370.                 // if we made it this far, pCampPlayer is valid
  4371.                 CAMP->ActivatePC(pCampPlayer);
  4372.             }
  4373.             else if (!strnicmp(szCurrentArg, "returnhavetarget", 17))
  4374.             {
  4375.                 CURCAMP->HaveTarget = true;
  4376.             }
  4377.             else if (!strnicmp(szCurrentArg, "returnnoaggro", 14))
  4378.             {
  4379.                 CURCAMP->NoAggro = true;
  4380.             }
  4381.             else if (!strnicmp(szCurrentArg, "returnnotlooting", 17))
  4382.             {
  4383.                 CURCAMP->NotLoot = true;
  4384.             }
  4385.             else if (!strnicmp(szCurrentArg, "realtimeplayer", 15))
  4386.             {
  4387.                 CURCAMP->Realtime = true;
  4388.             }
  4389.             else if (!strnicmp(szCurrentArg, "scatter", 8))
  4390.             {
  4391.                 CURCAMP->Scatter = true;
  4392.             }
  4393.             else if (!strnicmp(szCurrentArg, "bearing", 8))
  4394.             {
  4395.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4396.                 if (isdigit(szCurrentArg[0]))
  4397.                 {
  4398.                     CURCAMP->Bearing = (float)atof(szCurrentArg);
  4399.                 }
  4400.                 else
  4401.                 {
  4402.                     CAMP->NewCamp(false);
  4403.                     sprintf(szMsg, "\ay%s\aw:: \armakecamp bearing parameter must be a number.", MODULE_NAME);
  4404.                     WriteLine(szMsg, V_ERRORS);
  4405.                     return;
  4406.                 }
  4407.             }
  4408.             else if (!strnicmp(szCurrentArg, "scatsize", 9))
  4409.             {
  4410.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4411.                 if ((float)atof(szCurrentArg) > 1.0f)
  4412.                 {
  4413.                     CURCAMP->ScatSize = (float)atof(szCurrentArg);
  4414.                 }
  4415.                 else
  4416.                 {
  4417.                     CAMP->NewCamp(false);
  4418.                     sprintf(szMsg, "\ay%s\aw:: \armakecamp scatsize must be 1.0 or larger.", MODULE_NAME);
  4419.                     WriteLine(szMsg, V_ERRORS);
  4420.                     return;
  4421.                 }
  4422.             }
  4423.             else if (!strnicmp(szCurrentArg, "scatdist", 9))
  4424.             {
  4425.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4426.                 if ((float)atof(szCurrentArg) > 1.0f)
  4427.                 {
  4428.                     CURCAMP->ScatDist = (float)atof(szCurrentArg);
  4429.                 }
  4430.                 else
  4431.                 {
  4432.                     CAMP->NewCamp(false);
  4433.                     sprintf(szMsg, "\ay%s\aw:: \armakecamp scatdist must be 1.0 or larger.", MODULE_NAME);
  4434.                     WriteLine(szMsg, V_ERRORS);
  4435.                     return;
  4436.                 }
  4437.             }
  4438.             else
  4439.             {
  4440.                 // reset camp on failed input?
  4441.                 if (uiVerbLevel != 0 && (uiVerbLevel & V_HIDEHELP) != V_HIDEHELP) OutputHelp(ucCmdUsed, true);
  4442.                 return;
  4443.             }
  4444.         }
  4445.         // circle specific parameters
  4446.         else if (ucCmdUsed == CMD_CIRCLE)
  4447.         {
  4448.             if (!strnicmp(szCurrentArg, "drunken", 8))
  4449.             {
  4450.                 CIRCLE->Drunk = true;
  4451.             }
  4452.             else if (!strnicmp(szCurrentArg, "clockwise", 10) || !strnicmp(szCurrentArg, "cw", 3))
  4453.             {
  4454.                 CIRCLE->CCW = false;
  4455.             }
  4456.             else if (!strnicmp(szCurrentArg, "ccw", 4) || !strnicmp(szCurrentArg, "counterclockwise", 17) || !strnicmp(szCurrentArg, "reverse", 8))
  4457.             {
  4458.                 CIRCLE->CCW = true;
  4459.             }
  4460.             else if (!strnicmp(szCurrentArg, "forward", 7)) // allow 's'
  4461.             {
  4462.                 CIRCLE->Backward = false;
  4463.             }
  4464.             else if (!strnicmp(szCurrentArg, "backward", 8)) // allow 's'
  4465.             {
  4466.                 CIRCLE->Backward = true;
  4467.             }
  4468.             else if (!strnicmp(szCurrentArg, "radius", 7))
  4469.             {
  4470.                 GetArg(szCurrentArg, szInput, uiArgNum++);
  4471.                 if (isdigit(szCurrentArg[0]))
  4472.                 {
  4473.                     CIRCLE->SetRadius((float)atof(szCurrentArg));
  4474.                     GetArg(szCurrentArg, szInput, uiArgNum);
  4475.                 }
  4476.                 else
  4477.                 {
  4478.                     sprintf(szMsg, "\ay%s\aw:: (\arERROR\ax) Use \ay/circle radius [#]\ax to set radius.", MODULE_NAME);
  4479.                     WriteLine(szMsg, V_ERRORS);
  4480.                     return;
  4481.                 }
  4482.             }
  4483.             else
  4484.             {
  4485.                 EndPreviousCmd(true);
  4486.                 if (uiVerbLevel != 0 && (uiVerbLevel & V_HIDEHELP) != V_HIDEHELP) OutputHelp(ucCmdUsed, true);
  4487.                 return;
  4488.             }
  4489.         }
  4490.         // no valid parameter given
  4491.         else
  4492.         {
  4493.             EndPreviousCmd(true);
  4494.             if (uiVerbLevel != 0 && (uiVerbLevel & V_HIDEHELP) != V_HIDEHELP) OutputHelp(ucCmdUsed);
  4495.             return;
  4496.         }
  4497.         GetArg(szCurrentArg, szInput, uiArgNum++);
  4498.     }
  4499.  
  4500.     // Output Messages
  4501.     char szTempHead[50] = {0};
  4502.     switch (pMU->Head)
  4503.     {
  4504.     case H_TRUE:
  4505.         sprintf(szTempHead, "\agTrue\ax");
  4506.         break;
  4507.     case H_LOOSE:
  4508.         sprintf(szTempHead, "\ayLoose\ax");
  4509.         break;
  4510.     case H_FAST:
  4511.     default:
  4512.         sprintf(szTempHead, "\arFast\ax");
  4513.         break;
  4514.     }
  4515.  
  4516.     if (ucCmdUsed == CMD_STICK)
  4517.     {
  4518.         if (!STICK->Hold)
  4519.         {
  4520.             if (!psTarget)
  4521.             {
  4522.                 // dont continue if no target unless 'always' (returns) or 'id || hold'
  4523.                 EndPreviousCmd(true);
  4524.                 SpewMUError(ERR_STICKNONE);
  4525.                 return;
  4526.             }
  4527.             // if self targeted and not 'always' or 'id || hold'
  4528.             if (ME->IsMe(psTarget))
  4529.             {
  4530.                 EndPreviousCmd(true);
  4531.                 SpewMUError(ERR_STICKSELF);
  4532.                 return;
  4533.             }
  4534.             // else setup output msg
  4535.             sprintf(szTempID, "%s", psTarget->DisplayedName);
  4536.         }
  4537.         else if (pTargetUsed || (STICK->Hold && psTarget))
  4538.         {
  4539.             // setup output msg for 'id || hold'
  4540.             sprintf(szTempID, "%s", pTargetUsed->DisplayedName);
  4541.         }
  4542.         else
  4543.         {
  4544.             // error checking in command line parsing should prevent this from ever happening
  4545.             // if user reports this error, needs investigation
  4546.             EndPreviousCmd(true);
  4547.             char szTempOut[MAX_STRING] = {0};
  4548.             sprintf(szTempOut, "\ay%s\aw:: \ar/stick NO TARGET ERROR", MODULE_NAME);
  4549.             WriteLine(szTempOut, V_SILENCE);
  4550.             return;
  4551.         }
  4552.  
  4553.         // randomize arcs
  4554.         STICK->DoRandomize();
  4555.  
  4556.         char szDir[25] = "\agAny\ax";
  4557.         if (STICK->Behind)
  4558.         {
  4559.             sprintf(szDir, "\ayBehind\ax");
  4560.         }
  4561.         else if (STICK->Pin)
  4562.         {
  4563.             sprintf(szDir, "\aySide\ax");
  4564.         }
  4565.         else if (STICK->NotFront)
  4566.         {
  4567.             sprintf(szDir, "\ayNot Front\ax");
  4568.         }
  4569.         else if (STICK->Front)
  4570.         {
  4571.             sprintf(szDir, "\ayFront\ax");
  4572.         }
  4573.  
  4574.         char szTempHold[25] = {0};
  4575.         if (STICK->Hold && pTargetUsed) sprintf(szTempHold, " ID(\ay%d\ax)", pTargetUsed->SpawnID);
  4576.         char szTempMod[50] = {0};
  4577.         bool bOutputMod = false;
  4578.         if (STICK->DistMod != 0.0f)
  4579.         {
  4580.             bOutputMod = true;
  4581.             if (STICK->DistModP != 1.0f)
  4582.             {
  4583.                 sprintf(szTempMod, "Mod(\ag%.2f\ax | \ag%.2f%%\ax) ", STICK->DistMod, STICK->DistModP);
  4584.             }
  4585.             else
  4586.             {
  4587.                 sprintf(szTempMod, "Mod(\ag%.2f\ax) ", STICK->DistMod);
  4588.             }
  4589.         }
  4590.         else if (STICK->DistModP != 1.0f)
  4591.         {
  4592.             bOutputMod = true;
  4593.             sprintf(szTempMod, "Mod(\ag%.2f%%\ax) ", STICK->DistModP);
  4594.         }
  4595.  
  4596.         if (STICK->Behind || STICK->BehindOnce || STICK->Pin || STICK->NotFront) STICK->Strafe = true;
  4597.         sprintf(szMsg, "\ay%s\aw:: You are now sticking to %s.", MODULE_NAME, szTempID);
  4598.         WriteLine(szMsg, V_STICKV);
  4599.         sprintf(szMsg, "\ay%s\aw:: Dir(%s) Dist(\ag%.2f\ax) %sHead(%s)%s%s%s%s", MODULE_NAME, szDir, STICK->Dist, bOutputMod ? szTempMod : "", szTempHead, STICK->Hold ? szTempHold : "", STICK->UW ? " \agUW\ax" : "", STICK->MoveBack ? " \agMB\ax" : "", STICK->Healer ? " \agHEALER\ax" : "");
  4600.         WriteLine(szMsg, V_STICKFV);
  4601.     }
  4602.     else if (ucCmdUsed == CMD_MOVETO)
  4603.     {
  4604.         char szInfoY[35] = {0};
  4605.         char szInfoX[35] = {0};
  4606.         char szZInfo[35] = {0};
  4607.         sprintf(szZInfo, " %.2f.", MOVETO->Z);
  4608.         sprintf(szInfoY, " YDist(\ag%.2f\ax)", MOVETO->DistY);
  4609.         sprintf(szInfoX, " XDist(\ag%.2f\ax)", MOVETO->DistX);
  4610.         sprintf(szMsg, "\ay%s\aw:: Moving to loc %.2f %.2f%s  Dist(\ag%.2f\ax) Head(%s)%s", MODULE_NAME, MOVETO->Y, MOVETO->X, MOVETO->Z != 0.0f ? szZInfo : ".", MOVETO->Dist, szTempHead, MOVETO->PreciseY ? szInfoY : (MOVETO->PreciseX ? szInfoX : ""));
  4611.         WriteLine(szMsg, V_MOVETOV);
  4612.     }
  4613.     else if (ucCmdUsed == CMD_CIRCLE)
  4614.     {
  4615.         sprintf(szMsg, " \ay%s\aw:: Circling radius (\ag%.2f\ax), center (\ag%.2f\ax, \ag%.2f\ax)%s%s%s - Head(%s) : %s", MODULE_NAME, CIRCLE->Radius, CIRCLE->Y, CIRCLE->X, CIRCLE->CCW ? ", Reverse" : "", CIRCLE->Backward ? ", Backwards" : "", CIRCLE->Drunk ? ", \agDrunken\ax" : "", szTempHead, CIRCLE->On ? "\agON" : "\arOFF");
  4616.         WriteLine(szMsg, V_CIRCLEV);
  4617.     }
  4618.     else if (ucCmdUsed == CMD_MAKECAMP)
  4619.     {
  4620.         if (!CURCAMP->Pc)
  4621.         {
  4622.             sprintf(szMsg, "\ay%s\aw:: MakeCamp (%s). Y(\ag%.2f\ax) X(\ag%.2f\ax) Radius(\ag%.2f\ax) Leash(%s - \ag%.2f\ax) Delay(\ag%d\ax to \ag%d\ax)", MODULE_NAME, CURCAMP->On ? "\agon\ax" : "\aroff\ax", CURCAMP->Y, CURCAMP->X, CURCAMP->Radius, CURCAMP->Leash ? "\agon\ax" : "\aroff\ax", CURCAMP->Length, CAMP->Min, CAMP->Max);
  4623.         }
  4624.         else
  4625.         {
  4626.             sprintf(szMsg, "\ay%s\aw:: MakeCamp Player (\ag%s\ax). Radius(\ag%.2f\ax) Leash(%s - \ag%.2f\ax) Delay(\ag%d\ax to \ag%d\ax)", MODULE_NAME, CURCAMP->PcName, CURCAMP->Radius, CURCAMP->Leash ? "\agon\ax" : "\aroff\ax", CURCAMP->Length, CAMP->Min, CAMP->Max);
  4627.         }
  4628.         WriteLine(szMsg, V_MAKECAMPV);
  4629.         return; // return so makecamp doesnt stand up
  4630.     }
  4631.  
  4632.     bWrapped = false;
  4633.     MOVE->DoStand();
  4634. }
  4635.  
  4636.  
  4637. // exported wrapper for MQ2Melee support
  4638. void StickCommand(PSPAWNINFO pLPlayer, char* szLine)
  4639. {
  4640.     bWrapped = true;
  4641.     HandleOurCmd(CMD_STICK, szLine);
  4642. }
  4643.  
  4644. // main command wrappers
  4645. void StickWrapper(PSPAWNINFO pLPlayer, char* szLine)
  4646. {
  4647.     HandleOurCmd(CMD_STICK, szLine);
  4648.     bRunNextCommand = true;
  4649. }
  4650. void MoveToWrapper(PSPAWNINFO pLPlayer, char* szLine)
  4651. {
  4652.     HandleOurCmd(CMD_MOVETO, szLine);
  4653.     bRunNextCommand = true;
  4654. }
  4655. void CircleWrapper(PSPAWNINFO pLPlayer, char* szLine)
  4656. {
  4657.     HandleOurCmd(CMD_CIRCLE, szLine);
  4658.     bRunNextCommand = true;
  4659. }
  4660. void MakeCampWrapper(PSPAWNINFO pLPlayer, char* szLine)
  4661. {
  4662.     HandleOurCmd(CMD_MAKECAMP, szLine);
  4663.     bRunNextCommand = true;
  4664. }
  4665.  
  4666. // calcangle command
  4667. void CalcOurAngle(PSPAWNINFO pLPlayer, char* szLine)
  4668. {
  4669.     if (!ValidIngame() || !pTarget) return;
  4670.     PSPAWNINFO psTarget = (PSPAWNINFO)pTarget;
  4671.     PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  4672.     float fAngle   = MOVE->AngDist(psTarget->Heading, pChSpawn->Heading);
  4673.     float fReqHead = MOVE->SaneHead(atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * HEADING_HALF / (float)PI);
  4674.     fReqHead = pChSpawn->Heading - fReqHead;
  4675.     float fMeleeRng = get_melee_range(pLocalPlayer, (EQPlayer *)psTarget);
  4676.     float fStickRng = fMeleeRng * STICK->DistModP + STICK->DistMod;
  4677.     float fSaneH = MOVE->SaneHead(fReqHead);
  4678.     float fDist   = GetDistance(pChSpawn, psTarget);
  4679.     float fDist3D = GetDistance3D(pChSpawn->X, pChSpawn->Y, pChSpawn->Z, psTarget->X, psTarget->Y, psTarget->Z);
  4680.     char szTempOut[MAX_STRING] = {0};
  4681.     sprintf(szTempOut, "\ay%s\aw:: AngularDist ( \ag%.2f\ax ) Adjust ( \ag%.2f\ax ) Sane ( \ag%.2f\ax ) Dist ( \ag%.2f\ax ) Dist3D ( \ag%.2f\ax ) Melee ( \ag%f\ax ) Stick ( \ag%f\ax)", MODULE_NAME, fAngle, fReqHead, fSaneH, fDist, fDist3D, fMeleeRng, fStickRng);
  4682.     WriteChatf(szTempOut);
  4683.     sprintf(szTempOut, " - Walking ( %s )  RunSpeed ( \ag%.2f\ax ) SpeedMultiplier ( \ag%.2f\ax )", (*EQADDR_RUNWALKSTATE) ? "\arno\ax" : "\agyes\ax", pChSpawn->RunSpeed, pChSpawn->SpeedMultiplier);
  4684.     WriteChatf(szTempOut);
  4685. }
  4686.  
  4687. // root command
  4688. void RootCmd(PSPAWNINFO pLPlayer, char* szLine)
  4689. {
  4690.     if (!ValidIngame()) return;
  4691.     char szTempOut[MAX_STRING] = {0};
  4692.  
  4693.     if (SET->WinEQ || bOffsetOverride)
  4694.     {
  4695.         sprintf(szTempOut, "\ay%s\aw:: \arUnable to use this command due to use of old movement type.", MODULE_NAME);
  4696.         WriteLine(szTempOut, V_SILENCE);
  4697.         return;
  4698.     }
  4699.  
  4700.     char szArg1[MAX_STRING]    = {0};
  4701.     GetArg(szArg1, szLine, 1);
  4702.     if (!strnicmp(szArg1, "off", 4))
  4703.     {
  4704.         MOVE->StopRoot();
  4705.     }
  4706.     else
  4707.     {
  4708.         EndPreviousCmd(true);
  4709.         CAMP->NewCamp(CURCAMP->On);
  4710.         pMU->Rooted    = true;
  4711.         MOVE->RootHead = ((PSPAWNINFO)pCharSpawn)->Heading;
  4712.         sprintf(szTempOut, "\ay%s\aw:: You are now rooted in place.", MODULE_NAME);
  4713.         WriteLine(szTempOut, V_SILENCE);
  4714.     }
  4715. }
  4716.  
  4717. // End user command input handling
  4718. // ----------------------------------------
  4719. // settings - saved to INI
  4720.  
  4721. bool ToggleSetting(const char* pszToggleOutput, bool* pbEvalThis, bool* pbUsedToggle, bool* pbTurnOn)
  4722. {
  4723.     char szTheMsg[MAX_STRING] = {0};
  4724.  
  4725.     // setting we are changing = did we use 'toggle' ? setting toggled ELSE set to 'on' or 'off'
  4726.     *pbEvalThis = *pbUsedToggle ? !*pbEvalThis : *pbTurnOn;
  4727.     sprintf(szTheMsg, "\ay%s\aw:: %s turned %s", MODULE_NAME, pszToggleOutput, *pbEvalThis ? szOn : szOff);
  4728.     WriteLine(szTheMsg, V_SETTINGS);
  4729.     return *pbEvalThis; // changesetting is only evaluating
  4730. }
  4731.  
  4732. void ChangeSetting(unsigned char ucCmdUsed, bool bToggle, char szSetting[MAX_STRING])
  4733. {
  4734.     char szCommand[MAX_STRING] = {0};
  4735.     switch(ucCmdUsed)
  4736.     {
  4737.     case CMD_MAKECAMP:
  4738.         sprintf(szCommand, "/makecamp");
  4739.         break;
  4740.     case CMD_STICK:
  4741.         sprintf(szCommand, "/stick");
  4742.         break;
  4743.     case CMD_MOVETO:
  4744.         sprintf(szCommand, "/moveto");
  4745.         break;
  4746.     case CMD_CIRCLE:
  4747.         sprintf(szCommand, "/circle");
  4748.         break;
  4749.     default:
  4750.         return;
  4751.     }
  4752.  
  4753.     char szParameter[MAX_STRING] = {0};
  4754.     char szSetState[MAX_STRING]  = {0};
  4755.     char szSetDigit[MAX_STRING]  = {0};
  4756.     char szSetError[MAX_STRING]  = {0};
  4757.     bool bTurnOn                 = false;
  4758.     bool bSetDigit               = false;
  4759.     bool bCustomMsg              = false;
  4760.     unsigned int uiArgNum        = 1;
  4761.  
  4762.     GetArg(szParameter, szSetting, uiArgNum++);
  4763.  
  4764.     // check for valid parameter if "set" used (on, off, number)
  4765.     if (!bToggle)
  4766.     {
  4767.         GetArg(szSetState, szSetting, uiArgNum);
  4768.         if (isdigit(szSetState[0]) || szSetState[0] == '.' || szSetState[0] == '-')
  4769.         {
  4770.             bSetDigit = true;
  4771.             sprintf(szSetDigit, szSetState); // for naming clarification only, waste ram ftw.
  4772.         }
  4773.         else if (!strnicmp(szSetState, "on", 3))
  4774.         {
  4775.             bTurnOn = true;
  4776.         }
  4777.         else if (!strnicmp(szSetState, "off", 4))
  4778.         {
  4779.             bTurnOn = false; // serves no point other than to confirm valid input
  4780.         }
  4781.         else if (!strnicmp(szSetting, "heading", 7))
  4782.         {
  4783.             if (!strnicmp(szSetState, "true", 5))
  4784.             {
  4785.                 pMU->Head = SET->Head = H_TRUE;
  4786.                 sprintf(szMsg, "\ay%s\aw:: Heading adjustment type set to: \agtrue", MODULE_NAME);
  4787.             }
  4788.             else if (!strnicmp(szSetState, "loose", 6))
  4789.             {
  4790.                 pMU->Head = SET->Head = H_LOOSE;
  4791.                 sprintf(szMsg, "\ay%s\aw:: Heading adjustment type set to: \ayloose", MODULE_NAME);
  4792.             }
  4793.             else if (!strnicmp(szSetState, "fast", 5))
  4794.             {
  4795.                 pMU->Head = SET->Head = H_FAST;
  4796.                 sprintf(szMsg, "\ay%s\aw:: Heading adjustment type set to: \arfast", MODULE_NAME);
  4797.             }
  4798.             else
  4799.             {
  4800.                 sprintf(szSetError, "\ay%s\aw:: \arERROR\ax: Invalid '%s set' syntax ( \ar%s\ax ) [true|loose|fast]", MODULE_NAME, szCommand, szParameter);
  4801.                 WriteLine(szSetError, V_ERRORS);
  4802.                 return;
  4803.             }
  4804.             WriteLine(szMsg, V_SETTINGS);
  4805.             if (SET->AutoSave) SaveConfig();
  4806.             return;
  4807.         }
  4808.         else
  4809.         {
  4810.             sprintf(szSetError, "\ay%s\aw:: \arERROR\ax: Invalid '%s set' syntax ( \ar%s\ax ) [on|off|number]", MODULE_NAME, szCommand, szParameter);
  4811.             WriteLine(szSetError, V_ERRORS);
  4812.             return;
  4813.         }
  4814.     }
  4815.  
  4816.     if (!bCustomMsg && (bToggle || !bSetDigit))
  4817.     {
  4818.         if (!strnicmp(szParameter, "mpause", 7))
  4819.         {
  4820.             if (ToggleSetting("Pause from manual movement", &SET->PauseKB, &bToggle, &bTurnOn))
  4821.             {
  4822.                 SET->BreakKB = false;
  4823.             }
  4824.         }
  4825.         else if (!strnicmp(szParameter, "mousepause", 11))
  4826.         {
  4827.             if (ToggleSetting("Pause from mouse movement", &SET->PauseMouse, &bToggle, &bTurnOn))
  4828.             {
  4829.                 SET->BreakMouse = false;
  4830.             }
  4831.         }
  4832.         else if (!strnicmp(szParameter, "breakonkb", 10))
  4833.         {
  4834.             if (ToggleSetting("Break from keyboard movement", &SET->BreakKB, &bToggle, &bTurnOn))
  4835.             {
  4836.                 SET->PauseKB = false;
  4837.             }
  4838.         }
  4839.         else if (!strnicmp(szParameter, "breakonmouse", 13))
  4840.         {
  4841.             if (ToggleSetting("Break from mouse movement", &SET->BreakMouse, &bToggle, &bTurnOn))
  4842.             {
  4843.                 SET->PauseMouse = false;
  4844.             }
  4845.         }
  4846.         else if (!strnicmp(szParameter, "autosave", 9))
  4847.         {
  4848.             ToggleSetting("Auto-save settings to INI file", &SET->AutoSave, &bToggle, &bTurnOn);
  4849.         }
  4850.         else if (!strnicmp(szParameter, "savebychar", 11))
  4851.         {
  4852.             ToggleSetting("Save INI file Character Name section", &SET->SaveByChar, &bToggle, &bTurnOn);
  4853.         }
  4854.         else if (!strnicmp(szParameter, "feign", 6))
  4855.         {
  4856.             ToggleSetting("Remain feign support", &SET->Feign, &bToggle, &bTurnOn);
  4857.         }
  4858.         else if (!strnicmp(szParameter, "lockpause", 10))
  4859.         {
  4860.             ToggleSetting("Prevent command usage breaking pause", &SET->LockPause, &bToggle, &bTurnOn);
  4861.             pMU->LockPause = SET->LockPause;
  4862.         }
  4863.         else if (!strnicmp(szParameter, "autopause", 10))
  4864.         {
  4865.             ToggleSetting("AutoPause upon spell cast", &SET->AutoPause, &bToggle, &bTurnOn);
  4866.         }
  4867.         else if (!strnicmp(szParameter, "autopauseoutput", 16))
  4868.         {
  4869.             if (bToggle)
  4870.             {
  4871.                 uiVerbLevel ^= V_AUTOPAUSE;
  4872.             }
  4873.             else if (bTurnOn)
  4874.             {
  4875.                 uiVerbLevel |= V_AUTOPAUSE;
  4876.             }
  4877.             else
  4878.             {
  4879.                 uiVerbLevel &= ~V_AUTOPAUSE;
  4880.             }
  4881.             sprintf(szMsg, "\ay%s\aw:: Display AutoPause output: %s", MODULE_NAME, (uiVerbLevel & V_AUTOPAUSE) == V_AUTOPAUSE ? szOn : szOff);
  4882.             WriteLine(szMsg, V_SETTINGS);
  4883.         }
  4884.         else if (!strnicmp(szParameter, "stucklogic", 13))
  4885.         {
  4886.             ToggleSetting("Stuck-checking logic", &STUCK->On, &bToggle, &bTurnOn);
  4887.         }
  4888.         else if (!strnicmp(szParameter, "trytojump", 10))
  4889.         {
  4890.             ToggleSetting("Try to jump when stuck", &STUCK->Jump, &bToggle, &bTurnOn);
  4891.         }
  4892.         else if (!strnicmp(szParameter, "turnhalf", 9))
  4893.         {
  4894.             ToggleSetting("Switch direction if turned halfway (stucklogic)", &STUCK->TurnHalf, &bToggle, &bTurnOn);
  4895.         }
  4896.         else if (!strnicmp(szParameter, "verbosity", 10))
  4897.         {
  4898.             if (bToggle)
  4899.             {
  4900.                 uiVerbLevel ^= V_VERBOSITY;
  4901.             }
  4902.             else if (bTurnOn)
  4903.             {
  4904.                 uiVerbLevel |= V_VERBOSITY;
  4905.             }
  4906.             else
  4907.             {
  4908.                 uiVerbLevel &= ~V_VERBOSITY;
  4909.             }
  4910.             sprintf(szMsg, "\ay%s\aw:: Basic verbosity turned: %s", MODULE_NAME, (uiVerbLevel & V_VERBOSITY) == V_VERBOSITY ? szOn : szOff);
  4911.             WriteLine(szMsg, V_SETTINGS);
  4912.         }
  4913.         else if (!strnicmp(szParameter, "fullverbosity", 14))
  4914.         {
  4915.             if (bToggle)
  4916.             {
  4917.                 uiVerbLevel ^= V_FULLVERBOSITY;
  4918.             }
  4919.             else if (bTurnOn)
  4920.             {
  4921.                 uiVerbLevel |= V_FULLVERBOSITY;
  4922.             }
  4923.             else
  4924.             {
  4925.                 uiVerbLevel &= ~V_FULLVERBOSITY;
  4926.             }
  4927.             sprintf(szMsg, "\ay%s\aw:: Enhanced verbosity turned: %s", MODULE_NAME, (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY ? szOn : szOff);
  4928.             WriteLine(szMsg, V_SETTINGS);
  4929.         }
  4930.         else if (!strnicmp(szParameter, "totalsilence", 13))
  4931.         {
  4932.             if (bToggle)
  4933.             {
  4934.                 if (uiVerbLevel != V_SILENCE)
  4935.                 {
  4936.                     uiRetainFlags = uiVerbLevel;
  4937.                     uiVerbLevel = V_SILENCE;
  4938.                 }
  4939.                 else
  4940.                 {
  4941.                     uiVerbLevel = uiRetainFlags;
  4942.                 }
  4943.             }
  4944.             else if (bTurnOn)
  4945.             {
  4946.                 uiRetainFlags = uiVerbLevel;
  4947.                 uiVerbLevel = V_SILENCE;
  4948.             }
  4949.             else
  4950.             {
  4951.                 uiVerbLevel = uiRetainFlags;
  4952.             }
  4953.             sprintf(szMsg, "\ay%s\aw:: Plugin silence turned: %s", MODULE_NAME, (uiVerbLevel == V_SILENCE) ? szOn : szOff);
  4954.             WriteLine(szMsg, V_SILENCE);
  4955.         }
  4956.         else if (!strnicmp(szParameter, "totalverbosity", 15))
  4957.         {
  4958.             if (bToggle)
  4959.             {
  4960.                 if (uiVerbLevel != V_EVERYTHING)
  4961.                 {
  4962.                     uiRetainFlags = uiVerbLevel;
  4963.                     uiVerbLevel = V_EVERYTHING;
  4964.                 }
  4965.                 else
  4966.                 {
  4967.                     uiVerbLevel = uiRetainFlags;
  4968.                 }
  4969.             }
  4970.             else if (bTurnOn)
  4971.             {
  4972.                 uiRetainFlags = uiVerbLevel;
  4973.                 uiVerbLevel = V_EVERYTHING;
  4974.             }
  4975.             else
  4976.             {
  4977.                 uiVerbLevel = uiRetainFlags;
  4978.             }
  4979.             sprintf(szMsg, "\ay%s\aw:: Plugin total verbosity turned: %s", MODULE_NAME, (uiVerbLevel == V_EVERYTHING) ? szOn : szOff);
  4980.             WriteLine(szMsg, V_SILENCE);
  4981.         }
  4982.         else if (!strnicmp(szParameter, "window", 7))
  4983.         {
  4984.             if (ToggleSetting("Dedicated UI Window", &SET->Window, &bToggle, &bTurnOn))
  4985.             {
  4986.                 WINDOW->Create();
  4987.             }
  4988.             else
  4989.             {
  4990.                 WINDOW->Destroy(true);
  4991.             }
  4992.         }
  4993.         else if (!strnicmp(szParameter, "wineq", 6))
  4994.         {
  4995.             ToggleSetting("Use old-style movement", &SET->WinEQ, &bToggle, &bTurnOn);
  4996.             if (SET->WinEQ)
  4997.             {
  4998.                 if (SET->Head == H_TRUE) SET->Head = H_LOOSE;
  4999.                 if (pMU->Head == H_TRUE) pMU->Head = H_LOOSE;
  5000.             }
  5001.         }
  5002.         else if (!strnicmp(szParameter, "hidehelp", 9))
  5003.         {
  5004.             if (bToggle)
  5005.             {
  5006.                 uiVerbLevel ^= V_HIDEHELP;
  5007.             }
  5008.             else if (bTurnOn)
  5009.             {
  5010.                 uiVerbLevel |= V_HIDEHELP;
  5011.             }
  5012.             else
  5013.             {
  5014.                 uiVerbLevel &= ~V_HIDEHELP;
  5015.             }
  5016.             sprintf(szMsg, "\ay%s\aw:: Hide automatic help output: %s", MODULE_NAME, (uiVerbLevel & V_HIDEHELP) == V_HIDEHELP ? szOn : szOff);
  5017.             WriteLine(szMsg, V_SETTINGS);
  5018.         }
  5019.         else if (!strnicmp(szParameter, "breakontarget", 14))
  5020.         {
  5021.             STICK->BreakTarget = ToggleSetting("Break stick on target change", &SET_S->BreakTarget, &bToggle, &bTurnOn);
  5022.         }
  5023.         else if (!strnicmp(szParameter, "breakonsummon", 14))
  5024.         {
  5025.             ToggleSetting("Break command when summoned", &SET->BreakSummon, &bToggle, &bTurnOn);
  5026.         }
  5027.         else if (!strnicmp(szParameter, "breakongm", 10))
  5028.         {
  5029.             ToggleSetting("Break command when visible GM enters", &SET->BreakGM, &bToggle, &bTurnOn);
  5030.         }
  5031.         else if (!strnicmp(szParameter, "breakonwarp", 12))
  5032.         {
  5033.             if (ToggleSetting("Break command when NPC warps away", &SET_S->BreakWarp, &bToggle, &bTurnOn))
  5034.             {
  5035.                 SET_S->PauseWarp = STICK->PauseWarp = false;
  5036.             }
  5037.             STICK->BreakWarp = SET_S->BreakWarp;
  5038.         }
  5039.         else if (!strnicmp(szParameter, "pauseonwarp", 12))
  5040.         {
  5041.             if (ToggleSetting("Pause command when NPC warps away", &SET_S->PauseWarp, &bToggle, &bTurnOn))
  5042.             {
  5043.                 SET_S->PauseWarp = STICK->BreakWarp = false;
  5044.             }
  5045.             STICK->PauseWarp = SET_S->PauseWarp;
  5046.         }
  5047.         else if (!strnicmp(szParameter, "breakongate", 12))
  5048.         {
  5049.             SetupEvents(ToggleSetting("Break command when NPC gates", &SET_S->BreakGate, &bToggle, &bTurnOn));
  5050.             STICK->BreakGate = SET_S->BreakGate;
  5051.         }
  5052.         else if (!strnicmp(szParameter, "breakonhit", 11))
  5053.         {
  5054.             if (ucCmdUsed == CMD_MOVETO)
  5055.             {
  5056.                 SetupEvents(ToggleSetting("Break MoveTo if attacked", &SET_M->BreakHit, &bToggle, &bTurnOn));
  5057.                 MOVETO->BreakHit = SET_M->BreakHit;
  5058.             }
  5059.             else if (ucCmdUsed == CMD_STICK)
  5060.             {
  5061.                 SetupEvents(ToggleSetting("Break Stick if attacked", &SET_S->BreakHit, &bToggle, &bTurnOn));
  5062.                 STICK->BreakHit = SET_S->BreakHit;
  5063.             }
  5064.             else
  5065.             {
  5066.                 sprintf(szSetError, "\ay%s\aw:: \arERROR\ax: Not a valid %s %s ( \ar%s\ax ).", MODULE_NAME, szCommand, bToggle ? "toggle" : "set option", szParameter);
  5067.                 WriteLine(szSetError, V_ERRORS);
  5068.                 return;
  5069.             }
  5070.         }
  5071.         else if (!strnicmp(szParameter, "breakonaggro", 13))
  5072.         {
  5073.             SetupEvents(ToggleSetting("Break MoveTo if aggro", &SET_M->BreakAggro, &bToggle, &bTurnOn));
  5074.             MOVETO->BreakAggro = SET_M->BreakAggro;
  5075.         }
  5076.         else if (!strnicmp(szParameter, "alwaysdrunk", 12))
  5077.         {
  5078.             CIRCLE->Drunk = ToggleSetting("Circle always drunken", &SET_C->Drunk, &bToggle, &bTurnOn);
  5079.         }
  5080.         else if (!strnicmp(szParameter, "alwaysbackwards", 16))
  5081.         {
  5082.             CIRCLE->Backward = ToggleSetting("Circle always backwards", &SET_C->Backward, &bToggle, &bTurnOn);
  5083.         }
  5084.         else if (!strnicmp(szParameter, "alwaysccw", 10))
  5085.         {
  5086.             CIRCLE->CCW = ToggleSetting("Circle always counter-clockwise", &SET_C->CCW, &bToggle, &bTurnOn);
  5087.         }
  5088.         else if (!strnicmp(szParameter, "alwaysuw", 9) && (ucCmdUsed == CMD_MOVETO || ucCmdUsed == CMD_STICK))
  5089.         {
  5090.             if (ucCmdUsed == CMD_MOVETO)
  5091.             {
  5092.                 MOVETO->UW = ToggleSetting("Always use underwater parameter with /moveto", &SET_M->UW, &bToggle, &bTurnOn);
  5093.             }
  5094.             else
  5095.             {
  5096.                 STICK->UW = ToggleSetting("Always use underwater parameter with /stick", &SET_S->UW, &bToggle, &bTurnOn);
  5097.             }
  5098.         }
  5099.         else if (!strnicmp(szParameter, "loose", 6) && ucCmdUsed != CMD_MAKECAMP)
  5100.         {
  5101.             pMU->Head = bToggle ? (pMU->Head == H_LOOSE ? H_FAST : H_LOOSE) : (bTurnOn ? H_LOOSE : H_FAST);
  5102.             sprintf(szMsg, "\ay%s\aw:: Active \ay%s\ax loose heading turned %s (Cur: %s)", MODULE_NAME, szCommand, (pMU->Head == H_LOOSE) ? szOn : szOff, (pMU->Head == H_LOOSE) ? "\ayloose\ax" : "\arfast\ax");
  5103.             WriteLine(szMsg, V_SETTINGS);
  5104.         }
  5105.         else if (!strnicmp(szParameter, "truehead", 9) && ucCmdUsed != CMD_MAKECAMP)
  5106.         {
  5107.             pMU->Head = bToggle ? (pMU->Head == H_TRUE ? H_FAST : H_TRUE) : (bTurnOn ? H_TRUE : H_FAST);
  5108.             sprintf(szMsg, "\ay%s\aw:: Active \ay%s\ax true turning turned %s (Cur: %s)", MODULE_NAME, szCommand, (pMU->Head == H_TRUE) ? szOn : szOff, (pMU->Head == H_TRUE) ? "\ayloose\ax" : "\arfast\ax");
  5109.             WriteLine(szMsg, V_SETTINGS);
  5110.         }
  5111.         else if (!strnicmp(szParameter, "nohottfront", 12))
  5112.         {
  5113.             ToggleSetting("Spin in circles when I lose aggro with no HoTT using '/stick front'", &SET->Spin, &bToggle, &bTurnOn);
  5114.         }
  5115.         else if (!strnicmp(szParameter, "returnnoaggro", 14))
  5116.         {
  5117.             CURCAMP->NoAggro = ToggleSetting("Return to camp when not aggro", &SET_CAMP->NoAggro, &bToggle, &bTurnOn);
  5118.         }
  5119.         else if (!strnicmp(szParameter, "returnnotlooting", 17))
  5120.         {
  5121.             CURCAMP->NotLoot = ToggleSetting("Return to camp when not looting", &SET_CAMP->NotLoot, &bToggle, &bTurnOn);
  5122.         }
  5123.         else if (!strnicmp(szParameter, "returnhavetarget", 17))
  5124.         {
  5125.             CURCAMP->HaveTarget = ToggleSetting("Return to camp regardless of target", &SET_CAMP->HaveTarget, &bToggle, &bTurnOn);
  5126.         }
  5127.         else if (!strnicmp(szParameter, "realtimeplayer", 15))
  5128.         {
  5129.             CURCAMP->Realtime = ToggleSetting("Return to realtime camp player location", &SET_CAMP->Realtime, &bToggle, &bTurnOn);
  5130.         }
  5131.         else if (!strnicmp(szParameter, "leash", 6))
  5132.         {
  5133.             CURCAMP->Leash = ToggleSetting("Leash to camp", &SET_CAMP->Leash, &bToggle, &bTurnOn);
  5134.         }
  5135.         else if (!strnicmp(szParameter, "usewalk", 8))
  5136.         {
  5137.             MOVETO->Walk = ToggleSetting("Walk when close to moveto/camp return destination", &SET_M->Walk, &bToggle, &bTurnOn);
  5138.         }
  5139.         else if (!strnicmp(szParameter, "strafewalk", 11))
  5140.         {
  5141.             STICK->Walk = ToggleSetting("Walk when stick is close and strafing", &SET_S->Walk, &bToggle, &bTurnOn);
  5142.         }
  5143.         else if (!strnicmp(szParameter, "randomize", 10))
  5144.         {
  5145.             STICK->Randomize = ToggleSetting("Randomize custom arcs", &SET_S->Randomize, &bToggle, &bTurnOn);
  5146.         }
  5147.         else if (!strnicmp(szParameter, "delaystrafe", 12))
  5148.         {
  5149.             STICK->DelayStrafe = ToggleSetting("Enable custom stick angle delay", &SET_S->DelayStrafe, &bToggle, &bTurnOn);
  5150.         }
  5151.         else if (!strnicmp(szParameter, "autouw", 7))
  5152.         {
  5153.             ToggleSetting("Automatically use 'uw' when underwater", &SET->AutoUW, &bToggle, &bTurnOn);
  5154.         }
  5155.         else if (!strnicmp(szParameter, "useback", 8) && (ucCmdUsed == CMD_MOVETO || ucCmdUsed == CMD_STICK))
  5156.         {
  5157.             if (ucCmdUsed == CMD_MOVETO)
  5158.             {
  5159.                 MOVETO->UseBack = ToggleSetting("Use backward movement when close to destination", &SET_M->UseBack, &bToggle, &bTurnOn);
  5160.             }
  5161.             else
  5162.             {
  5163.                 STICK->UseBack = ToggleSetting("Use backwards movement when close to target", &SET_S->UseBack, &bToggle, &bTurnOn);
  5164.             }
  5165.         }
  5166.         else if (!strnicmp(szParameter, "usefleeing", 11))
  5167.         {
  5168.             STICK->UseFleeing = ToggleSetting("Stick front fleeing mob detection", &SET_S->UseFleeing, &bToggle, &bTurnOn);
  5169.         }
  5170.         else if (!strnicmp(szParameter, "usescatter", 11))
  5171.         {
  5172.             bCustomMsg = true;
  5173.             SET_CAMP->Scatter = bToggle ? !SET_CAMP->Scatter : bTurnOn;
  5174.             CURCAMP->Scatter = SET_CAMP->Scatter;
  5175.             sprintf(szMsg, "\ay%s\aw:: Scatter camp returns (%s) ScatDist(\ag%.2f\ax) Bearing(\ag%.2f\ax) ScatDist(\ag%.2f\ax) ScatSize(\ag%.2f\ax)", MODULE_NAME, SET_CAMP->Scatter ? szOn : szOff, SET_CAMP->ScatDist, SET_CAMP->Bearing, SET_CAMP->ScatSize);
  5176.         }
  5177.         else if (!strnicmp(szParameter, "flex", 5))
  5178.         {
  5179.             STICK->Flex = ToggleSetting("Flexible stick distance", &SET_S->Flex, &bToggle, &bTurnOn);
  5180.         }
  5181.         else
  5182.         {
  5183.             sprintf(szSetError, "\ay%s\aw:: \arERROR\ax: Not a valid %s %s ( \ar%s\ax ).", MODULE_NAME, szCommand, bToggle ? "toggle" : "set option", szParameter);
  5184.             WriteLine(szSetError, V_ERRORS);
  5185.             return;
  5186.         }
  5187.  
  5188.         if (!bCustomMsg)
  5189.         {
  5190.             if (SET->AutoSave) SaveConfig();
  5191.             return;
  5192.         }
  5193.     }
  5194.     else if (!bCustomMsg && bSetDigit)
  5195.     {
  5196.         float fDigit = (float)atof(szSetDigit);
  5197.         if (!strnicmp(szParameter, "pulsecheck", 11))
  5198.         {
  5199.             STUCK->Check = (unsigned int)fDigit > 1 ? (unsigned int)fDigit : STUCK->Check;
  5200.             sprintf(szMsg, "\ay%s\aw:: StuckLogic pulse check rate set to \ag%d\ax pulses.", MODULE_NAME, STUCK->Check);
  5201.         }
  5202.         else if (!strnicmp(szParameter, "pulseunstuck", 13))
  5203.         {
  5204.             STUCK->Unstuck = (unsigned int)fDigit > 1 ? (unsigned int)fDigit : STUCK->Unstuck;
  5205.             sprintf(szMsg, "\ay%s\aw:: StuckLogic pulse unstuck value set to \ag%d\ax pulses.", MODULE_NAME, STUCK->Unstuck);
  5206.         }
  5207.         else if (!strnicmp(szParameter, "diststuck", 10))
  5208.         {
  5209.             STUCK->Dist = fDigit > 0.0f ? fDigit : STUCK->Dist;
  5210.             sprintf(szMsg, "\ay%s\aw:: StuckLogic distance moved per pulse (else stuck) set to \ag%.3f", MODULE_NAME, STUCK->Dist);
  5211.         }
  5212.         else if (!strnicmp(szParameter, "campmindelay", 13))
  5213.         {
  5214.             SET_CAMP->MinDelay((int)fDigit);
  5215.             CAMP->MinDelay(SET_CAMP->Min);
  5216.             sprintf(szMsg, "\ay%s\aw:: Mindelay for camp return set to \ag%d", MODULE_NAME, SET_CAMP->Min);
  5217.         }
  5218.         else if (!strnicmp(szParameter, "campmaxdelay", 13))
  5219.         {
  5220.             SET_CAMP->MaxDelay((int)fDigit);
  5221.             CAMP->MaxDelay(SET_CAMP->Max);
  5222.             sprintf(szMsg, "\ay%s\aw:: Maxdelay for camp return set to \ag%d", MODULE_NAME, CAMP->Max);
  5223.         }
  5224.         else if (!strnicmp(szParameter, "pausemindelay", 14))
  5225.         {
  5226.             PAUSE->MinDelay((int)fDigit);
  5227.             sprintf(szMsg, "\ay%s\aw:: Mindelay for mpause/mousepause set to \ag%d", MODULE_NAME, PAUSE->Min);
  5228.         }
  5229.         else if (!strnicmp(szParameter, "pausemaxdelay", 14))
  5230.         {
  5231.             PAUSE->MaxDelay((int)fDigit);
  5232.             sprintf(szMsg, "\ay%s\aw:: Maxdelay for mpause/mousepause set to \ag%d", MODULE_NAME, PAUSE->Max);
  5233.         }
  5234.         else if (!strnicmp(szParameter, "strafemindelay", 15))
  5235.         {
  5236.             SET_S->MinDelay((int)fDigit);
  5237.             STICK->MinDelay(SET_S->Min);
  5238.             sprintf(szMsg, "\ay%s\aw:: Mindelay for strafe resume set to \ag%d", MODULE_NAME, SET_S->Min);
  5239.         }
  5240.         else if (!strnicmp(szParameter, "strafemaxdelay", 15))
  5241.         {
  5242.             SET_S->MaxDelay((int)fDigit);
  5243.             STICK->MaxDelay(SET_S->Max);
  5244.             sprintf(szMsg, "\ay%s\aw:: Maxdelay for strafe resume set to \ag%d", MODULE_NAME, SET_S->Max);
  5245.         }
  5246.         else if (!strnicmp(szParameter, "ydist", 6))
  5247.         {
  5248.             SET_M->DistY = fDigit >= 1.0f ? fDigit : SET_M->DistY;
  5249.             MOVETO->DistY = SET_M->DistY;
  5250.             sprintf(szMsg, "\ay%s\aw:: MoveTo Y-Precision set to \ag%.2f", MODULE_NAME, SET_M->DistY);
  5251.         }
  5252.         else if (!strnicmp(szParameter, "xdist", 6))
  5253.         {
  5254.             SET_M->DistX = fDigit >= 1.0f ? fDigit : SET_M->DistX;
  5255.             MOVETO->DistY = SET_M->DistY;
  5256.             sprintf(szMsg, "\ay%s\aw:: MoveTo X-Precision set to \ag%.2f", MODULE_NAME, SET_M->DistX);
  5257.         }
  5258.         else if (!strnicmp(szParameter, "dist", 5) && ucCmdUsed == CMD_MOVETO)
  5259.         {
  5260.             SET_M->Dist = fDigit >= 1.0f ? fDigit : SET_M->Dist;
  5261.             MOVETO->Dist = SET_M->Dist;
  5262.             sprintf(szMsg, "\ay%s\aw:: MoveTo ArrivalDist set to \ag%.2f", MODULE_NAME, SET_M->Dist);
  5263.         }
  5264.         else if (!strnicmp(szParameter, "snapdist", 9))
  5265.         {
  5266.             SET_S->DistSnap = fDigit >= 1.0f ? fDigit : SET_S->DistSnap;
  5267.             STICK->DistSnap = SET_S->DistSnap;
  5268.             sprintf(szMsg, "\ay%s\aw:: Snaproll Distance from target set to \ag%.2f", MODULE_NAME, SET_S->DistSnap);
  5269.         }
  5270.         else if (!strnicmp(szParameter, "summondist", 11))
  5271.         {
  5272.             SET->DistSummon = fDigit >= 1.0f ? fDigit : SET->DistSummon;
  5273.             sprintf(szMsg, "\ay%s\aw:: BreakOnSummon distance set to \ag%.2f", MODULE_NAME, SET->DistSummon);
  5274.         }
  5275.         else if (!strnicmp(szParameter, "turnrate", 9))
  5276.         {
  5277.             SET->TurnRate = fDigit >= 1.0f && fDigit <= 100.0f ? fDigit : SET->TurnRate;
  5278.             sprintf(szMsg, "\ay%s\aw:: Loose Turn Rate set to \ag%.2f", MODULE_NAME, SET->TurnRate);
  5279.         }
  5280.         else if (!strnicmp(szParameter, "!frontarc", 10))
  5281.         {
  5282.             SET_S->ArcNotFront = fDigit <= 260.0f && fDigit > 1.0f ? fDigit : SET_S->ArcNotFront;
  5283.             STICK->ArcNotFront = SET_S->ArcNotFront;
  5284.             sprintf(szMsg, "\ay%s\aw:: !front arc set to \ag%.2f", MODULE_NAME, SET_S->ArcNotFront);
  5285.         }
  5286.         else if (!strnicmp(szParameter, "behindarc", 10))
  5287.         {
  5288.             SET_S->ArcBehind = fDigit <= 260.0f && fDigit > 1.0f ? fDigit : SET_S->ArcBehind;
  5289.             STICK->ArcBehind = SET_S->ArcBehind;
  5290.             sprintf(szMsg, "\ay%s\aw:: behind arc set to \ag%.2f", MODULE_NAME, SET_S->ArcBehind);
  5291.         }
  5292.         else if (!strnicmp(szParameter, "breakdist", 10))
  5293.         {
  5294.             SET_S->DistBreak = fDigit >= 1.0f ? fDigit : SET_S->DistBreak;
  5295.             STICK->DistBreak = SET_S->DistBreak;
  5296.             sprintf(szMsg, "\ay%s\aw:: BreakOnWarp dist set to \ag%.2f", MODULE_NAME, SET_S->DistBreak);
  5297.         }
  5298.         else if (!strnicmp(szParameter, "campradius", 11))
  5299.         {
  5300.             SET_CAMP->SetRadius(fDigit);
  5301.             CURCAMP->SetRadius(SET_CAMP->Radius);
  5302.             sprintf(szMsg, "\ay%s\aw:: Camp radius set to \ag%.2f", MODULE_NAME, SET_CAMP->Radius);
  5303.         }
  5304.         else if (!strnicmp(szParameter, "circleradius", 13))
  5305.         {
  5306.             SET_C->SetRadius(fDigit);
  5307.             CIRCLE->SetRadius(SET_C->Radius);
  5308.             sprintf(szMsg, "\ay%s\aw:: Circle radius set to \ag%.2f", MODULE_NAME, SET_C->Radius);
  5309.         }
  5310.         else if (!strnicmp(szParameter, "leashlength", 12))
  5311.         {
  5312.             SET_CAMP->SetLeash(fDigit);
  5313.             CURCAMP->SetLeash(SET_CAMP->Length);
  5314.             sprintf(szMsg, "\ay%s\aw:: Leash length set to \ag%.2f", MODULE_NAME, SET_CAMP->Length);
  5315.         }
  5316.         else if (!strnicmp(szParameter, "bearing", 8))
  5317.         {
  5318.             SET_CAMP->Bearing = fDigit;
  5319.             CURCAMP->Bearing = SET_CAMP->Bearing;
  5320.             sprintf(szMsg, "\ay%s\aw:: Camp return scatter bearing set to \ag%.2f", MODULE_NAME, SET_CAMP->Bearing);
  5321.         }
  5322.         else if (!strnicmp(szParameter, "scatsize", 9))
  5323.         {
  5324.             SET_CAMP->ScatSize = fDigit >= 1.0f ? fDigit : SET_CAMP->ScatSize;
  5325.             CURCAMP->ScatSize = SET_CAMP->ScatSize;
  5326.             sprintf(szMsg, "\ay%s\aw:: Camp return scatter size set to \ag%.2f", MODULE_NAME, SET_CAMP->ScatSize);
  5327.         }
  5328.         else if (!strnicmp(szParameter, "scatdist", 9))
  5329.         {
  5330.             SET_CAMP->ScatDist = fDigit >= 1.0f ? fDigit : SET_CAMP->ScatDist;
  5331.             CURCAMP->ScatDist = SET_CAMP->ScatDist;
  5332.             sprintf(szMsg, "\ay%s\aw:: Camp return scatter dist set to \ag%.2f", MODULE_NAME, SET_CAMP->ScatDist);
  5333.         }
  5334.         else if (!strnicmp(szParameter, "backupdist", 11) && (ucCmdUsed == CMD_MOVETO || ucCmdUsed == CMD_STICK))
  5335.         {
  5336.             if (ucCmdUsed == CMD_MOVETO)
  5337.             {
  5338.                 SET_M->DistBack = fDigit > 1.0f ? fDigit : SET_M->DistBack;
  5339.                 MOVETO->DistBack = SET_M->DistBack;
  5340.             }
  5341.             else
  5342.             {
  5343.                 SET_S->DistBack = fDigit > 1.0f ? fDigit : SET_S->DistBack;
  5344.                 STICK->DistBack = SET_S->DistBack;
  5345.             }
  5346.             sprintf(szMsg, "\ay%s\aw:: Range to use %s backwards positioning set to \ag%.2f", MODULE_NAME, szCommand, (ucCmdUsed == CMD_MOVETO) ? SET_M->DistBack : SET_S->DistBack);
  5347.         }
  5348.         else if (!strnicmp(szParameter, "allowmove", 10))
  5349.         {
  5350.             SET->AllowMove = fDigit > 10.0f ? fDigit : SET->AllowMove;
  5351.             sprintf(szMsg, "\ay%s\aw:: Allow movement when turning at \ag%.2f", MODULE_NAME, SET->AllowMove);
  5352.         }
  5353.         else if (!strnicmp(szParameter, "flexdist", 9))
  5354.         {
  5355.             SET_S->DistFlex = (fDigit >= 2.0f && fDigit <= 20.0f) ? fDigit : SET_S->DistFlex;
  5356.             STICK->DistFlex = SET_S->DistFlex;
  5357.             sprintf(szMsg, "\ay%s\aw:: Stick Flexibility distance set to \ag%.2f", MODULE_NAME, SET_S->DistFlex);
  5358.         }
  5359.         else if (!strnicmp(szParameter, "font", 5))
  5360.         {
  5361.             int iValid = (int)fDigit > 0 && (int)fDigit < 11 ? (int)fDigit : 0;
  5362.             if (iValid == 0)
  5363.             {
  5364.                 sprintf(szMsg, "\ay%s\aw:: \arError\ax - Font must be between 1 and 10.", MODULE_NAME);
  5365.                 WriteLine(szMsg, V_ERRORS);
  5366.                 return;
  5367.             }
  5368.             WINDOW->NewFont(iValid);
  5369.         }
  5370.         else if (!strnicmp(szParameter, "verbflags", 10))
  5371.         {
  5372.             int iNewLevel = atoi(szSetDigit);
  5373.             if (iNewLevel > 0)
  5374.             {
  5375.                 uiVerbLevel = (unsigned int)iNewLevel;
  5376.             }
  5377.             else
  5378.             {
  5379.                 // set to silence for both 0 and negative numbers
  5380.                 uiVerbLevel = V_SILENCE;
  5381.             }
  5382.             sprintf(szMsg, "\ay%s\aw:: Verbosity flags set to \ag%d", MODULE_NAME, uiVerbLevel);
  5383.         }
  5384.         else
  5385.         {
  5386.             sprintf(szSetError, "\ay%s\aw:: \arERROR\ax: Invalid '%s set' parameter ( \ar%s\ax )", MODULE_NAME, szCommand, szParameter);
  5387.             WriteLine(szSetError, V_ERRORS);
  5388.             return;
  5389.         }
  5390.     }
  5391.  
  5392.     if (SET->AutoSave) SaveConfig();
  5393.     WriteLine(szMsg, V_SETTINGS);
  5394. }
  5395.  
  5396. // ----------------------------------------
  5397. // Begin Main function
  5398.  
  5399. void MainProcess(unsigned char ucCmdUsed)
  5400. {
  5401.     PCHARINFO  pChData     = (PCHARINFO)pCharData;
  5402.     PSPAWNINFO pChSpawn    = (PSPAWNINFO)pCharSpawn;
  5403.     PSPAWNINFO pLPlayer    = (PSPAWNINFO)pLocalPlayer;
  5404.     PSPAWNINFO psTarget    = (PSPAWNINFO)(STICK->Hold ? GetSpawnByID(STICK->HoldID) : pTarget);
  5405.     PSPAWNINFO pCampPlayer = (PSPAWNINFO)GetSpawnByID(CURCAMP->PcID);
  5406.  
  5407.     // ------------------------------------------
  5408.     // handle null stick pointers
  5409.     if (ucCmdUsed == CMD_STICK)
  5410.     {
  5411.         // prevent sticking to a target that does not exist or stick id to target that has changed types
  5412.         if (STICK->On && (!psTarget || (STICK->Hold && STICK->HoldType != GetSpawnType(psTarget))))
  5413.         {
  5414.             EndPreviousCmd(true);
  5415.             sprintf(szMsg, "\ay%s\aw:: You are no longer sticking to anything.", MODULE_NAME);
  5416.             WriteLine(szMsg, V_STICKV);
  5417.             return;
  5418.         }
  5419.     }
  5420.     // end null stick pointers
  5421.  
  5422.     // handle /makecamp player if the player no longer exists or has died
  5423.     if (CURCAMP->Pc && (!pCampPlayer || CURCAMP->PcType != GetSpawnType(pCampPlayer)))
  5424.     {
  5425.         sprintf(szMsg, "\ay%s\aw:: MakeCamp player ended due to player leaving/death.", MODULE_NAME);
  5426.         WriteLine(szMsg, V_MAKECAMPV);
  5427.         CAMP->ResetPlayer(false);
  5428.         return;
  5429.     }
  5430.     // end /makecamp player handling
  5431.  
  5432.     // handle null pointers for all commands
  5433.     if (!pChData || !pLPlayer || !pChSpawn->SpawnID || !GetCharInfo2())
  5434.     {
  5435.         sprintf(szMsg, "\ay%s\aw:: Null pointer, turning off current command", MODULE_NAME);
  5436.         WriteLine(szMsg, V_SILENCE);
  5437.         EndPreviousCmd(false);
  5438.         return;
  5439.     }
  5440.     // end null pointers
  5441.     // ------------------------------------------
  5442.  
  5443.     // setup used only in MainProcess
  5444.     float fNewHeading     = 0.0f; // heading changes used by all commands
  5445.     bool bMoveToOOR       = true;  // used by moveto, set to false if in range
  5446.     static bool sbJumping = false; // true if we executed a jump in stucklogic
  5447.  
  5448.     // variables reflecting character state
  5449.     float fSpeedMulti  = pChSpawn->SpeedMultiplier;
  5450.     bool  bSwimming    = pChSpawn->UnderWater                                      ? true : false; // used by stucklogic & uw
  5451.     bool  bMounted     = pChSpawn->Mount                                           ? true : false; // used by stucklogic
  5452.     bool  bStunned     = pChData->Stunned                                          ? true : false; // used by stucklogic and autopause
  5453.     bool  bLevitated   = (pChSpawn->Levitate == 2)                                 ? true : false; // used by stucklogic
  5454.     bool  bRooted      = (fSpeedMulti == -10000.0f  || pChSpawn->RunSpeed < -0.4f) ? true : false; // we return without moving when rooted
  5455.     bool  bSnared      = (fSpeedMulti < 0.0f        || pChSpawn->RunSpeed < 0.0f)  ? true : false; // used by stucklogic
  5456.     bool  bInJump      = (pChSpawn->Animation == 19 || pChSpawn->Animation == 20)  ? true : false; // used by trytojump
  5457.  
  5458.     if (!bInJump)                              sbJumping = false;
  5459.     if (bSwimming && SET->AutoUW) STICK->UW = MOVETO->UW = true;
  5460.     bool bUseStuck = (!bRooted && !bSnared) ? true : false; // we set false elsewhere if stucklogic is not desired this pulse
  5461.     // end MainProcess setup
  5462.  
  5463.     // handle breakonsummon
  5464.     if (SET->BreakSummon && ucCmdUsed != CMD_MAKECAMP)
  5465.     {
  5466.         if (SUMMON->CurDist == 0.0f && SUMMON->Y == 0.0f && SUMMON->X == 0.0f)
  5467.         {
  5468.             // set last loc to current loc if this is first evaluation for current command
  5469.             // so that comparison is near-zero and below 'if' will be false
  5470.             SUMMON->Y = pChSpawn->Y;
  5471.             SUMMON->X = pChSpawn->X;
  5472.         }
  5473.  
  5474.         // get the distance moved
  5475.         SUMMON->CurDist = fabs(GetDistance(SUMMON->Y, SUMMON->X, pChSpawn->Y, pChSpawn->X));
  5476.         // store current location for next pulse
  5477.         SUMMON->Y = pChSpawn->Y;
  5478.         SUMMON->X = pChSpawn->X;
  5479.  
  5480.         // if distance moved is larger than user value, halt commands & lock plugin
  5481.         if (SUMMON->CurDist > SET->DistSummon)
  5482.         {
  5483.             sprintf(szMsg, "\ay%s\aw:: \arWARNING\ax Command ended from character summoned \ag%.2f\ax distance in a pulse.", MODULE_NAME, SUMMON->CurDist);
  5484.             EndPreviousCmd(true);
  5485.             WriteLine(szMsg, V_BREAKONSUMMON);
  5486.             sprintf(szMsg, "\ay%s\aw:: \arWARNING\ax Verify you are not being monitored and type \ag/stick imsafe\ax to allow command usage.", MODULE_NAME);
  5487.             WriteLine(szMsg, V_BREAKONSUMMON);
  5488.             pMU->BrokeSummon = PAUSE->PausedMU = true;
  5489.             SpewDebug(DBG_MAIN, "Summon Detection fired. All Commands Paused. SET->DistSummon(%.2f) - Moved(%.2f)", SET->DistSummon, SUMMON->CurDist);
  5490.             return;
  5491.         }
  5492.     }
  5493.     //end breakonsummon
  5494.  
  5495.     // handle autopause
  5496.     if (SET->AutoPause && ucCmdUsed != CMD_MAKECAMP)
  5497.     {
  5498.         static bool sbAPOutput = false;
  5499.         // convert to long because spellid is defined as unsigned but data can be negative to represent not casting
  5500.         if (((long)(pChSpawn->CastingData.SpellID) >= 0 && !pMU->Bard) || (pChSpawn->StandState != STANDSTATE_STAND && pChSpawn->StandState != STANDSTATE_DUCK) || bStunned || bRooted || (ucCmdUsed == CMD_STICK && ME->IsMe(psTarget)))
  5501.         {
  5502.             if ((uiVerbLevel & V_AUTOPAUSE) == V_AUTOPAUSE && !sbAPOutput)
  5503.             {
  5504.                 sprintf(szMsg, "\ay%s\aw:: AutoPause halting movement...", MODULE_NAME);
  5505.                 WriteLine(szMsg, V_AUTOPAUSE);
  5506.                 sbAPOutput = true;
  5507.                 MOVE->StopHeading();
  5508.             }
  5509.             STICK->TimeStop();
  5510.             CAMP->TimeStop(); // reset delay times
  5511.             MOVE->StopMove(APPLY_TO_ALL);
  5512.             return; // return until above is false
  5513.         }
  5514.         sbAPOutput = false;
  5515.     }
  5516.     // end autopause
  5517.  
  5518.     // assign needed stick values
  5519.     if (ucCmdUsed == CMD_STICK)
  5520.     {
  5521.         if (!STICK->SetDist)
  5522.         {
  5523.             STICK->Dist    = (psTarget->StandState ? get_melee_range(pLocalPlayer, (EQPlayer *)psTarget) : 15.0f) * STICK->DistModP + STICK->DistMod;
  5524.             STICK->SetDist = true;
  5525.         }
  5526.  
  5527.         // assign distance
  5528.         STICK->DifDist = STICK->CurDist;
  5529.         STICK->CurDist = fabs(GetDistance(pChSpawn, psTarget));
  5530.  
  5531.         static bool sbSelfOutput = false;
  5532.         // if we've changed targets mid-stick or this is the first pulse, dont trigger stucklogic or breakonwarp
  5533.         if (STICK->LastID != psTarget->SpawnID)
  5534.         {
  5535.             if (STICK->LastID && STICK->BreakTarget) // if we had set the ID
  5536.             {
  5537.                 EndPreviousCmd(true);
  5538.                 sprintf(szMsg, "\ay%s\aw:: \arStick broken from target change.", MODULE_NAME);
  5539.                 WriteLine(szMsg, V_BREAKONWARP);
  5540.                 return;
  5541.             }
  5542.             bUseStuck = false;
  5543.             STICK->DifDist = 0.0f;
  5544.             sbSelfOutput = false;
  5545.         }
  5546.         STICK->LastID = psTarget->SpawnID;
  5547.  
  5548.         // make sure havent switched to self - if so, stop movement
  5549.         if (ME->IsMe(psTarget))
  5550.         {
  5551.             if (!sbSelfOutput)
  5552.             {
  5553.                 MOVE->StopMove(APPLY_TO_ALL);
  5554.                 sprintf(szMsg, "\ay%s\aw:: Movement pausing due to self target...", MODULE_NAME);
  5555.                 WriteLine(szMsg, V_AUTOPAUSE);
  5556.                 sbSelfOutput = true;
  5557.             }
  5558.             return;
  5559.         }
  5560.         sbSelfOutput = false;
  5561.  
  5562.         // if this is not the first pass and target has not changed
  5563.         // handle pauseonwarp or breakonwarp
  5564.         if ((STICK->PauseWarp || STICK->BreakWarp) && STICK->DifDist != 0.0f)
  5565.         {
  5566.             static bool sbBWOutput = false;
  5567.             // if the distance between us and the desired stick distance is > user break distance
  5568.             // (we compare prevdist so that user can initially stick from distances
  5569.             //       larger than breakdist as long as the distance keeps decreasing)
  5570.             if (sbBWOutput)
  5571.             {
  5572.                 if (STICK->CurDist - STICK->Dist > STICK->DistBreak) return;
  5573.                 // return until back in range
  5574.             }
  5575.             else if (STICK->CurDist - STICK->DifDist - STICK->Dist > STICK->DistBreak)
  5576.             {
  5577.                 if (STICK->PauseWarp)
  5578.                 {
  5579.                     if (!sbBWOutput)
  5580.                     {
  5581.                         MOVE->StopMove(APPLY_TO_ALL);
  5582.                         sprintf(szMsg, "\ay%s\aw: Stick pausing until target back in BreakDist range...", MODULE_NAME);
  5583.                         WriteLine(szMsg, V_BREAKONWARP);
  5584.                         sbBWOutput = true;
  5585.                         STICK->TimeStop();
  5586.                         CAMP->TimeStop(); // reset delay times
  5587.                     }
  5588.                     // return until above is false
  5589.                     return;
  5590.                 }
  5591.                 else
  5592.                 {
  5593.                     EndPreviousCmd(true);
  5594.                     sprintf(szMsg, "\ay%s\aw:: Stick ending from target warping out of BreakDist range.", MODULE_NAME);
  5595.                     WriteLine(szMsg, V_BREAKONWARP);
  5596.                     return;
  5597.                 }
  5598.             }
  5599.             sbBWOutput = false;
  5600.         }
  5601.         // end pauseonwarp/breakonwarp
  5602.     }
  5603.     // end stick values assignment
  5604.  
  5605.     // handle makecamp altreturn
  5606.     if (CAMP->DoAlt && !CAMP->Returning)
  5607.     {
  5608.         CAMP->TimeStop(); // reset delay time
  5609.         if (!CURCAMP->Scatter)
  5610.         {
  5611.             CampReturn(ALTCAMP->Y, ALTCAMP->X, ALTCAMP->Radius, &CAMP->Y, &CAMP->X);
  5612.         }
  5613.         else
  5614.         {
  5615.             PolarSpot(ALTCAMP->Y, ALTCAMP->X, 0.0f, CURCAMP->Bearing, CURCAMP->ScatDist, CURCAMP->ScatSize, &CAMP->Y, &CAMP->X);
  5616.         }
  5617.         MOVETO->On       = CAMP->Returning  = true;
  5618.         MOVETO->PreciseX = MOVETO->PreciseY = false;
  5619.         CAMP->DoReturn   = CAMP->Auto  = false;
  5620.         return;
  5621.     }
  5622.     // end altreturn
  5623.  
  5624.     // makecamp handling
  5625.     if (!CAMP->Returning && CURCAMP->On)
  5626.     {
  5627.         CAMP->CurDist = GetDistance(pChSpawn->Y, pChSpawn->X, CURCAMP->Pc ? pCampPlayer->Y : CURCAMP->Y, CURCAMP->Pc ? pCampPlayer->X : CURCAMP->X);
  5628.         CAMP->DifDist = GetDistance(STICK->On ? psTarget->Y : MOVETO->Y, STICK->On ? psTarget->X : MOVETO->X, CURCAMP->Pc ? pCampPlayer->Y : CURCAMP->Y, CURCAMP->Pc ? pCampPlayer->X : CURCAMP->X);
  5629.  
  5630.         // break from command if it would exceed active leash
  5631.         if (CURCAMP->Leash && (STICK->On || MOVETO->On))
  5632.         {
  5633.             if (CAMP->CurDist < CAMP->DifDist && CAMP->DifDist > CURCAMP->Length)
  5634.             {
  5635.                 EndPreviousCmd(true);
  5636.                 sprintf(szMsg, "\ay%s\aw:: Outside of leash length, breaking from current command", MODULE_NAME);
  5637.                 WriteLine(szMsg, V_MAKECAMPV);
  5638.                 return;
  5639.             }
  5640.         }
  5641.         // end leash new command check
  5642.  
  5643.         // if makecamp return issued, or if makecamp on check to see if we need to move back
  5644.         if (!PAUSE->UserKB && !PAUSE->UserMouse && !STICK->On && !MOVETO->On && !CIRCLE->On)
  5645.         {
  5646.             // normal return
  5647.             if (CAMP->CurDist > CURCAMP->Radius + 2.0f || CAMP->DoReturn) // give leeway to avoid teetering
  5648.             {
  5649.                 bool bDoReturn = true;
  5650.                 if (!CAMP->DoReturn)
  5651.                 {
  5652.                     if (CURCAMP->NoAggro     && ME->InCombat()) bDoReturn = false;
  5653.                     if (!CURCAMP->HaveTarget && pTarget)        bDoReturn = false;
  5654.                     if (CURCAMP->NotLoot     && pActiveCorpse)  bDoReturn = false;
  5655.                 }
  5656.  
  5657.                 // check this logic - if the timer starts and then doreturn turns false, the conditions might not reset
  5658.                 // and the return will happen instantly once doreturn is true again
  5659.                 //
  5660.                 // instead it SHOULD RESTART THE TIMER from the point the conditions are ready
  5661.  
  5662.                 // processed conditions in which not to return, if none are met, begin returning
  5663.                 if (bDoReturn)
  5664.                 {
  5665.                     char cResult = CAMP->TimeStatus();
  5666.                     if (CAMP->DoReturn || cResult == T_READY)
  5667.                     {
  5668.                         CAMP->TimeStop();
  5669.                         if (!CURCAMP->Scatter)
  5670.                         {
  5671.                             CampReturn(CURCAMP->Pc ? pCampPlayer->Y : CURCAMP->Y, CURCAMP->Pc ? pCampPlayer->X : CURCAMP->X, CURCAMP->Radius, &CAMP->Y, &CAMP->X);
  5672.                         }
  5673.                         else
  5674.                         {
  5675.                             PolarSpot(CURCAMP->Pc ? pCampPlayer->Y : CURCAMP->Y, CURCAMP->Pc ? pCampPlayer->X : CURCAMP->X, 0.0f, CURCAMP->Bearing, CURCAMP->ScatDist, CURCAMP->ScatSize, &CAMP->Y, &CAMP->X);
  5676.                         }
  5677.                         MOVETO->On       = CAMP->Returning  = true;
  5678.                         MOVETO->PreciseX = MOVETO->PreciseY = false;
  5679.                         CAMP->DoAlt                         = false;
  5680.                         if (!CAMP->DoReturn) CAMP->Auto     = true; // so the output msg isnt displayed unless user/macro issued command and used in pause
  5681.                     }
  5682.                     else if (cResult == T_INACTIVE)
  5683.                     {
  5684.                         CAMP->Auto = false;
  5685.                         CAMP->TimeStart();
  5686.                         return; // return here to begin waiting for return time
  5687.                     }
  5688.                 }
  5689.             }
  5690.             // end normal return
  5691.         }
  5692.         // end auto return checking
  5693.  
  5694.         // begin leash processing with active stick/circle
  5695.         if (!PAUSE->UserKB && !PAUSE->UserMouse && CURCAMP->Leash && (STICK->On || CIRCLE->On || CURCAMP->RedoStick || CURCAMP->RedoCircle))
  5696.         {
  5697.             CMULoc HeadBack;
  5698.             HeadBack.Y = CURCAMP->Pc ? pCampPlayer->Y : CURCAMP->Y;
  5699.             HeadBack.X = CURCAMP->Pc ? pCampPlayer->X : CURCAMP->X;
  5700.  
  5701.             if (CAMP->CurDist > CURCAMP->Length + 2.0f) // give leeway if teetering
  5702.             {
  5703.                 if (STICK->On || CIRCLE->On)
  5704.                 {
  5705.                     if (STICK->On)
  5706.                     {
  5707.                         EndPreviousCmd(true, CMD_STICK, true);
  5708.                         STICK->On         = bStickOn        = false; // disable stick but don't reset current cmd settings
  5709.                         STICK->BehindOnce = STICK->Snaproll = false; // disable these as well since locations will no longer be accurate
  5710.                         CURCAMP->RedoStick                = true;
  5711.                     }
  5712.                     else
  5713.                     {
  5714.                         EndPreviousCmd(true, CMD_CIRCLE, true);
  5715.                         CIRCLE->On            = false; // disable circling but don't reset current cmd settings
  5716.                         CURCAMP->RedoCircle = true;
  5717.                     }
  5718.                 }
  5719.                 if (psTarget && (CURCAMP->RedoStick || CURCAMP->RedoCircle))
  5720.                 {
  5721.                     fNewHeading = MOVE->SaneHead((atan2(HeadBack.Y - pChSpawn->Y, HeadBack.X - pChSpawn->X) * HEADING_HALF / (float)PI));
  5722.                     MOVE->TryMove(GO_FORWARD, MU_WALKOFF, fNewHeading, HeadBack.Y, HeadBack.X);
  5723.                 }
  5724.             }
  5725.             else if (CURCAMP->RedoStick || CURCAMP->RedoCircle)
  5726.             {
  5727.                 EndPreviousCmd(false, (CURCAMP->RedoStick ? CMD_STICK : CMD_CIRCLE), true);
  5728.                 CURCAMP->RedoStick ? STICK->TurnOn() : CIRCLE->On = true;
  5729.                 CURCAMP->RedoStick = CURCAMP->RedoCircle = false;
  5730.                 return;
  5731.             }
  5732.         }
  5733.     }
  5734.     // end return to camp handling
  5735.     if (ucCmdUsed == CMD_MAKECAMP) return; // nothing below applies makecamp, return turns bMoveTo on which calls with CMD_MOVETO
  5736.  
  5737.     // reset use of /face command
  5738.     gFaceAngle = H_INACTIVE;
  5739.  
  5740.     // assign values for circle
  5741.     if (ucCmdUsed == CMD_CIRCLE)
  5742.     {
  5743.         float fUseCirYX[2] = {(pChSpawn->Y - CIRCLE->Y), (pChSpawn->X - CIRCLE->X)};
  5744.         CIRCLE->CurDist = sqrt(fUseCirYX[0] * fUseCirYX[0] + fUseCirYX[1] * fUseCirYX[1]);
  5745.         if (CIRCLE->CurDist < CIRCLE->Radius * (2.0f / 3.0f)) bUseStuck = false;
  5746.     }
  5747.     // end circle assignments
  5748.  
  5749.     if (ucCmdUsed == CMD_MOVETO)
  5750.     {
  5751.         if (MOVETO->PreciseY)
  5752.         {
  5753.             MOVETO->CurDist = fabs(GetDistance(pChSpawn->Y, 0.0f, MOVETO->Y, 0.0f));
  5754.             MOVETO->DifDist = MOVETO->DistY;
  5755.         }
  5756.         else if (MOVETO->PreciseX)
  5757.         {
  5758.             MOVETO->CurDist = fabs(GetDistance(0.0f, pChSpawn->X, 0.0f, MOVETO->X));
  5759.             MOVETO->DifDist = MOVETO->DistX;
  5760.         }
  5761.         else
  5762.         {
  5763.             if (CAMP->Returning)
  5764.             {
  5765.                 // if camp player return is active, keep moveto location updated real time
  5766.                 if (CURCAMP->Pc && CURCAMP->Realtime)
  5767.                 {
  5768.                     if (!CURCAMP->Scatter)
  5769.                     {
  5770.                         CampReturn(pCampPlayer->Y, pCampPlayer->X, CURCAMP->Radius, &CAMP->Y, &CAMP->X);
  5771.                     }
  5772.                     else
  5773.                     {
  5774.                         PolarSpot(pCampPlayer->Y, pCampPlayer->X, 0.0f, CURCAMP->Bearing, CURCAMP->ScatDist, CURCAMP->ScatSize, &CAMP->Y, &CAMP->X);
  5775.                     }
  5776.                 }
  5777.                 MOVETO->CurDist = fabs(GetDistance(pChSpawn->Y, pChSpawn->X, CAMP->Y, CAMP->X));
  5778.             }
  5779.             else if (MOVETO->Z == 0.0f)
  5780.             {
  5781.                 MOVETO->CurDist = fabs(GetDistance(pChSpawn->Y, pChSpawn->X, MOVETO->Y, MOVETO->X));
  5782.             }
  5783.             else
  5784.             {
  5785.                 MOVETO->CurDist = fabs(GetDistance3D(pChSpawn->Y, pChSpawn->X, pChSpawn->Z, MOVETO->Y, MOVETO->X, MOVETO->Z));
  5786.             }
  5787.             MOVETO->DifDist = MOVETO->Dist;
  5788.         }
  5789.  
  5790.         // check for stucklogic and MoveToAggro
  5791.         if (MOVETO->CurDist <= MOVETO->DifDist)
  5792.         {
  5793.             bMoveToOOR = bUseStuck = false;
  5794.         }
  5795.         else
  5796.         {
  5797.             bMoveToOOR = true;
  5798.             if (MOVETO->BreakAggro && MOVETO->DidAggro()) return;
  5799.         }
  5800.     }
  5801.  
  5802.     // BEGIN STUCKLOGIC
  5803.     if (STUCK->On)
  5804.     {
  5805.         // use 3D to compare Z so stucklogic doesn't fire if we are moving more z than y/x (up/down slopes)
  5806.         // if bJumping then dont check z axis movement
  5807.         STUCK->DifDist = (bLevitated || (sbJumping && bInJump)) ? GetDistance(pChSpawn->Y, pChSpawn->X, STUCK->Y, STUCK->X) : GetDistance3D(pChSpawn->Y, pChSpawn->X, pChSpawn->Z, STUCK->Y, STUCK->X, STUCK->Z);
  5808.  
  5809.         // sanity check, if we've moved more than 5 (summon, knockback, user)
  5810.         // it will throw off our readjustment, so keep the last value instead
  5811.         if (STUCK->DifDist < 5.0f) STUCK->CurDist = MovingAvg(STUCK->DifDist, STUCK->Check);
  5812.         //SpewDebug(DBG_STUCK, "STUCK->CurDist = %.2f, fPulseMoved %.2f", STUCK->CurDist, fPulseMoved);
  5813.  
  5814.         STUCK->Y = pChSpawn->Y;
  5815.         STUCK->X = pChSpawn->X;
  5816.         STUCK->Z = pChSpawn->Z;
  5817.  
  5818.         //SpewDebug(DBG_DISABLE, "runspeed %.2f and walkspeed %.2f and speedrun %.2f and speedmultiplier %.2f", pChSpawn->RunSpeed, pChSpawn->WalkSpeed, pChSpawn->SpeedRun, pChSpawn->SpeedMultiplier);
  5819.         if (bSnared || bRooted)
  5820.         {
  5821.             // dont use stucklogic if snared
  5822.             bUseStuck = false;
  5823.             STUCK->StuckInc = 0;
  5824.             STUCK->StuckDec = 0;
  5825.         }
  5826.         else if (fSpeedMulti < 0.25f && *EQADDR_RUNWALKSTATE)
  5827.         {
  5828.             fSpeedMulti = 0.25f; // boost multiplier of those without runspeed if not walking
  5829.         }
  5830.         else if (!*EQADDR_RUNWALKSTATE)
  5831.         {
  5832.             fSpeedMulti = 0.1f; // boost multiplier of those walking
  5833.         }
  5834.  
  5835.         // if we were stuck last pulse and we moved more than stuckdist since (making progress to get unstuck)
  5836.         if (STUCK->StuckInc && STUCK->CurDist > STUCK->Dist)
  5837.         {
  5838.             STUCK->StuckInc--;
  5839.             //SpewDebug(DBG_STUCK, "Decremented STUCK->StuckInc to (%d) because we moved (%3.2f)", STUCK->StuckInc, STUCK->CurDist);
  5840.  
  5841.             //force unstuck after defined increments of not being stuck. we reset STUCK->StuckDec if we get stuck again
  5842.             STUCK->StuckDec++;
  5843.             if (STUCK->StuckDec > STUCK->Unstuck)
  5844.             {
  5845.                 STUCK->StuckInc = 0;
  5846.                 STUCK->StuckDec = 0;
  5847.                 //SpewDebug(DBG_STUCK, "Zeroed STUCK->StuckInc and STUCK->StuckDec after consecutive decrements");
  5848.             }
  5849.         }
  5850.  
  5851.         if (bStunned || MOVE->ChangeHead != H_INACTIVE) bUseStuck = false; // dont analyze if stunned or plugin is adjusting heading
  5852.         //SpewDebug(DBG_STUCK, "if STUCK->CurDist(%.2f) < STUCK->Dist(%.2f) * fSpeedMulti(%.2f) && bUse(%s) && Fwd(%s) or Side(%s)", STUCK->CurDist, STUCK->Dist, fSpeedMulti, bUseStuck ? "true" : "false", pMU->CmdFwd ? "true" : "false", pMU->CmdStrafe ? "true" : "false");
  5853.  
  5854.         if ((pMU->CmdFwd || pMU->CmdStrafe) && bUseStuck &&
  5855.             // if moved forward or strafe (not backwards)
  5856.             // bUseStuck is set false if using stucklogic this pulse is not desired
  5857.  
  5858.             // main stucklogic formula here
  5859.             ( (STUCK->CurDist < STUCK->Dist * fSpeedMulti && !bSwimming && !bMounted) ||
  5860.  
  5861.             // maybe handle water and mounts on their own system?
  5862.             (bSwimming && (double)STUCK->CurDist < 0.0010) ||
  5863.  
  5864.             (bMounted && STUCK->CurDist < (STUCK->Dist + fSpeedMulti) / 3.0f) )
  5865.  
  5866.             )
  5867.         {
  5868.             //SpewDebug(DBG_STUCK, "Im Stuck (STUCK->StuckInc = %d) -- if fpulsemoved (%.2f) < STUCK->Dist(%.2f) * fSpeedMultiplier(%.2f) then increment", STUCK->StuckInc, fPulseMoved, STUCK->Dist, fSpeedMulti);
  5869.  
  5870.             // 'big if' is true, if we've moved less than user-set dist * current speed multiplier
  5871.             if (STUCK->DifDist < STUCK->Dist * fSpeedMulti) // check if our movement this single pulse is still bad
  5872.             {
  5873.                 STUCK->StuckInc++;
  5874.                 STUCK->StuckDec = 0;
  5875.                 //SpewDebug(DBG_STUCK, "incremented STUCK->StuckInc %d, reset STUCK->StuckDec to zero", STUCK->StuckInc);
  5876.  
  5877.                 // STUCK->Jump user set value in INI
  5878.                 // try to jump early (but not 1-2pulse misfires) and again after a few seconds/turns
  5879.                 if (STUCK->Jump && !sbJumping && !bLevitated && !bSwimming && ((STUCK->StuckInc % 5) == 0))
  5880.                 {
  5881.                     MQ2Globals::ExecuteCmd(iJumpKey, 1, 0);
  5882.                     MQ2Globals::ExecuteCmd(iJumpKey, 0, 0);
  5883.                     sbJumping = true;
  5884.                 }
  5885.  
  5886.                 // calculate original heading for turnhalf before first turn attempt
  5887.                 float fOrigHead, fHalfHead, fCompNegHead, fCompPosHead = 0.0f;
  5888.                 if (STUCK->StuckInc == 4)
  5889.                 {
  5890.                     switch (ucCmdUsed)
  5891.                     {
  5892.                     case CMD_STICK:
  5893.                         fOrigHead = MOVE->SaneHead((atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * HEADING_HALF) / (float)PI);
  5894.                         break;
  5895.                     case CMD_MOVETO:
  5896.                         if (CAMP->Returning)
  5897.                         {
  5898.                             fOrigHead = MOVE->SaneHead((atan2(CAMP->X - pChSpawn->X, CAMP->Y - pChSpawn->Y) * HEADING_HALF) / (float)PI);
  5899.                             break;
  5900.                         }
  5901.                         fOrigHead = MOVE->SaneHead((atan2(MOVETO->X - pChSpawn->X, MOVETO->Y - pChSpawn->Y) * HEADING_HALF) / (float)PI);
  5902.                         break;
  5903.                     case CMD_CIRCLE:
  5904.                         fOrigHead = (atan2(pChSpawn->Y - CIRCLE->Y, CIRCLE->X - pChSpawn->X) * CIRCLE_HALF) / (float)PI * CIRCLE_QUARTER;
  5905.                         fOrigHead += CIRCLE_QUARTER * (CIRCLE->Radius / CIRCLE->CurDist);
  5906.                         fOrigHead = MOVE->SaneHead(fOrigHead *= HEADING_MAX / CIRCLE_MAX);
  5907.                     }
  5908.  
  5909.                     fHalfHead = MOVE->SaneHead(fOrigHead + HEADING_HALF);
  5910.                     //SpewDebug(DBG_STUCK, "We've determined that halfway from destination is %.2f", fHalfHead);
  5911.                     fCompNegHead = MOVE->SaneHead(fHalfHead - fabs(STUCK->TurnSize / 2.0f));
  5912.                     fCompPosHead = MOVE->SaneHead(fHalfHead + fabs(STUCK->TurnSize / 2.0f));
  5913.                 }
  5914.  
  5915.                 // if STUCK->StuckInc == multiple of 4 (try to turn 1 increment, every 4 pulses of being stuck)
  5916.                 if ((STUCK->StuckInc & 3) == 0)
  5917.                 {
  5918.                     fNewHeading = MOVE->SaneHead(pChSpawn->Heading + STUCK->TurnSize);
  5919.                     //SpewDebug(DBG_STUCK, "Stucklogic turned, New heading is %.2f", fNewHeading);
  5920.  
  5921.                     // if enabled, check if we are halfway away from our destination, reset heading to original heading and start again
  5922.                     if (STUCK->TurnHalf)
  5923.                     {
  5924.                         //SpewDebug(DBG_STUCK, "TURNHALF: Comparing desired heading (%.2f) > %.2f and < %.2f", fNewHeading, fCompNegHead, fCompPosHead);
  5925.                         if (fNewHeading > fCompNegHead && fNewHeading < fCompPosHead)
  5926.                         {
  5927.                             fNewHeading = fOrigHead;
  5928.                             STUCK->TurnSize *= -1.0f;
  5929.                             //SpewDebug(DBG_STUCK, "TRUE, so flipped STUCK->TurnSize to other way (%.2f) and reset heading to %.2f", STUCK->TurnSize, fNewHeading);
  5930.                         }
  5931.                     }
  5932.                     MOVE->NewHead(fNewHeading);
  5933.                     //SpewDebug(DBG_STUCK, "Stucklogic heading change: %.2f", fNewHeading);
  5934.                 }
  5935.             }
  5936.             // end fPulseMoved < STUCK->Dist * speedmulti
  5937.         }
  5938.         // end 'big if'
  5939.     }
  5940.     // end if STUCK->On (meaning use stucklogic or not)
  5941.  
  5942.     // if we are stuck or rooted dont process normal heading & movement
  5943.     if (STUCK->StuckInc || bRooted)
  5944.     {
  5945.         //SpewDebug(DBG_STUCK, "STUCK->StuckInc %d bRooted %s fired, returning without trying to move", STUCK->StuckInc, bRooted ? "true" : "false");
  5946.         return;
  5947.     }
  5948.     // END OF STUCKLOGIC
  5949.  
  5950.  
  5951.     // handle heading and movement
  5952.     switch (ucCmdUsed)
  5953.     {
  5954.     case CMD_STICK:
  5955.         if (!STICK->Snaproll) fNewHeading = MOVE->SaneHead(atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * HEADING_HALF / (float)PI);
  5956.         // jump ahead to stick handling
  5957.         break;
  5958.     case CMD_CIRCLE:
  5959.         fNewHeading = (!CIRCLE->CCW != CIRCLE->Backward) ? (atan2(pChSpawn->Y - CIRCLE->Y, CIRCLE->X - pChSpawn->X) * CIRCLE_HALF) / (float)PI : (atan2(CIRCLE->Y - pChSpawn->Y, pChSpawn->X - CIRCLE->X) * CIRCLE_HALF) / (float)PI;
  5960.         CIRCLE->CCW ?  fNewHeading -= CIRCLE_QUARTER + CIRCLE_QUARTER * (CIRCLE->Radius / CIRCLE->CurDist) : fNewHeading += CIRCLE_QUARTER + CIRCLE_QUARTER * (CIRCLE->Radius / CIRCLE->CurDist);
  5961.         MOVE->NewHead(MOVE->SaneHead(fNewHeading *= HEADING_MAX / CIRCLE_MAX));
  5962.         CIRCLE->Backward ? MOVE->DoMove(GO_BACKWARD) : MOVE->DoMove(GO_FORWARD);
  5963.         // end of all circle processing
  5964.         return;
  5965.     case CMD_MOVETO:
  5966.         if (bMoveToOOR)
  5967.         {
  5968.             if (psTarget && MOVETO->UW)
  5969.             {
  5970.                 double dLookAngle = (double)atan2(psTarget->Z + psTarget->AvatarHeight * StateHeightMultiplier(psTarget->StandState) -
  5971.                     pChSpawn->Z - pChSpawn->AvatarHeight * StateHeightMultiplier(pChSpawn->StandState), fabs(GetDistance3D(pChSpawn->Y, pChSpawn->X, pChSpawn->Z, psTarget->Y, psTarget->X, psTarget->Z))) * HEADING_HALF / (double)PI;
  5972.                 MOVE->NewFace(dLookAngle);
  5973.             }
  5974.             if (CAMP->Returning)
  5975.             {
  5976.                 fNewHeading = MOVE->SaneHead(atan2(CAMP->X - pChSpawn->X, CAMP->Y - pChSpawn->Y) * HEADING_HALF / (float)PI);
  5977.                 if (MOVETO->UseBack)
  5978.                 {
  5979.                     if (MOVE->ChangeHead == H_INACTIVE && MOVETO->CurDist < MOVETO->DistBack)
  5980.                     {
  5981.                         float fHeadDiff = MOVE->SaneHead(pChSpawn->Heading - fNewHeading);
  5982.                         if (fHeadDiff >= 200.0f && fHeadDiff <= 300.0f)
  5983.                         {
  5984.                             MOVE->DoMove(GO_BACKWARD, true, MOVETO->CurDist < 20.0f ? MU_WALKON : MU_WALKOFF);
  5985.                             return;
  5986.                         }
  5987.                     }
  5988.                 }
  5989.                 MOVE->NewHead(fNewHeading);
  5990.                 MOVE->TryMove(GO_FORWARD, (MOVETO->Walk && MOVETO->CurDist < 20.0f) ? MU_WALKON : MU_WALKOFF, fNewHeading, CAMP->Y, CAMP->X);
  5991.                 return;
  5992.             }
  5993.             fNewHeading = MOVE->SaneHead(atan2(MOVETO->X - pChSpawn->X, MOVETO->Y - pChSpawn->Y) * HEADING_HALF / (float)PI);
  5994.             if (MOVETO->UseBack)
  5995.             {
  5996.                 if (MOVE->ChangeHead == H_INACTIVE && MOVETO->CurDist < MOVETO->DistBack)
  5997.                 {
  5998.                     float fHeadDiff = MOVE->SaneHead(pChSpawn->Heading - fNewHeading);
  5999.                     if (fHeadDiff >= 200.0f && fHeadDiff <= 300.0f)
  6000.                     {
  6001.                         MOVE->DoMove(GO_BACKWARD, true, MOVETO->CurDist < 20.0f ? MU_WALKON : MU_WALKOFF);
  6002.                         return;
  6003.                     }
  6004.                 }
  6005.             }
  6006.             MOVE->NewHead(fNewHeading);
  6007.             MOVE->TryMove(GO_FORWARD, (MOVETO->Walk && MOVETO->CurDist < 20.0f) ? MU_WALKON : MU_WALKOFF, fNewHeading, MOVETO->Y, MOVETO->X);
  6008.             return;
  6009.         }
  6010.         if (!CAMP->Auto) // we do not want output for auto-returns
  6011.         {
  6012.             if (CAMP->DoReturn)
  6013.             {
  6014.                 sprintf(szMsg, "\ay%s\aw:: Arrived at %s", MODULE_NAME, szArriveCamp);
  6015.             }
  6016.             else if (CAMP->DoAlt)
  6017.             {
  6018.                 sprintf(szMsg, "\ay%s\aw:: Arrived at %s", MODULE_NAME, szArriveAlt);
  6019.             }
  6020.             else
  6021.             {
  6022.                 sprintf(szMsg, "\ay%s\aw:: Arrived at %s", MODULE_NAME, szArriveMove);
  6023.                 pMU->StoppedMoveto = true;
  6024.             }
  6025.             WriteLine(szMsg, V_MOVETOV);
  6026.         }
  6027.         CAMP->Auto = CAMP->DoAlt = CAMP->DoReturn = false;
  6028.         EndPreviousCmd(true);
  6029.         // end of all moveto processing
  6030.         return;
  6031.     default:
  6032.         return;
  6033.     }
  6034.  
  6035.     // -----------------------------------------------------
  6036.     // everything below this point relates to '/stick' ONLY
  6037.     // -----------------------------------------------------
  6038.  
  6039.     // diff between cur heading vs. desired heading
  6040.     float fHeadDiff = MOVE->SaneHead(pChSpawn->Heading - fNewHeading);
  6041.  
  6042.     // if we are close to the mob and our desired heading change is large, move backwards instead
  6043.     if (STICK->UseBack && !STICK->Snaproll && !STICK->Healer && MOVE->ChangeHead == H_INACTIVE && STICK->CurDist < STICK->Dist + STICK->DistBack)
  6044.     {
  6045.         // we check the MOVE->ChangeHead so not to affect turns already in motion
  6046.         if (fHeadDiff >= 200.0f && fHeadDiff <= 300.0f)
  6047.         {
  6048.             MOVE->DoMove(GO_BACKWARD);
  6049.             return;
  6050.         }
  6051.     }
  6052.  
  6053.     // what is clarity?
  6054.     bool bTurnHealer = (!STICK->Healer ? true : (STICK->CurDist > STICK->Dist + 10.0f ? true : false));
  6055.     if (bTurnHealer)
  6056.     {
  6057.         MOVE->NewHead(fNewHeading); // adjust heading for all cases except stick healer being oor
  6058.  
  6059.         if (STICK->UW) // adjust look angle if underwater param or autouw
  6060.         {
  6061.             double dLookAngle = (double)atan2(psTarget->Z + psTarget->AvatarHeight * StateHeightMultiplier(psTarget->StandState) -
  6062.                 pChSpawn->Z - pChSpawn->AvatarHeight * StateHeightMultiplier(pChSpawn->StandState), STICK->CurDist) * HEADING_HALF / (double)PI;
  6063.             MOVE->NewFace(dLookAngle);
  6064.         }
  6065.     }
  6066.  
  6067.     // if stucklogic is on and we are ducking while sticking, un-duck
  6068.     if (STUCK->On && pChSpawn->StandState == STANDSTATE_DUCK) MOVE->DoStand();
  6069.  
  6070.     // move FORWARD ONLY until near stick range (except snaproll)
  6071.     if (STICK->CurDist > STICK->Dist + 10.0f && !STICK->Snaproll)
  6072.     {
  6073.         MOVE->StopMove(KILL_STRAFE);
  6074.         MOVE->TryMove(GO_FORWARD, (STICK->CurDist > STICK->Dist + 20.0f) ? MU_WALKOFF : (STICK->Walk ? MU_WALKON : MU_WALKIGNORE), fNewHeading, psTarget->Y, psTarget->X);
  6075.         return;
  6076.     }
  6077.     // everything below: only if near stick range
  6078.  
  6079.     // calculate our angular distance
  6080.     float fAngDist     = MOVE->AngDist(psTarget->Heading, pChSpawn->Heading);
  6081.     float fFabsAngDist = fabs(fAngDist);
  6082.     bool b3xRange   = (STICK->CurDist <  STICK->Dist * 3) ? true : false;
  6083.     bool bAnyStrafe = (STICK->Strafe  || STICK->Front)    ? true : false;
  6084.  
  6085.     // if too far away, don't do pin or behind or aggro checking (if awareness on)
  6086.     if (bAnyStrafe && b3xRange)
  6087.     {
  6088.         // handling for behind/pin/!front
  6089.         if (STICK->Strafe)
  6090.         {
  6091.             // halt strafing if we are on HoTT
  6092.             if (pMU->CmdStrafe && (int)pLPlayer->SpawnID == pChSpawn->TargetOfTarget)
  6093.             {
  6094.                 MOVE->StopMove(KILL_STRAFE);
  6095.             }
  6096.             // we are not on HoTT
  6097.             else
  6098.             {
  6099.                 // if randomize is enabled and using /stick behind or /stick !front, but not /stick pin
  6100.                 if (STICK->Randomize && !STICK->BehindOnce)
  6101.                 {
  6102.                     bool bPosFlag = (rand() % 100 > 50);
  6103.                     if (!STICK->Pin)
  6104.                     {
  6105.                         // our randomized "flag" is negative or positive sign - to determine which arc was modified
  6106.                         // we make this eval multiple times, so set it to a bool first
  6107.                         if (fAngDist < 0.0f && fFabsAngDist > (bPosFlag ? STICK->RandMax : STICK->RandMin))
  6108.                         {
  6109.                             MOVE->StickStrafe(GO_LEFT);
  6110.                         }
  6111.                         else if (fAngDist > 0.0f && fFabsAngDist > (bPosFlag ? STICK->RandMin : STICK->RandMax))
  6112.                         {
  6113.                             MOVE->StickStrafe(GO_RIGHT);
  6114.                         }
  6115.                         // else we are within the arc range, so stop strafing
  6116.                         else
  6117.                         {
  6118.                             MOVE->StopMove(KILL_STRAFE);
  6119.                         }
  6120.                     }
  6121.                     else
  6122.                     {
  6123.                         if (STICK->UseFleeing && IsMobFleeing(pChSpawn, psTarget) && (psTarget->HPCurrent * 100 / psTarget->HPMax) < 25)
  6124.                         {
  6125.                             MOVE->StopMove(KILL_STRAFE);
  6126.                         }
  6127.                         else if (fFabsAngDist > PIN_ARC_MAX || fFabsAngDist < PIN_ARC_MIN)
  6128.                         {
  6129.                             if ((fAngDist < 0.0f && fAngDist > (bPosFlag ? (PIN_ARC_MIN * -1.0f) : (STICK->RandMin * -1.0f))) || fAngDist > (bPosFlag ? STICK->RandMax : PIN_ARC_MAX))
  6130.                             {
  6131.                                 MOVE->StickStrafe(GO_RIGHT);
  6132.                             }
  6133.                             if ((fAngDist > 0.0f && fAngDist < (bPosFlag ? PIN_ARC_MIN : STICK->RandMin)) || fAngDist < (bPosFlag ? (PIN_ARC_MAX * -1.0f) : (STICK->RandMax * -1.0f)))
  6134.                             {
  6135.                                 MOVE->StickStrafe(GO_LEFT);
  6136.                             }
  6137.                         }
  6138.                         else
  6139.                         {
  6140.                             MOVE->StopMove(KILL_STRAFE);
  6141.                         }
  6142.                     }
  6143.                 }
  6144.                 // else randomize is not on, or /stick behindonce
  6145.                 else
  6146.                 {
  6147.                     // normal processing for 'behind' and 'behindonce'
  6148.                     if (STICK->Behind || STICK->BehindOnce)
  6149.                     {
  6150.                         if (fFabsAngDist > STICK->ArcBehind)
  6151.                         {
  6152.                             if (fAngDist < 0.0f)
  6153.                             {
  6154.                                 MOVE->StickStrafe(GO_LEFT);
  6155.                             }
  6156.                             else
  6157.                             {
  6158.                                 MOVE->StickStrafe(GO_RIGHT);
  6159.                             }
  6160.                         }
  6161.                         else
  6162.                         {
  6163.                             STICK->BehindOnce = false;
  6164.                             MOVE->StopMove(KILL_STRAFE);
  6165.                         }
  6166.                     }
  6167.                     // processing for '/stick pin'
  6168.                     else if (STICK->Pin)
  6169.                     {
  6170.                         if (STICK->UseFleeing && IsMobFleeing(pChSpawn, psTarget) && (psTarget->HPCurrent * 100 / psTarget->HPMax) < 25)
  6171.                         {
  6172.                             MOVE->StopMove(KILL_STRAFE);
  6173.                         }
  6174.                         else if (fFabsAngDist > PIN_ARC_MAX || fFabsAngDist < PIN_ARC_MIN)
  6175.                         {
  6176.                             if ((fAngDist < 0.0f && fAngDist > (PIN_ARC_MIN * -1.0f)) || fAngDist > PIN_ARC_MAX)
  6177.                             {
  6178.                                 MOVE->StickStrafe(GO_RIGHT);
  6179.                             }
  6180.                             if ((fAngDist > 0.0f && fAngDist < PIN_ARC_MIN) || fAngDist < (PIN_ARC_MAX * -1.0f))
  6181.                             {
  6182.                                 MOVE->StickStrafe(GO_LEFT);
  6183.                             }
  6184.                         }
  6185.                         else
  6186.                         {
  6187.                             MOVE->StopMove(KILL_STRAFE);
  6188.                         }
  6189.                     }
  6190.                     // else non-random processing for stick !front
  6191.                     else if (STICK->NotFront)
  6192.                     {
  6193.                         if (fFabsAngDist > STICK->ArcNotFront)
  6194.                         {
  6195.                             int iRandT = rand() % 100;
  6196.                             if (iRandT > 85)
  6197.                             {
  6198.                                 STICK->BehindOnce = true;
  6199.                             }
  6200.                             else if (fAngDist < 0.0f)
  6201.                             {
  6202.                                 MOVE->StickStrafe(GO_LEFT);
  6203.                             }
  6204.                             else
  6205.                             {
  6206.                                 MOVE->StickStrafe(GO_RIGHT);
  6207.                             }
  6208.                         }
  6209.                         else
  6210.                         {
  6211.                             MOVE->StopMove(KILL_STRAFE);
  6212.                         }
  6213.                     }
  6214.                 }
  6215.             }
  6216.         }
  6217.         else if (STICK->Front)
  6218.         {
  6219.             if (SET->Spin || (int)pLPlayer->SpawnID == pChSpawn->TargetOfTarget)
  6220.             {
  6221.                 // if im the target of target or deliberately want to spin if lose aggro
  6222.                 if (STICK->UseFleeing && IsMobFleeing(pChSpawn, psTarget) && (psTarget->HPCurrent * 100 / psTarget->HPMax) < 25)
  6223.                 {
  6224.                     MOVE->StopMove(KILL_STRAFE);
  6225.                 }
  6226.                 else if (fFabsAngDist < FRONT_ARC)
  6227.                 {
  6228.                     if (fAngDist > 0.0f)
  6229.                     {
  6230.                         MOVE->StickStrafe(GO_LEFT);
  6231.                     }
  6232.                     else
  6233.                     {
  6234.                         MOVE->StickStrafe(GO_RIGHT);
  6235.                     }
  6236.                 }
  6237.                 else
  6238.                 {
  6239.                     MOVE->StopMove(KILL_STRAFE);
  6240.                 }
  6241.             }
  6242.             else
  6243.             {
  6244.                 MOVE->StopMove(KILL_STRAFE);
  6245.             }
  6246.         }
  6247.     }
  6248.     else
  6249.     {
  6250.         MOVE->StopMove(KILL_STRAFE);
  6251.     }
  6252.     //end pin/!front/behind/front
  6253.  
  6254.     // handling for stick snaproll
  6255.     if (STICK->Snaproll)
  6256.     {
  6257.         PolarSpot(psTarget->Y, psTarget->X, psTarget->Heading, STICK->Snap->Bearing, STICK->DistSnap, 0.0f, &STICK->Snap->Y, &STICK->Snap->X); // calculate location we want
  6258.         STICK->Snap->CurDist = fabs(GetDistance(pChSpawn->Y, pChSpawn->X, STICK->Snap->Y, STICK->Snap->X)); // get distance from that location
  6259.  
  6260.         // 3D problems when levitated
  6261.         //STICK->Snap->CurDist = fabs(GetDistance3D(pChSpawn->Y, pChSpawn->X, pChSpawn->Z, STICK->Snap->Y, STICK->Snap->X, psTarget->Z)); // get distance from that location
  6262.  
  6263.         if (STICK->Snap->CurDist <= 5.0f) // if distance is close enough on first pass, no need to snaproll, this also breaks in future pulses
  6264.         {
  6265.             MOVE->StopMove(APPLY_TO_ALL);
  6266.             STICK->Snaproll      = false;
  6267.             STICK->On = bStickOn = true;
  6268.             MOVE->NewHead(MOVE->SaneHead(atan2(psTarget->X - pChSpawn->X, psTarget->Y - pChSpawn->Y) * HEADING_HALF / (float)PI));
  6269.             STICK->NewSnaproll();
  6270.             return;
  6271.         }
  6272.         // determine heading to that location
  6273.         STICK->Snap->Head = MOVE->SaneHead((atan2(STICK->Snap->X - pChSpawn->X, STICK->Snap->Y - pChSpawn->Y) * HEADING_HALF) / (float)PI);
  6274.         MOVE->NewHead(STICK->Snap->Head);
  6275.         // start movement
  6276.         if (STICK->Snap->CurDist > 5.0f)
  6277.         {
  6278.             MOVE->TryMove(GO_FORWARD, MU_WALKOFF, STICK->Snap->Head, STICK->Snap->Y, STICK->Snap->X);
  6279.         }
  6280.         return;
  6281.     }
  6282.     // end snaproll handling
  6283.  
  6284.     // ******** main movement handling for stick *******
  6285.     // if we are outside stick distance
  6286.     if (STICK->CurDist > STICK->Dist)
  6287.     {
  6288.         bool bWithinRange = (STICK->CurDist < STICK->Dist + 20.0f) ? true : false;
  6289.         // flex option, return if we don't want to make small adjustment when close
  6290.         if (bWithinRange && STICK->Flex && STICK->CurDist < STICK->CurDist + STICK->DistFlex) return;
  6291.         // we are outside of flexible range, or flex is disabled
  6292.         MOVE->TryMove(GO_FORWARD, bWithinRange ? (STICK->Walk ? MU_WALKON : MU_WALKIGNORE) : MU_WALKIGNORE, fNewHeading, psTarget->Y, psTarget->X);
  6293.         return;
  6294.     }
  6295.     // else do moveback handling
  6296.     if (STICK->MoveBack)
  6297.     {
  6298.         // if not stick healer, stop movement if we are not within one turn of heading
  6299.         if (!STICK->Healer && fabs(pChSpawn->Heading - fNewHeading) > 14.0f)
  6300.         {
  6301.             MOVE->StopMove(KILL_FB);
  6302.             return;
  6303.         }
  6304.         // moveback not supported unless dist set to more than 5
  6305.         float fClose = STICK->Dist > 5.0f ? STICK->Dist - 5.0f : 0.0f;
  6306.         // if we are closer than 5.0 from our desired stick distance
  6307.         if (STICK->CurDist < fClose)
  6308.         {
  6309.             MOVE->Walk(GO_BACKWARD);
  6310.             return;
  6311.         }
  6312.         MOVE->StopMove(KILL_FB);
  6313.         return;
  6314.     }
  6315.     // else we are within desired distance, stop forward/backward movement
  6316.     MOVE->StopMove(KILL_FB);
  6317. }
  6318.  
  6319. // End Main function
  6320. // ----------------------------------------
  6321. // Begin Window Output
  6322.  
  6323. void WriteLine(char szOutput[MAX_STRING], VERBLEVEL V_COMPARE)
  6324. {
  6325.     // never write out if total silence is set
  6326.     if (uiVerbLevel == V_SILENCE) return;
  6327.  
  6328.     // if we passed totalsilence (0) as type (always output except when totalsilence on, former VERB_ENFORCE)  OR
  6329.     // set to display all output OR
  6330.     // flag for this msg output is on
  6331.     if ((V_COMPARE == V_SILENCE) || (uiVerbLevel & V_EVERYTHING) == V_EVERYTHING || (uiVerbLevel & V_COMPARE) == V_COMPARE)
  6332.     {
  6333.         if (SET->Window)
  6334.         {
  6335.             WINDOW->Write(szOutput);
  6336.             return;
  6337.         }
  6338.         WriteChatf(szOutput);
  6339.     }
  6340. }
  6341.  
  6342. void OutputHelp(unsigned char ucCmdUsed, bool bOnlyCmdHelp)
  6343. {
  6344.     // to support hidehelp, compare uiVerbLevel before calling
  6345.  
  6346.     if (!ValidIngame(false)) return;
  6347.  
  6348.     char szCommand[20]    = {0};
  6349.     bool bDisplaySettings = false;
  6350.  
  6351.     switch (ucCmdUsed)
  6352.     {
  6353.     case CMD_MAKECAMP:
  6354.         sprintf(szCommand, "/makecamp");
  6355.         break;
  6356.     case CMD_STICK:
  6357.         sprintf(szCommand, "/stick");
  6358.         break;
  6359.     case CMD_MOVETO:
  6360.         sprintf(szCommand, "/moveto");
  6361.         break;
  6362.     case CMD_CIRCLE:
  6363.         sprintf(szCommand, "/circle");
  6364.         break;
  6365.     case HELP_SETTINGS:
  6366.         bDisplaySettings = true;
  6367.         break;
  6368.     }
  6369.  
  6370.     char szTempOut[MAX_STRING] = {0};
  6371.     sprintf(szTempOut, "\ay%s \agv%1.4f", MODULE_NAME, MODULE_VERSION);
  6372.     WriteLine(szTempOut, V_SILENCE);
  6373.  
  6374.     if (bDisplaySettings)
  6375.     {
  6376.         WriteLine("\arThe following settings can be changed with any of the 4 commands. There are three options (using /stick as an example).", V_SILENCE);
  6377.         WriteLine("\ay/stick [set] [\agsetting\ax] [on | off]\ax - This will turn the setting on or off", V_SILENCE);
  6378.         WriteLine("\ay/stick [set] [\agsetting\ax] [#]\ax - This will change settings that use numerical values", V_SILENCE);
  6379.         WriteLine("\ay/stick [toggle] [\agsetting\ax]\ax - This will toggle the setting on and off.", V_SILENCE);
  6380.         WriteLine("\arThe following settings can be set on/off OR toggled:", V_SILENCE);
  6381.         WriteLine("\ag[autosave]\ax - Automatic saving of configuration file each time you change a setting.", V_SILENCE);
  6382.         WriteLine("\ag[feign]\ax - Stay-FD support, awaiting you to manually stand before resuming command.", V_SILENCE);
  6383.         WriteLine("\ag[breakonkb|breakonmouse]\ax - End command from manual keyboard/mouse movement.", V_SILENCE);
  6384.         WriteLine("\ag[mpause|mousepause]\ax - Pause from manual keyboard/mouse movement. Resumes after pausemindelay/pausemaxdelay values.", V_SILENCE);
  6385.         WriteLine("\ag[autopause]\ax - Automatic pause&resume command when casting(non-bard), ducking, stunned, targeting self.", V_SILENCE);
  6386.         WriteLine("\ag[verbosity|fullverbosity]\ax - MQ2ChatWnd command output and detailed ouput.", V_SILENCE);
  6387.         WriteLine("\ag[hidehelp]\ax - Hides help output from showing automatically on command failures.", V_SILENCE);
  6388.         WriteLine("\ag[totalsilence]\ax - Hide all MQ2ChatWnd output except critial warnings and requested information.", V_SILENCE);
  6389.         WriteLine("\ag[stucklogic]\ax - Automatic detection of stuck movement and attempted correction.", V_SILENCE);
  6390.         WriteLine("\ag[trytojump]\ax - Try to jump as part of stucklogic getting over obstacles.", V_SILENCE);
  6391.         WriteLine("\ag[turnhalf]\ax - Reset heading and try the other way if halfway from destination in stucklogic.", V_SILENCE);
  6392.         WriteLine("\ag[nohottfront]\ax - Awareness for stick front to not spin if loose aggro.", V_SILENCE);
  6393.         WriteLine("\ag[savebychar]\ax - Save character-specific settings to [CharName] section of configuration file.", V_SILENCE);
  6394.         WriteLine("\ag[breakonsummon]\ax - Halt plugin if character summoned beyond certain distance in a single pulse.", V_SILENCE);
  6395.         WriteLine("\ag[usewalk]\ax - Walk when closing in on moveto / camp return locations for precision.", V_SILENCE);
  6396.         WriteLine("\ag[alwaystruehed]\ax - Use legit heading adjustments with right/left keys.", V_SILENCE);
  6397.         WriteLine("\arThe following settings use a numerical value:", V_SILENCE);
  6398.         WriteLine("\ag[pulsecheck] [#]\ax - Set number of frames used to calculate moving average for stucklogic. (default 4)", V_SILENCE);
  6399.         WriteLine("\ag[pulseunstuck] [#]\ax - Set number of frames successfully moved forward to consider unstuck (default 5)", V_SILENCE);
  6400.         WriteLine("\ag[diststuck] [#.###]\ax - Set distance needed to move per pulse to not be considered stuck. (default 0.5)", V_SILENCE);
  6401.         WriteLine("\ag[campmindelay|campmaxdelay|pausemindelay|pausemaxdelay] [#]\ax - Set camp return or mpause/mousepause delays.", V_SILENCE);
  6402.         WriteLine("\ag[turnrate] [#.##]\ax (\ay1.0\ax to \ay100.0\ax) - Set increment used for loose heading turns.", V_SILENCE);
  6403.         return; // dont re-spam the output below
  6404.     }
  6405.  
  6406.     if (!bOnlyCmdHelp)
  6407.     {
  6408.         WriteLine("\arThe following options work for all commands (\ay/makecamp\ax, \ay/stick\ax, \ay/moveto\ax, \ay/circle\ax)", V_SILENCE);
  6409.         sprintf(szTempOut, "\ay%s [help]\ax - Displays help output for the command.", szCommand);
  6410.         WriteLine(szTempOut, V_SILENCE);
  6411.         sprintf(szTempOut, "\ay%s [debug]\ax - Outputs debugging information to file.", szCommand);
  6412.         WriteLine(szTempOut, V_SILENCE);
  6413.         sprintf(szTempOut, "\ay%s [load|save]\ax - Load settings from or save settings to the configuration file. (MQ2MoveUtils.ini)", szCommand);
  6414.         WriteLine(szTempOut, V_SILENCE);
  6415.         sprintf(szTempOut, "\ay%s [pause|unpause]\ax - Pauses/Unpauses all aspects of this plugin.", szCommand);
  6416.         WriteLine(szTempOut, V_SILENCE);
  6417.         sprintf(szTempOut, "\arFor detailed information on plugin settings, use \ay%s [help] [settings]\ax for more information.", szCommand);
  6418.         WriteLine(szTempOut, V_SILENCE);
  6419.         sprintf(szTempOut, "\arThe remaining options apply to \ay%s\ax only.", szCommand);
  6420.         WriteLine(szTempOut, V_SILENCE);
  6421.     }
  6422.  
  6423.     sprintf(szTempOut, "\ay%s [off]\ax - Ends the command.", szCommand);
  6424.     WriteLine(szTempOut, V_SILENCE);
  6425.  
  6426.     switch (ucCmdUsed)
  6427.     {
  6428.     case CMD_STICK:
  6429.         sprintf(szTempOut, "\ay%s\ax - Sticks to current target using default values.", szCommand);
  6430.         WriteLine(szTempOut, V_SILENCE);
  6431.         sprintf(szTempOut, "\ay%s [id #]\ax - Sticks to a target by its SpawnID or your target if the SpawnID is invalid.", szCommand);
  6432.         WriteLine(szTempOut, V_SILENCE);
  6433.         sprintf(szTempOut, "\ay%s [<#>]\ax - Sticks to target using the distance you supply, i.e. /stick 10 starts 10 range away.", szCommand);
  6434.         WriteLine(szTempOut, V_SILENCE);
  6435.         sprintf(szTempOut, "\ay%s [<#%%%>]\ax - Sticks to given %% of max melee range from target.", szCommand);
  6436.         WriteLine(szTempOut, V_SILENCE);
  6437.         sprintf(szTempOut, "\ay%s [moveback]\ax - Backs you up to current distance value if you get closer to your target.", szCommand);
  6438.         WriteLine(szTempOut, V_SILENCE);
  6439.         sprintf(szTempOut, "\ay%s [uw/underwater]\ax - Look Up/Down to face your target (underwater or not).", szCommand);
  6440.         WriteLine(szTempOut, V_SILENCE);
  6441.         sprintf(szTempOut, "\ay%s [truehead|loose]\ax - Adjusts your heading legit/close to legit instead of instantly.", szCommand);
  6442.         WriteLine(szTempOut, V_SILENCE);
  6443.         sprintf(szTempOut, "\ay%s [snaproll]\ax - Moves you behind the target in a straight line, then proceeds with a basic stick.", szCommand);
  6444.         WriteLine(szTempOut, V_SILENCE);
  6445.         sprintf(szTempOut, "\ay%s [behind]\ax - Sticks you behind your target. \ar*Will spin in circles if you get aggro and no HoTT", szCommand);
  6446.         WriteLine(szTempOut, V_SILENCE);
  6447.         sprintf(szTempOut, "\ay%s [behindonce]\ax - Sticks you behind target immediately, then proceeds with a basic stick.", szCommand);
  6448.         WriteLine(szTempOut, V_SILENCE);
  6449.         sprintf(szTempOut, "\ay%s [hold]\ax - Sticks you to current target even if your target changes.", szCommand);
  6450.         WriteLine(szTempOut, V_SILENCE);
  6451.         sprintf(szTempOut, "\ay%s [!front]\ax - Sticks you anywhere but front melee arc of target.", szCommand);
  6452.         WriteLine(szTempOut, V_SILENCE);
  6453.         sprintf(szTempOut, "\ay%s [front]\ax - Sticks you to the front melee arc of the target.", szCommand);
  6454.         WriteLine(szTempOut, V_SILENCE);
  6455.         sprintf(szTempOut, "\ay%s [pin]\ax - Sticks you to the sides of target.", szCommand);
  6456.         WriteLine(szTempOut, V_SILENCE);
  6457.         sprintf(szTempOut, "\ay%s [toggle] [breakongate|breakonwarp]\ax - Toggle command ending on mob gate/warp.", szCommand);
  6458.         WriteLine(szTempOut, V_SILENCE);
  6459.         sprintf(szTempOut, "\ay%s [set] [breakdist] [#]\ax - Set distance for breakonwarp to trigger.", szCommand);
  6460.         WriteLine(szTempOut, V_SILENCE);
  6461.         sprintf(szTempOut, "\ay%s <your_normal_options> [always]\ax - \arMust be at the end\ax. Will continue to stick to all new NPC targets supplied. Turns off hold/id.", szCommand);
  6462.         WriteLine(szTempOut, V_SILENCE);
  6463.         break;
  6464.     case CMD_MOVETO:
  6465.         sprintf(szTempOut, "\ay%s [loc Y X [Z]|off]\ax - Move to location | stop moving", szCommand);
  6466.         WriteLine(szTempOut, V_SILENCE);
  6467.         sprintf(szTempOut, "\ay%s id [SpawnID]\ax - Move to spawnid. If not numeric value then move to current target", szCommand);
  6468.         WriteLine(szTempOut, V_SILENCE);
  6469.         sprintf(szTempOut, "\ay%s [loose]\ax - Toggles more realistic movement", szCommand);
  6470.         WriteLine(szTempOut, V_SILENCE);
  6471.         sprintf(szTempOut, "\ay%s [dist <#|-#>]\ax - Furthest distance to be considered 'at location', negative subtracts from value", szCommand);
  6472.         WriteLine(szTempOut, V_SILENCE);
  6473.         sprintf(szTempOut, "\ay%s [set] [ydist|xdist] [#.##]\ax - Set distance used for precisey/precisex distance checking.", szCommand);
  6474.         WriteLine(szTempOut, V_SILENCE);
  6475.         sprintf(szTempOut, "\ay%s mdist <#> [id | loc] \ax - Set distance inline with a moveto command.", szCommand);
  6476.         WriteLine(szTempOut, V_SILENCE);
  6477.         break;
  6478.     case CMD_MAKECAMP:
  6479.         sprintf(szTempOut, "\ay%s [on|off]\ax - Drops anchor at current location | removes anchor", szCommand);
  6480.         WriteLine(szTempOut, V_SILENCE);
  6481.         sprintf(szTempOut, "\ay%s [loc <y> <x>]\ax - Makes camp at supplied anchor location", szCommand);
  6482.         WriteLine(szTempOut, V_SILENCE);
  6483.         sprintf(szTempOut, "\ay%s [leash]\ax - Toggles leashing to current camp", szCommand);
  6484.         WriteLine(szTempOut, V_SILENCE);
  6485.         sprintf(szTempOut, "\ay%s [leash [<dist>]]\ax - Set distance to exceed camp before leashing, always turns leash on", szCommand);
  6486.         WriteLine(szTempOut, V_SILENCE);
  6487.         sprintf(szTempOut, "\ay%s [radius <dist>]\ax - Sets radius/size of camp", szCommand);
  6488.         WriteLine(szTempOut, V_SILENCE);
  6489.         sprintf(szTempOut, "\ay%s [maxdelay <#>|mindelay <#>]\ax - Sets the max/minimum amount of time before returning to camp.", szCommand);
  6490.         WriteLine(szTempOut, V_SILENCE);
  6491.         sprintf(szTempOut, "\ay%s [return]\ax - Immediately return to camp", szCommand);
  6492.         WriteLine(szTempOut, V_SILENCE);
  6493.         sprintf(szTempOut, "\ay%s [altreturn]\ax - Immediately return to alternate camp (if established)", szCommand);
  6494.         WriteLine(szTempOut, V_SILENCE);
  6495.         sprintf(szTempOut, "\ay%s [player [<name>]]\ax - Set dynamic camp around player name in zone, or current target", szCommand);
  6496.         WriteLine(szTempOut, V_SILENCE);
  6497.         sprintf(szTempOut, "\ay%s [set] [leashlength] [#.##]\ax - Set leash length size.", szCommand);
  6498.         WriteLine(szTempOut, V_SILENCE);
  6499.         sprintf(szTempOut, "\ay%s [set] [returnnoaggro] [on|off]\ax - Return to camp if not aggro (regardless of target).", szCommand);
  6500.         WriteLine(szTempOut, V_SILENCE);
  6501.         sprintf(szTempOut, "\ay%s [set] [returnnotlooting] [on|off]\ax - Do not return to camp if looting.", szCommand);
  6502.         WriteLine(szTempOut, V_SILENCE);
  6503.         sprintf(szTempOut, "\ay%s [set] [returnhavetarget] [on|off]\ax - Return to camp even if have target.", szCommand);
  6504.         WriteLine(szTempOut, V_SILENCE);
  6505.         sprintf(szTempOut, "\ay%s [set] [campradius] [#]\ax - Change radius of existing camp.", szCommand);
  6506.         WriteLine(szTempOut, V_SILENCE);
  6507.         sprintf(szTempOut, "\ay%s [set] [scatdist] [#.##]\ax - Set scatter distance from center.", szCommand);
  6508.         WriteLine(szTempOut, V_SILENCE);
  6509.         sprintf(szTempOut, "\ay%s [set] [scatsize] [#.##]\ax - Set scatter radius size.", szCommand);
  6510.         WriteLine(szTempOut, V_SILENCE);
  6511.         sprintf(szTempOut, "\ay%s [set] [bearing] [#.##]\ax - Set scatter bearing from center.", szCommand);
  6512.         WriteLine(szTempOut, V_SILENCE);
  6513.         sprintf(szTempOut, "\ay%s [toggle] [usescatter]\ax - Use user-defined scatter values for camp returns.", szCommand);
  6514.         WriteLine(szTempOut, V_SILENCE);
  6515.         break;
  6516.     case CMD_CIRCLE:
  6517.         sprintf(szTempOut, "\ay%s [on <radius>]\ax - Turn circle on at current loc. If radius supplied sets size of circle.", szCommand);
  6518.         WriteLine(szTempOut, V_SILENCE);
  6519.         sprintf(szTempOut, "\ay%s [loc <y> <x>]\ax - Turn on circle at given anchor location. (Y X are the order /loc prints them).", szCommand);
  6520.         WriteLine(szTempOut, V_SILENCE);
  6521.         sprintf(szTempOut, "\ay%s [radius <#>]\ax - Change the circle radius without resetting circle.", szCommand);
  6522.         WriteLine(szTempOut, V_SILENCE);
  6523.         sprintf(szTempOut, "\ay%s [drunken]\ax - Toggles random turns.", szCommand);
  6524.         WriteLine(szTempOut, V_SILENCE);
  6525.         sprintf(szTempOut, "\ay%s [clockwise|cw]\ax - Toggles circling clockwise.", szCommand);
  6526.         WriteLine(szTempOut, V_SILENCE);
  6527.         sprintf(szTempOut, "\ay%s [counterclockwise|ccw|reverse]\ax - Toggles circling counter-clockwise.", szCommand);
  6528.         WriteLine(szTempOut, V_SILENCE);
  6529.         sprintf(szTempOut, "\ay%s [forwards|backwards]\ax - Set movement direction forwards or backwards.", szCommand);
  6530.         WriteLine(szTempOut, V_SILENCE);
  6531.         sprintf(szTempOut, "\ay%s [toggle] [alwaysccw]\ax - Always use counter-clockwise (default is clockwise).", szCommand);
  6532.         WriteLine(szTempOut, V_SILENCE);
  6533.         sprintf(szTempOut, "\ay%s [toggle] [alwaysbackwards]\ax - Always use backwards (default is forwards).", szCommand);
  6534.         WriteLine(szTempOut, V_SILENCE);
  6535.         sprintf(szTempOut, "\ay%s [toggle] [alwaysdrunk]\ax - Always use drunken movement.", szCommand);
  6536.         WriteLine(szTempOut, V_SILENCE);
  6537.         sprintf(szTempOut, "\ay%s [set] [circleradius] [#]\ax - Change the circle radius without resetting circle.", szCommand);
  6538.         WriteLine(szTempOut, V_SILENCE);
  6539.         break;
  6540.     }
  6541. }
  6542.  
  6543. void DebugToWnd(unsigned char ucCmdUsed)
  6544. {
  6545.     char szTemp[MAX_STRING]   = {0};
  6546.     char szTempID[MAX_STRING] = "NULL";
  6547.     char szYes[8]             = "\agyes\ax";
  6548.     char szNo[7]              = "\arno\ax";
  6549.     char szDir[25]            = "\agNormal\ax";
  6550.     char szLongLine[48]       = "\ay---------------------------------------------";
  6551.  
  6552.     sprintf(szTemp, "\ay%s v%1.4f - Current Status", MODULE_NAME, MODULE_VERSION);
  6553.     WriteLine(szTemp, V_SILENCE);
  6554.     if (ucCmdUsed == CMD_STICK || ucCmdUsed == APPLY_TO_ALL)
  6555.     {
  6556.         if (STICK->Behind)
  6557.         {
  6558.             sprintf(szDir, "\agBehind\ax");
  6559.         }
  6560.         else if (STICK->Pin)
  6561.         {
  6562.             sprintf(szDir, "\agSide\ax");
  6563.         }
  6564.         else if (STICK->NotFront)
  6565.         {
  6566.             sprintf(szDir, "\agNot Front\ax");
  6567.         }
  6568.         else if (STICK->Front)
  6569.         {
  6570.             sprintf(szDir, "\agFront\ax");
  6571.         }
  6572.         WriteLine(szLongLine, V_SILENCE);
  6573.         sprintf(szTemp, "\ayStick\ax: Status(%s) Dir(%s) Dist(\ag%.2f\ax) Mod(\ag%.2f\ax) Mod%%%%(\ag%.2f%%%%\ax) Head(%s) Water(%s) MoveBack(%s) Hold(%s) Always(%s)", STICK->On ? szOn : szOff, szDir, STICK->Dist, STICK->DistMod, STICK->DistModP, (pMU->Head == H_TRUE) ? "\agTrue\ax" : ((pMU->Head == H_LOOSE) ? "\ayLoose\ax" : "\arFast\ax"), STICK->UW ? szYes : szNo, STICK->MoveBack ? szYes : szNo, STICK->Hold ? szYes : szNo, STICK->Always ? szOn : szOff);
  6574.         WriteLine(szTemp, V_SILENCE);
  6575.         if (STICK->Hold)
  6576.         {
  6577.             PSPAWNINFO pStickThis = (PSPAWNINFO)GetSpawnByID(STICK->HoldID);
  6578.             if (pStickThis)
  6579.             {
  6580.                 sprintf(szTempID, "%s", pStickThis->DisplayedName);
  6581.             }
  6582.             sprintf(szTemp, "\ayStick\ax: Holding to ID(\ag%d\ax) Name(\ag%s\ax)", STICK->HoldID, szTempID);
  6583.             WriteLine(szTemp, V_SILENCE);
  6584.         }
  6585.         sprintf(szTemp, "\ayStick Options\ax: BreakOnWarp(%s) BreakDist(\ag%.2f\ax) BreakOnGate(%s) ", STICK->BreakWarp ? szOn : szOff, STICK->DistBreak, STICK->BreakGate ? szOn : szOff);
  6586.         WriteLine(szTemp, V_SILENCE);
  6587.     }
  6588.     if (ucCmdUsed == CMD_MOVETO || ucCmdUsed == APPLY_TO_ALL)
  6589.     {
  6590.         WriteLine(szLongLine, V_SILENCE);
  6591.         sprintf(szTemp, "\ayMoveto\ax: Status(%s) Y(\ag%.2f\ax) X(\ay%.2f\ax) Dist(\ag%.2f\ax) Mod(\ag%.2f\ax) YPrecise(%s) XPrecise(%s)", MOVETO->On ? szOn : szOff, MOVETO->Y, MOVETO->X, MOVETO->Dist, MOVETO->Mod, MOVETO->PreciseY ? szYes : szNo, MOVETO->PreciseX ? szYes : szNo);
  6592.         WriteLine(szTemp, V_SILENCE);
  6593.         sprintf(szTemp, "\ayMoveto Options\ax: Y-Dist(\ag%.2f\ax) X-Dist(\ag%.2f\ax)", MOVETO->DistY, MOVETO->DistX);
  6594.         WriteLine(szTemp, V_SILENCE);
  6595.     }
  6596.     if (ucCmdUsed == CMD_CIRCLE || ucCmdUsed == APPLY_TO_ALL)
  6597.     {
  6598.         WriteLine(szLongLine, V_SILENCE);
  6599.         sprintf(szTemp, "\ayCircle\ax: Status(%s) Y(\ag%.2f\ax) X(\ag%.2f\ax) Radius(\ag%.2f\ax) Drunken(%s) Backwards(%s) Clockwise(%s)", CIRCLE->On ? szOn : szOff, CIRCLE->Y, CIRCLE->X, CIRCLE->Radius, CIRCLE->Drunk ? szYes : szNo, CIRCLE->Backward ? szYes : szNo, CIRCLE->CCW ? szNo : szYes);
  6600.         WriteLine(szTemp, V_SILENCE);
  6601.         sprintf(szTemp, "\ayCircle Options\ax: AlwaysDrunk(%s) AlwaysBackwards(%s) AlwaysCCW(%s)", SET_C->Drunk ? szYes : szNo, SET_C->Backward ? szYes : szNo, SET_C->CCW ? szYes : szNo);
  6602.         WriteLine(szTemp, V_SILENCE);
  6603.     }
  6604.     if (ucCmdUsed == CMD_MAKECAMP || ucCmdUsed == APPLY_TO_ALL)
  6605.     {
  6606.         WriteLine(szLongLine, V_SILENCE);
  6607.         sprintf(szTemp, "\ayMakeCamp\ax: Status(%s) Player(%s) Y(\ag%.2f\ax) X(\ag%.2f\ax) Radius(\ag%.2f\ax) Leash(%s) LeashLen(\ag%.2f\ax) Returning(%s) ", CURCAMP->On ? szOn : szOff, CURCAMP->Pc ? szYes : szNo, CURCAMP->Y, CURCAMP->X, CURCAMP->Radius, CURCAMP->Leash ? szOn : szOff, CURCAMP->Length, CAMP->Auto ? szYes : szNo);
  6608.         WriteLine(szTemp, V_SILENCE);
  6609.         sprintf(szTemp, "\ayMakeCamp\ax: Scatter(%s) Bearing(\ag%.2f\ax) ScatDist(\ag%.2f\ax) ScatSize(\ag%.2f\ax)", CURCAMP->Scatter ? szOn : szOff, CURCAMP->Bearing, CURCAMP->ScatDist, CURCAMP->ScatSize);
  6610.         WriteLine(szTemp, V_SILENCE);
  6611.         if (CURCAMP->Pc)
  6612.         {
  6613.             PSPAWNINFO pCampThis = (PSPAWNINFO)GetSpawnByID(CURCAMP->PcID);
  6614.             if (pCampThis)
  6615.             {
  6616.                 sprintf(szTempID, "%s", pCampThis->DisplayedName);
  6617.             }
  6618.             sprintf(szTemp, "\ayMakeCamp\ax: Player Name(\ag%s\ax) ID(\ag%d\ax)", szTempID, CURCAMP->PcID);
  6619.             WriteLine(szTemp, V_SILENCE);
  6620.         }
  6621.         if (ALTCAMP->On)
  6622.         {
  6623.             sprintf(szTemp, "\ayMakeCamp\ax: AlternateCamp(\agon\ax) AltAnchorY(\ag%.2f\ax) AltAnchorX(\ag%.2f\ax) AltRadius(\ag%.2f\ax)", ALTCAMP->Y, ALTCAMP->X, ALTCAMP->Radius);
  6624.             WriteLine(szTemp, V_SILENCE);
  6625.         }
  6626.         sprintf(szTemp, "\ayMakeCamp Options\ax: ReturnNoAggro(%s) MinDelay(\ag%d\ax) MaxDelay(\ag%d\ax)", CURCAMP->NoAggro ? szOn : szOff, CAMP->Min, CAMP->Max);
  6627.         WriteLine(szTemp, V_SILENCE);
  6628.     }
  6629.  
  6630.     if (ucCmdUsed == APPLY_TO_ALL)
  6631.     {
  6632.         WriteLine(szLongLine, V_SILENCE);
  6633.         sprintf(szTemp, "\ayPlugin Status\ax: Paused(%s) MinPause(\ag%d\ax) MaxPause(\ag%d\ax)", PAUSE->PausedMU ? szYes : szNo, PAUSE->Min, PAUSE->Max);
  6634.         WriteLine(szTemp, V_SILENCE);
  6635.         sprintf(szTemp, "\ayStuckLogic\ax: Enabled(%s) DistStuck(\ag%.3f\ax) PulseCheck(\ag%d\ax) PulseUnstuck(\ag%d\ax)", STUCK->On ? szYes : szNo, STUCK->Dist, STUCK->Check, STUCK->Unstuck);
  6636.         WriteLine(szTemp, V_SILENCE);
  6637.         sprintf(szTemp, "\ayPause Options\ax: AutoPause(%s) MPause(%s) BreakOnKB(%s) MousePause(%s) BreakOnMouse(%s)", SET->AutoPause ? szOn : szOff, SET->PauseKB ? szOn : szOff, SET->PauseMouse ? szOn : szOff, SET->BreakKB ? szOn : szOff, SET->BreakMouse ? szOn : szOff);
  6638.         WriteLine(szTemp, V_SILENCE);
  6639.         sprintf(szTemp, "\ayPlugin Options\ax: AutoSave(%s) FeignSupport(%s) BreakOnSummon(%s) BreakSummonDist(\ag%.2f\ax) AwareNotAggro(%s)", SET->AutoSave ? szOn : szOff, SET->Feign ? szOn : szOff, SET->BreakSummon ? szOn : szOff, SET->DistSummon, SET->Spin ? szOn : szOff);
  6640.         WriteLine(szTemp, V_SILENCE);
  6641.     }
  6642. }
  6643.  
  6644. void SpewMUError(unsigned char ucErrorNum)
  6645. {
  6646.     // this function exists to avoid the duplicate code for error messages that are used multiple places
  6647.     // any one-time error will still be in its own logic for clarity
  6648.     char szErrorMsg[MAX_STRING] = {0};
  6649.  
  6650.     switch(ucErrorNum)
  6651.     {
  6652.     case ERR_STICKSELF:
  6653.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) You cannot stick to yourself!", MODULE_NAME);
  6654.         break;
  6655.     case ERR_STICKNONE:
  6656.         sprintf(szErrorMsg, "\ay%s\aw:: You must specify something to stick to!", MODULE_NAME);
  6657.         break;
  6658.     case ERR_BADMOVETO:
  6659.         EndPreviousCmd(true);
  6660.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) \ay/moveto loc [ <Y> <X> [z] ]\ax was supplied incorrectly.", MODULE_NAME);
  6661.         break;
  6662.     case ERR_BADMAKECAMP:
  6663.         CAMP->NewCamp(false);
  6664.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) \ay/makecamp loc [ <Y> <X> ]\ax was supplied incorrectly.", MODULE_NAME);
  6665.         break;
  6666.     case ERR_BADCIRCLE:
  6667.         EndPreviousCmd(true);
  6668.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) Usage \ay/circle loc [ <y> <x> ] [other options]\ax", MODULE_NAME);
  6669.         break;
  6670.     case ERR_BADSPAWN:
  6671.         EndPreviousCmd(true);
  6672.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) Invalid SpawnID and do not have a valid target.", MODULE_NAME);
  6673.         break;
  6674.     case ERR_BADDELAY:
  6675.         sprintf(szErrorMsg, "\ay%s\aw:: (\arERROR\ax) \ay[mindelay|maxdelay] [#]\ax was supplied incorrectly.", MODULE_NAME);
  6676.         break;
  6677.     default:
  6678.         // return if we didnt pass a valid msg number
  6679.         return;
  6680.     }
  6681.     WriteLine(szErrorMsg, V_ERRORS);
  6682. }
  6683.  
  6684. // End window output
  6685. // ----------------------------------------
  6686. // Debugger
  6687.  
  6688. void DebugToDebugger(char* szFormat, ...)
  6689. {
  6690.     char szDbgOutput[MAX_STRING] = {0};
  6691.     va_list vaList;
  6692.     va_start(vaList, szFormat);
  6693.     vsprintf(szDbgOutput, szFormat, vaList);
  6694.     OutputDebugString("[MUTILS] ");
  6695.     OutputDebugString(szDbgOutput);
  6696.     OutputDebugString("\n");
  6697. }
  6698.  
  6699. void SpewDebug(unsigned char ucDbgType, char* szOutput, ...)
  6700. {
  6701.     int i = 1;
  6702.     switch (ucDbgType)
  6703.     {
  6704.     case DBG_MAIN:
  6705. #ifdef DEBUGMAIN
  6706.         DebugToDebugger(szOutput);
  6707. #else
  6708.         i++;
  6709. #endif
  6710.         break;
  6711.     case DBG_STUCK:
  6712. #ifdef DEBUGSTUCK
  6713.         DebugToDebugger(szOutput);
  6714. #else
  6715.         i++;
  6716. #endif
  6717.         break;
  6718.     case DBG_MISC:
  6719. #ifdef DEBUGMISC
  6720.         DebugToDebugger(szOutput);
  6721. #else
  6722.         i++;
  6723. #endif
  6724.         break;
  6725.     case DBG_DISABLE:
  6726.         // do nothing with output
  6727.         i++;
  6728.         break;
  6729.     default:
  6730.         i++;
  6731.         break;
  6732.     }
  6733. }
  6734.  
  6735. // ----------------------------------------
  6736. // Begin file input/output
  6737.  
  6738. void DebugToINI(unsigned char ucCmdUsed)
  6739. {
  6740.     if (!ValidIngame(false)) return;
  6741.  
  6742.     char szTemp[MAX_STRING] = {0};
  6743.     char szCommand[15]      = {0};
  6744.  
  6745.     switch (ucCmdUsed)
  6746.     {
  6747.     case CMD_MAKECAMP:
  6748.         sprintf(szCommand, "/makecamp");
  6749.         break;
  6750.     case CMD_STICK:
  6751.         sprintf(szCommand, "/stick");
  6752.         break;
  6753.     case CMD_MOVETO:
  6754.         sprintf(szCommand, "/moveto");
  6755.         break;
  6756.     case CMD_CIRCLE:
  6757.         sprintf(szCommand, "/circle");
  6758.         break;
  6759.     }
  6760.  
  6761.     sprintf(szTemp, "%s v%1.4f", MODULE_NAME, MODULE_VERSION);
  6762.     WritePrivateProfileString("Version",       "Number",                szTemp,                                     szDebugName);
  6763.     WritePrivateProfileString("Commands",      "CommandUsed",           szCommand,                                  szDebugName);
  6764.     WritePrivateProfileString("GenericBOOL",   "pMU->Keybinds",         pMU->Keybinds         ? "true" : "false",   szDebugName);
  6765.     WritePrivateProfileString("GenericBOOL",   "PAUSE->PausedMU",       PAUSE->PausedMU       ? "true" : "false",   szDebugName);
  6766.     WritePrivateProfileString("GenericBOOL",   "pMU->BrokeSummon",      pMU->BrokeSummon      ? "true" : "false",   szDebugName);
  6767.     WritePrivateProfileString("Strings",       "szMsg",                 szMsg,                                      szDebugName);
  6768.     WritePrivateProfileString("AggroChecking", "SET->Spin",             SET->Spin             ? "true" : "false",   szDebugName);
  6769.     WritePrivateProfileString("AggroChecking", "pMU->Aggro",            pMU->Aggro            ? "true" : "false",   szDebugName);
  6770.     WritePrivateProfileString("INISettings",   "SET->AutoPause",        SET->AutoPause        ? "true" : "false",   szDebugName);
  6771.     WritePrivateProfileString("INISettings",   "SET->PauseKB",          SET->PauseKB          ? "true" : "false",   szDebugName);
  6772.     WritePrivateProfileString("INISettings",   "SET->PauseMouse",       SET->PauseMouse       ? "true" : "false",   szDebugName);
  6773.     WritePrivateProfileString("INISettings",   "SET->BreakKB",          SET->BreakKB          ? "true" : "false",   szDebugName);
  6774.     WritePrivateProfileString("INISettings",   "SET->BreakMouse",       SET->BreakMouse       ? "true" : "false",   szDebugName);
  6775.     WritePrivateProfileString("INISettings",   "STUCK->On",             STUCK->On             ? "true" : "false",   szDebugName);
  6776.     WritePrivateProfileString("INISettings",   "SET->AutoSave",         SET->AutoSave         ? "true" : "false",   szDebugName);
  6777.     WritePrivateProfileString("INISettings",   "SET->Feign",            SET->Feign            ? "true" : "false",   szDebugName);
  6778.     WritePrivateProfileString("INISettings",   "SET->SaveByChar",       SET->SaveByChar       ? "true" : "false",   szDebugName);
  6779.     WritePrivateProfileString("INISettings",   "SET->BreakSummon",      SET->BreakSummon      ? "true" : "false",   szDebugName);
  6780.     WritePrivateProfileString("INISettings",   "SET->DistSummon",       ftoa(SET->DistSummon,          szTemp),     szDebugName);
  6781.     WritePrivateProfileString("INISettings",   "SET->TurnRate",         ftoa(SET->TurnRate,            szTemp),     szDebugName);
  6782.     WritePrivateProfileString("INISettings",   "PAUSE->Min",            itoa(PAUSE->Min,               szTemp, 10), szDebugName);
  6783.     WritePrivateProfileString("INISettings",   "PAUSE->Max",            itoa(PAUSE->Max,               szTemp, 10), szDebugName);
  6784.     WritePrivateProfileString("INISettings",   "CAMP->Min",             itoa(CAMP->Min,                szTemp, 10), szDebugName);
  6785.     WritePrivateProfileString("INISettings",   "CAMP->Max",             itoa(CAMP->Max,                szTemp, 10), szDebugName);
  6786.     WritePrivateProfileString("SetOnPulse",    "MOVE->ChangeHead",      ftoa(MOVE->ChangeHead,         szTemp),     szDebugName);
  6787.     WritePrivateProfileString("SetOnPulse",    "PAUSE->UserKB",         PAUSE->UserKB         ? "true" : "false",   szDebugName);
  6788.     WritePrivateProfileString("SetOnPulse",    "CAMP->Returning",       CAMP->Returning       ? "true" : "false",   szDebugName);
  6789.     WritePrivateProfileString("SetOnPulse",    "CAMP->Auto",            CAMP->Auto            ? "true" : "false",   szDebugName);
  6790.     WritePrivateProfileString("SetOnPulse",    "STICK->HaveTarget",     STICK->HaveTarget     ? "true" : "false",   szDebugName);
  6791.     WritePrivateProfileString("SetOnPulse",    "STICK->CurDist",        ftoa(STICK->CurDist,           szTemp),     szDebugName);
  6792.     WritePrivateProfileString("Stick",         "STICK->BreakGate",      STICK->BreakGate      ? "true" : "false",   szDebugName);
  6793.     WritePrivateProfileString("Stick",         "STICK->BreakWarp",      STICK->BreakWarp      ? "true" : "false",   szDebugName);
  6794.     WritePrivateProfileString("Stick",         "STICK->DistBreak",      ftoa(STICK->DistBreak,         szTemp),     szDebugName);
  6795.     WritePrivateProfileString("Stick",         "STICK->On",             STICK->On             ? "true" : "false",   szDebugName);
  6796.     WritePrivateProfileString("Stick",         "STICK->SetDist",        STICK->SetDist        ? "true" : "false",   szDebugName);
  6797.     WritePrivateProfileString("Stick",         "STICK->Dist",           ftoa(STICK->Dist,              szTemp),     szDebugName);
  6798.     WritePrivateProfileString("Stick",         "STICK->DistMod",        ftoa(STICK->DistMod,           szTemp),     szDebugName);
  6799.     WritePrivateProfileString("Stick",         "STICK->DistModP",       ftoa(STICK->DistModP,          szTemp),     szDebugName);
  6800.     WritePrivateProfileString("Stick",         "STICK->MoveBack",       STICK->MoveBack       ? "true" : "false",   szDebugName);
  6801.     WritePrivateProfileString("Stick",         "STICK->Behind",         STICK->Behind         ? "true" : "false",   szDebugName);
  6802.     WritePrivateProfileString("Stick",         "STICK->BehindOnce",     STICK->BehindOnce     ? "true" : "false",   szDebugName);
  6803.     WritePrivateProfileString("Stick",         "STICK->Front",          STICK->Front          ? "true" : "false",   szDebugName);
  6804.     WritePrivateProfileString("Stick",         "STICK->NotFront",       STICK->NotFront       ? "true" : "false",   szDebugName);
  6805.     WritePrivateProfileString("Stick",         "STICK->Pin",            STICK->Pin            ? "true" : "false",   szDebugName);
  6806.     WritePrivateProfileString("Stick",         "STICK->Snaproll",       STICK->Snaproll       ? "true" : "false",   szDebugName);
  6807.     WritePrivateProfileString("Stick",         "STICK->Hold",           STICK->Hold           ? "true" : "false",   szDebugName);
  6808.     WritePrivateProfileString("Stick",         "STICK->HoldID",         itoa((int)STICK->HoldID,       szTemp, 10), szDebugName);
  6809.     WritePrivateProfileString("Stick",         "STICK->UW",             STICK->UW             ? "true" : "false",   szDebugName);
  6810.     WritePrivateProfileString("Stick",         "STICK->Always",         STICK->Always         ? "true" : "false",   szDebugName);
  6811.     WritePrivateProfileString("StickSnaproll", "STICK->Snap->Y",        ftoa(STICK->Snap->Y,           szTemp),     szDebugName);
  6812.     WritePrivateProfileString("StickSnaproll", "STICK->Snap->X",        ftoa(STICK->Snap->X,           szTemp),     szDebugName);
  6813.     WritePrivateProfileString("MakeCamp",      "CURCAMP->On",         CURCAMP->On         ? "true" : "false",   szDebugName);
  6814.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Y",          ftoa(CURCAMP->Y,             szTemp),     szDebugName);
  6815.     WritePrivateProfileString("MakeCamp",      "CURCAMP->X",          ftoa(CURCAMP->X,             szTemp),     szDebugName);
  6816.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Radius",     ftoa(CURCAMP->Radius,        szTemp),     szDebugName);
  6817.     WritePrivateProfileString("MakeCamp",      "ALTCAMP->On",         ALTCAMP->On         ? "true" : "false",   szDebugName);
  6818.     WritePrivateProfileString("MakeCamp",      "ALTCAMP->Y",          ftoa(ALTCAMP->Y,             szTemp),     szDebugName);
  6819.     WritePrivateProfileString("MakeCamp",      "ALTCAMP->X",          ftoa(ALTCAMP->X,             szTemp),     szDebugName);
  6820.     WritePrivateProfileString("MakeCamp",      "ALTCAMP->Radius",     ftoa(ALTCAMP->Radius,        szTemp),     szDebugName);
  6821.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Pc",         CURCAMP->Pc         ? "true" : "false",   szDebugName);
  6822.     WritePrivateProfileString("MakeCamp",      "CURCAMP->PcID",       itoa((int)CURCAMP->PcID,     szTemp, 10), szDebugName);
  6823.     WritePrivateProfileString("MakeCamp",      "CAMP->DoReturn",        CAMP->DoReturn        ? "true" : "false",   szDebugName);
  6824.     WritePrivateProfileString("MakeCamp",      "CAMP->DoAlt",           CAMP->DoAlt           ? "true" : "false",   szDebugName);
  6825.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Leash",      CURCAMP->Leash      ? "true" : "false",   szDebugName);
  6826.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Length",     ftoa(CURCAMP->Length,        szTemp),     szDebugName);
  6827.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Scatter",    CURCAMP->Scatter    ? "true" : "false",   szDebugName);
  6828.     WritePrivateProfileString("MakeCamp",      "CURCAMP->Bearing",    ftoa(CURCAMP->Bearing,       szTemp),     szDebugName);
  6829.     WritePrivateProfileString("MakeCamp",      "CURCAMP->ScatSize",   ftoa(CURCAMP->ScatSize,      szTemp),     szDebugName);
  6830.     WritePrivateProfileString("MakeCamp",      "CURCAMP->ScatDist",   ftoa(CURCAMP->ScatDist,      szTemp),     szDebugName);
  6831.     WritePrivateProfileString("MakeCamp",      "CURCAMP->NoAggro",    CURCAMP->NoAggro    ? "true" : "false",   szDebugName);
  6832.     WritePrivateProfileString("MakeCamp",      "CURCAMP->HaveTarget", CURCAMP->HaveTarget ? "true" : "false",   szDebugName);
  6833.     WritePrivateProfileString("MakeCamp",      "CURCAMP->NotLoot",    CURCAMP->NotLoot    ? "true" : "false",   szDebugName);
  6834.     WritePrivateProfileString("MoveTo",        "MOVETO->On",            MOVETO->On            ? "true" : "false",   szDebugName);
  6835.     WritePrivateProfileString("MoveTo",        "MOVETO->Y",             ftoa(MOVETO->Y,                szTemp),     szDebugName);
  6836.     WritePrivateProfileString("MoveTo",        "MOVETO->X",             ftoa(MOVETO->X,                szTemp),     szDebugName);
  6837.     WritePrivateProfileString("MoveTo",        "MOVETO->Dist",          ftoa(MOVETO->Dist,             szTemp),     szDebugName);
  6838.     WritePrivateProfileString("MoveTo",        "MOVETO->PreciseY",      MOVETO->PreciseY      ? "true" : "false",   szDebugName);
  6839.     WritePrivateProfileString("MoveTo",        "MOVETO->DistY",         ftoa(MOVETO->DistY,            szTemp),     szDebugName);
  6840.     WritePrivateProfileString("MoveTo",        "MOVETO->PreciseX",      MOVETO->PreciseX      ? "true" : "false",   szDebugName);
  6841.     WritePrivateProfileString("MoveTo",        "MOVETO->DistX",         ftoa(MOVETO->DistX,            szTemp),     szDebugName);
  6842.     WritePrivateProfileString("MoveTo",        "MOVETO->Walk",          MOVETO->Walk          ? "true" : "false",   szDebugName);
  6843.     WritePrivateProfileString("Circle",        "CIRCLE->On",            CIRCLE->On            ? "true" : "false",   szDebugName);
  6844.     WritePrivateProfileString("Circle",        "CIRCLE->Y",             ftoa(CIRCLE->Y,                szTemp),     szDebugName);
  6845.     WritePrivateProfileString("Circle",        "CIRCLE->X",             ftoa(CIRCLE->X,                szTemp),     szDebugName);
  6846.     WritePrivateProfileString("Circle",        "CIRCLE->Radius",        ftoa(CIRCLE->Radius,           szTemp),     szDebugName);
  6847.     WritePrivateProfileString("Circle",        "CIRCLE->Backward",      CIRCLE->Backward      ? "true" : "false",   szDebugName);
  6848.     WritePrivateProfileString("Circle",        "CIRCLE->CCW",           CIRCLE->CCW           ? "true" : "false",   szDebugName);
  6849.     WritePrivateProfileString("Circle",        "CIRCLE->Drunk",         CIRCLE->Drunk         ? "true" : "false",   szDebugName);
  6850.     WritePrivateProfileString("StuckLogic",    "pMU->CmdFwd",           pMU->CmdFwd           ? "true" : "false",   szDebugName);
  6851.     WritePrivateProfileString("StuckLogic",    "STUCK->Jump",           STUCK->Jump           ? "true" : "false",   szDebugName);
  6852.     WritePrivateProfileString("StuckLogic",    "STUCK->TurnHalf",       STUCK->TurnHalf       ? "true" : "false",   szDebugName);
  6853.     WritePrivateProfileString("StuckLogic",    "STUCK->Check",          itoa((int)STUCK->Check,        szTemp, 10), szDebugName);
  6854.     WritePrivateProfileString("StuckLogic",    "STUCK->Unstuck",        itoa((int)STUCK->Unstuck,      szTemp, 10), szDebugName);
  6855.     WritePrivateProfileString("StuckLogic",    "STUCK->StuckInc",       itoa((int)STUCK->StuckInc,     szTemp, 10), szDebugName);
  6856.     WritePrivateProfileString("StuckLogic",    "STUCK->StuckDec",       itoa((int)STUCK->StuckDec,     szTemp, 10), szDebugName);
  6857.     WritePrivateProfileString("StuckLogic",    "STUCK->Dist",           ftoa(STUCK->Dist,              szTemp),     szDebugName);
  6858.     WritePrivateProfileString("StuckLogic",    "PulseAvg",              ftoa(STUCK->CurDist,           szTemp),     szDebugName);
  6859.     WritePrivateProfileString("StuckLogic",    "STUCK->TurnSize",       ftoa(STUCK->TurnSize,          szTemp),     szDebugName);
  6860.     WritePrivateProfileString("StuckLogic",    "STUCK->Y",              ftoa(STUCK->Y,                 szTemp),     szDebugName);
  6861.     WritePrivateProfileString("StuckLogic",    "STUCK->X",              ftoa(STUCK->X,                 szTemp),     szDebugName);
  6862.     WritePrivateProfileString("StuckLogic",    "STUCK->Z",              ftoa(STUCK->Z,                 szTemp),     szDebugName);
  6863. }
  6864.  
  6865. void SaveConfig()
  6866. {
  6867.     char szTemp[MAX_STRING]     = {0};
  6868.  
  6869.     // default settings
  6870.     WritePrivateProfileString("Defaults",   "AllowMove",              ftoa(SET->AllowMove,      szTemp),     INIFileName);
  6871.     WritePrivateProfileString("Defaults",   "AutoPause",              SET->AutoPause       ? "on" : "off",   INIFileName);
  6872.     WritePrivateProfileString("Defaults",   "AutoPauseMsg",           (uiVerbLevel & V_AUTOPAUSE) == V_AUTOPAUSE             ? "on" : "off",      INIFileName);
  6873.     WritePrivateProfileString("Defaults",   "AutoSave",               SET->AutoSave        ? "on" : "off",   INIFileName);
  6874.     WritePrivateProfileString("Defaults",   "AutoUW",                 SET->AutoUW          ? "on" : "off",   INIFileName);
  6875.     WritePrivateProfileString("Defaults",   "BreakKeyboard",          SET->BreakKB         ? "on" : "off",   INIFileName);
  6876.     WritePrivateProfileString("Defaults",   "BreakMouse",             SET->BreakMouse      ? "on" : "off",   INIFileName);
  6877.     WritePrivateProfileString("Defaults",   "BreakOnGM",              SET->BreakGM         ? "on" : "off",   INIFileName);
  6878.     WritePrivateProfileString("Defaults",   "BreakOnSummon",          SET->BreakSummon     ? "on" : "off",   INIFileName);
  6879.     WritePrivateProfileString("Defaults",   "DistSummon",             ftoa(SET->DistSummon,      szTemp),    INIFileName);
  6880.     WritePrivateProfileString("Defaults",   "FeignSupport",           SET->Feign           ? "on" : "off",   INIFileName);
  6881.     WritePrivateProfileString("Defaults",   "Heading",                (SET->Head == H_TRUE) ? "true" : (SET->Head == H_LOOSE ? "loose" : "fast"), INIFileName);
  6882.     WritePrivateProfileString("Defaults",   "HideHelp",               (uiVerbLevel & V_HIDEHELP) == V_HIDEHELP               ? "on" : "off",      INIFileName);
  6883.     WritePrivateProfileString("Defaults",   "KeyboardPause",          SET->PauseKB         ? "on" : "off",   INIFileName);
  6884.     WritePrivateProfileString("Defaults",   "MousePause",             SET->PauseMouse      ? "on" : "off",   INIFileName);
  6885.     WritePrivateProfileString("Defaults",   "LockPause",              SET->LockPause       ? "on" : "off",   INIFileName);
  6886.     WritePrivateProfileString("Defaults",   "PauseMinDelay",          itoa(PAUSE->Min,          szTemp, 10), INIFileName);
  6887.     WritePrivateProfileString("Defaults",   "PauseMaxDelay",          itoa(PAUSE->Max,          szTemp, 10), INIFileName);
  6888.     WritePrivateProfileString("Defaults",   "SaveByChar",             SET->SaveByChar      ? "on" : "off",   INIFileName);
  6889.     WritePrivateProfileString("Defaults",   "TurnRate",               ftoa(SET->TurnRate,       szTemp),     INIFileName);
  6890.     WritePrivateProfileString("Defaults",   "UseWindow",              SET->Window          ? "on" : "off",   INIFileName);
  6891.     WritePrivateProfileString("Defaults",   "Verbosity",              (uiVerbLevel & V_VERBOSITY) == V_VERBOSITY             ? "on" : "off",      INIFileName);
  6892.     // FullVerbosity is more frequent, detailed output, and differs from Verbosity
  6893.     // Setting one does not include the text of the other.
  6894.     WritePrivateProfileString("Defaults",   "FullVerbosity",          (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY     ? "on" : "off",      INIFileName);
  6895.     // Total Silence writes no output except critical or user-requested
  6896.     WritePrivateProfileString("Defaults",   "TotalSilence",           (uiVerbLevel == 0)   ? "on" : "off",   INIFileName);
  6897.     WritePrivateProfileString("Defaults",   "VerbosityFlags",         itoa(uiVerbLevel,         szTemp, 10), INIFileName);
  6898.     WritePrivateProfileString("Defaults",   "WinEQ",                  SET->WinEQ           ? "on" : "off",   INIFileName);
  6899.     // stick settings
  6900.     WritePrivateProfileString("Stick",      "AlwaysUW",               SET_S->UW            ? "on" : "off",   INIFileName);
  6901.     WritePrivateProfileString("Stick",      "AwareNotAggro",          SET->Spin            ? "on" : "off",   INIFileName);
  6902.     WritePrivateProfileString("Stick",      "ArcBehind",              ftoa(SET_S->ArcBehind,    szTemp),     INIFileName);
  6903.     WritePrivateProfileString("Stick",      "ArcNotFront",            ftoa(SET_S->ArcNotFront,  szTemp),     INIFileName);
  6904.     WritePrivateProfileString("Stick",      "BreakOnGate",            SET_S->BreakGate     ? "on" : "off",   INIFileName);
  6905.     WritePrivateProfileString("Stick",      "BreakOnHit",             SET_S->BreakHit      ? "on" : "off",   INIFileName);
  6906.     WritePrivateProfileString("Stick",      "BreakOnTarget",          SET_S->BreakTarget   ? "on" : "off",   INIFileName);
  6907.     WritePrivateProfileString("Stick",      "BreakOnWarp",            SET_S->BreakWarp     ? "on" : "off",   INIFileName);
  6908.     WritePrivateProfileString("Stick",      "PauseOnWarp",            SET_S->PauseWarp     ? "on" : "off",   INIFileName);
  6909.     WritePrivateProfileString("Stick",      "DelayStrafe",            SET_S->DelayStrafe   ? "on" : "off",   INIFileName);
  6910.     WritePrivateProfileString("Stick",      "DistBackup",             ftoa(SET_S->DistBack,     szTemp),     INIFileName);
  6911.     WritePrivateProfileString("Stick",      "DistBreak",              ftoa(SET_S->DistBreak,    szTemp),     INIFileName);
  6912.     WritePrivateProfileString("Stick",      "DistFlex",               ftoa(SET_S->DistFlex,     szTemp),     INIFileName);
  6913.     WritePrivateProfileString("Stick",      "DistMod",                ftoa(SET_S->DistMod,      szTemp),     INIFileName);
  6914.     WritePrivateProfileString("Stick",      "DistMod%",               ftoa(SET_S->DistModP,     szTemp),     INIFileName);
  6915.     WritePrivateProfileString("Stick",      "DistSnaproll",           ftoa(SET_S->DistSnap,     szTemp),     INIFileName);
  6916.     WritePrivateProfileString("Stick",      "RandomArc",              SET_S->Randomize     ? "on" : "off",   INIFileName);
  6917.     WritePrivateProfileString("Stick",      "StrafeMinDelay",         itoa(SET_S->Min,          szTemp, 10), INIFileName);
  6918.     WritePrivateProfileString("Stick",      "StrafeMaxDelay",         itoa(SET_S->Max,          szTemp, 10), INIFileName);
  6919.     WritePrivateProfileString("Stick",      "UseBackward",            SET_S->UseBack       ? "on" : "off",   INIFileName);
  6920.     WritePrivateProfileString("Stick",      "UseFleeing",             SET_S->UseFleeing    ? "on" : "off",   INIFileName);
  6921.     WritePrivateProfileString("Stick",      "UseFlex",                SET_S->Flex          ? "on" : "off",   INIFileName);
  6922.     WritePrivateProfileString("Stick",      "UseWalk",                SET_S->Walk          ? "on" : "off",   INIFileName);
  6923.     // makecamp settings
  6924.     WritePrivateProfileString("MakeCamp",   "CampRadius",             ftoa(SET_CAMP->Radius,    szTemp),     INIFileName);
  6925.     WritePrivateProfileString("MakeCamp",   "MinDelay",               itoa(SET_CAMP->Min,       szTemp, 10), INIFileName);
  6926.     WritePrivateProfileString("MakeCamp",   "MaxDelay",               itoa(SET_CAMP->Max,       szTemp, 10), INIFileName);
  6927.     WritePrivateProfileString("MakeCamp",   "RealtimePlayer",         SET_CAMP->Realtime   ? "on" : "off",   INIFileName);
  6928.     WritePrivateProfileString("MakeCamp",   "ReturnHaveTarget",       SET_CAMP->HaveTarget ? "on" : "off",   INIFileName);
  6929.     WritePrivateProfileString("MakeCamp",   "ReturnNoAggro",          SET_CAMP->NoAggro    ? "on" : "off",   INIFileName);
  6930.     WritePrivateProfileString("MakeCamp",   "ReturnNotLooting",       SET_CAMP->NotLoot    ? "on" : "off",   INIFileName);
  6931.     WritePrivateProfileString("MakeCamp",   "UseLeash",               SET_CAMP->Leash      ? "on" : "off",   INIFileName);
  6932.     WritePrivateProfileString("MakeCamp",   "LeashLength",            ftoa(SET_CAMP->Length,    szTemp),     INIFileName);
  6933.     // camp scattering
  6934.     WritePrivateProfileString("MakeCamp",   "UseScatter",             SET_CAMP->Scatter    ? "on" : "off",   INIFileName);
  6935.     WritePrivateProfileString("MakeCamp",   "Bearing",                ftoa(SET_CAMP->Bearing,   szTemp),     INIFileName);
  6936.     WritePrivateProfileString("MakeCamp",   "ScatDist",               ftoa(SET_CAMP->ScatDist,  szTemp),     INIFileName);
  6937.     WritePrivateProfileString("MakeCamp",   "ScatSize",               ftoa(SET_CAMP->ScatSize,  szTemp),     INIFileName);
  6938.     // moveto
  6939.     WritePrivateProfileString("MoveTo",     "AlwaysUW",               SET_M->UW            ? "on" : "off",   INIFileName);
  6940.     WritePrivateProfileString("MoveTo",     "ArrivalDist",            ftoa(SET_M->Dist,         szTemp),     INIFileName);
  6941.     WritePrivateProfileString("MoveTo",     "ArrivalDistX",           ftoa(SET_M->DistX,        szTemp),     INIFileName);
  6942.     WritePrivateProfileString("MoveTo",     "ArrivalDistY",           ftoa(SET_M->DistY,        szTemp),     INIFileName);
  6943.     WritePrivateProfileString("MoveTo",     "BreakOnAggro",           SET_M->BreakAggro    ? "on" : "off",   INIFileName);
  6944.     WritePrivateProfileString("MoveTo",     "BreakOnHit",             SET_M->BreakHit      ? "on" : "off",   INIFileName);
  6945.     WritePrivateProfileString("MoveTo",     "DistBackup",             ftoa(SET_M->DistBack,     szTemp),     INIFileName);
  6946.     WritePrivateProfileString("MoveTo",     "MoveToMod",              ftoa(SET_M->Mod,          szTemp),     INIFileName);
  6947.     WritePrivateProfileString("MoveTo",     "UseBackward",            SET_M->UseBack       ? "on" : "off",   INIFileName);
  6948.     WritePrivateProfileString("MoveTo",     "UseWalk",                SET_M->Walk          ? "on" : "off",   INIFileName);
  6949.     // circle
  6950.     WritePrivateProfileString("Circle",     "Backward",               SET_C->Backward      ? "on" : "off",   INIFileName);
  6951.     WritePrivateProfileString("Circle",     "CCW",                    SET_C->CCW           ? "on" : "off",   INIFileName);
  6952.     WritePrivateProfileString("Circle",     "Drunken",                SET_C->Drunk         ? "on" : "off",   INIFileName);
  6953.     WritePrivateProfileString("Circle",     "RadiusSize",             ftoa(SET_C->Radius,       szTemp),     INIFileName);
  6954.     // stucklogic
  6955.     WritePrivateProfileString("StuckLogic", "StuckLogic",             STUCK->On            ? "on" : "off",   INIFileName);
  6956.     WritePrivateProfileString("StuckLogic", "DistStuck",              ftoa(STUCK->Dist,         szTemp),     INIFileName);
  6957.     WritePrivateProfileString("StuckLogic", "PulseCheck",             itoa((int)STUCK->Check,   szTemp, 10), INIFileName);
  6958.     WritePrivateProfileString("StuckLogic", "PulseUnstuck",           itoa((int)STUCK->Unstuck, szTemp, 10), INIFileName);
  6959.     WritePrivateProfileString("StuckLogic", "TryToJump",              STUCK->Jump          ? "on" : "off",   INIFileName);
  6960.     WritePrivateProfileString("StuckLogic", "TurnHalf",               STUCK->TurnHalf      ? "on" : "off",   INIFileName);
  6961.  
  6962.     // check if we want to explicitly ignore this chars custom section
  6963.     GetPrivateProfileString(szCharName, "DisregardMe", "false", szTemp, MAX_STRING, INIFileName);
  6964.     if (SET->SaveByChar && strnicmp(szTemp, "true", 5))
  6965.     {
  6966.         // Character specific
  6967.         WritePrivateProfileString(szCharName, "AllowMove",      ftoa(SET->AllowMove,            szTemp),     INIFileName);
  6968.         WritePrivateProfileString(szCharName, "ArcBehind",      ftoa(SET_S->ArcBehind,          szTemp),     INIFileName);
  6969.         WritePrivateProfileString(szCharName, "ArcNotFront",    ftoa(SET_S->ArcNotFront,        szTemp),     INIFileName);
  6970.         WritePrivateProfileString(szCharName, "AutoSave",       SET->AutoSave              ? "on" : "off",   INIFileName);
  6971.         WritePrivateProfileString(szCharName, "AutoUW",         SET->AutoUW                ? "on" : "off",   INIFileName);
  6972.         WritePrivateProfileString(szCharName, "DistBreak",      ftoa(SET_S->DistBreak,          szTemp),     INIFileName);
  6973.         WritePrivateProfileString(szCharName, "BreakOnGate",    SET_S->BreakGate           ? "on" : "off",   INIFileName);
  6974.         WritePrivateProfileString(szCharName, "BreakOnWarp",    SET_S->BreakWarp           ? "on" : "off",   INIFileName);
  6975.         WritePrivateProfileString(szCharName, "PauseOnWarp",    SET_S->PauseWarp           ? "on" : "off",   INIFileName);
  6976.         WritePrivateProfileString(szCharName, "LockPause",      SET->LockPause             ? "on" : "off",   INIFileName);
  6977.         WritePrivateProfileString(szCharName, "DistSnaproll",   ftoa(SET_S->DistSnap,           szTemp),     INIFileName);
  6978.         WritePrivateProfileString(szCharName, "FeignSupport",   SET->Feign                 ? "on" : "off",   INIFileName);
  6979.         WritePrivateProfileString(szCharName, "Heading",        (SET->Head == H_TRUE)      ? "true" : (SET->Head == H_LOOSE  ? "loose" : "fast"), INIFileName);
  6980.         WritePrivateProfileString(szCharName, "LeashLength",    ftoa(SET_CAMP->Length,          szTemp),     INIFileName);
  6981.         WritePrivateProfileString(szCharName, "UseLeash",       SET_CAMP->Leash            ? "on" : "off",   INIFileName);
  6982.         WritePrivateProfileString(szCharName, "UseWindow",      SET->Window                ? "on" : "off",   INIFileName);
  6983.         WritePrivateProfileString(szCharName, "Verbosity",      (uiVerbLevel & V_VERBOSITY)     == V_VERBOSITY               ? "on" : "off",      INIFileName);
  6984.         WritePrivateProfileString(szCharName, "FullVerbosity",  (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY           ? "on" : "off",      INIFileName);
  6985.         WritePrivateProfileString(szCharName, "VerbosityFlags", itoa(uiVerbLevel,               szTemp, 10), INIFileName);
  6986.         WritePrivateProfileString(szCharName, "CampRadius",     ftoa(SET_CAMP->Radius,          szTemp),     INIFileName);
  6987.         WritePrivateProfileString(szCharName, "RealtimePlayer", SET_CAMP->Realtime         ? "on" : "off",   INIFileName);
  6988.         // scatter values
  6989.         WritePrivateProfileString(szCharName, "UseScatter",     SET_CAMP->Scatter          ? "on" : "off",   INIFileName);
  6990.         WritePrivateProfileString(szCharName, "Bearing",        ftoa(SET_CAMP->Bearing,         szTemp),     INIFileName);
  6991.         WritePrivateProfileString(szCharName, "ScatDist",       ftoa(SET_CAMP->ScatDist,        szTemp),     INIFileName);
  6992.         WritePrivateProfileString(szCharName, "ScatSize",       ftoa(SET_CAMP->ScatSize,        szTemp),     INIFileName);
  6993.     }
  6994.  
  6995.     WINDOW->Save();
  6996. }
  6997.  
  6998. void LoadConfig()
  6999. {
  7000.     char szTemp[MAX_STRING]     = {0};
  7001.     char szTempF[MAX_STRING]    = {0};
  7002.     bool bRewriteIni            = false; // re-save if bad values were read
  7003.  
  7004.     // default settings
  7005.     GetPrivateProfileString("Defaults", "AllowMove",       ftoa(SET->AllowMove, szTempF),   szTemp, MAX_STRING, INIFileName);
  7006.     if ((float)atof(szTemp) >= 10.0f)
  7007.     {
  7008.         SET->AllowMove = (float)atof(szTemp);
  7009.     }
  7010.     else
  7011.     {
  7012.         bRewriteIni = true;
  7013.     }
  7014.     GetPrivateProfileString("Defaults", "AutoPause",       SET->AutoPause   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7015.     SET->AutoPause = (!strnicmp(szTemp, "on", 3));
  7016.     GetPrivateProfileString("Defaults", "AutoSave",        SET->AutoSave    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7017.     SET->AutoSave = (!strnicmp(szTemp, "on", 3));
  7018.     GetPrivateProfileString("Defaults", "AutoUW",          SET->AutoUW      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7019.     SET->AutoUW = (!strnicmp(szTemp, "on", 3));
  7020.     GetPrivateProfileString("Defaults", "BreakKeyboard",   SET->BreakKB     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7021.     SET->BreakKB = (!strnicmp(szTemp, "on", 3));
  7022.     GetPrivateProfileString("Defaults", "BreakMouse",      SET->BreakMouse  ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7023.     SET->BreakMouse = (!strnicmp(szTemp, "on", 3));
  7024.     GetPrivateProfileString("Defaults", "BreakOnGM",       SET->BreakGM     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7025.     SET->BreakGM = (!strnicmp(szTemp, "on", 3));
  7026.     GetPrivateProfileString("Defaults", "BreakOnSummon",   SET->BreakSummon ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7027.     SET->BreakSummon = (!strnicmp(szTemp, "on", 3));
  7028.     GetPrivateProfileString("Defaults", "DistSummon",      ftoa(SET->DistSummon, szTempF),  szTemp, MAX_STRING, INIFileName);
  7029.     if ((float)atof(szTemp) >= 2.0f)
  7030.     {
  7031.         SET->DistSummon = (float)atof(szTemp);
  7032.     }
  7033.     else
  7034.     {
  7035.         bRewriteIni = true;
  7036.     }
  7037.     GetPrivateProfileString("Defaults", "FeignSupport",    SET->Feign       ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7038.     SET->Feign = (!strnicmp(szTemp, "on", 3));
  7039.     GetPrivateProfileString("Defaults", "Heading", (SET->Head == H_TRUE) ? "true" : (SET->Head == H_LOOSE ? "loose" : "fast"), szTemp, MAX_STRING, INIFileName);
  7040.     SET->Head = H_FAST;
  7041.     if (!strnicmp(szTemp, "true", 5))
  7042.     {
  7043.         SET->Head = H_TRUE;
  7044.     }
  7045.     else if (!strnicmp(szTemp, "loose", 6))
  7046.     {
  7047.         SET->Head = H_LOOSE;
  7048.     }
  7049.     GetPrivateProfileString("Defaults", "KeyboardPause",   SET->PauseKB     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7050.     SET->PauseKB = (!strnicmp(szTemp, "on", 3));
  7051.     if (SET->PauseKB) SET->BreakKB = false;
  7052.     GetPrivateProfileString("Defaults", "MousePause",      SET->PauseMouse  ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7053.     SET->PauseMouse = (!strnicmp(szTemp, "on", 3));
  7054.     if (SET->PauseMouse) SET->BreakMouse = false;
  7055.     GetPrivateProfileString("Defaults", "LockPause",       SET->LockPause   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7056.     SET->LockPause = (!strnicmp(szTemp, "on", 3));
  7057.     PAUSE->MaxDelay(GetPrivateProfileInt("Defaults", "PauseMaxDelay", PAUSE->Max, INIFileName));
  7058.     PAUSE->MinDelay(GetPrivateProfileInt("Defaults", "PauseMinDelay", PAUSE->Min, INIFileName));
  7059.     GetPrivateProfileString("Defaults", "SaveByChar",      SET->SaveByChar  ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7060.     SET->SaveByChar = (!strnicmp(szTemp, "on", 3));
  7061.     GetPrivateProfileString("Defaults", "TurnRate",        ftoa(SET->TurnRate, szTempF),    szTemp, MAX_STRING, INIFileName);
  7062.     if ((float)atof(szTemp) >= 1.0f && (float)atof(szTemp) <= 100.0f)
  7063.     {
  7064.         SET->TurnRate = (float)atof(szTemp);
  7065.     }
  7066.     else
  7067.     {
  7068.         bRewriteIni = true;
  7069.     }
  7070.     GetPrivateProfileString("Defaults", "UseWindow",       SET->Window      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7071.     SET->Window = (!strnicmp(szTemp, "on", 3));
  7072.     // verbosity flag handling
  7073.     GetPrivateProfileString("Defaults", "Verbosity", (uiVerbLevel & V_VERBOSITY) == V_VERBOSITY ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7074.     if (!strnicmp(szTemp, "on", 3))
  7075.     {
  7076.         uiVerbLevel |= V_VERBOSITY;
  7077.     }
  7078.     else
  7079.     {
  7080.         uiVerbLevel &= ~V_VERBOSITY;
  7081.     }
  7082.     // FullVerbosity is more frequent, detailed output, and differs from Verbosity
  7083.     // Setting one does not include the text of the other.
  7084.     GetPrivateProfileString("Defaults", "FullVerbosity", (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7085.     if (!strnicmp(szTemp, "on", 3))
  7086.     {
  7087.         uiVerbLevel |= V_FULLVERBOSITY;
  7088.     }
  7089.     else
  7090.     {
  7091.         uiVerbLevel &= ~V_FULLVERBOSITY;
  7092.     }
  7093.     // Total Silence disables all output except extreme error messages and BreakOnSummon
  7094.     GetPrivateProfileString("Defaults", "TotalSilence", (uiVerbLevel == V_SILENCE) ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7095.     if (!strnicmp(szTemp, "on", 3))
  7096.     {
  7097.         uiVerbLevel = V_SILENCE;
  7098.     }
  7099.     // do not need an else, just leaves flags alone if we arent silencing
  7100.     // if totalsilence is not set to 'on', set flags directly. if ini entry doesnt exist, default will have been set by verb/full reads above
  7101.     if (uiVerbLevel != V_SILENCE)
  7102.     {
  7103.         uiVerbLevel = GetPrivateProfileInt("Defaults", "VerbosityFlags", uiVerbLevel, INIFileName);
  7104.         GetPrivateProfileString("Defaults", "AutoPauseMsg", (uiVerbLevel & V_AUTOPAUSE) == V_AUTOPAUSE ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7105.         if (!strnicmp(szTemp, "on", 3))
  7106.         {
  7107.             uiVerbLevel |= V_AUTOPAUSE;
  7108.         }
  7109.         else
  7110.         {
  7111.             uiVerbLevel &= ~V_AUTOPAUSE;
  7112.         }
  7113.         GetPrivateProfileString("Defaults", "HideHelp", (uiVerbLevel & V_HIDEHELP) == V_HIDEHELP ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7114.         if (!strnicmp(szTemp, "on", 3))
  7115.         {
  7116.             uiVerbLevel |= V_HIDEHELP;
  7117.         }
  7118.         else
  7119.         {
  7120.             uiVerbLevel &= ~V_HIDEHELP;
  7121.         }
  7122.     }
  7123.     GetPrivateProfileString("Defaults", "WinEQ",           SET->WinEQ       ? "on" : "off",   szTemp, MAX_STRING, INIFileName);
  7124.     SET->WinEQ = (!strnicmp(szTemp, "on", 3));
  7125.  
  7126.     // stick settings
  7127.     GetPrivateProfileString("Stick",    "AlwaysUW",        SET_S->UW        ? "on" : "off",   szTemp, MAX_STRING, INIFileName);
  7128.     SET_S->UW = (!strnicmp(szTemp, "on", 3));
  7129.     GetPrivateProfileString("Stick",    "ArcBehind",       ftoa(SET_S->ArcBehind, szTempF),   szTemp, MAX_STRING, INIFileName);
  7130.     if ((float)atof(szTemp) > 5.0f && (float)atof(szTemp) < 260.0f)
  7131.     {
  7132.         SET_S->ArcBehind = (float)atof(szTemp);
  7133.     }
  7134.     else
  7135.     {
  7136.         bRewriteIni = true;
  7137.     }
  7138.     GetPrivateProfileString("Stick",    "ArcNotFront",     ftoa(SET_S->ArcNotFront, szTempF), szTemp, MAX_STRING, INIFileName);
  7139.     if ((float)atof(szTemp) > 5.0f && (float)atof(szTemp) < 260.0f)
  7140.     {
  7141.         SET_S->ArcNotFront = (float)atof(szTemp);
  7142.     }
  7143.     else
  7144.     {
  7145.         bRewriteIni = true;
  7146.     }
  7147.     GetPrivateProfileString("Stick",    "AwareNotAggro",   SET->Spin          ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7148.     SET->Spin = (!strnicmp(szTemp, "on", 3));
  7149.     GetPrivateProfileString("Stick",    "BreakOnGate",     SET_S->BreakGate   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7150.     SET_S->BreakGate = (!strnicmp(szTemp, "on", 3));
  7151.     GetPrivateProfileString("Stick",    "BreakOnHit",      SET_S->BreakHit    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7152.     SET_S->BreakHit = (!strnicmp(szTemp, "on", 3));
  7153.     GetPrivateProfileString("Stick",    "BreakOnTarget",   SET_S->BreakTarget ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7154.     SET_S->BreakTarget = (!strnicmp(szTemp, "on", 3));
  7155.     GetPrivateProfileString("Stick",    "BreakOnWarp",     SET_S->BreakWarp   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7156.     SET_S->BreakWarp = (!strnicmp(szTemp, "on", 3));
  7157.     if (SET_S->BreakWarp) SET_S->PauseWarp = false;
  7158.     GetPrivateProfileString("Stick",    "PauseOnWarp",     SET_S->PauseWarp   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7159.     SET_S->PauseWarp = (!strnicmp(szTemp, "on", 3));
  7160.     if (SET_S->PauseWarp) SET_S->BreakWarp = false;
  7161.     GetPrivateProfileString("Stick",    "DelayStrafe",     SET_S->DelayStrafe ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7162.     SET_S->DelayStrafe = (!strnicmp(szTemp, "on", 3));
  7163.     GetPrivateProfileString("Stick",    "DistBackup",      ftoa(SET_S->DistBack, szTempF),    szTemp, MAX_STRING, INIFileName);
  7164.     if ((float)atof(szTemp) >= 1.0f)
  7165.     {
  7166.         SET_S->DistBack = (float)atof(szTemp);
  7167.     }
  7168.     else
  7169.     {
  7170.         bRewriteIni = true;
  7171.     }
  7172.     GetPrivateProfileString("Stick",    "DistBreak",       ftoa(SET_S->DistBreak, szTempF),   szTemp, MAX_STRING, INIFileName);
  7173.     if ((float)atof(szTemp) >= 1.0f)
  7174.     {
  7175.         SET_S->DistBreak = (float)atof(szTemp);
  7176.     }
  7177.     else
  7178.     {
  7179.         bRewriteIni = true;
  7180.     }
  7181.     GetPrivateProfileString("Stick",    "DistFlex",        ftoa(SET_S->DistFlex,  szTempF),   szTemp, MAX_STRING, INIFileName);
  7182.     if ((float)atof(szTemp) >= 2.0f && (float)atof(szTemp) <= 20.0f)
  7183.     {
  7184.         SET_S->DistFlex = (float)atof(szTemp);
  7185.     }
  7186.     else
  7187.     {
  7188.         bRewriteIni = true;
  7189.     }
  7190.     GetPrivateProfileString("Stick",    "DistMod",         ftoa(SET_S->DistMod, szTempF),     szTemp, MAX_STRING, INIFileName);
  7191.     if ((float)atof(szTemp) >= 0.0f)
  7192.     {
  7193.         SET_S->DistMod = (float)atof(szTemp);
  7194.     }
  7195.     else
  7196.     {
  7197.         bRewriteIni = true;
  7198.     }
  7199.     GetPrivateProfileString("Stick",    "DistMod%",        ftoa(SET_S->DistModP, szTempF),    szTemp, MAX_STRING, INIFileName);
  7200.     if ((float)atof(szTemp) >= 0.0f)
  7201.     {
  7202.         SET_S->DistModP = (float)atof(szTemp);
  7203.     }
  7204.     else
  7205.     {
  7206.         bRewriteIni = true;
  7207.     }
  7208.     GetPrivateProfileString("Stick",    "DistSnaproll",    ftoa(SET_S->DistSnap, szTempF),    szTemp, MAX_STRING, INIFileName);
  7209.     if ((float)atof(szTemp) >= 1.0f)
  7210.     {
  7211.         SET_S->DistSnap = (float)atof(szTemp);
  7212.     }
  7213.     else
  7214.     {
  7215.         bRewriteIni = true;
  7216.     }
  7217.     SET_S->MaxDelay(GetPrivateProfileInt("Stick", "StrafeMaxDelay", SET_S->Max, INIFileName));
  7218.     SET_S->MinDelay(GetPrivateProfileInt("Stick", "StrafeMinDelay", SET_S->Min, INIFileName));
  7219.     // end stick delays
  7220.     GetPrivateProfileString("Stick",    "RandomArc",       SET_S->Randomize   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7221.     SET_S->Randomize = (!strnicmp(szTemp, "on", 3));
  7222.     GetPrivateProfileString("Stick",    "UseBackward",     SET_S->UseBack     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7223.     SET_S->UseBack = (!strnicmp(szTemp, "on", 3));
  7224.     GetPrivateProfileString("Stick",    "UseFleeing",      SET_S->UseFleeing  ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7225.     SET_S->UseFleeing = (!strnicmp(szTemp, "on", 3));
  7226.     GetPrivateProfileString("Stick",    "UseFlex",         SET_S->Flex        ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7227.     SET_S->Flex = (!strnicmp(szTemp, "on", 3));
  7228.     GetPrivateProfileString("Stick",    "UseWalk",         SET_S->Walk        ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7229.     SET_S->Walk = (!strnicmp(szTemp, "on", 3));
  7230.  
  7231.     // makecamp settings
  7232.     GetPrivateProfileString("MakeCamp", "CampRadius",      ftoa(SET_CAMP->Radius, szTempF),   szTemp, MAX_STRING, INIFileName);
  7233.     if ((float)atof(szTemp) >= 5.0f)
  7234.     {
  7235.         SET_CAMP->SetRadius((float)atof(szTemp));
  7236.     }
  7237.     else
  7238.     {
  7239.         bRewriteIni = true;
  7240.     }
  7241.     SET_CAMP->MaxDelay(GetPrivateProfileInt("MakeCamp", "MaxDelay", SET_CAMP->Max, INIFileName));
  7242.     SET_CAMP->MinDelay(GetPrivateProfileInt("MakeCamp", "MinDelay", SET_CAMP->Min, INIFileName));
  7243.     GetPrivateProfileString("MakeCamp", "RealtimePlayer",   SET_CAMP->Realtime   ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7244.     SET_CAMP->Realtime = (!strnicmp(szTemp, "on", 3));
  7245.     GetPrivateProfileString("MakeCamp", "ReturnHaveTarget", SET_CAMP->HaveTarget ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7246.     SET_CAMP->HaveTarget = (!strnicmp(szTemp, "on", 3));
  7247.     GetPrivateProfileString("MakeCamp", "ReturnNoAggro",    SET_CAMP->NoAggro    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7248.     SET_CAMP->NoAggro = (!strnicmp(szTemp, "on", 3));;
  7249.     GetPrivateProfileString("MakeCamp", "ReturnNotLooting", SET_CAMP->NotLoot    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7250.     SET_CAMP->NotLoot = (!strnicmp(szTemp, "on", 3));
  7251.     GetPrivateProfileString("MakeCamp", "UseLeash",         SET_CAMP->Leash      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7252.     SET_CAMP->Leash = (!strnicmp(szTemp, "on", 3));
  7253.     GetPrivateProfileString("MakeCamp", "LeashLength",      ftoa(SET_CAMP->Length, szTempF),     szTemp, MAX_STRING, INIFileName);
  7254.     if ((float)atof(szTemp) >= SET_CAMP->Radius)
  7255.     {
  7256.         SET_CAMP->SetLeash((float)atof(szTemp));
  7257.     }
  7258.     else
  7259.     {
  7260.         bRewriteIni = true;
  7261.     }
  7262.     // scatter configuration (makecamp)
  7263.     GetPrivateProfileString("MakeCamp", "UseScatter",       SET_CAMP->Scatter    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7264.     SET_CAMP->Scatter = (!strnicmp(szTemp, "on", 3));
  7265.     GetPrivateProfileString("MakeCamp", "Bearing",          ftoa(SET_CAMP->Bearing, szTempF),    szTemp, MAX_STRING, INIFileName);
  7266.     SET_CAMP->Bearing = (float)atof(szTemp);
  7267.     GetPrivateProfileString("MakeCamp", "ScatDist",         ftoa(SET_CAMP->ScatDist, szTempF),   szTemp, MAX_STRING, INIFileName);
  7268.     if ((float)atof(szTemp) >= 1.0f)
  7269.     {
  7270.         SET_CAMP->ScatDist = (float)atof(szTemp);
  7271.     }
  7272.     else
  7273.     {
  7274.         bRewriteIni = true;
  7275.     }
  7276.     GetPrivateProfileString("MakeCamp", "ScatSize",         ftoa(SET_CAMP->ScatSize, szTempF),   szTemp, MAX_STRING, INIFileName);
  7277.     if ((float)atof(szTemp) >= 1.0f)
  7278.     {
  7279.         SET_CAMP->ScatSize = (float)atof(szTemp);
  7280.     }
  7281.     else
  7282.     {
  7283.         bRewriteIni = true;
  7284.     }
  7285.  
  7286.     // moveto settings
  7287.     GetPrivateProfileString("MoveTo",   "AlwaysUW",         SET_M->UW            ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7288.     SET_M->UW = (!strnicmp(szTemp, "on", 3));
  7289.     GetPrivateProfileString("MoveTo",   "ArrivalDist",      ftoa(SET_M->Dist, szTempF),          szTemp, MAX_STRING, INIFileName);
  7290.     if ((float)atof(szTemp) >= 1.0f)
  7291.     {
  7292.         SET_M->Dist = (float)atof(szTemp);
  7293.     }
  7294.     else
  7295.     {
  7296.         bRewriteIni = true;
  7297.     }
  7298.     GetPrivateProfileString("MoveTo",   "ArrivalDistX",     ftoa(SET_M->DistX, szTempF),         szTemp, MAX_STRING, INIFileName);
  7299.     if ((float)atof(szTemp) >= 1.0f)
  7300.     {
  7301.         SET_M->DistX = (float)atof(szTemp);
  7302.     }
  7303.     else
  7304.     {
  7305.         bRewriteIni = true;
  7306.     }
  7307.     GetPrivateProfileString("MoveTo",   "ArrivalDistY",     ftoa(MOVETO->DistY, szTempF),        szTemp, MAX_STRING, INIFileName);
  7308.     if ((float)atof(szTemp) >= 1.0f)
  7309.     {
  7310.         SET_M->DistY = (float)atof(szTemp);
  7311.     }
  7312.     else
  7313.     {
  7314.         bRewriteIni = true;
  7315.     }
  7316.     GetPrivateProfileString("MoveTo",   "BreakOnAggro",     SET_M->BreakAggro    ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7317.     SET_M->BreakAggro = (!strnicmp(szTemp, "on", 3));
  7318.     GetPrivateProfileString("MoveTo",   "BreakOnHit",       SET_M->BreakHit      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7319.     SET_M->BreakHit = (!strnicmp(szTemp, "on", 3));
  7320.     GetPrivateProfileString("MoveTo",   "DistBackup",      ftoa(SET_M->DistBack, szTempF),       szTemp, MAX_STRING, INIFileName);
  7321.     if ((float)atof(szTemp) >= 1.0f)
  7322.     {
  7323.         SET_M->DistBack = (float)atof(szTemp);
  7324.     }
  7325.     else
  7326.     {
  7327.         bRewriteIni = true;
  7328.     }
  7329.     GetPrivateProfileString("MoveTo",   "MoveToMod",        ftoa(SET_M->Mod, szTempF),           szTemp, MAX_STRING, INIFileName);
  7330.     if ((float)atof(szTemp) >= 0.0f)
  7331.     {
  7332.         SET_M->Mod = (float)atof(szTemp);
  7333.     }
  7334.     else
  7335.     {
  7336.         bRewriteIni = true;
  7337.     }
  7338.     GetPrivateProfileString("MoveTo",   "UseBackward",      SET_M->UseBack       ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7339.     SET_M->UseBack = (!strnicmp(szTemp, "on", 3));
  7340.     GetPrivateProfileString("MoveTo",   "UseWalk",          SET_M->Walk          ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7341.     SET_M->Walk = (!strnicmp(szTemp, "on", 3));
  7342.  
  7343.     // circle settings
  7344.     GetPrivateProfileString("Circle",   "Backward",         SET_C->Backward      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7345.     SET_C->Backward = (!strnicmp(szTemp, "on", 3));
  7346.     GetPrivateProfileString("Circle",   "CCW",              SET_C->CCW           ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7347.     SET_C->CCW = (!strnicmp(szTemp, "on", 3));
  7348.     GetPrivateProfileString("Circle",   "Drunken",          SET_C->Drunk         ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7349.     SET_C->Drunk = (!strnicmp(szTemp, "on", 3));
  7350.     GetPrivateProfileString("Circle",   "RadiusSize",       ftoa(SET_C->Radius, szTempF),        szTemp, MAX_STRING, INIFileName);
  7351.     if ((float)atof(szTemp) >= 5.0f)
  7352.     {
  7353.         SET_C->SetRadius((float)atof(szTemp));
  7354.     }
  7355.     else
  7356.     {
  7357.         bRewriteIni = true;
  7358.     }
  7359.  
  7360.     // stuck logic related
  7361.     GetPrivateProfileString("StuckLogic", "StuckLogic",     STUCK->On            ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7362.     STUCK->On = (!strnicmp(szTemp, "on", 3));
  7363.     GetPrivateProfileString("StuckLogic", "DistStuck",      ftoa(STUCK->Dist, szTempF),          szTemp, MAX_STRING, INIFileName);
  7364.     if ((float)atof(szTemp) > 0.0f)
  7365.     {
  7366.         STUCK->Dist = (float)atof(szTemp);
  7367.     }
  7368.     else
  7369.     {
  7370.         bRewriteIni = true;
  7371.     }
  7372.     sprintf(szTempF, "%uh", STUCK->Check);
  7373.     GetPrivateProfileString("StuckLogic", "PulseCheck",     szTempF,                             szTemp, MAX_STRING, INIFileName);
  7374.     if ((unsigned int)atoi(szTemp) > 1)
  7375.     {
  7376.         STUCK->Check = (unsigned int)atoi(szTemp);
  7377.     }
  7378.     else
  7379.     {
  7380.         bRewriteIni = true;
  7381.     }
  7382.     sprintf(szTempF, "%uh", STUCK->Unstuck);
  7383.     GetPrivateProfileString("StuckLogic", "PulseUnstuck",   szTempF,                             szTemp, MAX_STRING, INIFileName);
  7384.     if ((unsigned int)atoi(szTemp) > 1)
  7385.     {
  7386.         STUCK->Unstuck = (unsigned int)atoi(szTemp);
  7387.     }
  7388.     else
  7389.     {
  7390.         bRewriteIni = true;
  7391.     }
  7392.     GetPrivateProfileString("StuckLogic", "TryToJump",      STUCK->Jump          ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7393.     STUCK->Jump = (!strnicmp(szTemp, "on", 3));
  7394.     GetPrivateProfileString("StuckLogic", "TurnHalf",       STUCK->TurnHalf      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7395.     STUCK->TurnHalf = (!strnicmp(szTemp, "on", 3));
  7396.  
  7397.     // check if we want to explicitly ignore this char's custom ini
  7398.     GetPrivateProfileString(szCharName, "DisregardMe", "false", szTemp, MAX_STRING, INIFileName);
  7399.     if (SET->SaveByChar && strnicmp(szTemp, "true", 5))
  7400.     {
  7401.         // Character specific
  7402.         GetPrivateProfileString(szCharName, "AllowMove",    ftoa(SET->AllowMove, szTempF),       szTemp, MAX_STRING, INIFileName);
  7403.         if ((float)atof(szTemp) > 10.0f)
  7404.         {
  7405.             SET->AllowMove = (float)atof(szTemp);
  7406.         }
  7407.         else
  7408.         {
  7409.             bRewriteIni = true;
  7410.         }
  7411.         GetPrivateProfileString(szCharName, "ArcBehind",    ftoa(SET_S->ArcBehind, szTempF),     szTemp, MAX_STRING, INIFileName);
  7412.         if ((float)atof(szTemp) > 5.0f && (float)atof(szTemp) < 260.0f)
  7413.         {
  7414.             SET_S->ArcBehind = (float)atof(szTemp);
  7415.         }
  7416.         else
  7417.         {
  7418.             bRewriteIni = true;
  7419.         }
  7420.         GetPrivateProfileString(szCharName, "ArcNotFront",  ftoa(SET_S->ArcNotFront, szTempF),   szTemp, MAX_STRING, INIFileName);
  7421.         if ((float)atof(szTemp) > 5.0f && (float)atof(szTemp) < 260.0f)
  7422.         {
  7423.             SET_S->ArcNotFront = (float)atof(szTemp);
  7424.         }
  7425.         else
  7426.         {
  7427.             bRewriteIni = true;
  7428.         }
  7429.         GetPrivateProfileString(szCharName, "AutoSave",     SET->AutoSave        ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7430.         SET->AutoSave = (!strnicmp(szTemp, "on", 3));
  7431.         GetPrivateProfileString(szCharName, "AutoUW",       SET->AutoUW          ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7432.         SET->AutoUW = (!strnicmp(szTemp, "on", 3));
  7433.         GetPrivateProfileString(szCharName, "BreakOnGate",  SET_S->BreakGate     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7434.         SET_S->BreakGate = (!strnicmp(szTemp, "on", 3));
  7435.         GetPrivateProfileString(szCharName, "BreakOnWarp",  SET_S->BreakWarp     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7436.         SET_S->BreakWarp = (!strnicmp(szTemp, "on", 3));
  7437.         if (SET_S->BreakWarp) SET_S->PauseWarp = false;
  7438.         GetPrivateProfileString(szCharName, "PauseOnWarp",  SET_S->PauseWarp     ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7439.         SET_S->PauseWarp = (!strnicmp(szTemp, "on", 3));
  7440.         if (SET_S->PauseWarp) SET_S->BreakWarp = false;
  7441.         GetPrivateProfileString(szCharName, "LockPause",    SET->LockPause       ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7442.         SET->LockPause = (!strnicmp(szTemp, "on", 3));
  7443.         GetPrivateProfileString(szCharName, "DistBreak",    ftoa(STICK->DistBreak, szTempF),     szTemp, MAX_STRING, INIFileName);
  7444.         if ((float)atof(szTemp) >= 1.0f)
  7445.         {
  7446.             STICK->DistBreak = (float)atof(szTemp);
  7447.         }
  7448.         else
  7449.         {
  7450.             bRewriteIni = true;
  7451.         }
  7452.         GetPrivateProfileString(szCharName, "DistSnaproll", ftoa(SET_S->DistSnap, szTempF),      szTemp, MAX_STRING, INIFileName);
  7453.         if ((float)atof(szTemp) >= 1.0f)
  7454.         {
  7455.             SET_S->DistSnap = (float)atof(szTemp);
  7456.         }
  7457.         else
  7458.         {
  7459.             bRewriteIni = true;
  7460.         }
  7461.         GetPrivateProfileString(szCharName, "FeignSupport", SET->Feign           ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7462.         SET->Feign = (!strnicmp(szTemp, "on", 3));
  7463.         GetPrivateProfileString(szCharName, "Heading",      (SET->Head == H_TRUE ? "true" : (SET->Head == H_LOOSE ? "loose" : "fast")), szTemp, MAX_STRING, INIFileName);
  7464.         SET->Head = H_FAST;
  7465.         if (!strnicmp(szTemp, "true", 5))
  7466.         {
  7467.             SET->Head = H_TRUE;
  7468.         }
  7469.         else if (!strnicmp(szTemp, "loose", 6))
  7470.         {
  7471.             SET->Head = H_LOOSE;
  7472.         }
  7473.         GetPrivateProfileString(szCharName, "LeashLength",  ftoa(SET_CAMP->Length, szTempF),      szTemp, MAX_STRING, INIFileName);
  7474.         if ((float)atof(szTemp) >= SET_CAMP->Radius)
  7475.         {
  7476.             SET_CAMP->SetLeash((float)atof(szTemp));
  7477.         }
  7478.         else
  7479.         {
  7480.             bRewriteIni = true;
  7481.         }
  7482.         GetPrivateProfileString(szCharName, "UseLeash",     SET_CAMP->Leash      ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7483.         SET_CAMP->Leash = (!strnicmp(szTemp, "on", 3));
  7484.         GetPrivateProfileString(szCharName, "UseWindow",    SET->Window          ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7485.         SET->Window = (!strnicmp(szTemp, "on", 3));
  7486.         // verbosity flag handling
  7487.         GetPrivateProfileString(szCharName, "Verbosity", (uiVerbLevel & V_VERBOSITY) == V_VERBOSITY ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7488.         if (!strnicmp(szTemp, "on", 3))
  7489.         {
  7490.             uiVerbLevel |= V_VERBOSITY;
  7491.         }
  7492.         else
  7493.         {
  7494.             uiVerbLevel &= ~V_VERBOSITY;
  7495.         }
  7496.         // FullVerbosity is more frequent, detailed output, and differs from Verbosity
  7497.         // Setting one does not include the text of the other.
  7498.         GetPrivateProfileString(szCharName, "FullVerbosity", (uiVerbLevel & V_FULLVERBOSITY) == V_FULLVERBOSITY ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7499.         if (!strnicmp(szTemp, "on", 3))
  7500.         {
  7501.             uiVerbLevel |= V_FULLVERBOSITY;
  7502.         }
  7503.         else
  7504.         {
  7505.             uiVerbLevel &= ~V_FULLVERBOSITY;
  7506.         }
  7507.         // set flags directly, if no entry present use results of above reads
  7508.         uiVerbLevel = GetPrivateProfileInt(szCharName, "VerbosityFlags", uiVerbLevel, INIFileName);
  7509.  
  7510.         GetPrivateProfileString(szCharName, "CampRadius",   ftoa(SET_CAMP->Radius, szTempF),     szTemp, MAX_STRING, INIFileName);
  7511.         if ((float)atof(szTemp) >= 5.0f)
  7512.         {
  7513.             SET_CAMP->SetRadius((float)atof(szTemp));
  7514.         }
  7515.         else
  7516.         {
  7517.             bRewriteIni = true;
  7518.         }
  7519.         GetPrivateProfileString(szCharName, "RealtimePlayer", SET_CAMP->Realtime ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7520.         SET_CAMP->Realtime = (!strnicmp(szTemp, "on", 3));
  7521.         // scatter configuration (makecamp)
  7522.         GetPrivateProfileString(szCharName, "UseScatter",     SET_CAMP->Scatter  ? "on" : "off", szTemp, MAX_STRING, INIFileName);
  7523.         SET_CAMP->Scatter = (!strnicmp(szTemp, "on", 3));
  7524.         GetPrivateProfileString(szCharName, "Bearing",        ftoa(SET_CAMP->Bearing, szTempF),  szTemp, MAX_STRING, INIFileName);
  7525.         SET_CAMP->Bearing = (float)atof(szTemp);
  7526.         GetPrivateProfileString(szCharName, "ScatDist",       ftoa(SET_CAMP->ScatDist, szTempF), szTemp, MAX_STRING, INIFileName);
  7527.         if ((float)atof(szTemp) >= 1.0f)
  7528.         {
  7529.             SET_CAMP->ScatDist = (float)atof(szTemp);
  7530.         }
  7531.         else
  7532.         {
  7533.             bRewriteIni = true;
  7534.         }
  7535.         GetPrivateProfileString(szCharName, "ScatSize",      ftoa(SET_CAMP->ScatSize, szTempF),  szTemp, MAX_STRING, INIFileName);
  7536.         if ((float)atof(szTemp) >= 1.0f)
  7537.         {
  7538.             SET_CAMP->ScatSize = (float)atof(szTemp);
  7539.         }
  7540.         else
  7541.         {
  7542.             bRewriteIni = true;
  7543.         }
  7544.     }
  7545.  
  7546.     if (bRewriteIni) SaveConfig();
  7547.     // copy new setting defaults to active
  7548.     pMU->NewDefaults();
  7549.     // create window if needed
  7550.     if (SET->Window)
  7551.     {
  7552.         WINDOW->Create();
  7553.     }
  7554.     else
  7555.     {
  7556.         WINDOW->Destroy(true);
  7557.     }
  7558. }
  7559.  
  7560. // End file input / output
  7561. // ----------------------------------------
  7562. // Keybind handling
  7563.  
  7564. inline void KeyKiller(int iKeyPressed)
  7565. {
  7566.     if (iKeyPressed == iForward)
  7567.     {
  7568.         MOVE->DoMove(KILL_STRAFE, false, MU_WALKOFF);
  7569.         MOVE->DoMove(GO_BACKWARD, false, MU_WALKOFF);
  7570.     }
  7571.     else if (iKeyPressed == iBackward)
  7572.     {
  7573.         MOVE->DoMove(KILL_STRAFE, false, MU_WALKOFF);
  7574.         MOVE->DoMove(GO_FORWARD,  false, MU_WALKOFF);
  7575.     }
  7576.     else if (iKeyPressed == iStrafeLeft)
  7577.     {
  7578.         MOVE->DoMove(KILL_FB,     false, MU_WALKOFF);
  7579.         MOVE->DoMove(GO_RIGHT,    false, MU_WALKOFF);
  7580.     }
  7581.     else if (iKeyPressed == iStrafeRight)
  7582.     {
  7583.         MOVE->DoMove(KILL_FB,     false, MU_WALKOFF);
  7584.         MOVE->DoMove(GO_LEFT,     false, MU_WALKOFF);
  7585.     }
  7586.     else if (iKeyPressed == iAutoRun)
  7587.     {
  7588.         MOVE->DoMove(KILL_STRAFE, false, MU_WALKOFF);
  7589.     }
  7590.     else if (iKeyPressed == iTurnRight)
  7591.     {
  7592.         MOVE->DoMove(APPLY_TO_ALL, false, MU_WALKOFF);
  7593.         MOVE->ChangeHead = H_INACTIVE;
  7594.         if (pMU->Head == H_TRUE)
  7595.         {
  7596.            *pulTurnLeft                              = 0;
  7597.            pKeypressHandler->CommandState[iTurnLeft] = 0;
  7598.         }
  7599.         return; // return so that we do not auto heading adjust via StopHeading()
  7600.     }
  7601.     else if (iKeyPressed == iTurnLeft)
  7602.     {
  7603.         MOVE->DoMove(APPLY_TO_ALL, false, MU_WALKOFF);
  7604.         MOVE->ChangeHead = H_INACTIVE;
  7605.         if (pMU->Head == H_TRUE)
  7606.         {
  7607.            *pulTurnRight                              = 0;
  7608.            pKeypressHandler->CommandState[iTurnRight] = 0;
  7609.         }
  7610.         return; // return so that we do not auto heading adjust via StopHeading()
  7611.     }
  7612.     MOVE->StopHeading();
  7613. }
  7614.  
  7615. void KeybindPressed(int iKeyPressed, int iKeyDown)
  7616. {
  7617.     if (!ValidIngame(false)) return;
  7618.  
  7619.     if (pMU->Rooted)
  7620.     {
  7621.         MOVE->DoRoot();
  7622.         return;
  7623.     }
  7624.  
  7625.     //MOVE->ChangeHead = H_INACTIVE; // true/loose fights for heading if not reset
  7626.     bool bCmdActive = (STICK->Ready() || MOVETO->On || CIRCLE->On || CAMP->Auto) ? true : false;
  7627.  
  7628.     if (iKeyDown)
  7629.     {
  7630.         PAUSE->UserKB = true; // so makecamp wont auto return
  7631.         PAUSE->TimeStop(); // stop return time from kicking in if you let go of the key and repress again.
  7632.         if (!bCmdActive || PAUSE->PausedCmd) return; // do nothing else if plugin not currently moving or 'pause' from user already active
  7633.  
  7634.         if (SET->PauseKB)
  7635.         {
  7636.             if (MOVETO->On && CURCAMP->On && CURCAMP->Leash && !CAMP->Auto)
  7637.             {
  7638.                 sprintf(szMsg, "\ay%s\aw:: Ended '/moveto' or '/makecamp return' because leash is on.", MODULE_NAME);
  7639.                 WriteLine(szMsg, V_MAKECAMPFV);
  7640.                 EndPreviousCmd(false);
  7641.             }
  7642.             PAUSE->PausedMU = true;
  7643.             if (!pMU->KeyKilled && !SET->WinEQ && !bOffsetOverride)
  7644.             {
  7645.                 KeyKiller(iKeyPressed);
  7646.                 pMU->KeyKilled = true;
  7647.             }
  7648.         }
  7649.         else if (SET->BreakKB)
  7650.         {
  7651.             if (!CAMP->Auto)
  7652.             {
  7653.                 sprintf(szMsg, "\ay%s\aw:: Current command ended from manual movement.", MODULE_NAME);
  7654.                 WriteLine(szMsg, V_MOVEPAUSE);
  7655.             }
  7656.             EndPreviousCmd(false); //EndPreviousCmd(true); // this stops kb input
  7657.             if (!pMU->KeyKilled && !SET->WinEQ && !bOffsetOverride)
  7658.             {
  7659.                 KeyKiller(iKeyPressed);
  7660.                 pMU->KeyKilled = true;
  7661.             }
  7662.         }
  7663.     }
  7664.     else
  7665.     {
  7666.         if (!SET->WinEQ && !bOffsetOverride)
  7667.         {
  7668.             if (*pulForward || *pulBackward || *pulTurnLeft || *pulTurnRight || *pulStrafeLeft || *pulStrafeRight || *pulAutoRun)
  7669.             {
  7670.                 // return until all keys let go
  7671.                 return;
  7672.             }
  7673.         }
  7674.  
  7675.         PAUSE->UserKB = pMU->KeyKilled = false;
  7676.         if (!SET->PauseKB || !bCmdActive || PAUSE->PausedCmd) return; // return if no reason to resume
  7677.         PAUSE->TimeStart(); // start resume timer, picked back up OnPulse()
  7678.     }
  7679. }
  7680.  
  7681. void FwdWrapper(char* szName, int iKeyDown)
  7682. {
  7683.     KeybindPressed(iForward, iKeyDown);
  7684. }
  7685.  
  7686. void BckWrapper(char* szName, int iKeyDown)
  7687. {
  7688.     KeybindPressed(iBackward, iKeyDown);
  7689. }
  7690.  
  7691. void LftWrapper(char* szName, int iKeyDown)
  7692. {
  7693.     KeybindPressed(iTurnLeft, iKeyDown);
  7694. }
  7695.  
  7696. void RgtWrapper(char* szName, int iKeyDown)
  7697. {
  7698.     KeybindPressed(iTurnRight, iKeyDown);
  7699. }
  7700.  
  7701. void StrafeLftWrapper(char* szName, int iKeyDown)
  7702. {
  7703.     KeybindPressed(iStrafeLeft, iKeyDown);
  7704. }
  7705.  
  7706. void StrafeRgtWrapper(char* szName, int iKeyDown)
  7707. {
  7708.     KeybindPressed(iStrafeRight, iKeyDown);
  7709. }
  7710.  
  7711. void AutoRunWrapper(char* szName, int iKeyDown)
  7712. {
  7713.     KeybindPressed(iAutoRun, iKeyDown);
  7714. }
  7715.  
  7716. void DoKeybinds()
  7717. {
  7718.     if (!pMU || pMU->Keybinds) return;
  7719.     AddMQ2KeyBind("MUTILS_FWD",        FwdWrapper);
  7720.     AddMQ2KeyBind("MUTILS_BCK",        BckWrapper);
  7721.     AddMQ2KeyBind("MUTILS_LFT",        LftWrapper);
  7722.     AddMQ2KeyBind("MUTILS_RGT",        RgtWrapper);
  7723.     AddMQ2KeyBind("MUTILS_STRAFE_LFT", StrafeLftWrapper);
  7724.     AddMQ2KeyBind("MUTILS_STRAFE_RGT", StrafeRgtWrapper);
  7725.     AddMQ2KeyBind("MUTILS_AUTORUN",    AutoRunWrapper);
  7726.     SetMQ2KeyBind("MUTILS_FWD",        FALSE, pKeypressHandler->NormalKey[iForward]);
  7727.     SetMQ2KeyBind("MUTILS_BCK",        FALSE, pKeypressHandler->NormalKey[iBackward]);
  7728.     SetMQ2KeyBind("MUTILS_LFT",        FALSE, pKeypressHandler->NormalKey[iTurnLeft]);
  7729.     SetMQ2KeyBind("MUTILS_RGT",        FALSE, pKeypressHandler->NormalKey[iTurnRight]);
  7730.     SetMQ2KeyBind("MUTILS_STRAFE_LFT", FALSE, pKeypressHandler->NormalKey[iStrafeLeft]);
  7731.     SetMQ2KeyBind("MUTILS_STRAFE_RGT", FALSE, pKeypressHandler->NormalKey[iStrafeRight]);
  7732.     SetMQ2KeyBind("MUTILS_AUTORUN",    FALSE, pKeypressHandler->NormalKey[iAutoRun]);
  7733.     SetMQ2KeyBind("MUTILS_FWD",        TRUE,  pKeypressHandler->AltKey[iForward]);
  7734.     SetMQ2KeyBind("MUTILS_BCK",        TRUE,  pKeypressHandler->AltKey[iBackward]);
  7735.     SetMQ2KeyBind("MUTILS_LFT",        TRUE,  pKeypressHandler->AltKey[iTurnLeft]);
  7736.     SetMQ2KeyBind("MUTILS_RGT",        TRUE,  pKeypressHandler->AltKey[iTurnRight]);
  7737.     SetMQ2KeyBind("MUTILS_STRAFE_LFT", TRUE,  pKeypressHandler->AltKey[iStrafeLeft]);
  7738.     SetMQ2KeyBind("MUTILS_STRAFE_RGT", TRUE,  pKeypressHandler->AltKey[iStrafeRight]);
  7739.     SetMQ2KeyBind("MUTILS_AUTORUN",    TRUE,  pKeypressHandler->AltKey[iAutoRun]);
  7740.     pMU->Keybinds = true;
  7741. }
  7742.  
  7743. void UndoKeybinds()
  7744. {
  7745.     if (!pMU || !pMU->Keybinds) return;
  7746.     RemoveMQ2KeyBind("MUTILS_FWD");
  7747.     RemoveMQ2KeyBind("MUTILS_BCK");
  7748.     RemoveMQ2KeyBind("MUTILS_LFT");
  7749.     RemoveMQ2KeyBind("MUTILS_RGT");
  7750.     RemoveMQ2KeyBind("MUTILS_STRAFE_LFT");
  7751.     RemoveMQ2KeyBind("MUTILS_STRAFE_RGT");
  7752.     RemoveMQ2KeyBind("MUTILS_AUTORUN");
  7753.     pMU->Keybinds = false;
  7754. }
  7755.  
  7756. inline void FindKeys()
  7757. {
  7758.     iForward     = FindMappableCommand("forward");
  7759.     iBackward    = FindMappableCommand("back");
  7760.     iAutoRun     = FindMappableCommand("autorun");
  7761.     iStrafeLeft  = FindMappableCommand("strafe_left");
  7762.     iStrafeRight = FindMappableCommand("strafe_right");
  7763.     iTurnLeft    = FindMappableCommand("left");
  7764.     iTurnRight   = FindMappableCommand("right");
  7765.     iJumpKey     = FindMappableCommand("jump");
  7766.     iDuckKey     = FindMappableCommand("duck");
  7767.     iRunWalk     = FindMappableCommand("run_walk");
  7768. }
  7769.  
  7770. // End keybind handling
  7771. // ----------------------------------------
  7772. // Offsets & pointers
  7773.  
  7774. // ---------------------------------------------------------------------------
  7775. // credit: radioactiveman/bunny771/(dom1n1k?) --------------------------------
  7776. bool DataCompare(const unsigned char* pucData, const unsigned char* pucMask, const char* pszMask)
  7777. {
  7778.     for (; *pszMask; ++pszMask, ++pucData, ++pucMask)
  7779.         if (*pszMask == 'x' && *pucData != *pucMask) return false;
  7780.     return (*pszMask) == NULL;
  7781. }
  7782.  
  7783. unsigned long FindPattern(unsigned long ulAddress, unsigned long ulLen, unsigned char* pucMask, char* pszMask)
  7784. {
  7785.     for (unsigned long i = 0; i < ulLen; i++)
  7786.     {
  7787.         if (DataCompare((unsigned char*)(ulAddress + i), pucMask, pszMask)) return (unsigned long)(ulAddress + i);
  7788.     }
  7789.     return 0;
  7790. }
  7791. // ---------------------------------------------------------------------------
  7792. // copyright: ieatacid -------------------------------------------------------
  7793. unsigned long GetDWordAt(unsigned long ulAddress, unsigned long ulNumBytes)
  7794. {
  7795.     if (ulAddress)
  7796.     {
  7797.         ulAddress += ulNumBytes;
  7798.         return *(unsigned long*)ulAddress;
  7799.     }
  7800.     return 0;
  7801. }
  7802. // ---------------------------------------------------------------------------
  7803. inline unsigned char FindPointers()
  7804. {
  7805.    if ((addrTurnRight   = FindPattern(FixOffset(0x420000), 0x100000, patternTurnRight, maskTurnRight)) == 0)     return 1;
  7806.    if ((pulTurnRight    = (unsigned long*)GetDWordAt(addrTurnRight, 1)) == 0)                         return 2;
  7807.    if ((pulStrafeLeft   = (unsigned long*)GetDWordAt(addrTurnRight, 7)) == 0)                         return 3;
  7808.    if ((pulStrafeRight  = (unsigned long*)GetDWordAt(addrTurnRight, 13)) == 0)                        return 4;
  7809.    if ((pulAutoRun      = (unsigned long*)GetDWordAt(addrTurnRight, 27)) == 0)                        return 5;
  7810.    if ((pulTurnLeft     = (unsigned long*)GetDWordAt(addrTurnRight, 42)) == 0)                        return 6;
  7811.    if ((addrMoveForward = FindPattern(FixOffset(0x420000), 0x100000, patternMoveForward, maskMoveForward)) == 0) return 7;
  7812.    if ((pulForward      = (unsigned long*)GetDWordAt(addrMoveForward, 1)) == 0)                       return 8;
  7813.    if (pulAutoRun      != (unsigned long*)GetDWordAt(addrMoveForward, 15))                            return 9;
  7814.    if ((pulBackward     = (unsigned long*)GetDWordAt(addrMoveForward, 30)) == 0)                      return 10;
  7815.    return 0;
  7816. }
  7817.  
  7818. PMQPLUGIN FindPlugin(char* PluginName)
  7819. {
  7820.     unsigned int uiLength = strlen(PluginName) + 1;
  7821.     PMQPLUGIN pLook = pPlugins;
  7822.     while (pLook && strnicmp(PluginName, pLook->szFilename, uiLength))
  7823.     {
  7824.         pLook = pLook->pNext;
  7825.     }
  7826.     return pLook;
  7827. }
  7828.  
  7829. // ---------------------------------------------------------------------------
  7830. // MQ2 Exported functions
  7831.  
  7832. PLUGIN_API void InitializePlugin()
  7833. {
  7834.     // offset-driven movement
  7835.     unsigned char ucFailedLoad = FindPointers();
  7836.     if (ucFailedLoad)
  7837.     {
  7838.         char szFailOffset[500] = {0};
  7839.         sprintf(szFailOffset, "\ay%s\aw:: Couldn't find movement pointer: \ar%s\ax.", MODULE_NAME, szFailedLoad[ucFailedLoad]);
  7840.         WriteChatf(szFailOffset);
  7841.         MessageBox(NULL, szFailOffset, "MQ2MoveUtils v11.x", MB_OK);
  7842.         bOffsetOverride = true;
  7843.     }
  7844.  
  7845.     // commands
  7846.     AddCommand("/makecamp",  MakeCampWrapper, FALSE, TRUE, TRUE);
  7847.     AddCommand("/moveto",    MoveToWrapper,   FALSE, TRUE, TRUE);
  7848.     AddCommand("/stick",     StickWrapper,    FALSE, TRUE, TRUE);
  7849.     AddCommand("/circle",    CircleWrapper,   FALSE, TRUE, TRUE);
  7850.     AddCommand("/calcangle", CalcOurAngle,    FALSE, TRUE, TRUE);
  7851.     AddCommand("/rootme",    RootCmd,         FALSE, TRUE, TRUE);
  7852.  
  7853.     srand((unsigned int)time(0));
  7854.  
  7855.     // setup global vars
  7856.     sprintf(szDebugName, "%s\\MQ2MoveUtils-debug.ini", gszINIPath);
  7857.  
  7858.     // instance classes
  7859.     ME     = new CMUCharacter();
  7860.     SET    = new CMUSettings();
  7861.     MOVE   = new CMUMovement();
  7862.     WINDOW = new CMUWndHandler();
  7863.     pMU    = new CMUActive();
  7864.  
  7865.     // TLO
  7866.     AddMQ2Data("Stick",     dataStick);
  7867.     AddMQ2Data("MakeCamp",  dataMakeCamp);
  7868.     AddMQ2Data("MoveTo",    dataMoveTo);
  7869.     AddMQ2Data("Circle",    dataCircling);
  7870.     AddMQ2Data("MoveUtils", dataMoveUtils);
  7871.  
  7872.     pStickType     = new MQ2StickType;
  7873.     pMakeCampType  = new MQ2MakeCampType;
  7874.     pMoveToType    = new MQ2MoveToType;
  7875.     pCircleType    = new MQ2CircleType;
  7876.     pMoveUtilsType = new MQ2MoveUtilsType;
  7877.  
  7878.     // setup mq2melee pointers
  7879.     pbMULoaded = NULL;
  7880.     if (PMQPLUGIN pLook = FindPlugin("mq2melee"))
  7881.     {
  7882.         pbMULoaded = (bool *)GetProcAddress(pLook->hModule, "bMULoaded");
  7883.         if (pbMULoaded) *pbMULoaded = true;
  7884.     }
  7885. }
  7886.  
  7887. PLUGIN_API void ShutdownPlugin()
  7888. {
  7889.     // remove commands
  7890.     RemoveCommand("/makecamp");
  7891.     RemoveCommand("/moveto");
  7892.     RemoveCommand("/stick");
  7893.     RemoveCommand("/circle");
  7894.     RemoveCommand("/calcangle");
  7895.     RemoveCommand("/rootme");
  7896.  
  7897.     // remove TLOs
  7898.     RemoveMQ2Data("Stick");
  7899.     RemoveMQ2Data("MakeCamp");
  7900.     RemoveMQ2Data("MoveTo");
  7901.     RemoveMQ2Data("Circle");
  7902.     RemoveMQ2Data("MoveUtils");
  7903.  
  7904.     delete pStickType;
  7905.     delete pMoveToType;
  7906.     delete pMakeCampType;
  7907.     delete pCircleType;
  7908.     delete pMoveUtilsType;
  7909.  
  7910.     // destroy mq2 linkage
  7911.     UndoKeybinds();
  7912.     SetupEvents(false, true);
  7913.  
  7914.     // destroy mq2 melee linkage
  7915.     pbMULoaded = NULL;
  7916.     if (PMQPLUGIN pLook = FindPlugin("mq2melee"))
  7917.     {
  7918.         pbMULoaded = (bool *)GetProcAddress(pLook->hModule, "bMULoaded");
  7919.         if (pbMULoaded) *pbMULoaded = false;
  7920.     }
  7921.  
  7922.     // destroy UI window
  7923.     WINDOW->Destroy(ValidIngame());
  7924.  
  7925.     // do not leave character walking
  7926.     MOVE->SetWalk(false);
  7927.  
  7928.     // destroy classes
  7929.     delete ME;
  7930.     delete WINDOW;
  7931.     delete MOVE;
  7932.     delete pMU;
  7933.     delete SET;
  7934. }
  7935.  
  7936. PLUGIN_API void SetGameState(unsigned long ulGameState)
  7937. {
  7938.     //DebugToDebugger("SetGameState %d", ulGameState);
  7939.     if (ulGameState == GAMESTATE_INGAME)
  7940.     {
  7941.         sprintf(szCharName, "%s.%s", EQADDR_SERVERNAME, ((PCHARINFO)pCharData)->Name);
  7942.         FindKeys();
  7943.         if (!pMU->Keybinds)
  7944.         {
  7945.             DoKeybinds();
  7946.         }
  7947.         if (!pMU->Loaded)
  7948.         {
  7949.             LoadConfig();
  7950.             pMU->Loaded = true;
  7951.         }
  7952.         SetupEvents(true);
  7953.  
  7954.         // randomly flip arc flag
  7955.         if (rand() % 100 > 50) STICK->RandFlag = !STICK->RandFlag;
  7956.         // draw window if enabled
  7957.         WINDOW->Create();
  7958.         // turn walking off
  7959.         MOVE->SetWalk(false);
  7960.         // keybind bug fix
  7961.         pMU->KeyKilled = false;
  7962.     }
  7963.     else
  7964.     {
  7965.         if (pMU->Active() || CURCAMP->On)
  7966.         {
  7967.             sprintf(szMsg, "\ay%s\aw:: GameState change ended previous command.", MODULE_NAME);
  7968.             WriteLine(szMsg, V_SILENCE);
  7969.         }
  7970.         EndPreviousCmd(false); // using true here causes ctd
  7971.         CAMP->ResetBoth();
  7972.         pMU->MovetoBroke = pMU->StoppedMoveto = pMU->StickBroke = false;
  7973.         if (ulGameState == GAMESTATE_CHARSELECT)
  7974.         {
  7975.             UndoKeybinds();
  7976.             pMU->Loaded = false;
  7977.             SetupEvents(false, true);
  7978.             WINDOW->Destroy(true);
  7979.             pMU->BrokeGM = pMU->BrokeSummon = false;
  7980.         }
  7981.     }
  7982. }
  7983.  
  7984. PLUGIN_API void OnReloadUI()
  7985. {
  7986.     WINDOW->Create();
  7987. }
  7988.  
  7989. PLUGIN_API void OnCleanUI()
  7990. {
  7991.     WINDOW->Destroy(true);
  7992. }
  7993.  
  7994. PLUGIN_API void OnZoned()
  7995. {
  7996.     EndPreviousCmd(false); // no need to use true here
  7997.     CAMP->ResetBoth();
  7998.     // keybind bug fix
  7999.     pMU->KeyKilled = false;
  8000. }
  8001.  
  8002. PLUGIN_API void OnAddSpawn(PSPAWNINFO pNewSpawn)
  8003. {
  8004.     if (SET->BreakGM || !pNewSpawn->SpawnID)
  8005.     {
  8006.         return;
  8007.     }
  8008.  
  8009.     if (pNewSpawn->GM)
  8010.     {
  8011.         A_TIME_TYPE tCurrentTime;
  8012.         char szTime[30] = {0};
  8013.         struct tm* THE_TIME;
  8014. #ifdef OLD_COMPILER_USER
  8015.         time(&tCurrentTime);
  8016.         THE_TIME = localtime(&tCurrentTime);
  8017. #else
  8018.         _time64(&tCurrentTime);
  8019.         THE_TIME = _localtime64(&tCurrentTime);
  8020. #endif
  8021.         strftime(szTime, 20, " [%H:%M:%S]", THE_TIME);
  8022.         sprintf(szMsg, "\ay%s\aw:: \arWARNING\ax Plugin halted from\ag [GM] %s\ax in zone. -- \aw%s", MODULE_NAME, pNewSpawn->DisplayedName, szTime);
  8023.         WriteLine(szMsg, V_BREAKONGM);
  8024.         pMU->BrokeGM = true;
  8025.         EndPreviousCmd(ValidIngame());
  8026.     }
  8027. }
  8028.  
  8029. PLUGIN_API void OnRemoveSpawn(PSPAWNINFO pOldSpawn)
  8030. {
  8031.     if (!pOldSpawn->SpawnID) return;
  8032.  
  8033.     if (pOldSpawn->SpawnID == STICK->HoldID)
  8034.     {
  8035.         STICK->StopHold();
  8036.     }
  8037.  
  8038.     if (pOldSpawn->SpawnID == CURCAMP->PcID)
  8039.     {
  8040.         CAMP->ResetPlayer(true);
  8041.     }
  8042.  
  8043.     if (pOldSpawn->GM && SET->BreakGM && pMU && pMU->BrokeGM)
  8044.     {
  8045.         A_TIME_TYPE tCurrentTime;
  8046.         char szTime[30] = {0};
  8047.         struct tm* THE_TIME;
  8048. #ifdef OLD_COMPILER_USER
  8049.         time(&tCurrentTime);
  8050.         THE_TIME = localtime(&tCurrentTime);
  8051. #else
  8052.         _time64(&tCurrentTime);
  8053.         THE_TIME = _localtime64(&tCurrentTime);
  8054. #endif
  8055.         strftime(szTime, 20, " [%H:%M:%S]", THE_TIME);
  8056.         sprintf(szMsg, "\ay%s\aw::\ag [GM] %s\ax has left the zone or turned invisible. Use \ag/stick imsafe\ax to allow command usage. -- \aw%s", MODULE_NAME, pOldSpawn->DisplayedName, szTime);
  8057.         WriteLine(szMsg, V_BREAKONGM);
  8058.     }
  8059. }
  8060.  
  8061. PLUGIN_API void OnPulse()
  8062. {
  8063.     if (!ValidIngame(false)) return;
  8064.  
  8065.     if (InHoverState())
  8066.     {
  8067.         // keep window up when hovering
  8068.         WINDOW->Hover();
  8069.         // end root command if active
  8070.         MOVE->StopRoot();
  8071.         // end movement commands (not camp) when hovering
  8072.         if (pMU->Active())
  8073.         {
  8074.             EndPreviousCmd(false);
  8075.             sprintf(szMsg, "\ay%s\aw:: \arYour death has ended the previous command.", MODULE_NAME);
  8076.             WriteLine(szMsg, V_SILENCE);
  8077.         }
  8078.         pMU->FixWalk = true;
  8079.         return;
  8080.     }
  8081.     // if we died, turn walking off when we rez
  8082.     if (pMU->FixWalk)
  8083.     {
  8084.         MOVE->SetWalk(false);
  8085.         pMU->FixWalk = false;
  8086.     }
  8087.  
  8088.     // heading adjustment if needed
  8089.     MOVE->AutoHead();
  8090.     // MoveUtils.Aggro TLO
  8091.     pMU->AggroTLO();
  8092.     // check BreakOnSummon and BreakOnGM
  8093.     if (pMU->Broken()) return;
  8094.     // rootme command
  8095.     MOVE->DoRoot();
  8096.     // handle mousepause & movepause timers
  8097.     PAUSE->HandlePause();
  8098.     // if plugin is paused, do not process commands
  8099.     if (PAUSE->Waiting()) return;
  8100.  
  8101.     // no initial checks preventing main process call
  8102.     // check if individual commands are active & ready
  8103.     if (STICK->On)
  8104.     {
  8105.         if (!STICK->Ready()) return;
  8106.         MainProcess(CMD_STICK);
  8107.     }
  8108.     else if (MOVETO->On)
  8109.     {
  8110.         MainProcess(CMD_MOVETO);
  8111.     }
  8112.     else if (CIRCLE->On)
  8113.     {
  8114.         if (CIRCLE->Drunk && CIRCLE->Wait()) return;
  8115.         MainProcess(CMD_CIRCLE);
  8116.     }
  8117.     else if (!PAUSE->UserMouse && (CURCAMP->On || CAMP->DoAlt))
  8118.     {
  8119.         // this will process camp returns when no other commands active
  8120.         MainProcess(CMD_MAKECAMP);
  8121.     }
  8122. }
  8123.  
  8124. // ---------------------------------------------------------------------------
  8125. // old debug info
  8126. //
  8127.     //PSPAWNINFO pChSpawn = (PSPAWNINFO)pCharSpawn;
  8128.     //PSPAWNINFO psTarget = (PSPAWNINFO)pTarget;
  8129.     //DebugSpew("For - %x - Back - %x - Left - %x - Right - %x", pKeypressHandler->CommandState[iForward], pKeypressHandler->CommandState[iBackward], pKeypressHandler->CommandState[iStrafeLeft], pKeypressHandler->CommandState[iStrafeRight]);
  8130.     /*char szHead[100] = {0};
  8131.     sprintf(szHead, "%.4f", pChSpawn->Heading);
  8132.     DebugSpew("Heading %s", szHead);
  8133.     return;*/
  8134.     /*if (!psTarget) return;
  8135.     float fTempCalc = CalcAngularDist(psTarget->Heading, pChSpawn->Heading);
  8136.     DebugSpew("fAngDist: %.2f", fTempCalc);
  8137.     //return;*/
  8138.     // 19 = jump while moving, 20 = downwards fall from jump only
  8139.     // 24 = duck and START of jump, 71/32 = normal stand, 34 = turning left/right
  8140.     // 33 = on the way to sit, 38 = has sat down
  8141.     // 72 = shake the head shit after 5-6 seconds of standing still
  8142.     // 18 = run forward, 17=slow run (backwards, or end of run forward as decelerating, or strafe sideways)
  8143.     // 21 = falling through air
  8144.     //DebugSpew("Anim: %d, StandState: %d, pspawn anim: %d", pChSpawn->Animation, pChSpawn->StandState, pChSpawn->pSpawn->Animation);
  8145.     // values for  ->Animation and ->pSpawn->Animation are always the same
  8146.     // uncomment to spew real turn values using right/left keys
  8147.     // they do gradually increase if any want to try to solve the real scaling formula
  8148.     // otherwise 16.0 seems to be the max and a safe turn value
  8149.     /*static float fHeadChangeTime = pChSpawn->Heading;
  8150.     char szAnotherTemp[MAX_STRING] = {0};
  8151.     sprintf(szAnotherTemp, "%.2f", fHeadChangeTime - pChSpawn->Heading);
  8152.     DebugSpew("Heading Change %s Speed %.2f", szAnotherTemp, pChSpawn->SpeedHeading);
  8153.     fHeadChangeTime = pChSpawn->Heading;
  8154.     //return;*/
  8155. // ---------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement