Skip to content

Instantly share code, notes, and snippets.

@Zoxc
Created June 8, 2011 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Zoxc/1014340 to your computer and use it in GitHub Desktop.
Save Zoxc/1014340 to your computer and use it in GitHub Desktop.
unit BitClass;
interface
uses SysUtils;
type
Bit = 0..7;
BitByte = set of Bit;
TBitArray = packed array of BitByte;
TBitClass = class
private
FArraySize:Integer;
public
Position:Integer;
Memory:PChar;
Size : Integer;
procedure ToData(var Data; const bitLen:Cardinal; const Pos:Cardinal); overload;
procedure ToData(var Data; const bitLen:Cardinal); overload;
procedure DirectData(var Data; const byteLength, byteIndex:Cardinal);
function IsSet(const Pos:Cardinal):boolean;
procedure SetBit(const Pos:Cardinal);
procedure ClearBit(const Pos:Cardinal);
constructor Create(const Data); overload;
constructor Create(const bitLength:Cardinal); overload;
procedure AssignData(const Data); overload;
procedure AssignData(const Data; const BytePos, Length:Cardinal); overload;
procedure AssignBitData(const Data; const BitPos, BitLength:Cardinal);
destructor Destroy; override;
end;
implementation
procedure TBitClass.DirectData(var Data; const byteLength, byteIndex:Cardinal);
begin
Move(Pointer(Cardinal(Memory)+byteIndex)^, Data, byteLength);
end;
procedure TBitClass.ToData(var Data; const bitLen:Cardinal; const Pos:Cardinal);
var i:cardinal;
ByteIndex, bytelen:cardinal;
Mask: Bit;
OutData:TBitArray;
begin
bytelen := bitLen shr 3;
if (bitLen and 7) > 0 then
Inc(bytelen);
SetLength(OutData, byteLen);
FillChar(OutData[0], byteLen, 0);
for i := 0 to bitLen - 1 do
if IsSet(i+pos) then
begin
ByteIndex := i shr 3;
Mask := (i-(ByteIndex*8));
OutData[ByteIndex] := OutData[ByteIndex] + [Mask];
end;
Move(OutData[0], Data, byteLen);
end;
procedure TBitClass.ToData(var Data; const bitLen:Cardinal);
begin
ToData(Data, bitLen, Position);
Inc(Position, bitLen);
end;
destructor TBitClass.Destroy;
begin
FreeMem(Memory);
inherited;
end;
constructor TBitClass.Create(const Data);
begin
inherited Create;
Position := 0;
Memory := @Data;
end;
constructor TBitClass.Create(const bitLength:Cardinal);
begin
inherited Create;
Size := bitLength;
Position := 0;
FArraySize := bitLength shr 3;
if (bitLength and 7) > 0 then
Inc(FArraySize);
GetMem(Memory, FArraySize);
FillChar(Memory[0], FArraySize, 0);
end;
procedure TBitClass.AssignData(const Data);
begin
Move(Data, Memory[0], FArraySize);
end;
procedure TBitClass.AssignData(const Data; const BytePos, Length:Cardinal);
begin
Move(Data, Memory[BytePos], Length);
end;
procedure TBitClass.AssignBitData(const Data; const BitPos, BitLength:Cardinal);
var i, ASize:Cardinal;
InData:TBitArray;
begin
ASize := bitLength shr 3;
if (bitLength and 7) > 0 then
Inc(ASize);
SetLength(InData, ASize);
Move(Data, InData[0], ASize);
for i := 0 to BitLength do
begin
if (i and 7) in BitByte(Memory[i shr 3]) then
SetBit(BitPos+i)
else
ClearBit(BitPos+i);
end;
end;
procedure TBitClass.ClearBit(const Pos:Cardinal);
var
ByteIndex:cardinal;
begin
ByteIndex := Pos shr 3;
Byte(Memory[ByteIndex]) := Byte(Memory[ByteIndex]) xor (Pos and 7);
end;
procedure TBitClass.SetBit(const Pos:Cardinal);
var
ByteIndex:cardinal;
begin
ByteIndex := Pos shr 3;
BitByte(Memory[ByteIndex]) := BitByte(Memory[ByteIndex]) + [Pos and 7];
end;
function TBitClass.IsSet(const Pos:Cardinal):boolean;
begin
Result := (Pos and 7) in BitByte(Memory[Pos shr 3]);
end;
end.
unit ParseItems;
interface
uses Windows, SysUtils, BitClass, Classes, DiabloPackets;
const
dtArmor = 2;
dtWeapon = 1;
dtMisc = 0;
type
TItemFlag = (ifEquipped, ifUNKNOWN01, ifUNKNOWN02, ifInSocket,
ifIdentified, ifUNKNOWN03, ifSwitchedIn, ifSwitchedOut, ifBroken,
ifUNKNOWN04, ifPotion, ifSocketed, ifUNKNOWN05, ifInStore, ifNotInSocket,
ifUNKNOWN06, ifEar, ifStartItem, ifUNKNOWN07, ifUNKNOWN08, ifUNKNOWN09,
ifSimpleItem, ifEthereal, ifAny, ifPersonalized, ifGamble, ifRuneword,
ifUNKNOWN10, ifUNKNOWN11, ifUNKNOWN12, ifUNKNOWN13, ifUNKNOWN14);
TItemFlags = set of TItemFlag;
const
rwEnigma = 20539;
type
PItemData = ^TItemData;
TItemData = packed record
Name, Code, ItemType:String;
From:Byte;
Diff:Byte;
end;
TItemQuality = (itNone, itInferior, itNormal, itSuperior, itMagic, itSet, itRare, itUnique, itCrafted);
PExtendedItem = ^TExtendedItem;
TExtendedItem = packed record
DropLevel:Word;
Quality:TItemQuality;
UniqueName:String;
Personalized: string;
Runeword: string;
Defense, Dur, MaxDur:Word;
SocketCount:Byte;
RunewordID:Word;
MagicSuffix, MagicSuffixData:Word;
end;
PEarStruct = ^TEarStruct;
TEarStruct = packed record
CharacterClass: TCharacterClass;
Character: string;
Level:Byte;
end;
PItemStruct = ^TItemStruct;
TItemStruct = packed record
PacketId:Byte;
Action: TItemActionType;
MessageSize:BYTE;
OwnerType, OwnerID:DWORD;
ItemType:BYTE;
ItemID:DWORD;
GemsInserted:Byte;
EquipmentLocation, GridX, GridY, Container:Byte;
Flags: TItemFlags;
VersionField:Byte;
Location:BYTE;
PositionX:WORD;
PositionY:WORD;
ItemCode: string;
EarStruct:PEarStruct;
// gold specific
GoldSize:Boolean;
GoldAmount:DWORD;
Extended: PExtendedItem;
ItemData: PItemData;
end;
function ParseItemData(Data:PChar; Size:Cardinal):PItemStruct;
procedure FreeItemData(Data: PItemStruct);
function GetItemName(Item:PItemStruct):String;
implementation
uses uItemTypes, uPickupItems;
procedure FreeItemData(Data: PItemStruct);
begin
if Data.Extended <> nil then
Dispose(Data.Extended);
if Data.EarStruct <> nil then
Dispose(Data.EarStruct);
Dispose(Data);
end;
function GetItemName(Item:PItemStruct):String;
begin
Result := '';
if not (ifSimpleItem in Item.Flags) then
begin
if Item.ItemCode = 'std' then
begin
Result := 'Standard of Heroes';
Exit;
end;
if Item.Extended.Quality = itInferior then
Result := 'Cracked ';
if ifIdentified in Item.Flags then
if (Item.Extended.Quality = itUnique) or (Item.Extended.Quality = itSet) then
Result := Item.Extended.UniqueName+' ';
if Item.Extended.Quality = itSuperior then
Result := 'Superior ';
end;
if ifEar in Item.Flags then
begin
Result := Item.EarStruct.Character+ '''s Ear';
end
else
Result := Result + Item.ItemData.Name;
end;
function ParseItemData(Data:PChar; Size:Cardinal):PItemStruct;
var Bits: TBitClass;
Temp:Boolean;
Index:Word;
Offset:Cardinal;
C:Char;
IsDropItem:Boolean;
begin
New(Result);
FillChar(Result^, SizeOf(TItemStruct), 0);
try
Result.PacketId := Byte((@Data[0])^);
Result.Action := TItemActionType((@Data[1])^);
Result.MessageSize := Byte((@Data[2])^);
Result.ItemType := Byte((@Data[3])^);
Result.ItemID := Cardinal((@Data[4])^);
IsDropItem := (Result.Action = iatAddToGround) or
(Result.Action = iatDropToGround) or
(Result.Action = iatOnGround);
if Result.PacketId = $9d then
begin
Result.OwnerType := Byte((@Data[8])^);
Result.OwnerID := Cardinal((@Data[9])^);
Offset := 13;
end
else Offset := 8;
Result.Flags := TItemFlags((@Data[Offset])^);
Inc(Offset, 4);
if ifStartItem in Result.Flags then
Result.Flags := Result.Flags - [ifEar];
// Bits:= TBitClass.Create(Data[10]);
Bits:= TBitClass.Create((Size-Offset)*8);
Bits.AssignData(Data[Offset]);
Bits.ToData(Result.VersionField, 8);
Inc(Bits.Position, 2);
Bits.ToData(Result.Location, 3);
if IsDropItem then
begin
Bits.ToData(Result.PositionX, 16);
Bits.ToData(Result.PositionY, 16);
end
else
begin
Bits.ToData(Result.EquipmentLocation, 4);
Bits.ToData(Result.GridX, 4);
Bits.ToData(Result.GridY, 3);
Bits.ToData(Result.Container, 4);
end;
if ifEar in Result.Flags then
begin
New(Result.EarStruct);
FillChar(Result.EarStruct^, SizeOf(TEarStruct), 0);
Bits.ToData(Result.EarStruct.CharacterClass, 3);
Bits.ToData(Result.EarStruct.Level, 7);
Result.EarStruct.Character := '';
Bits.ToData(C, 7);
while C <> #0 do
begin
Result.EarStruct.Character := Result.EarStruct.Character + C;
Bits.ToData(C, 7);
end;
Exit;
end;
SetLength(Result.ItemCode, 4);
Bits.ToData(Result.ItemCode[1], 8);
Bits.ToData(Result.ItemCode[2], 8);
Bits.ToData(Result.ItemCode[3], 8);
Bits.ToData(Result.ItemCode[4], 8);
Result.ItemCode := Trim(Result.ItemCode);
Result.ItemData := FindData(PChar(Result.ItemCode));
if Result.ItemCode[3] = ' ' then
Result.ItemCode[3] := #0
else
Result.ItemCode[4] := #0;
// For Gold only
if Result.ItemCode = 'gld' then
begin
Bits.ToData(Result.GoldSize, 1);
if Result.GoldSize then
Bits.ToData(Result.GoldAmount, 32)
else
Bits.ToData(Result.GoldAmount, 12);
Exit;
end;
Bits.ToData(Result.GemsInserted, 3);
if ifGamble in Result.Flags then
Result.Flags := Result.Flags + [ifSimpleItem];
if ifSimpleItem in Result.Flags then
Exit;
New(Result.Extended);
FillChar(Result.Extended^, SizeOf(TExtendedItem), 0);
{ if not IsDropItem then
Inc(Bits.Position, 8); }
Bits.ToData(Result.Extended.DropLevel, 7);
Bits.ToData(Result.Extended.Quality, 4);
Bits.ToData(Temp, 1);
if Temp then
Inc(Bits.Position, 3);
Bits.ToData(Temp, 1);
if Temp then
Inc(Bits.Position, 11);
if ifIdentified in Result.Flags then
begin
case Result.Extended.Quality of
itInferior: Inc(Bits.Position, 3);
itSuperior: Inc(Bits.Position, 3);
itMagic:
begin
Inc(Bits.Position, 11); //Prefix
Bits.ToData(Result.Extended.MagicSuffix, 11); //Suffix
end;
itRare, itCrafted:
begin
Inc(Bits.Position, 8);
Inc(Bits.Position, 8);
for Index := 0 to 2 do
begin
Bits.ToData(Temp, 1);
if Temp then
Inc(Bits.Position, 11);
end;
end;
itSet:
begin
Index := 0;
Bits.ToData(Index, 12);
Result.Extended.UniqueName := Sets[Index];
end;
itUnique:
begin
if Result.ItemCode <> 'std' then
begin
Index := 0;
Bits.ToData(Index, 12);
Result.Extended.UniqueName := Uniques[Index];
end;
end;
end;
if ifRuneword in Result.Flags then
Bits.ToData(Result.Extended.RunewordID, 16);
if ifPersonalized in Result.Flags then
begin
Result.Extended.Personalized := '';
Bits.ToData(C, 7);
while C <> #0 do
begin
Result.Extended.Personalized := Result.Extended.Personalized + C;
Bits.ToData(C, 7);
end;
end;
if Result.ItemData.From = dtArmor then
Bits.ToData(Result.Extended.Defense, 11);
if Result.ItemData.From <> dtMisc then
begin
Bits.ToData(Result.Extended.MaxDur, 8);
if Result.Extended.MaxDur > 0 then
begin
Bits.ToData(Result.Extended.Dur, 8);
Inc(Bits.Position, 1);
end;
end;
if ifSocketed in Result.Flags then
Bits.ToData(Result.Extended.SocketCount, 4);
end;
except on E:Exception do
begin
raise Exception.Create('Error reading item. Message: '+E.Message);
end;
end;
Bits.Free;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment