It comes from the first good discusion in edgeofnowhere about d2 hacking:
//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
You forgot an important part
// 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
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
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
ahhhhh you are RaMz? :D cool
I allways merge the info from long theads like it for my ref library :P
Excellent. I think they banned herzog from here though over some stupid C++ discussion. Not sure though...
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:
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
If you still need this, here's how I do it (this comes right after the version byte):
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);
}
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,
}
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
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:
Container = 0,
Equipment = 1,
Belt = 2,
Ground = 3,
Cursor = 4,
Item = 6,
EquipmentLocation:
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,
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.
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:
Equipment = 0x00,
Ground = 0x01,
Inventory = 0x02,
TraderOffer = 0x04,
ForTrade = 0x06,
Cube = 0x08,
Stash = 0x0A,
NPC Buffer:
ArmorTab = 0x02,
ArmorTabBottom = 0x03,
WeaponTab1 = 0x04,
WeaponTab1Bottom = 0x05,
WeaponTab2 = 0x06,
MiscTab = 0x08,
MiscTabBottom = 0x09,
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:
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,
ItemFlag:
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,
ItemQuality:
NotApplicable = 0,
Inferior = 1,
Normal = 2,
Superior = 3,
Magic = 4,
Set = 5,
Rare = 6,
Unique = 7,
Crafted = 8,
Category:
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,
I haven't been able to make much sense of this one...
Any corrections or additional info would be very welcome...
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...
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:
[bold]Sure :D [/bold]
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;
Quote from: ShadowDancer on February 09, 2007, 06:46 AM
excuse my rooughness :( i only tryed to say that it was obsolete compared with the one posted by ringo.
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 from: ShadowDancer on February 09, 2007, 06:46 AM
anymode this thead is too old... Posted on: July 14, 2006, 09:53 AM
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.
Quote
Exit Sub <<< that is a problem
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:
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
Quote from: RingoWhy? :)
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.-
Quote from: ShadowDancer on February 09, 2007, 02:04 PM
Quote from: RingoWhy? :)
B'coz i don't just pick the items.
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 from: Ringo on February 09, 2007, 02:35 PM
Quote from: ShadowDancer on February 09, 2007, 02:04 PM
Quote from: RingoWhy? :)
B'coz i don't just pick the items.
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
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?
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...