Created
June 8, 2011 12:43
-
-
Save Zoxc/1014340 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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