Author | Message | Time |
---|---|---|
ShadowDancer | It comes from the first good discusion in edgeofnowhere about d2 hacking: [code] //common bits// Bit(8) Packet ID (0x9c) (0x9D) bit(8) Action ID bit(8) Packet size bit(8) Item Type bit(32) Item ID //9D only, owner ID / ownerAction// bit(8) Owner Action bit(32) Owner ID // item flags // bit(1) isQuestItem bit(3) Unknown bit(1) isIdentified bit(3) Unknown* bit(1) Illegal Inventory?* bit(1) Unknown* bit(1) isDuplicated?* bit(1) isSocketed bit(2) Unknown* bit(1) Illegal Equip bit(1) Unknown* bit(1) Ear Structure bit(1) Starter Item bit(2) Unknown* bit(1) Unknown* bit(1) Simple Structure bit(1) isEthereal bit(1) Unknown* bit(1) isInscribed bit(1) Unknown* bit(1) isRuneword // item version // bit(5) unknown* bit(8) Item version bit(2) unknown* // item location // bit(3) Item Location if Item location <> 0x03 bit(4) Position on body bit(4) Grid Column bit(4) Grid Row bit(3) Stored In else bit(16) Location X bit(16) Location Y // Item code bit(32) Item Code if Item code == "ear" bit(3) Class bit(7) Level bit(18) Name end else ...... * = seems to be true but not 100% sure Items are usually encoded along the lines of: origin, id, [player info,] flags, location, item code, item info (sockets, quality, image, etc), item quality data, runeword data, personalization data, more item info (defense, durability, sockets, etc), mods. The exceptions to the scheme seems to be: 1) Gambled items should stop decoding after reading the item code 2) Ears are decoded differently and is already known After reading the item code, for items with the misc bit not set in the flags: 1) Read in 3 bits. If it is socketed, that is the total number of sockets 2) Read in 7 bits for the item level 3) Read in 4 bits for the item quality 4) Read in 1 bit. This tells you if the item has an image. If it has an image, read in 3 bits for the image number. 5) Read in 1 bit. This tells you if it has class specific data. If it does, read in 11 bits to get that info. The above should get you synced up to read in data about the quality. The 2nd section on item info is decoded as such: 1) If it comes from the armor file, read in 10 bits and subtract 10 to get the base defense. 2) If the item does not come from the misc item file (*), read in 8 bits for the base durability. If this is 0, it is indestructible. If it is not 0, read in 8 bits to get the current durability. Bows and throwing items have durability and WILL break if durability becomes 0 (try it out with ethereal javelins if you want). 3) If it is socketed, read 4 bits for the number of used sockets 4) If it is a set item, read in 5 bits to get the number of set bonuses associated with the set. 5) If it is stackable (from mpq file (*)): 5a) If it is useable (from mpq file) (*), read in 5 bits (I didn't check the value to find out what it might be) 5b) Read in 9 bits to get the quantity 4 and 5 might be reversed, but I don't think there are any set stackable items to test it with. This should get you synced up to start reading in the mods. Mods are decoded along the lines of: 1) Read stat 1a) If stat is 0x1ff, go to 3. If not, read info related to stat 2) Go to 1. 3) If it is a set, repeat from 1 for the count indicated in the set bonuses field That should get you to the end of the packet with less than 8 bits left in the packet. Special stats: STATS_ITEM_MAXDAMAGE_PERCENT (and probably STATS_ITEM_MINDAMAGE_PERCENT): encoded in 2 pairs of length "SaveBits". Probably for left/ right hand, primary/secondary weapon or something along those lines Replenish stats: rate is given as 1 per 100/value seconds Cold/poison duration: duration is given as value * 0.04 (*) seconds Posion damage: rate is given as value / 10.25 (*) damage per second STATS_FIREMINDAM, STATS_LIGHTMINDAM, STATS_MAGICMINDAM, STATS_COLDMINDAM, STATS_COLDMAXDAM, STATS_POISONMINDAM, STATS_POISONMAXDAM: require reading looping back to 1a using stat + 1 as the current stat. I'm guessing this was done to save 9 bits each stat. Per level: ((level * value) >> PerLevelShift) - SaveAdd (better done with floats instead of integers so use division instead of shifts) By time: "max value" : "min value" : "best time" (x : 10 : 2). Max/min values subtracted by 0x100. Times: 0 = daytime, 1 = dusk, 2 = nighttime, 3 = dawn. Best time = max value, worst time = min value, others = average of max + min +Skill tab: encoded as "# of skills" : "skill tab" (x : 5) (x = remaining bits, calculated as SaveBits - used up bits (in this case, 5)) +Skill: encoded as "# of skills" : "skill" (x : 9) +Skill on attack/striking/struck: "% chance" : "skill level" : "skill" (x : 5 : 9) +Charges: "total charges" : "current charges" : "skill level" : "skill" (x : 8 : 5 : 9) /*************** Tables ***************/ /***** Item actions ***** 0x00 - Lying on the ground (just dropped) (9c) 0x01 - Picked up from ground to cursor (9c) 0x02 - Dropped by Player (9c) 0x03 - Lying on the ground (been lying there) (9c) 0x04 - Moved in Cube/Inventory (9c) 0x05 - Put onto cursor (9d) 0x06 - Item on cursor was equipped (9d) 0x08 - Removed from equipment slot (9d) 0x09 - Item on cursor was swapped with item in equipment slot (9d) 0x0b - Added to Shop/Gamble buffer (9c) 0x0c - Removed from Shop/Gamble buffer (9c) 0x0d - Item on Cursor was swapped with item in inventory (9c) 0x0e - Put into belt (9c) 0x0f - Removed from Belt (9c) 0x10 - Item on Cursor was switched with item in belt (9c) 0x12 - Item on cursor when entering game (9c) 0x13 - Item is socketed into another (9d) 0x15 - An item was just inserted into socket (9d) 0x17 - Item on equipment slot was swapped with one from the second set of slots (9d) ***** Buffer IDs ***** 0x00 - Belt,equipment slots and merc 0x0a - Stash 0x10 - Ground 0x20 - Inventory (there is also a part of this buffer which is used by NPCs (shop+gamble)) 0x30 - NPC Buffer (Shop + Gamble) 0x40 - NPC Buffer (Shop + Gamble) 0x50 - NPC Buffer (Shop + Gamble) 0x60 - NPC Buffer (Shop + Gamble) 0x80 - Cube (same thing here as in 0x20) ***** Item Qualities ***** 1 - Inferior 2 - Normal 3 - Superior 4 - Magic 5 - Set 6 - Rare 7 - Unique 8 - Crafted [/code] | July 14, 2006, 2:53 PM |
Infamous | You forgot an important part [code] // Item code bit(32) Item Code if Item code == "ear" bit(3) Class bit(7) Level bit(18) Name end else bit(3) Number of gems bit(7) Drop level bit(4) Quality bit(1) Variable Graphic flag bit(1) Class Info //case Quality 0x00 //crafted bit(8) RarePrefix bit(8) RareSuffix 0x01 //inferior bit(3) iQualityType 0x02 //Normal 0x03 //Superior bit(3) iQualityType 0x04 //Magic bit(3) unknown? bit(11) Magic Prefix bit(11) Magic Suffix 0x05 //Set bit(12) Set ID 0x06 //Rare bit(8) RarePrefix bit(8) RareSuffix 0x07 //Unique bit(12) Unique ID //end case if isRuneWord bit(16) Runeword ID if isInscribed bit(15) Name // item base bit(11) Defence bit(8) Max Durability bit(9) Durability bit(4) Number of sockets bit(9) Quantity // arrows, throwing axe etc.. // item mods bit(>) Property list [/code] | July 14, 2006, 3:44 PM |
ShadowDancer | no, it is there but in text format bcoz herzog_zwei have writed it better conditionated and explained... soo if u can edit and remove to not cause confusion :P // excuse my spelling, i know it is really bad | July 14, 2006, 3:55 PM |
Infamous | Pretty funny how you manged to take my code from EoN and herzog_zwei and placed it under one.. you should have kept the it the same..less confusing imo btw heres the thread in EoN. http://www.edgeofnowhere.cc/viewtopic.php?t=312208&start=15 | July 14, 2006, 4:01 PM |
ShadowDancer | ahhhhh you are RaMz? :D cool I allways merge the info from long theads like it for my ref library :P | July 14, 2006, 4:06 PM |
UserLoser | Excellent. I think they banned herzog from here though over some stupid C++ discussion. Not sure though... | July 15, 2006, 5:46 AM |
Ringo | Hm, iv been doing alota research on this packet over the last few days, and i cant see how the item location is parseable from your code. Depending on the event, depends on format of the location area of the bit fields, example: [code] ItemFlag = Reader.ReadAsLong(32) Call Reader.SkipBits(10) 'unknown Select Case ItemEvent Case &H0, &H2, &H3 'FLOOR ITEM Position = Reader.ReadAsByte(3) LocalX = Reader.ReadAsInteger(16) LocalY = Reader.ReadAsInteger(16) Case &H4, &H5, &HD, &HE, &HF, &H10, &H15 'Stash item and belt item Call Reader.SkipBits(7) 'unknown 0x64/0x65 LocalX = Reader.ReadAsByte(4) 'If belt then Belt slot LocalY = Reader.ReadAsByte(3) Position = Reader.ReadAsByte(4) Case &H6, &H8, &H9 'body item add/del/switch Position = Reader.ReadAsByte(3) Call Reader.SkipBits(3) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(4) Call Reader.SkipBits(4) Case Else Exit Sub End Select [/code] | July 15, 2006, 6:35 AM |
E.T. | If you still need this, here's how I do it (this comes right after the version byte): [code] this.destination = (ItemDestination)ByteConverter.GetBits(data, ref pOffset, 5); if (this.destination == ItemDestination.Ground) { this.x = (ushort)ByteConverter.GetBits(data, ref pOffset, 16); this.y = (ushort)ByteConverter.GetBits(data, ref pOffset, 16); this.container = ItemContainer.Ground; } else { this.location = (EquipmentLocation)ByteConverter.GetBits(data, ref pOffset, 4); this.x = (ushort)ByteConverter.GetBits(data, ref pOffset, 4); this.y = (ushort)ByteConverter.GetBits(data, ref pOffset, 3); this.container = (ItemContainer)ByteConverter.GetBits(data, ref pOffset, 4); } [/code] [code] public enum ItemDestination { /// <summary> /// The item is going in the specified container /// </summary> Container = 0, Equipment = 4, Belt = 8, Ground = 0x0C, Cursor = 0x10, Item = 0x18, } [/code] | February 9, 2007, 4:02 AM |
ShadowDancer | Posted on: July 15, 2006, 01:35 AM [QOUTE] if (this.destination == ItemDestination.Ground) { this.x = (ushort)ByteConverter.GetBits(data, ref pOffset, 16); this.y = (ushort)ByteConverter.GetBits(data, ref pOffset, 16); this.container = ItemContainer.Ground; } else { this.location = (EquipmentLocation)ByteConverter.GetBits(data, ref pOffset, 4); this.x = (ushort)ByteConverter.GetBits(data, ref pOffset, 4); this.y = (ushort)ByteConverter.GetBits(data, ref pOffset, 3); this.container = (ItemContainer)ByteConverter.GetBits(data, ref pOffset, 4); } [/QUOTE] imho useless... [QUOTE] ItemFlag = Reader.ReadAsLong(32) Call Reader.SkipBits(10) 'unknown Select Case ItemEvent Case &H0, &H2, &H3 'FLOOR ITEM Position = Reader.ReadAsByte(3) LocalX = Reader.ReadAsInteger(16) LocalY = Reader.ReadAsInteger(16) Case &H4, &H5, &HD, &HE, &HF, &H10, &H15 'Stash item and belt item Call Reader.SkipBits(7) 'unknown 0x64/0x65 LocalX = Reader.ReadAsByte(4) 'If belt then Belt slot LocalY = Reader.ReadAsByte(3) Position = Reader.ReadAsByte(4) Case &H6, &H8, &H9 'body item add/del/switch Position = Reader.ReadAsByte(3) Call Reader.SkipBits(3) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(4) Call Reader.SkipBits(4) Case Else Exit Sub <<< that is a problem End Select [/QUOTE] | February 9, 2007, 7:29 AM |
E.T. | Useless? I'd like to know why it's useless... you're doing almost the same as me but ignoring more bits. You're probably right about the first 5 bits being 2 separate info (or first 2 bits being part of version maybe?), but other than that... If you mean useless because it's in a different language, I'm sure Ringo can extract the offsets from my simple code... I do a little post processing for convenience after that, but the important info is there. I'll investigate the first bits and build a plain text reference to make it clearer. Edit: here's first part of ref with the ItemDestination corrected: (BYTE) Action (BYTE) Length (BYTE) Category (DWORD) Item UID For 0x9D only: (BYTE) Owner UnitType (DWORD) Owner UID (DWORD) Flags (BYTE) Version (2 bits) Unknown (3 bits) Destination If Destination == 3 (Ground): (WORD) X (WORD) Y Else: (4 bits) EquipmentLocation (4 bits) X (3 bits) Y (4 bits) Container Destination: [code] Container = 0, Equipment = 1, Belt = 2, Ground = 3, Cursor = 4, Item = 6, [/code] EquipmentLocation: [code] NotApplicable = 0, Helm = 1, Amulet = 2, Armor = 3, RightHand = 4, LeftHand = 5, RightHandRing = 6, LeftHandRing = 7, Belt = 8, Boots = 9, Gloves = 10, RightHandSwitch = 11, LeftHandSwitch = 12, [/code] EquipmentLocation will only be non-0 if applicable, in which case X will be the same value. But X is also defined for other actions so better get it from first spot to know without having to check action type... Really it's just simpler like that, avoids relying on known action types and works for all I tested with... But I'd appreciate constructive criticism. Just saying it's useless is not very nice or useful though. | February 9, 2007, 8:46 AM |
E.T. | Oh, I misread Ringo's post, the code you quoted was his and he already had a pretty good start :o Yes the code posted on EoN had the location stuff wrong. Anyhow it should still be useful to compare our code and build a reference... here are a few more of my current enum values: Container: [code] Equipment = 0x00, Ground = 0x01, Inventory = 0x02, TraderOffer = 0x04, ForTrade = 0x06, Cube = 0x08, Stash = 0x0A, [/code] NPC Buffer: [code] ArmorTab = 0x02, ArmorTabBottom = 0x03, WeaponTab1 = 0x04, WeaponTab1Bottom = 0x05, WeaponTab2 = 0x06, MiscTab = 0x08, MiscTabBottom = 0x09, [/code] NPC Buffer and Container are from the same value which I call container in the above... I assume NPC buffer 0x07 would be WeaponTab2Bottom but I haven't been able to test this yet... Bottom here means the last 2 rows which don't fit in the 16x8 buffers... ItemAction: [code] AddToGround = 0, /// <summary> /// Only sent if item goes to cursor (packet 0x0A removes item from ground...) /// </summary> GroundToCursor = 1, DropToGround = 2, OnGround = 3, PutInContainer = 4, RemoveFromContainer = 5, Equip = 6, /// <summary> /// Sent for the equipped item when changing from a two handed weapon to a single handed weapon or vice versa. /// The item must be equipped on the "empty" hand or a regular SwapBodyItem will be sent instead. /// Empty hand meaning left hand if currently wearing a two handed weapon or the empty hand if wearing a single hand item. /// The result will be the new item being equipped and the old going to cursor. /// </summary> IndirectlySwapBodyItem = 7, Unequip = 8, SwapBodyItem = 9, AddQuantity = 0x0A, AddToShop = 0x0B, RemoveFromShop = 0x0C, SwapInContainer = 0x0D, PutInBelt = 0x0E, RemoveFromBelt = 0x0F, SwapInBelt = 0x10, /// <summary> /// Sent for the secondary hand's item going to inventory when changing from a dual item setup to a two handed weapon. /// </summary> AutoUnequip = 0x11, /// <summary> /// Sent along with a 0x9d type 0x08 packet... /// Also Item on cursor when entering game ?? MiscToCursor?? /// </summary> RemoveFromHireling = 0x12, ItemInSocket = 0x13, UNKNOWN1 = 0x14, /// <summary> /// When inserting item in socket, for each potion that drops in belt when lower one is removed, etc. /// </summary> UpdateStats = 0x15, UNKNOWN2 = 0x16, WeaponSwitch = 0x17, [/code] ItemFlag: [code] None = 0, Equipped = 1, // UNKNOWN = 2, // UNKNOWN = 4, InSocket = 8, /// <summary> /// Not undentified, really... also set for items that cannot be identified. /// </summary> Identified = 0x10, /// <summary> /// Has to do with aura / state change !? /// </summary> x20 = 0x20, SwitchedIn = 0x40, SwitchedOut = 0x80, Broken = 0x100, // UNKNOWN = 0x200, /// <summary> /// Set for Mana, Healing and Rejuvenation potions, but not always !?! /// </summary> Potion = 0x400, Socketed = 0x800, /// <summary> /// Can't be removed? Set for items equipped by Valkyrie... /// </summary> x1000 = 0x1000, /// <summary> /// This flag is sometimes set for items in npc buffers, quest items and items equipped by Valkyrie... /// </summary> x2000 = 0x2000, NotInSocket = 0x4000, // Illegal Equip ? // UNKNOWN = 0x8000, /// <summary> /// Is a player's ear. Ear packets have a different structure... /// </summary> Ear = 0x10000, /// <summary> /// Item a character started with (meaning the item worthless to resell.) /// </summary> StartItem = 0x20000, //UNKNOWN = 0x40000, //UNKNOWN = 0x80000, //UNKNOWN = 0x100000, /// <summary> /// Item that doesn't have an ILevel or stats. /// </summary> SimpleItem = 0x200000, Ethereal = 0x400000, Any = 0x800000, // Which means ?? Personalized = 0x1000000, /// <summary> /// Item a town folk is offering for gambling (same purpose as SimpleItem: no ILevel + extra info.) /// </summary> Gamble = 0x2000000, Runeword = 0x4000000, /// <summary> /// InducesTempStatusChange ?? /// </summary> x8000000 = 0x8000000, [/code] ItemQuality: [code] NotApplicable = 0, Inferior = 1, Normal = 2, Superior = 3, Magic = 4, Set = 5, Rare = 6, Unique = 7, Crafted = 8, [/code] Category: [code] Helm = 0, Armor = 1, /// <summary> /// Most weapons, including Crossbows /// </summary> Weapon = 5, /// <summary> /// Bows (not crossbows), sometimes shield (if equipped in LeftHand?) /// </summary> Weapon2 = 6, /// <summary> /// Shields can some sometimes be Weapon2... /// </summary> Shield = 7, /// <summary> /// Class specific items !? /// </summary> Special = 10, /// <summary> /// BaseMiscItems and gloves, boots... /// </summary> Misc = 16, [/code] I haven't been able to make much sense of this one... Any corrections or additional info would be very welcome... | February 9, 2007, 10:26 AM |
ShadowDancer | [QUOTE] Useless? I'd like to know why it's useless... you're doing almost the same as me but ignoring more bits. You're probably right about the first 5 bits being 2 separate info (or first 2 bits being part of version maybe?), but other than that... If you mean useless because it's in a different language, I'm sure Ringo can extract the offsets from my simple code... [/QUOTE] excuse my rooughness :( i only tryed to say that it was obsolete compared with the one posted by ringo. anymode this thead is too old... Posted on: July 14, 2006, 09:53 AM [QUOTE] Anyhow it should still be useful to compare our code and build a reference... here are a few more of my current enum values: [/QUOTE] [bold]Sure :D [/bold] [code] procedure process_0x9C_0x9D(); type titemstats = record start : integer; itemstat:integer; param:string; paramint:integer; addparam:string; addparamint:integer; end; titemdec = array of titemstats; titem = array of titemdec; var i,j,k,l:integer; s:string; tstr:array[0..10] of string; tinteger:array[0..10] of integer; lastreaded:integer; t:ttreenode; rcode:integer; keep1, keep2:boolean; mods:array[0..50] of dword; mpqitem:tvirtuallistitem; itype:integer; gitemlist:tvirtuallist; dontadd:boolean; // item:tvirtuallist; li,li2,li1:tvirtuallistitem; prefix, sufix:string; //when comes a +min readthemax:boolean; tfile:textfile; iwidth, iheight:integer; tmpstr:array[0..10] of string; icodeat:integer; item2:titem; gt:ttreeview; r,v:integer; itemmustbesaved:boolean; savetitle:string; function inttobin(a:integer):string; var w:longword; s:string; i:integer; begin w:=$01; for i:=1 to 8 do begin if a and w = w then begin s:=s+'1'; end else s:=s+'0'; w:=w * 2; end; result:=s; end; function readbits(bitstring:string; var from:integer; amount:integer):string; begin result:=copy(bitstring,from,amount); inc(from,amount); end; function strbittostr(bstr:string; bitsaling:integer):string; var j,i,k,q,a:integer; s:string; begin k:=0; for i:=1 to (length(bstr) div bitsaling) do begin q:=1; a:=0; for j:=1 to bitsaling do begin inc(k); if bstr[k]='1' then a:=a+q; q:=q*2; end; s:=s+chr(a); end; result:=s; end; function strbittoint(bstr:string):integer; var j,i,k,q,a:integer; begin if length(bstr) > 32 then exit; k:=0; q:=1; a:=0; for j:=1 to length(bstr) do begin inc(k); if bstr[k]='1' then a:=a+q; q:=q*2; end; result:=a; end; var itemread:tvirtuallist; xli:tlistitem; function strtoint(a:string):integer; var c,d:integer; begin val(a,c,d); if d = 0 then result:=c else result:=0; end; function decquality(s:String):integer; begin result:=0; s:=lowercase(s); if s='crafted' then result:=0; if s='inferior' then result:=1; if s='normal' then result:=2; if s='superior' then result:=3; if s='magic' then result:=4; if s='set' then result:=5; if s='rare' then result:=6; if s='unique' then result:=7; end; procedure add2(s,g,h:string); var li:tvirtuallistitem; begin li:= itemread.find(0,s); if li = nil then li:=itemread.add; li.strings[0]:=s; li.strings[1]:=g; li.strings[2]:=h; end; function rprop(s:string):string; var li:tvirtuallistitem; begin li:=itemread.find(0,s); if li<>nil then result:=li.strings[1]; end; procedure readmod(id:integer); var savebits:integer; saveparambits:integer; saveadd:integer; sendother:integer; callback:integer; extraparams:integer; op, opparam:integer; eparam, eparam2:integer; li2,li1:tvirtuallistitem; begin li:=itemstats.find('ID',inttostr(id)); if li <> nil then begin savebits:=strtoint(li.strings[itemstats.findcolumn(0,'Save Bits')]); saveparambits:=strtoint(li.strings[itemstats.findcolumn(0,'Save Param Bits')]); saveadd:=strtoint(li.strings[itemstats.findcolumn(0,'Save Add')]); sendother:=strtoint(li.strings[itemstats.findcolumn(0,'Send Other')]); callback:=strtoint(li.strings[itemstats.findcolumn(0,'fCallback')]); op:=strtoint(li.strings[itemstats.findcolumn(0,'op')]); opparam:=strtoint(li.strings[itemstats.findcolumn(0,'op param')]); if li.strings[itemstats.findcolumn(0,'read next')] = '1' then readthemax:=true else readthemax:=false; tmpstr[1]:=readbits(s,lastreaded,savebits); if saveparambits > 0 then begin readbits(s,lastreaded,saveparambits); end; end; end; procedure readmod2(id:integer); var savebits:integer; saveparambits:integer; saveadd:integer; sendother:integer; callback:integer; extraparams:integer; op, opparam:integer; eparam, eparam2:integer; li2,li1:tvirtuallistitem; begin li:=itemstats.find('ID',inttostr(id)); if li <> nil then begin savebits:=strtoint(li.strings[itemstats.findcolumn(0,'Save Bits')]); saveparambits:=strtoint(li.strings[itemstats.findcolumn(0,'Save Param Bits')]); saveadd:=strtoint(li.strings[itemstats.findcolumn(0,'Save Add')]); sendother:=strtoint(li.strings[itemstats.findcolumn(0,'Send Other')]); callback:=strtoint(li.strings[itemstats.findcolumn(0,'fCallback')]); op:=strtoint(li.strings[itemstats.findcolumn(0,'op')]); opparam:=strtoint(li.strings[itemstats.findcolumn(0,'op param')]); if li.strings[itemstats.findcolumn(0,'read max')] = '1' then readthemax:=true else readthemax:=false; // if sendother > 0 then // tmpstr[2]:=readbits(s,lastreaded,sendother); tmpstr[1]:=readbits(s,lastreaded,savebits); //add2('- mod '+li.strings[0]+' value ',inttostr(strbittoint(tmpstr[1])- saveadd),tmpstr[1]); item2[high(item2)][high(item2[high(item2)])].param:=tmpstr[1]; item2[high(item2)][high(item2[high(item2)])].paramint:=strbittoint(tmpstr[1])- saveadd; // if sendother > 0 then // add2('- sendother',tmpstr[2],''); if saveparambits > 0 then begin tmpstr[2]:=readbits(s,lastreaded,saveparambits); item2[high(item2)][high(item2[high(item2)])].addparam:=tmpstr[2]; item2[high(item2)][high(item2[high(item2)])].addparamint:=strbittoint(tmpstr[2]); //add2('- param ',tmpstr[2],''); end; end; end; function checkmods(i:integer):boolean; var pop:integer; g:String; begin result:=false; pop:=lastreaded; lastreaded:=i; repeat readthemax:=false; g:=readbits(s,lastreaded,9); if ($1FF = strbittoint(g)) then if (lastreaded+8 >= length(s)) then begin result:=true; lastreaded:=pop; exit; end; if $1FF <> strbittoint(g) then begin readmod(strbittoint(g)); end; if readthemax = true then begin readmod(strbittoint(g)+1); end; until (lastreaded-1+8 >= length(s)); lastreaded:=pop; end; procedure addmods(lr:integer); var pop:integer; k,l,i:integer; begin pop:=lastreaded; lastreaded:=lr; l:=-1; for i:=0 to high(item2) do for k:=0 to high(item2[i]) do if item2[i][k].start=lr then begin l:=k; break; end; if l=-1 then begin add2('Optional mod list',inttostr(j),''); setlength(item2,high(item2)+2); repeat readthemax:=false; tmpstr[0]:=readbits(s,lastreaded,9); setlength(item2[high(item2)],high(item2[high(item2)])+2); item2[high(item2)][high(item2[high(item2)])].start:=lastreaded; item2[high(item2)][high(item2[high(item2)])].itemstat:=strbittoint(tmpstr[0]); li:=nil; if $1FF <> strbittoint(tmpstr[0]) then readmod2(strbittoint(tmpstr[0])); if readthemax = true then readmod2(strbittoint(tmpstr[0])+1); if li<>nil then add2('Mod '+li.strings[0]+' ('+tmpstr[0]+')',item2[high(item2)][high(item2[high(item2)])].param+' '+item2[high(item2)][high(item2[high(item2)])].addparam,''); if (strbittoint(tmpstr[0]) = $1FF) then break; until (lastreaded+8 >= length(s)); end; lastreaded:=pop; end; procedure make_name(); var pre,suf:integer; prefix, suffix:string; i,j,k:integer; s:string; begin if mpqitem<>nil then s:=mpqitem.strings[0] else exit; case strbittoint(rprop('Quality')) of 0: //crafted begin end; 01: //inferior begin end; 02: //Normal begin end; 03: //Superior begin s:='Superior '+s+''; end; 04: //Magic begin if (strbittoint(rprop('Magic Prefix')) <> 0) and (strbittoint(rprop('Magic Prefix')) < magicprefix.count) then begin li:=magicprefix.items[strbittoint(rprop('Magic Prefix'))+1]; prefix:=li.strings[0]+' '; end; if (strbittoint(rprop('Magic Suffix')) <> 0) and (strbittoint(rprop('Magic Suffix')) < magicsuffix.count) then begin li:=magicsuffix.items[strbittoint(rprop('Magic Suffix'))+1]; sufix:=' '+li.strings[0]; end; s:='Magic '+prefix+s+sufix; end; 05: //Set begin s:='Set '+s+''; end; 06: //Rare begin s:='Rare '+s+''; end; 07: //Unique begin if (strbittoint(rprop('Unique ID')) <> 0) and (strbittoint(rprop('Unique ID')) < uniqueitems_txt.count) then begin li:=UniqueItems_ex_txt.items[strbittoint(rprop('Unique ID'))]; li:=uniqueitems_txt.find('index',li.strings[0]); prefix:=li.strings[0]+' '; //get more data about this unique... end; s:='Unique '+prefix+' ('+s+') '; end; end; if rprop('isIdentified') = '0' then s:=s+' [unidentified]'; if rprop('isEthereal') = '1' then s:='ETH >> '+s; if debuglvl > 6 then s:=s+' {'+strbittostr(rprop('Item Code'),8)+'}'; add2('Item Name',s,''); end; procedure graphitem(gt:ttreeview); var pre,suf:integer; prefix, suffix:string; i,j,k:integer; s:string; begin if bots[vlink].winpointer2 <>nil then if (strbittoint(rprop('Action')) <> 4) and (strbittoint(rprop('Action')) <> 3) and (strbittoint(rprop('Action')) <> 2) and (strbittoint(rprop('Action')) <> 0) then begin exit; end; if (strbittoint(rprop('Action')) = 4) and (strbittoint(rprop('Position')) <> 2) and (strbittoint(rprop('Position')) <> 4) then begin exit; end; t:=gt.Items.Add(nil,rprop('Item Name')); gt.Items.AddChild(t,rprop('Action')); // t.strings[0]:='Magic '+prefix+' '+item.items[0].strings[0]+' '+sufix; { if high(item2)>0 then begin for i:=0 to high(item2) do for j:=0 to high(item2[i]) do gt.Items.AddChild(t,inttostr(item2[i][j].itemstat)); end; } end; procedure checksave(); var v,i,r,l,j:integer; li:tvirtuallistitem; s,g:string; begin if high(item2)>=0 then begin for v:=0 to pick_by_mod.count-1 do begin li:=pick_by_mod.items[v]; if (strbittoint(rprop('Quality')) = decquality(li.strings[pick_by_mod.findcolumn(0,'quality')])) then if (mpqitem.strings[gitemlist.findcolumn(0,'type')] = li.strings[pick_by_mod.findcolumn(0,'itype')]) or (li.strings[pick_by_mod.findcolumn(0,'itype')] = '') then begin for i:=0 to high(item2) do begin l:=0; for r :=1 to 8 do begin s:=li.strings[pick_by_mod.findcolumn(0,'mod '+inttostr(r))]; g:=li.strings[pick_by_mod.findcolumn(0,'mod param '+inttostr(r))]; if s = '' then inc(l) else for j:=0 to high(item2[i]) do begin if (item2[i][j].itemstat=strtoint(s)) then begin if (g = '') or (item2[i][j].paramint=strtoint(g)) then begin inc(l); break; end; end; end; end; if l = 8 then begin add2('Item must be saved','',''); itemmustbesaved:=true; break; end; end; end; end; end; end; var gstats:tstats; m1:integer; begin j:=dlen; itemread:=tvirtuallist.create(3); s:=''; tstr[0]:=''; for i:=0 to j-1 do begin s:=s+inttobin(cbuf[i]); end; for i:=0 to high(mods) do mods[i]:=0; for i:=1 to (j+1)*8 do begin tstr[0]:=s[i]+tstr[0]; end; if debuglevel = 9 then begin memo1.lines.add('+ <- 0'); memo1.lines.add(tstr[0]); memo1.lines.add('0 -> +'); memo1.lines.add(s); end; lastreaded:=1; add2('Packet message',readbits(s,lastreaded,8),''); add2('Action',readbits(s,lastreaded,8),''); add2('Item type',readbits(s,lastreaded,8),''); add2('Data size',readbits(s,lastreaded,8),''); add2('Item ID',readbits(s,lastreaded,32),''); if strbittoint(rprop('Packet message')) = $9d then begin add2('Action2',readbits(s,lastreaded,8),''); add2('User ID',readbits(s,lastreaded,32),''); end; dontadd:=false; { if strbittoint(rprop('Action')) = 11 then dontadd:=true; //in trade } add2('isQuestItem',readbits(s,lastreaded,1),''); add2('Unknow',readbits(s,lastreaded,3),''); add2('isIdentified',readbits(s,lastreaded,1),''); add2('Unknow2',readbits(s,lastreaded,3),''); add2('IlegalInventory',readbits(s,lastreaded,1),''); add2('Unknow3',readbits(s,lastreaded,1),''); add2('isDuplicated',readbits(s,lastreaded,1),''); add2('isSocketed',readbits(s,lastreaded,1),''); add2('Unknow4',readbits(s,lastreaded,2),''); add2('Illegal Equip',readbits(s,lastreaded,1),''); add2('Unknow5',readbits(s,lastreaded,1),''); add2('Ear Structure',readbits(s,lastreaded,1),''); add2('Starter Item',readbits(s,lastreaded,1),''); add2('Unknow6',readbits(s,lastreaded,2),''); add2('Unknow7',readbits(s,lastreaded,1),''); add2('Simple Structure',readbits(s,lastreaded,1),''); add2('isEthereal',readbits(s,lastreaded,1),''); add2('Unknow8',readbits(s,lastreaded,1),''); add2('isInscribed',readbits(s,lastreaded,1),''); add2('Unknow9',readbits(s,lastreaded,1),''); add2('isRuneword',readbits(s,lastreaded,1),''); add2('Unknow10',readbits(s,lastreaded,5),''); //flags end here 32 bits add2('Item version',readbits(s,lastreaded,8),''); add2('Unknow11',readbits(s,lastreaded,2),''); if bots[vlink].ig_currentstatus=$fb then if strbittoint(rprop('Item ID')) = strtoint('$0'+bots[vlink].paramstack[0]) then case strbittoint(rprop('Action')) of $00, $02, $03:begin end; else begin bots[vlink].queue_step(1); end; end; case strbittoint(rprop('Action')) of //FLOOR ITEM $00, $02, $03: begin add2('Position',readbits(s,lastreaded,3),''); add2('LocalX',readbits(s,lastreaded,16),''); add2('LocalY',readbits(s,lastreaded,16),''); end; //Stash item $04, $05, $0D, $0E, $0F, $10, $12, //item at cursor when beggin $13, $15, $17: begin add2('Unknow12',readbits(s,lastreaded,7),''); add2('LocalX',readbits(s,lastreaded,4),''); add2('LocalY',readbits(s,lastreaded,3),''); add2('Position',readbits(s,lastreaded,4),''); end; //body item add/del/switch $06, $08, $09: begin add2('Position',readbits(s,lastreaded,3),''); add2('Unknow13',readbits(s,lastreaded,3),''); add2('LocalX',readbits(s,lastreaded,4),''); add2('LocalY',readbits(s,lastreaded,4),''); add2('Unknow14',readbits(s,lastreaded,4),''); end; $0b:begin add2('Unknow12',readbits(s,lastreaded,7),''); add2('LocalX',readbits(s,lastreaded,4),''); add2('LocalY',readbits(s,lastreaded,3),''); add2('Position',readbits(s,lastreaded,4),''); end; else begin assignfile(tfile,'logs\failed.txt'); if fileexists('logs\failed.txt') then append(tfile) else rewrite(tfile); writeln(tfile,s); for i:=0 to itemread.count-1 do begin write(tfile,itemread.items[i].strings[0]+' '); write(tfile,itemread.items[i].strings[1]+' '); write(tfile,inttostr(strbittoint(itemread.items[i].strings[1]))+' '); write(tfile,inttohex(strbittoint(itemread.items[i].strings[1]),4)+' '); writeln(tfile,strbittostr(itemread.items[i].strings[1],8)+' '); end; closefile(tfile); memo1.lines.add('why end ?'+inttohex(strbittoint(rprop('Action')),2)); exit; end; end; add2('Item Code',readbits(s,lastreaded,32),''); icodeat:=lastreaded; itype:=0; mpqitem:=misc.find(misc.findcolumn(0,'code'),zstring(strbittostr(rprop('Item Code'),8),1)); if mpqitem<>nil then begin itype:=1; gitemlist:=misc; end; if mpqitem=nil then begin mpqitem:=weapons.find(weapons.findcolumn(0,'code'),zstring(strbittostr(rprop('Item Code'),8),1)); if mpqitem<>nil then begin itype:=2; gitemlist:=weapons; end; end; if mpqitem=nil then begin mpqitem:=armors.find(armors.findcolumn(0,'code'),zstring(strbittostr(rprop('Item Code'),8),1)); if mpqitem<>nil then begin itype:=3; gitemlist:=armors; end; end; if mpqitem=nil then begin memo1.lines.add('******************** item is unknow!!!!'); exit; end; add2('InvFile',mpqitem.strings[gitemlist.findcolumn(0,'invfile')],''); { if fileexists('S:\Diablo II\D2SysBot 2.5\PCXFiles\c_inv'+zstring(strbittostr(rprop('Item Code'),8),1)+'.pcx') then add2('InvFile','S:\Diablo II\D2SysBot 2.5\PCXFiles\c_inv'+zstring(strbittostr(rprop('Item Code'),8),1)+'.pcx',''); } // if mpqitem<>nil then // item.items[0].strings[0]:=mpqitem.strings[0]; if zstring(strbittostr(rprop('Item Code'),8),1) = 'ear' then begin // bit(3) Class // bit(7) Level // bit(18) Name memo1.lines.add('ear ... '); exit; end; add2('Number of gems',readbits(s,lastreaded,3),''); add2('Drop level',readbits(s,lastreaded,7),''); add2('Quality',readbits(s,lastreaded,4),''); add2('is Graphic Variable',readbits(s,lastreaded,1),''); if rprop('is Graphic Variable') = '1' then add2('Image',readbits(s,lastreaded,3),''); li1:=tables[tbl_itemtypes].find('Code',mpqitem.strings[gitemlist.findcolumn(0,'type')]); if li1 = nil then begin li1:=tables[tbl_itemtypes].find('Equiv1',mpqitem.strings[gitemlist.findcolumn(0,'type')]); if li1 = nil then begin li1:=tables[tbl_itemtypes].find('Equiv2',mpqitem.strings[gitemlist.findcolumn(0,'type')]); if li1 = nil then begin memo1.lines.add('******************** item type is unknow!!!!'); exit; end; end; end; if strtoint(li1.strings[tables[tbl_itemtypes].findcolumn(0,'VarInvGfx')]) > 0 then begin add2('InvFile',li1.strings[tables[tbl_itemtypes].findcolumn(0,'InvGfx'+inttostr(strbittoint(rprop('Image'))+1))],''); end; //¿? skip classinfo if misc add2('have Class Info?',readbits(s,lastreaded,1),''); if rprop('have Class Info?') = '1' then add2('Class info',readbits(s,lastreaded,11),''); case strbittoint(rprop('Quality')) of 0: //crafted begin add2('RarePrefix',readbits(s,lastreaded,8),''); add2('RareSuffix',readbits(s,lastreaded,8),''); end; 01: //inferior begin add2('iQualityType',readbits(s,lastreaded,3),''); end; 02: //Normal begin end; 03: //Superior begin add2('iQualityType',readbits(s,lastreaded,3),''); end; 04: //Magic begin add2('Magic Prefix',readbits(s,lastreaded,11),''); add2('Magic Suffix',readbits(s,lastreaded,11),''); end; 05: //Set begin add2('Set ID',readbits(s,lastreaded,12),''); end; 06: //Rare begin add2('RarePrefix',readbits(s,lastreaded,8),''); add2('RareSuffix',readbits(s,lastreaded,8),''); for i:=1 to 3 do begin add2('Prefix '+inttostr(i)+' flag',readbits(s,lastreaded,1),''); if rprop('Prefix '+inttostr(i)+' flag') = '1' then add2('Prefix '+inttostr(i),readbits(s,lastreaded,11),''); add2('Suffix '+inttostr(i)+' flag',readbits(s,lastreaded,1),''); if rprop('Suffix '+inttostr(i)+' flag') = '1' then add2('Suffix '+inttostr(i),readbits(s,lastreaded,11),''); end; end; 07: //Unique begin add2('Unique ID',readbits(s,lastreaded,12),''); if (strbittoint(rprop('Unique ID')) <> 0) and (strbittoint(rprop('Unique ID')) < uniqueitems_txt.count) then begin li1:=UniqueItems_ex_txt.items[strbittoint(rprop('Unique ID'))]; li1:=uniqueitems_txt.find('index',li1.strings[0]); if li1.strings[uniqueitems_txt.findcolumn(0,'invfile')]<>'' then add2('InvFile',li1.strings[uniqueitems_txt.findcolumn(0,'invfile')],''); //get more data about this unique... end; end; end; //fixme: If it is a set item, read in 5 bits to get the number of set bonuses associated with the set. if rprop('isRuneword')='1' then add2('Runeword ID',readbits(s,lastreaded,16),''); if itype = 3 then add2('Defense',readbits(s,lastreaded,11),''); //If the item does not come from the misc item file, read in 8 bits for the base durability. If this is 0, it is indestructible. If it is not 0, read in 8 bits to get the current durability. Bows and throwing items have durability and WILL break if durability becomes 0 (try it out with ethereal javelins if you want). if itype <> 1 then begin //if mpqitem.strings[gitemlist.findcolumn(0,'nodurability')] <> '1' then begin add2('Duravility',readbits(s,lastreaded,8),''); if strbittoint(rprop('Duravility')) <> 0 then begin add2('r Duravility',readbits(s,lastreaded,8),''); add2('Unknow Flag',readbits(s,lastreaded,1),''); end else //item.add.strings[0]:=('Duravility: Indestructible'); end; end; // add2('Unknow Flag',readbits(s,lastreaded,1),''); // If it is stackable (from mpq file (*)): if (mpqitem.strings[gitemlist.findcolumn(0,'stackable')] = '1') then begin //fixme: If it is useable (from mpq file) (*), read in 5 bits (I didn't check the value to find out what it might be) //add2('Stack ',readbits(s,lastreaded,5),''); add2('Stack ',readbits(s,lastreaded,9),''); end; //If it is socketed, read 4 bits for the number of used sockets if rprop('isSocketed') = '1' then begin add2('Sockets Amount',readbits(s,lastreaded,4),''); end; if rprop('isInscribed')='1' then add2('Inscribed Name',readbits(s,lastreaded,15),''); //runewords must skip first break j:=0; if rprop('isRuneword')='1' then j:=1; if checkmods(lastreaded) then begin add2('Checkmods '+inttostr(lastreaded),booltostr(checkmods(lastreaded),true),''); addmods(lastreaded); end; if checkmods(lastreaded-1) then begin add2('Checkmods '+inttostr(lastreaded-1),booltostr(checkmods(lastreaded-1),true),''); addmods(lastreaded-1); end; if (strbittoint(rprop('Quality'))<>0) and (strbittoint(rprop('Quality'))<>2) and (high(item2)<0) then begin if length(s)-icodeat < 200 then k:=length(s)-icodeat else k:=200; for j:=icodeat to icodeat+k do begin if checkmods(j) then addmods(j); end; end; if (strbittoint(rprop('Quality'))<>0) and (strbittoint(rprop('Quality'))<>2) and (high(item2)<=0) then begin { assignfile(tfile,'logs\failed.txt'); if fileexists('logs\failed.txt') then append(tfile) else rewrite(tfile); writeln(tfile,s); for i:=0 to itemread.count-1 do begin write(tfile,itemread.items[i].strings[0]+' '); write(tfile,itemread.items[i].strings[1]+' '); write(tfile,inttostr(strbittoint(itemread.items[i].strings[1]))+' '); write(tfile,inttohex(strbittoint(itemread.items[i].strings[1]),4)+' '); writeln(tfile,strbittostr(itemread.items[i].strings[1],8)+' '); end; closefile(tfile); } end; { assignfile(tfile,'logs\failed.txt'); if fileexists('logs\failed.txt') then append(tfile) else rewrite(tfile); writeln(tfile,s); for i:=0 to itemread.count-1 do begin write(tfile,itemread.items[i].strings[0]+' '); write(tfile,itemread.items[i].strings[1]+' '); write(tfile,inttostr(strbittoint(itemread.items[i].strings[1]))+' '); write(tfile,inttohex(strbittoint(itemread.items[i].strings[1]),4)+' '); writeln(tfile,strbittostr(itemread.items[i].strings[1],8)+' '); end; closefile(tfile); } make_name(); if strbittoint(rprop('Action'))=$06 then begin if (strbittoint(rprop('Duravility')) <> 0) and (strbittoint(rprop('r Duravility')) = 0) then bots[vlink].setvar('broken_body','1'); // memo1.lines.add('body item '+rprop('Item Name')+' '+inttostr(strbittoint(rprop('Duravility')))+' '+inttostr(strbittoint(rprop('r Duravility')))); end; case strbittoint(rprop('Action')) of //FLOOR ITEM $00, $02, $03: begin end; //Stash item $04, $0D, $0F, $010, $015: begin if high(item2) > -1 then begin m1:=high(item2[0])+1; setlength(gstats,m1); for i:=0 to high(item2[0]) do begin gstats[i].statid:=item2[0][i].itemstat; gstats[i].stat:=item2[0][i].paramint; gstats[i].stat_add:=item2[0][i].addparamint; end; end; bots[vlink].inv_add( strbittostr(rprop('Item Code'),8), rprop('InvFile'), strtoint('0'+mpqitem.strings[gitemlist.findcolumn(0,'invwidth')]), strtoint('0'+mpqitem.strings[gitemlist.findcolumn(0,'invheight')]), strbittoint(rprop('LocalX')), strbittoint(rprop('LocalY')), strbittoint(rprop('Action')), strbittoint(rprop('Position')), strbittoint(rprop('Image')), strbittoint(rprop('Item ID')), rprop('Item Name'), gstats); case strbittoint(rprop('Position')) of 10:begin end; 2:begin iwidth:=strtoint('0'+mpqitem.strings[gitemlist.findcolumn(0,'invwidth')]); iheight:=strtoint('0'+mpqitem.strings[gitemlist.findcolumn(0,'invheight')]); for i:=0 to iwidth-1 do for j:=0 to iheight-1 do bots[vlink].back[strbittoint(rprop('LocalX'))+i,strbittoint(rprop('LocalY'))+j]:=strbittoint(rprop('Item ID')); if (zstring(strbittostr(rprop('Item Code'),8),1)='rvl') or (zstring(strbittostr(rprop('Item Code'),8),1)='mp4') or (zstring(strbittostr(rprop('Item Code'),8),1)='mp5') then begin //... end; end; //case 2 end end; //case strbittoint(itemdecoded[29]) position in body end; // case $04, $0D, $0F, $010, $015 stash item $05:begin // unestash item for i:=0 to high(bots[vlink].back) do for j:=0 to high(bots[vlink].back[i]) do if strbittoint(rprop('Item ID')) = bots[vlink].back[i,j] then bots[vlink].back[i,j]:=0; end; $0E: // belt item begin end; //body item add/del/switch $06, $08, $09: begin end; $0b:begin end; else begin exit; end; end; ///////////// bothing ////////////// if strbittoint(rprop('Action'))=$15 then if strbittoint(rprop('isIdentified'))=1 then begin itemmustbesaved:=false; { tlist:=tvirtuallist.create(1); for i:=1 to actionsqueue.count-1 do tlist.add.strings[0]:=actionsqueue.items[i].strings[0]; for i:=1 to actionsqueue.count-1 do actionsqueue.delete(1); } case strbittoint(rprop('Quality')) of 0: //crafted begin itemmustbesaved:=true; end; 01: //inferior begin itemmustbesaved:=true; end; 02: //Normal begin itemmustbesaved:=true; end; 03: //Superior begin itemmustbesaved:=true; end; 04: //Magic begin li1:=Saved_MagicPrefix.items[strbittoint(rprop('Magic Prefix'))+1]; k:=0; for j:=1 to 7 do if li1.strings[saved_magicprefix.findcolumn(0,'itype'+inttostr(j))] = mpqitem.strings[gitemlist.findcolumn(0,'type')] then k:=1; if (k = 1) and (li1.strings[saved_magicprefix.findcolumn(0,'Save')] = '1') then begin itemmustbesaved:=true; end; li1:=Saved_MagicSuffix.items[strbittoint(rprop('Magic Suffix'))+1]; k:=0; for j:=1 to 7 do if li1.strings[saved_MagicSuffix.findcolumn(0,'itype'+inttostr(j))] = mpqitem.strings[gitemlist.findcolumn(0,'type')] then k:=1; if (k = 1) and (li1.strings[saved_MagicSuffix.findcolumn(0,'Save')] = '1') then begin itemmustbesaved:=true; end; end; // case 0x04 ends 5:begin //set items itemmustbesaved:=true; //if set items are collected then.... end; //case 0x05 ends 7:begin // unique items itemmustbesaved:=true; if (strbittoint(rprop('Unique ID')) <> 0) and (strbittoint(rprop('Unique ID')) < uniqueitems_txt.count) then begin li:=UniqueItems_ex_txt.items[strbittoint(rprop('Unique ID'))]; li:=uniqueitems_autodrop.find('index',li.strings[0]); if li.strings[UniqueItems_autodrop.findcolumn(0,'Drop')] = '1' then begin itemmustbesaved:=false; end; end; end; end; // end of case checksave(); s:=mpqitem.strings[0]; case strbittoint(rprop('Quality')) of 0: //crafted begin end; 01: //inferior begin end; 02: //Normal begin end; 03: //Superior begin s:='Superior '+s+''; end; 04: //Magic begin if (strbittoint(rprop('Magic Prefix')) <> 0) and (strbittoint(rprop('Magic Prefix')) < magicprefix.count) then begin li:=magicprefix.items[strbittoint(rprop('Magic Prefix'))+1]; prefix:=li.strings[0]+' '; end; if (strbittoint(rprop('Magic Suffix')) <> 0) and (strbittoint(rprop('Magic Suffix')) < magicsuffix.count) then begin li:=magicsuffix.items[strbittoint(rprop('Magic Suffix'))+1]; sufix:=' '+li.strings[0]; end; s:='Magic '+prefix+' '+s+' '+sufix+' ('+inttostr(strbittoint(rprop('Magic Prefix')))+','+inttostr(strbittoint(rprop('Magic Suffix')))+')'; end; 05: //Set begin s:='Set '+s+''; end; 06: //Rare begin s:='Rare '+s+''; end; 07: //Unique begin if (strbittoint(rprop('Unique ID')) <> 0) and (strbittoint(rprop('Unique ID')) < uniqueitems_txt.count) then begin li:=UniqueItems_ex_txt.items[strbittoint(rprop('Unique ID'))]; li:=uniqueitems_txt.find('index',li.strings[0]); prefix:=li.strings[0]+' '; end; s:='Unique '+prefix+' ('+s+') '; end; end; if itemmustbesaved = false then begin assignfile(tfile,'logs\dropeds.txt'); if fileexists('logs\dropeds.txt') then append(tfile) else rewrite(tfile); writeln(tfile,s); if strbittoint(rprop('Quality')) =6 then if high(item2)>=0 then begin s:=inttohex(cbuf[0],2); for i:=1 to dlen-1 do s:=s+' '+inttohex(cbuf[i],2); writeln(tfile,'packet: '+s); for i:=0 to high(item2) do begin writeln(tfile,'----- mods -----'); for j:=0 to high(item2[i]) do writeln(tfile,inttostr(item2[i][j].itemstat)+' '+item2[i][j].param); end; end; closefile(tfile); if bots[vlink].getvar('sell_garbage') = 'true' then begin bots[vlink].interruptsqueue.add.strings[0]:='setvar last_picked_id '+inttohex(strbittoint(rprop('Item ID')),8); bots[vlink].interruptsqueue.add.strings[0]:='pick_to_cursor '+inttohex(strbittoint(rprop('Item ID')),8); bots[vlink].interruptsqueue.add.strings[0]:='sell_item last_picked_id'; bots[vlink].interruptsqueue.add.strings[0]:='delay 250'; end else begin bots[vlink].interruptsqueue.add.strings[0]:='setvar last_picked_id '+inttohex(strbittoint(rprop('Item ID')),8); bots[vlink].interruptsqueue.add.strings[0]:='pick_to_cursor '+inttohex(strbittoint(rprop('Item ID')),8); bots[vlink].interruptsqueue.add.strings[0]:='item_at_cursor_to_floor last_picked_id'; bots[vlink].interruptsqueue.add.strings[0]:='delay 250'; end; end else begin memo1.lines.add('item must be saved: '+s); if strbittoint(rprop('Position')) = 2 then dxwavelist1.Items.Find('ICEQuery.wav').Play(false); end; { for i:=0 to tlist.count-1 do actionsqueue.add.strings[0]:=tlist.items[i].strings[0]; tlist.destroy; } end; //pickit s:=rprop('Action'); case strbittoint(s) of 0, 2, 3:begin s:=zstring(strbittostr(rprop('Item Code'),8),1); j:=gitemlist.findcolumn(0,'type'); for i:=0 to pickup_txt.count - 1 do begin li2:=pickup_txt.items[i]; if ((pickup_txt.items[i].strings[1]=s) and (pickup_txt.items[i].strings[1]<>'')) or ((li2.strings[4] = mpqitem.strings[j]) and (li2.strings[4] <> '')) then begin k:=1; //quality if (li2.strings[5] <> '') and (decquality(li2.strings[5]) <> strbittoint(rprop('Quality'))) then k:=0; //ethereal if (strtoint('$0'+li2.strings[8]) <> strbittoint(rprop('isEthereal'))) then k:=0; //identified if (strtoint('$0'+li2.strings[3]) <> strbittoint(rprop('isIdentified'))) then k:=0; //socketed items if ((li2.strings[7] <> '') and (strtoint('$0'+li2.strings[7]) <> strbittoint(rprop('Sockets Amount')))) then k:=0; if k = 1 then begin if strtoint('0'+li2.strings[2]) <> 0 then begin assignfile(tfile,'logs\itemslog.txt'); if fileexists('logs\itemslog.txt') then append(tfile) else rewrite(tfile); writeln(tfile,pickup_txt.items[i].strings[0]); closefile(tfile); memo1.lines.add(li2.strings[0]); end; s:=rprop('Item ID'); k:=strbittoint(s); if bots[vlink].getvar('instant_pick') = 'true' then begin bots[vlink].run_command('telehackt to location '+inttohex(strbittoint(rprop('LocalX')),4)+' '+inttohex(strbittoint(rprop('LocalY')),4)); bots[vlink].run_command('pick id '+inttohex(k,8)); end else begin bots[vlink].interruptsqueue.add.strings[0]:='walk to location '+inttohex(strbittoint(rprop('LocalX')),4)+' '+inttohex(strbittoint(rprop('LocalY')),4); bots[vlink].interruptsqueue.add.strings[0]:='pick id '+inttohex(k,8); end; break; end; end; end; end; end; if (itemslist.find(0,inttohex(strbittoint(rprop('Item ID')),8)) = nil) then if (bots[vlink].ig_currentstatus <> 5) and (bots[vlink].ig_currentstatus <> 6) and (strbittoint(rprop('Action')) <> 11) then begin if bots[vlink].winpointer2 <>nil then gt:=bots[vlink].winpointer2.treeview1 else gt:=treeview1; graphitem(gt); end; s:=rprop('Action'); if (strbittoint(s) = 11) then begin if (strbittoint(rprop('Magic Prefix')) <> 0) and (strbittoint(rprop('Magic Prefix')) < magicprefix.count) then begin li:=magicprefix.items[strbittoint(rprop('Magic Prefix'))+1]; prefix:=li.strings[0]+' '; end; if (strbittoint(rprop('Magic Suffix')) <> 0) and (strbittoint(rprop('Magic Suffix')) < magicsuffix.count) then begin li:=magicsuffix.items[strbittoint(rprop('Magic Suffix'))+1]; sufix:=' '+li.strings[0]; end; assignfile(tfile,'logs\itemslog.txt'); if fileexists('logs\itemslog.txt') then append(tfile) else rewrite(tfile); writeln(tfile, inttohex(strbittoint(rprop('Item ID')),4)+' '+ prefix+ mpqitem.strings[0]+ sufix+' ('+inttostr(strbittoint(rprop('Magic Prefix')))+','+inttostr(strbittoint(rprop('Magic Suffix')))+')'); closefile(tfile); inc(seenitems); label15.caption:='items seen: '+inttostr(seenitems); // if zstring(strbittostr(rprop('Item Code'),8),1) = edit9.Text then for j:=0 to listbox1.Items.Count-1 do begin stringstack[0]:=listbox1.items.strings[j]; stringstack[1]:=zstring(stringstack[0],1); stringstack[2]:=zstring(stringstack[0],2); val(stringstack[1],i,rcode); if (rcode=0) and (strbittoint(rprop('Magic Prefix')) = i) then begin val(stringstack[2],i,rcode); if (stringstack[2] = '*') or ((rcode=0) and (strbittoint(rprop('Magic Suffix')) = i)) then begin { memo4.Clear; for i:=0 to item.count-1 do memo4.Lines.Add(item.items[i].strings[0]); } dec_ig_actionsstack(vlink,bots[vlink].actionsqueue.count); dxwavelist1.Items.Find('ICEQuery.wav').Play(false); end; end; end; end; if bots[vlink].ig_currentstatus = $F1 then begin if ((strbittoint(rprop('Item ID')) = strtoint('$0'+bots[vlink].paramstack[0]))) and (strbittoint(rprop('Action')) = 05) then begin assignfile(tfile,'logs\study1.txt'); if fileexists('logs\study1.txt') then append(tfile) else rewrite(tfile); writeln(tfile,pickup_txt.items[i].strings[0]); closefile(tfile); end; if (strbittoint(rprop('Action')) = 05) then begin //item to cursor bots[vlink].queue_step(1); end; end; if (strbittoint(rprop('Action')) = 08) then if bots[vlink].ig_currentstatus = $F6 then bots[vlink].queue_step(1); if (strbittoint(rprop('Action')) = 02) then if bots[vlink].ig_currentstatus = $Fc then if (strbittoint(rprop('Item ID')) = strtoint('$0'+bots[vlink].paramstack[0])) then bots[vlink].queue_step(1); if (strbittoint(rprop('Action')) = 04) then begin //item to cursor if bots[vlink].ig_currentstatus = $F3 then bots[vlink].queue_step(1); //do_cube if bots[vlink].ig_currentstatus = $F4 then begin bots[vlink].ig_lastcubed:=strbittoint(rprop('Item ID')); bots[vlink].queue_step(1); end; end; if (strbittoint(rprop('Action')) = 11) then begin //do_cube if bots[vlink].ig_currentstatus = $F4 then bots[vlink].queue_step(1); if (bots[vlink].ig_currentstatus = 5) or (bots[vlink].ig_currentstatus = 6) then begin //is in cube if (strbittoint(rprop('Quality')) = 7) then begin //is unique dwordstack[0]:=strbittoint(rprop('Item ID')); bots[vlink].ig_currentstatus:=9; bots[vlink].ig_state_9_p[1]:=dwordstack[0]; d2g_sendpacket_0x19(socket,dwordstack[0]); d2g_sendpacket_0x4f(socket, $17, $00); dxwavelist1.Items.find('Beep.wav').Play(false); end; if (strbittoint(rprop('Quality')) = 4) then begin //is magic if (bots[vlink].ig_currentstatus = 5) then begin keep1:=false; keep2:=false; for i:=0 to high(bots[vlink].ig_findprefix) do if (bots[vlink].ig_findprefix[i] = strbittoint(rprop('Magic Prefix'))) then keep1:=true; for i:=0 to high(bots[vlink].ig_findsufix) do if (bots[vlink].ig_findsufix[i] = strbittoint(rprop('Magic Suffix'))) then keep2:=true; if mods[7] <> 50 then keep2:=false; if keep1 and keep2= false then d2g_sendpacket_0x4f(socket,$18,$00) else begin dwordstack[0]:=strbittoint(rprop('Item ID')); bots[vlink].ig_currentstatus:=9; bots[vlink].ig_state_9_p[1]:=dwordstack[0]; d2g_sendpacket_0x19(socket,dwordstack[0]); d2g_sendpacket_0x4f(socket, $17, $00); dxwavelist1.Items.find('Beep.wav').Play(false); end; end; if bots[vlink].ig_currentstatus = 6 then begin li1:=itemslist.find(0,'box'); if li1<>nil then dwordstack[3]:=strtoint('$'+li1.strings[1]); li1:=playerslist.Find(0,inttohex(bots[vlink].ig_id,8)); if li1 <> nil then begin wordstack[0]:=strtoint('$'+zfield(li1.Strings[3],',',1,false)); wordstack[1]:=strtoint('$'+zfield(li1.Strings[3],',',2,false)); end; d2g_sendpacket_0x20(socket, dwordstack[3], wordstack[0], wordstack[1]); bots[vlink].ig_currentstatus:=7; // d2g_sendpacket_0x4F(socket, $18, $00); // bots[vlink].ig_currentstatus:=5; //rerolling for a prefix end; end; //is magic end end; //status is 4 or 5 end; //is in cube end if li1:=itemslist.find(1,inttohex(strbittoint(rprop('Item ID')),8)); if (li1 = nil) then li1:=itemslist.add; li1.strings[0]:=zstring(strbittostr(rprop('Item Code'),8),1); // code li1.strings[1]:=inttohex(strbittoint(rprop('Item ID')),8); // item id li1.strings[2]:=inttohex(strbittoint(rprop('Position')),2); // item id li1.strings[4]:=s; li1.strings[5]:=inttohex(strbittoint(rprop('Action')),2); // action li1.strings[6]:=inttohex(strbittoint(rprop('isIdentified')),2); //identified li1.strings[7]:=inttohex(strbittoint(rprop('Quality')),2); //quality li1.strings[8]:=mpqitem.strings[gitemlist.findcolumn(0,'type')]; //quality //9 is used ^^ li1.strings[10]:=savetitle; case strbittoint(rprop('Quality')) of 0: //crafted begin end; 01: //inferior begin end; 02: //Normal begin end; 03: //Superior begin end; 04: //Magic begin li1.strings[9]:=inttohex(strbittoint(rprop('Magic Prefix')),4)+' '+inttohex(strbittoint(rprop('Magic Suffix')),4); end; 05: //Set begin end; 06: //Rare begin end; 07: //Unique begin li1.strings[9]:=inttohex(strbittoint(rprop('Unique ID')),4); end; end; setlength(item2,0); end; [/code] | February 9, 2007, 12:46 PM |
E.T. | [quote author=ShadowDancer link=topic=15398.msg164401#msg164401 date=1171025191] excuse my rooughness :( i only tryed to say that it was obsolete compared with the one posted by ringo. [/quote] The stuff from EoN may be obsolete compared to the one by Ringo, but the code I posted is my own and I still think it's a better way to parse it, and is not obsolete at all... [quote author=ShadowDancer link=topic=15398.msg164401#msg164401 date=1171025191] anymode this thead is too old... Posted on: July 14, 2006, 09:53 AM [/quote] Well it's old, but then again most references / packet disscusions threads start in 2005 and still contain useful information... gotta work from what we have. I'll take a look at your code later... I don't know Delphi and the code looks a bit messy, but I should be able to make some sense of it... I'll post mine later too. | February 9, 2007, 3:17 PM |
Ringo | [quote] Exit Sub <<< that is a problem [/quote] Why? :) Its been awhile, and I have made so many d2 bots todate, so im not sure what project the code I posted before came from, but the first item location parser I came to seems more compleat: [code] Select Case ItemEvent Case &H0, &H2, &H3 'FLOOR ITEM Position = Reader.ReadAsByte(3) LocalX = Reader.ReadAsInteger(16) LocalY = Reader.ReadAsInteger(16) Case &H4, &H5, &HD, &HB, &HC 'Stash item/NPC Item add-rem UnKnBin(0) = Reader.ReadAsBinary(2) 'unknown ItemToMouse = Reader.ReadAsByte(1) 'boolean, the item's destination is to mouse UnKnBin(1) = Reader.ReadAsBinary(4) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(3) Position = Reader.ReadAsByte(4) Case &HE, &HF, &H10, &H15 'Belt item add/del/switch/swap UnKnBin(0) = Reader.ReadAsBinary(2) 'unknown ItemToMouse = Reader.ReadAsByte(1) 'boolean, the item's destination is to mouse UnKnBin(1) = Reader.ReadAsBinary(4) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(3) Position = Reader.ReadAsByte(4) Case &H6, &H8, &H9, &H17 'body item add/del/switch/swap Position = Reader.ReadAsByte(3) UnKnBin(0) = Reader.ReadAsBinary(3) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(4) UnKnBin(1) = Reader.ReadAsBinary(4) Case &H1, &H12 'ground item to buffer/in buffer on join Position = Reader.ReadAsByte(4) LocalX = Reader.ReadAsByte(4) 'null LocalY = Reader.ReadAsByte(4) 'null UnKnBin(0) = Reader.ReadAsBinary(6) 'unknown (null) Case &H13 'item in a socket Position = Reader.ReadAsByte(4) UnKnBin(0) = Reader.ReadAsBinary(3) LocalX = Reader.ReadAsByte(4) LocalY = Reader.ReadAsByte(4) UnKnBin(1) = Reader.ReadAsBinary(3) Case Else UnKnBin(0) = Reader.ReadAsBinary(200) ParseItemLocation = False Exit Function End Select ParseItemLocation = True [/code] | February 9, 2007, 4:49 PM |
ShadowDancer | [QUOTE=Ringo]Why? :)[/QUOTE] B'coz i don't just pick the items. I know that nobody will read that code, it was a joke... I will document it later. ;D Shadow Dancer.- | February 9, 2007, 8:04 PM |
Ringo | [quote author=ShadowDancer link=topic=15398.msg164412#msg164412 date=1171051488] [QUOTE=Ringo]Why? :)[/QUOTE] B'coz i don't just pick the items. [/quote] Well, I posted it for the item loction bitfield format. But even so, its still a good idea to stop the parseing from continueing on unresearched/unsupported events, so you can analyze the data. :P | February 9, 2007, 8:35 PM |
ShadowDancer | [quote author=Ringo link=topic=15398.msg164414#msg164414 date=1171053344] [quote author=ShadowDancer link=topic=15398.msg164412#msg164412 date=1171051488] [QUOTE=Ringo]Why? :)[/QUOTE] B'coz i don't just pick the items. [/quote] Well, I posted it for the item loction bitfield format. But even so, its still a good idea to stop the parseing from continueing on unresearched/unsupported events, so you can analyze the data. :P [/quote] Yes, and is better if you save the code to a file. (?) xD My bot haven't seen the 0x16 action, do you know what is it for? | February 9, 2007, 10:20 PM |
E.T. | Haven't seen 0x16 or 0x14 either... I posted my completed ref in packet discussion forum since you said this thread was too old ^^ I'll update with a better version of bitfield values later... | February 13, 2007, 12:18 AM |