Plugin: MQ2Linkdb2

Rusty

Lifetimer
Joined
Aug 29, 2005
Messages
199
Reaction score
2
Points
18
All credit to Psycotic for the changes
Changed plugin commands to /showlink so it doesnt interfear with self Linkdb. This plugin has been modified to respond to tells with the command
!link itemname. Also note command /showlink itemname will send itemlist to your last tell. Stuff to do add Masterlist and Channel support.


Code:
// MQ2LinkDB2 
// 
// Version 1.1 - 20th Sep 2005 - Originally by Ziggy, then updated for DoD 
// 
// Personal link database 
// 
// Usage: /Showlink         - Display statistics 
//        /Showlink /import - Import items.txt as downloaded from 13th Floor 
//                        (Unzip the items.txt file to the mq2\release directory) 
//        /Showlink /max n  - Set number of maximum displayed results (default 10) 
//        /Showlink search  - Find items containg search string 
// 
// Item links are displayed as tells from Linkdb in normal chat windows. This is 
// so you can use the links given. MQ2's ChatWnd removes links. 
// They do not go to log file. Nor will you get the Linkdb name pop up when you hit 
// your reply button. 
// 
// Incoming chat is scanned for links, and the database is checked for this item. 
// If it's not in database, it will be added. 
// 
// Changes: 
// 1.1  Updated to reflect new link format. Thanks to ksmith and Nilwean 
//          and topside from 
//          http://eqitems.13th-floor.org/phpBB2/viewtopic.php?t=145 
//      
// 1.06 Alpha sorts the list 
//      Makes sure that if an exact match is found, then it's displayed, even if we've 
//                already displayed max results 
//      Only searches the name for the item name, previously searched the whole link 
//                (eg: EB41 would have matched 2 items from their hash key) 
// 
// 1.05 Fixed the really stupid mistake with item bitfield. And found out a new equation: 
//      Moved items.txt import into plugin (You can still use it external if you want) 
// 
// 1.04 Added Max item list so we don't get too spammed by results. 
// 
// 1.03 Added some more clues for debugging purposes (do: /Showlink /!quiet to show) 
// 
// 1.02 Fixed file locking fudge up. Should now add items to database properly. 
// 
// 1.01 Added item index so we know already which items the DB has to save a bunch 
//      of time with checking when adding new items 
// 
// TODO: 
// Auto update from 13th floor website 
// 
// 

#include "../MQ2Plugin.h" 

#define MY_STRING    "MQ2LinkDB \ar1.1\ax by Ziggy" 

PreSetup("MQ2LinkDB"); 

static int ConvertItemsDotTxt (void); 

static bool bQuietMode = true;               // Display debug chatter? 
static int iAddedThisSession = 0;            // How many new links found since startup 
static int iTotalInDB = 0;                   // Number of links in db 
static bool bKnowTotal = false;              // Do we know how many links in db? 
static int iMaxResults = 10;                 // Display at most this many results 

#define MAX_PRESENT     100000 
static unsigned char * abPresent = NULL;     // Bitfield to say yes/no we have/don't have each item id 

#define MAX_INTERNAL_RESULTS  500            // Max size of our sort array 
#define SORTEM 
char TellSource[MAX_STRING];
char szTemp[MAX_STRING]; 
char MyMaster[MAX_STRING]; 


// 
// static void SaveSettings (void) 
// 
static void SaveSettings (void) 
{ 
   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.ini", gszINIPath); 

   char cNumber[16]; 
   itoa (iMaxResults, cNumber, 10); 

   WritePrivateProfileString ("Settings", "MaxResults", cNumber, cFilename); 
} 

// 
// static void LoadSettings (void) 
// 
static void LoadSettings (void) 
{ 
   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.ini", gszINIPath); 

   iMaxResults = GetPrivateProfileInt ("Settings", "MaxResults", 10, cFilename); 
   if (iMaxResults < 1) iMaxResults = 1; 
} 

// 
// static int ItemID (const char * cLink) 
// 
static int ItemID (const char * cLink) 
{ 
   char cMid[6]; 

   // Skip \x12 and firt number 
   memcpy (cMid, cLink + 2, 5); 
   cMid[5] = '\0'; 

   return (int) (strtol (cMid, NULL, 16)); 
} 

// 
// void CreateIndex (void) 
// 
void CreateIndex (void) 
{ 
   if (abPresent != NULL) { 
      return; 
   } 

   // TODO: Make this dynamic size 
   abPresent = new unsigned char[MAX_PRESENT / 8 + 1]; 
   memset (abPresent, 0, MAX_PRESENT / 8 + 1); 

   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.txt", gszINIPath); 
   FILE * File = fopen (cFilename, "rt"); 
   iTotalInDB = 0; 
   bKnowTotal = true; 

   if (File != NULL) { 
      char cLine[1024]; 
      while (fgets (cLine, 1024, File) != NULL) { 
         int iItemID = ItemID (cLine); 

         if (iItemID >= MAX_PRESENT) { 
            WriteChatf ("MQ2LinkDB: ERROR! Make max index size bigger. (Max: %d, ItemID: %d)", MAX_PRESENT, iItemID); 
            continue; 
         } 

         unsigned char cOR = 1 << (iItemID % 8); 
         abPresent[iItemID / 8] |= cOR; 

         iTotalInDB++; 
      } 

      fclose (File); 
   } 
} 

// 
// static bool IsAuged (const char * cLink) 
// Make sure no augs in the link 
// 
static bool IsAuged (const char * cLink) 
{ 
   char cMid[6]; 
   for (int i = 0; i < 5; i++) { 
      memcpy (cMid, cLink + 7 + (i * 5), 5); 
      cMid[5] = '\0'; 
      if (atoi (cMid) != 0) { 
         return (true); 
      } 
   } 

   return (false); 
} 

// 
// static bool FindLink (const char * cLink) 
// 
static bool FindLink (const char * cLink) 
{ 
   int iItemID = ItemID (cLink); 

   if (abPresent != NULL) { 
      unsigned char cOR = 1 << (iItemID % 8); 
      if ((abPresent[iItemID / 8] & cOR) != 0) { 
         if (!bQuietMode) { 
            WriteChatf ("MQ2LinkDB: Saw link \ay%d\ax, but we already have it.", iItemID); 
         } 

         return (true); 
      } 
   } 

   // Since we're scanning the file anyway, we'll make the index here to save some time, and to 
   // account for ppl creating new MQ2LinkDB.txt files or whatever. 
   if (abPresent == NULL) { 
      abPresent = new unsigned char[MAX_PRESENT / 8 + 1]; 
   } 
   memset (abPresent, 0, MAX_PRESENT / 8 + 1); 

   bool bRet = false; 
   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.txt", gszINIPath); 

   FILE * File = fopen (cFilename, "rt"); 
   if (File != NULL) { 
      char cLine[1024]; 

      while (fgets (cLine, 1024, File) != NULL) { 
         cLine[strlen (cLine) - 1] = '\0';   // No LF pls 

         if (ItemID (cLine) == iItemID) { 
            unsigned char cOR = 1 << (iItemID % 8); 
            abPresent[iItemID / 8] |= cOR; 

            bRet = true; 

            if (IsAuged (cLine) && !IsAuged (cLink)) { 
               if (strlen (cLine) == strlen (cLink)) { 
                  long lPos = ftell (File); 
                  fclose (File); 

                  if (!bQuietMode) { 
                     WriteChatf ("MQ2LinkDB: Replacing auged link with un-auged link for item \ay%d\ax", iItemID); 
                  } 

                  File = fopen (cFilename, "r+"); 
                  if (File != NULL) { 
                     fseek (File, lPos - strlen (cLine) - 2, SEEK_SET); 

                     // Double check position - paranoia! 
                     char cTemp[10]; 
                     fread (cTemp, 10, 1, File); 
                     if (memcmp (cTemp, cLink, 8) == 0) { 
                        fseek (File, lPos - strlen (cLine) - 2, SEEK_SET); // Seek same place again 
                        fwrite (cLink, strlen (cLink), 1, File); 
                     } else { 
                        if (!bQuietMode) { 
                           WriteChatf ("MQ2LinkDB: \arERROR - Sanity check failed while replacing"); 
                        } 
                     } 

                     fclose (File); 
                  } else { 
                     if (!bQuietMode) { 
                        WriteChatf ("MQ2LinkDB: \arERROR - Could not open db file for writing (%d)", errno); 
                     } 
                  } 

                  return (true); 
               } 
            } else { 
               if (!bQuietMode) { 
                  WriteChatf ("MQ2LinkDB: Saw link \ay%d\ax, but we already have it.", iItemID); 
               } 
            } 
         } 
      } 

      fclose (File); 
   } 

   return (bRet); 
} 

// 
// static void StoreLink (const char * cLink) 
// 
static void StoreLink (const char * cLink) 
{ 
   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.txt", gszINIPath); 

   FILE * File = fopen (cFilename, "at"); 
   if (File != NULL) { 
      fputs (cLink, File); 
      fputs ("\n", File); 
      iAddedThisSession++; 
      iTotalInDB++; 

      CreateIndex ();         // Won't create if it's already there 
      if (abPresent != NULL) { 
         int iItemID = ItemID (cLink); 
         unsigned char cOR = 1 << (iItemID % 8); 
         abPresent[iItemID / 8] |= cOR; 
      } 

      if (!bQuietMode) { 
         WriteChatf ("MQ2LinkDB: Stored link for item ID: \ay%d\ax (\ay%d\ax stored this session)", ItemID (cLink), iAddedThisSession); 
      } 

      fclose (File); 
   } else { 
      if (!bQuietMode) { 
         WriteChatf ("MQ2LinkDB: \arERROR - Could not open db file for writing (%d)", errno); 
      } 
   } 
} 

// 
// static char * LinkExtract (char * cLink) 
// 
static char * LinkExtract (char * cLink) 
{ 
   char * cTemp = strdup (cLink); 
   char * cEnd = strchr (cTemp + 46, '\x12'); 
   int iLen = 1; 

   if (cEnd != NULL) { 
      *(cEnd + 1) = '\0'; 
      iLen = strlen (cTemp); 

      if (!FindLink (cTemp)) { 
         StoreLink (cTemp); 
      } 
   } 

   free (cTemp); 

   return (cLink + iLen); 
} 

// 
// static void ChatTell (char * cLine) 
// 
static void ChatTell (char * cLine) 
{ 
   char cTemp[1024]; 
sprintf(cTemp, ";tell %s %s",TellSource, cLine); 
DoCommand(GetCharInfo()->pSpawn, cTemp); 
}
// 
// static void DoParameters (PCHAR cParams) 
// 
static void DoParameters (PCHAR cParams) 
{ 
   bool bAnyParams = false; 

   strlwr (cParams); 
   char * cWord = strtok (cParams, " "); 
   while (cWord != NULL) { 
      if (strcmp (cWord, "/quiet") == 0) { 
         bQuietMode = !bQuietMode; 

         WriteChatf ("MQ2LinkDB: Quiet mode \ay%s\ax", bQuietMode ? "on" : "off"); 
         bAnyParams = true; 

      } else if (strcmp (cWord, "/max") == 0) { 
         cWord = strtok (NULL, " "); 

         if (atoi (cWord) > 0) { 
            iMaxResults = atoi (cWord); 
            WriteChatf ("MQ2LinkDB: Max results now \ay%d\ax", iMaxResults); 

            SaveSettings (); 
         } 

         bAnyParams = true; 
      } else if (strcmp (cWord, "/import") == 0) { 
         ConvertItemsDotTxt (); 
         bAnyParams = true; 

      } 

      cWord = strtok (NULL, " "); 
   } 

   if (!bAnyParams) { 
      WriteChatf (MY_STRING); 
      WriteChatf ("MQ2LinkDB: Syntax: \ay/Showlink [/import] [/max n] [search string]\ax"); 
      if (bKnowTotal) { 
         WriteChatf ("MQ2LinkDB: \ay%d\ax links in database, \ay%d\ax links added this session", iTotalInDB, iAddedThisSession); 
      } else { 
         WriteChatf ("MQ2LinkDB: \ay%d\ax links added this session", iAddedThisSession); 
      } 
      WriteChatf ("MQ2LinkDB: Max Results \ay%d\ax", iMaxResults); 
   } 
} 

// 
// static VOID CommandLink (PSPAWNINFO pChar, PCHAR szline) 
// 
static VOID CommandLink (PSPAWNINFO pChar, PCHAR szline) 
{ 
   if (strlen (szline) < 3) { 
      DoParameters (""); 
      return;       // We don't list entire DB. that's just not funny 
   } 

   if (szline[0] == '/' || szline[0] == '-') { 
      DoParameters (szline); 
      return; 
   } 

   bool bRet = false; 
   char cTemp[1024]; 

   if (abPresent == NULL) { 
      abPresent = new unsigned char[MAX_PRESENT / 8 + 1]; 
   } 
   memset (abPresent, 0, MAX_PRESENT / 8 + 1); 

   int iFound = 0, iTotal = 0; 
   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\MQ2LinkDB.txt", gszINIPath); 
   FILE * File = fopen (cFilename, "rt"); 
   if (File != NULL) { 
      WriteChatf ("MQ2LinkDB: Searching for '\ay%s\ax'...", szline); 

      strlwr (szline); 
      char cLine[256]; 
      char cCopy[256]; 

      char ** cArray = new char * [MAX_INTERNAL_RESULTS]; 
      char ** cArrayPtr = cArray; 
      memset (cArray, 0, sizeof (char *) * MAX_INTERNAL_RESULTS); 

      while (fgets (cLine, sizeof (cLine), File) != NULL) { 
         int iItemID = ItemID (cLine); 
         unsigned char cOR = 1 << (iItemID % 8); 
         abPresent[iItemID / 8] |= cOR; 

         cLine[strlen (cLine) - 1] = '\0';   // No LF pls 
         strcpy (cCopy, cLine); 
         strlwr (cCopy); 

         if (strstr (cCopy + 46, szline) != NULL) { 
            if (iFound < MAX_INTERNAL_RESULTS) { 
               *cArrayPtr = strdup (cLine); 
               cArrayPtr++; 
            } 

            iFound++; 
         } 

         iTotal++; 
      } 

      bKnowTotal = true; 
      iTotalInDB = iTotal; 

      fclose (File); 

      bool bForcedExtra = false; 
      int iMaxLoop = (iFound > MAX_INTERNAL_RESULTS ? MAX_INTERNAL_RESULTS : iFound); 
      if (iFound > 0) { 
         // Sort the list 
         for (int j = 0; j < iMaxLoop; j++) { 
            for (int i = 0; i < iMaxLoop - 1; i++) { 
               if (strcmp (cArray[i] + 46, cArray[i + 1] + 46) > 0) { 
                  char * cTemp = cArray[i]; 
                  cArray[i] = cArray[i + 1]; 
                  cArray[i + 1] = cTemp; 
               } 
            } 
         } 

         // Show list 
         for (int i = 0; i < iMaxLoop; i++) { 
            bool bShow = i < iMaxResults; 
            char cTemp[256]; 
            strcpy (cTemp, cArray[i]); 

            if (IsAuged (cArray[i])) { 
               strcat (cTemp, " (Augmented)"); 
            } 

            if (strlen (cArray[i] + 47) == strlen (szline) && memicmp (cArray[i] + 46, szline, strlen (szline)) == 0) { 
               strcat (cTemp, " <Exact Match>"); 
               bShow = true;        // We display this result even if we've already shown iMaxResults count 
               bForcedExtra = i >= iMaxResults; 
            } 

            if (bShow) { 
               ChatTell (cTemp); 
            } 

            free (cArray[i]); 
            cArray[i] = NULL; 
         } 
      } 

      free (cArray); 

      char cTemp3[128]; 
      sprintf (cTemp3, "MQ2LinkDB: Found \ay%d\ax items from database of \ay%d\ax total items", iFound, iTotal); 
      sprintf (cTemp, "Found %d items from database of %d total items", iFound, iTotal); 

      if (iFound > iMaxResults) { 
         char cTemp2[64]; 
         sprintf (cTemp2, " - \arList capped to \ay%d\ar results", iMaxResults); 
         strcat (cTemp3, cTemp2); 

         sprintf (cTemp2, " - List capped to %d results", iMaxResults); 
         strcat (cTemp, cTemp2); 

         if (bForcedExtra) { 
            strcat (cTemp, " plus exact match"); 
            strcat (cTemp3, " plus exact match"); 
         } 
      } 

      WriteChatf (cTemp3); 
      ChatTell (cTemp); 

   } else { 
      WriteChatf ("MQ2LinkDB: No item database yet"); 
   } 
} 

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

   LoadSettings (); 

   abPresent = NULL; 
} 

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

   free (abPresent); 
   abPresent = NULL; 
} 

// This is called every time EQ shows a line of chat with CEverQuest::dsp_chat, 
// but after MQ filters and chat events are taken care of. 
PLUGIN_API DWORD OnIncomingChat(PCHAR Line, DWORD Color) 
{ 
   DebugSpewAlways("MQ2LinkDB::OnIncomingChat(%s)",Line); 

// 
// Find a link from a tell 
// 

    if (strstr (Line, "tells you,")) { 

        GetArg(TellSource,Line,1);
        char * cTemp = strdup (Line); 
        char * cRequest = strtok (cTemp, "'"); 
      
   cRequest = strtok (NULL, "'"); // Should containt their input string 

        if (memicmp (cRequest, "!link ", 6) == 0) { // Did they type !link <something>? 
          CommandLink(NULL, cRequest + 6); // Do it 
        } 

         free (cTemp); 
    } 

// End linkbot tell 

   char *cPtr = Line; 
   while (*cPtr) { 
      if (*cPtr == '\x12') { 
         cPtr = LinkExtract(cPtr); 
      } else { 
         cPtr++; 
      } 
   } 



   return 0; 
} 

// DB Converter now part of plugin 
typedef struct { 
   int itemclass; 
   char name[64]; 
   char lore[64]; 
   char idfile[16]; 
   unsigned long id; 
   int weight; 
   short norent; 
   short nodrop; 
   short size; 
   short slots; 
   long price; 
   short icon; 
   short UNK012; 
   short UNK013; 
   int benefitflag; 
   short tradeskills; 
   short cr; 
   short dr; 
   short pr; 
   short mr; 
   short fr; 
   short astr; 
   short asta; 
   short aagi; 
   short adex; 
   short acha; 
   short aint; 
   short awis; 
   short hp; 
   short mana; 
   short ac; 
   short deity; 
   short UNK033; 
   short skillmodvalue; 
   short skillmodtype; 
   short banedmgrace; 
   short banedmgamt; 
   short banedmgbody; 
   short magic; 
   short casttime_; 
   short reqlevel; 
   short bardtype; 
   short bardvalue; 
   short light; 
   short delay; 
   short reclevel; 
   short recskill; 
   short elemdmgtype; 
   short elemdmgamt; 
   short range; 
   short damage; 
   short color; 
   short classes; 
   short races; 
   short UNK053; 
   short maxcharges; 
   short itemtype; 
   short material; 
   short sellrate; 
   short UNK058; 
   short casttime; 
   short UNK060; 
   short procrate; 
   short combateffects; 
   short shielding; 
   short stunresist; 
   short strikethrough; 
   short extradmgskill; 
   short extradmgamt; 
   short spellshield; 
   short avoidance; 
   short accuracy; 
   short charmfileid; 
   short factionmod1; 
   short factionmod2; 
   short factionmod3; 
   short factionmod4; 
   short factionamt1; 
   short factionamt2; 
   short factionamt3; 
   short factionamt4; 
   short charmfile; 
   short augtype; 
   short augslot1type; 
   short augslot1unk; 
   short augslot2type; 
   short augslot2unk; 
   short augslot3type; 
   short augslot3unk; 
   short augslot4type; 
   short augslot4unk; 
   short augslot5type; 
   short augslot5unk; 
   short ldontheme; 
   short ldonprice; 
   short ldonsold; 
   short bagtype; 
   short bagslots; 
   short bagsize; 
   short bagwr; 
   short book; 
   short booktype; 
   short filename; 
   short banedmgraceamt; 
   short augrestrict; 
   short loregroup; 
   short pendingloreflag; 
   short artifactflag; 
   short summonedflag; 
   short favor; 
   short fvnodrop; 
   short endur; 
   short dotshielding; 
   short attack; 
   short regen; 
   short manaregen; 
   short endregen; 
   short haste; 
   short damageshield; 
   short recastdelay; 
   short recasttype; 
   short guildfavor; 
   short augdistiller; 
   short UNK123; 
   short UNK124; 
   short attuneable; 
   short nopet; 
   short UNK127; 
   short pointtype; 
   short potionbelt; 
   short UNK130; 
   short stacksize; 
   short notransfer; 
   short clickeffect; 
   short clicktype; 
   short clicklevel2; 
   short clicklevel; 
   short UNK137; 
   short proceffect; 
   short proctype; 
   short proclevel2; 
   short proclevel; 
   short UNK142; 
   short worneffect; 
   short worntype; 
   short wornlevel2; 
   short wornlevel; 
   short UNK147; 
   short focuseffect; 
   short focustype; 
   short focuslevel2; 
   short focuslevel; 
   short UNK152; 
   short scrolleffect; 
   short scrolltype; 
   short scrolllevel2; 
   short scrolllevel; 
   short UNK157; 
   short verified; 
} EQITEM, * PEQITEM; 

// 
// void SetField (PEQITEM Item, int iField, const char * cField) 
// 
void SetField (PEQITEM Item, int iField, const char * cField) 
{ 
   int iInt = atoi (cField); 
   bool bBool = iInt > 0; 

   switch (iField) { 
      case   0: Item->itemclass = iInt; break; 
      case   1: strcpy (Item->name, cField); break; 
      case   2: strcpy (Item->lore, cField); break; 
      case   3: strcpy (Item->idfile, cField); break; 
      case   4: Item->id = iInt; break; 
      case   5: Item->weight = iInt; break; 
      case   6: Item->norent = iInt; break; 
      case   7: Item->nodrop = iInt; break; 
      case   8: Item->size = iInt; break; 
      case   9: Item->slots = iInt; break; 
      case  10: Item->price = iInt; break; 
      case  11: Item->icon = iInt; break; 
      case  12: Item->UNK012 = iInt; break; 
      case  13: Item->UNK013 = iInt; break; 
      case  14: Item->benefitflag = iInt; break; 
      case  15: Item->tradeskills = bBool; 
      case  16: Item->cr = iInt; break; 
      case  17: Item->dr = iInt; break; 
      case  18: Item->pr = iInt; break; 
      case  19: Item->mr = iInt; break; 
      case  20: Item->fr = iInt; break; 
      case  21: Item->astr = iInt; break; 
      case  22: Item->asta = iInt; break; 
      case  23: Item->aagi = iInt; break; 
      case  24: Item->adex = iInt; break; 
      case  25: Item->acha = iInt; break; 
      case  26: Item->aint = iInt; break; 
      case  27: Item->awis = iInt; break; 
      case  28: Item->hp = iInt; break; 
      case  29: Item->mana = iInt; break; 
      case  30: Item->ac = iInt; break; 
      case  31: Item->deity = iInt; break; 
     case  32: Item->UNK033 = iInt; break; 
      case  33: Item->skillmodvalue = iInt; break; 
      case  34: Item->skillmodtype = iInt; break; 
      case  35: Item->banedmgrace = iInt; break; 
      case  36: Item->banedmgamt = iInt; break; 
      case  37: Item->banedmgbody = iInt; break; 
      case  38: Item->magic = iInt; break; 
      case  39: Item->casttime_ = iInt; break; 
      case  40: Item->reqlevel = iInt; break; 
      case  41: Item->bardtype = iInt; break; 
      case  42: Item->bardvalue = iInt; break; 
      case  43: Item->light = iInt; break; 
      case  44: Item->delay = iInt; break; 
      case  45: Item->reclevel = iInt; break; 
      case  46: Item->recskill = iInt; break; 
      case  47: Item->elemdmgtype = iInt; break; 
      case  48: Item->elemdmgamt = iInt; break; 
      case  49: Item->range = iInt; break; 
      case  50: Item->damage = iInt; break; 
      case  51: Item->color = iInt; break; 
      case  52: Item->classes = iInt; break; 
      case  53: Item->races = iInt; break; 
      case  54: Item->UNK053 = iInt; break; 
      case  55: Item->maxcharges = iInt; break; 
      case  56: Item->itemtype = iInt; break; 
      case  57: Item->material = iInt; break; 
      case  58: Item->sellrate = iInt; break; 
      case  59: Item->UNK058 = iInt; break; 
      case  60: Item->casttime = iInt; break; 
      case  61: Item->UNK060 = iInt; break; 
      case  62: Item->procrate = iInt; break; 
      case  63: Item->combateffects = iInt; break; 
      case  64: Item->shielding = iInt; break; 
      case  65: Item->stunresist = iInt; break; 
      case  66: Item->strikethrough = iInt; break; 
      case  67: Item->extradmgskill = iInt; break; 
      case  68: Item->extradmgamt = iInt; break; 
      case  69: Item->spellshield = iInt; break; 
      case  70: Item->avoidance = iInt; break; 
      case  71: Item->accuracy = iInt; break; 
      case  72: Item->charmfileid = iInt; break; 
      case  73: Item->factionmod1 = iInt; break; 
      case  74: Item->factionmod2 = iInt; break; 
      case  75: Item->factionmod3 = iInt; break; 
      case  76: Item->factionmod4 = iInt; break; 
      case  77: Item->factionamt1 = iInt; break; 
      case  78: Item->factionamt2 = iInt; break; 
      case  79: Item->factionamt3 = iInt; break; 
      case  80: Item->factionamt4 = iInt; break; 

      case  81: Item->charmfile = iInt; break; 
      case  82: Item->augtype = iInt; break; 
      case  83: Item->augslot1type = iInt; break; 
     case  84: Item->augslot1unk = iInt; break; 
      case  85: Item->augslot2type = iInt; break; 
     case  86: Item->augslot2unk = iInt; break; 
      case  87: Item->augslot3type = iInt; break; 
      case  88: Item->augslot3unk = iInt; break; 
      case  89: Item->augslot4type = iInt; break; 
     case  90: Item->augslot4unk = iInt; break; 
      case  91: Item->augslot5type = iInt; break; 
      case  92: Item->augslot5unk = iInt; break; 
      case  93: Item->ldontheme = iInt; break; 
      case  94: Item->ldonprice = iInt; break; 
      case  95: Item->ldonsold = iInt; break; 
      case  96: Item->bagtype = iInt; break; 
      case  97: Item->bagslots = iInt; break; 
      case  98: Item->bagsize = iInt; break; 
      case  99: Item->bagwr = iInt; break; 
      case 100: Item->book = iInt; break; 
      case 101: Item->booktype = iInt; break; 
      case 102: Item->filename = iInt; break; 
      case 103: Item->banedmgraceamt = iInt; break; 
      case 104: Item->augrestrict = iInt; break; 
      case 105: Item->loregroup = iInt; break; 
      case 106: Item->pendingloreflag = iInt; break; 
      case 107: Item->artifactflag = iInt; break; 
      case 108: Item->summonedflag = iInt; break; 
      case 109: Item->favor = iInt; break; 
      case 110: Item->fvnodrop = iInt; break; 
      case 111: Item->endur = iInt; break; 
      case 112: Item->dotshielding = iInt; break; 
      case 113: Item->attack = iInt; break; 
      case 114: Item->regen = iInt; break; 
      case 115: Item->manaregen = iInt; break; 
      case 116: Item->endregen = iInt; break; 
      case 117: Item->haste = iInt; break; 
      case 118: Item->damageshield = iInt; break; 
      case 119: Item->recastdelay = iInt; break; 
      case 120: Item->recasttype = iInt; break; 
      case 121: Item->guildfavor = iInt; break; 
      case 122: Item->augdistiller = iInt; break; 
     case 123: Item->UNK123 = iInt; break; 
      case 124: Item->UNK124 = iInt; break; 
      case 125: Item->attuneable = iInt; break; 
      case 126: Item->nopet = iInt; break; 
      case 127: Item->UNK127 = iInt; break; 
      case 128: Item->pointtype = iInt; break; 
      case 129: Item->potionbelt = iInt; break; 
      case 130: Item->UNK130 = iInt; break; 
      case 131: Item->stacksize = iInt; break; 
     case 132: Item->notransfer = iInt; break; 
     case 133: Item->clickeffect = iInt; break; 
      case 134: Item->clicktype = iInt; break; 
      case 135: Item->clicklevel2 = iInt; break; 
     case 136: Item->clicklevel = iInt; break; 
     case 137: Item->UNK137 = iInt; break; 
      case 138: Item->proceffect = iInt; break; 
      case 139: Item->proctype = iInt; break; 
      case 140: Item->proclevel2 = iInt; break; 
      case 141: Item->proclevel = iInt; break; 
     case 142: Item->UNK142 = iInt; break; 
      case 143: Item->worneffect = iInt; break; 
      case 144: Item->worntype = iInt; break; 
     case 145: Item->wornlevel2 = iInt; break; 
      case 146: Item->wornlevel = iInt; break; 
     case 147: Item->UNK147 = iInt; break; 
      case 148: Item->focuseffect = iInt; break; 
      case 149: Item->focustype = iInt; break; 
      case 150: Item->focuslevel2 = iInt; break; 
     case 151: Item->focuslevel = iInt; break; 
     case 152: Item->UNK152 = iInt; break; 
      case 153: Item->scrolleffect = iInt; break; 
      case 154: Item->scrolltype = iInt; break; 
     case 155: Item->scrolllevel2 = iInt; break; 
      case 156: Item->scrolllevel = iInt; break; 
     case 157: Item->UNK157 = iInt; break; 
      case 158: Item->verified = iInt; break; 
   } 
} 

// 
// void ReadItem (char * cLine) 
// 
static void ReadItem (PEQITEM Item, char * cLine) 
{ 
   char * cPtr = cLine; 
   int iField = 0; 

   while (*cPtr) { 
      char cField[256]; 
      char * cDest = cField; 

      while (*cPtr != '|' && *cPtr != '\0') { 
         *(cDest++) = *(cPtr++); 
      } 
      *cDest = '\0'; 
      cPtr++; 

      SetField (Item, iField++, cField); 
   } 
} 

typedef unsigned long uint32_t; 
// 
// uint32_t calc_hash (const char *string) 
// 
static uint32_t calc_hash (const char *string) 
{ 
   register hash = 0; 

   while (*string != '\0') { 
      register c = toupper(*string); 
      hash *= 0x1F; 
      hash += (int) c; 

      string++; 
   } 

   return hash; 
} 

// 
// void MakeLink (PEQITEM Item) 
// 
static void MakeLink (PEQITEM Item, char * cLink) 
{ 
   char hashstr[512]; 

   if(Item->itemclass == 0 && Item->charmfileid != 0) { 

      sprintf(hashstr, "%d%s-1-1-1-1-1%d %d %d %d %d %d %d %d %d", 

        Item->id, Item->name, 

        Item->light, Item->icon, Item->price, Item->size, 

        Item->weight, Item->itemclass, Item->itemtype, Item->favor, 

        Item->guildfavor); 

      //WriteChatf("Charm: %s", Item->name); 

     //WriteChatf("Hash: %s", hashstr); 

   } else if(Item->itemclass == 2) { 

      sprintf(hashstr, "%d%s%d%d%09X", 

        Item->id, Item->name, 

        Item->weight, Item->booktype, Item->price); 

      //WriteChatf("Book: %s", Item->name); 

     //WriteChatf("Hash: %s", hashstr); 

   } else if(Item->itemclass == 1) { 

      sprintf(hashstr, "%d%s%x%d%09X%d", 

        Item->id, Item->name, 

        Item->bagslots, Item->bagwr, Item->price, Item->weight); 

      //WriteChatf("Bag: %s", Item->name); 

     //WriteChatf("Hash: %s", hashstr); 

   } else { 

      sprintf(hashstr, "%d%s-1-1-1-1-1%d %d %d %d %d %d %d %d %d %d %d %d %d", 

        Item->id, Item->name, 

        Item->mana, Item->hp, Item->favor, Item->light, 

        Item->icon, Item->price, Item->weight, Item->reqlevel, 

        Item->size, Item->itemclass, Item->itemtype, Item->ac, 

        Item->guildfavor); 

     //WriteChatf("Item: %s", Item->name); 
     //WriteChatf("Hash: %s", hashstr); 
   } 

   uint32_t hash = calc_hash (hashstr); 

   if (Item->loregroup > 1000) 
   { 
     // Evolving 
      sprintf (cLink, "\x12%d%05X%05X%05X%05X%05X%05X%1d%04X%1X%08X%s\x12", 
         0, 
         Item->id, 
         0, 0, 0, 0, 0, // Augs 
         1, Item->loregroup, (Item->id%10)+1, // Evolving items (0=no 1=evolving, lore group, level) 
         hash, // Item hash 
         Item->name); 
   } 
   else 
   { 
      // Non-evolving 
      sprintf (cLink, "\x12%d%05X%05X%05X%05X%05X%05X%1d%04X%1X%08X%s\x12", 
         0, 
         Item->id, 
         0, 0, 0, 0, 0, // Augs 
         0, 0, 0, // Evolving items (0=no 1=evolving, lore group, level) 
         hash, // Item hash 
         Item->name); 
   } 
} 

// 
// static int ConvertItemsDotTxt (void) 
// 
static int ConvertItemsDotTxt (void) 
{ 
   WriteChatf ("MQ2LinkDB: Importing items.txt..."); 

   char cFilename[MAX_PATH]; 
   sprintf(cFilename,"%s\\items.txt", gszINIPath); 
   FILE * File = fopen (cFilename, "rt"); 
   if (File != NULL) { 
      char cFilename2[MAX_PATH]; 
      sprintf(cFilename2, "%s\\MQ2LinkDB.txt", gszINIPath); 
      FILE * LinkFile = fopen (cFilename2, "wt"); 

      if (LinkFile != NULL) { 
         if (abPresent != NULL) { 
            bKnowTotal = false; 
            free (abPresent); 
            abPresent = NULL; 
         } 

         WriteChatf ("MQ2LinkDB: Generating links..."); 
         char cLine[1500]; 

         bool bFirst = true;; 
         int iCount = 0; 
         while (fgets (cLine, 1500, File) != NULL) { 
            cLine[strlen (cLine) - 1] = '\0'; 

            if (bFirst) { 
               // Small sanity check on file 
               char * cCheck = "itemclass|name|lore|idfile|id|weight|norent|nodrop|size|slots|price"; 
               if (memcmp (cLine, cCheck, strlen (cCheck)) != 0) { 
                  WriteChatf ("MQ2LinkDB: \arInvalid items.txt file. Aborting", iCount); 
                  break; 
               } 

               bFirst = false; 
            } else { 
               EQITEM Item; 
               memset (&Item, 0, sizeof (Item)); 
               ReadItem (&Item, cLine); 

               char cLink[256]; 
               MakeLink (&Item, cLink); 

            //WriteChatf("Test ItemID: %d", ItemID(cLink)); 

               fprintf (LinkFile, "%s\n", cLink); 
               iCount++; 
            } 
         } 

         WriteChatf ("MQ2LinkDB: Complete! \ay%d\ax links generated", iCount); 

         fclose (LinkFile); 
      } else { 
         WriteChatf ("MQ2LinkDB: \arCould not create link file (MQ2LinkDB.txt) (err: %d)", errno); 
      } 

      fclose (File); 
   } else { 
      WriteChatf ("MQ2LinkDB: \arSource file not found (items.txt)"); 
   } 

   return 0; 
}
 

Attachments

  • MQ2Linkdb2.dll
    80.1 KB · Views: 96
Last edited by a moderator:
Very nice rusty :) people will be happy to have linkbots again.
 
yeah can we get a new working version of this pretty please
 
Here's the latest compiled version.. I haven't tested it yet, so please let me if there's any problems..
 

Attachments

  • MQ2LinkDB2.dll
    92.1 KB · Views: 63
Hmm MQ2linkDb a bit broken.. some links do not show up but i find them when i search... but do not show the stats of the item... is the Items.txt broken ? got the newest...
 
when i run the /showlink *** it says can not find player but, does nto have any links and it show that it found a couple items. anythign i am missing or is this still broken?
 
Where do you download the item db to? What folder? The main MQ2 folder, macro folder, make a new folder?
 
I have the text file extracted into the release folder and try to do /showlink /import and get an invalid items.txt file error
 
I also am getting the invalid items.txt file aborting....any idea how to fix this?
 
Yep, needs updated now (so will linkdb for that matter). Will get it updated soon, or someone else can knock it out (I'm working).

htw
 
Just curious, whats the difference between MQ2Linkdb2 and MQ2Linkdb? Other than the commands from in game...
 
ThunderStruck said:
Just curious, whats the difference between MQ2Linkdb2 and MQ2Linkdb? Other than the commands from in game...

basically...
Rusty said:
This plugin has been modified to respond to tells with the command !link itemname.

in other words, someone can send you a tell in the format: !link itemname

...and you would automatically respond (or rather the plugin would) with links. aka a linkbot. linkdb is nothing more than a localized linkbot where only you can access the links
 
i have tried the /import command but it keeps telling me no item database yet. any help?