Hey all, I was bored on a family holiday, and I discovered a bunch of saved tutorials on my netbook's hd, and the source of a my old half completed one, so I decided to give my object manager a rewrite.
NOTES
It was written in delphi 7, I tried to take advantage of oop like in this tut:
http://www.mmowned.com/forums/world-...e-objects.html
The descriptors etc are largely uncompleted as well as outdated because I only had old info and offsets, and I don't intend to finish the project because I have no gametime and my graphics card just fried (oh joys of life :S). The most important things such as the object arrays, localplayer, guid, most object's x and y position should be working though.
USAGE AND DEVELOPMENT
If you want to use this in your own project you are welcome to, however if you release it please give credit to me, I put this up just in case anyone wants to try learn from it, I personally wouldn't endorse my work, but I have commented it somewhat, and if you are familiar with classes and inheritance in delphi you should be able to follow what it does.
To "Install" the object manager:
- Create and save the .pas files (unit files) by copying the unit code that is down the bottom of this post, into notepad, and saving them as theunitsname.pas eg moduleWoWObjectManager.pas
Add them as components to delphi:
- Go to delphi
- Click the component drop-down menu
- Click install component
- Either install them into an existing package (I did dclusr.dpk, the default) or new package NOTE YOU MUST INSTALL ALL 4 COMPONENTS.
Now you can access the object manager component by adding moduleWoWObjectManager to your uses clause.
To use the object manager:
- With moduleWoWObjectManager in uses, create a new TWoWObjectManager
eg as a global var
Code:
var
ObjMgr: TWoWObjectManager;
- Before use you must run the constructor method so
Code:
objmgr:= TWoWObjectManager.CreateObjMgr(Form1, FindWoWWindow, 250)
where Form1 is the owner of objmgr, findwowwindow holds or returns the hwnd of the wow window, and 250 is the rate you want the object arrays to update at.
- Now, with some luck, ObjMgr.GameObjects will hold all game objects, ObjMgr.PlayerObjects all player objects, etc. They auto update, take a look at the TWoWObjects to see the classes used for the arrays.
Anyway heres the source:
NOTE: o_GTTimer and UInt64Lib weren't created by me (duh)
Code:
unit UInt64Lib;
{
Unsigned 64 bit Integer support for Delphi 6 and Kylix.
Copyright (c) 2002 by DelphiFactory Netherlands BV
This unit provides to routines to convert between strings and unsigned
64 bit integers.
UInt64 range: 0..18446744073709551615
Thanks to J.H.Plantenberg for the assembler part.
For comments mail to:
[email protected]
}
interface
resourcestring
SInvalidUInt64 = '''%s'' is not a valid UInt64 value';
{ The UInt64 type is declared as a strong typed Int64, since both compilers
don't support unsigned 64 bit integers. This way you can at least do some
calculations. }
type
UInt64 = type Int64;
{ StrToUInt64 converts the given string to an unsigned 64 bit integer value.
If the string doesn't contain a valid value, an EConvertError exception is
raised. }
function StrToUInt64(const S: AnsiString): UInt64;
{ UInt64ToStr converts the given value to its decimal string representation. }
function UInt64ToStr(Value: UInt64): string;
implementation
// For speed we are going to use the fact that long strings are
// guaranteed to be null-terminated:
{$R-} // Range checking must be disabled
{$B-} // Do not perform complete boolean expression evaluations
uses
SysUtils;
type
_UInt64 = packed record // Split the 64 bit into 2x32 bit
Lo, Hi : LongWord;
end;
procedure RaiseEConvertError(const S: AnsiString);
begin
// raise an exception explaining the input string was invalid
raise EConvertError.CreateResFmt(@SInvalidUInt64, [S]);
end;
function StrToUInt64(const S: AnsiString): UInt64;
var
I: LongWord;
Dig: Integer;
Digit : LongWord;
Hi,Lo : LongWord;
begin
// check if S is empty (is nil pointer)
if S = '' then
RaiseEConvertError(S);
// start at the first character
I := 1;
// trim leading spaces
while S[I] = ' ' do
Inc(I);
if S[I] = '-' then // check for minus sign
RaiseEConvertError(S);
if S[I] = '+' then // check for plus sign
Inc(I);
// Check for hexidecimal string id: '$' or '0x'
if (S[I] = '$') or ((S[I] = '0') and (Upcase(S[I+1]) = 'X')) then
begin
// trim leading zero (if '0x' hex marker)
if S[I] = '0' then
Inc(I);
// trim hex marker
Inc(I);
// Check if empty
if S[I] = #0 then
RaiseEConvertError(S);
// init loop
Dig := 0;
Result := 0;
// while not end of string
while S[I] <> #0 do
begin
// try character convert
case S[I] of
'0'..'9': Dig := Ord(S[I]) - Ord('0');
'A'..'F': Dig := Ord(S[I]) - (Ord('A') - 10);
'a'..'f': Dig := Ord(S[I]) - (Ord('a') - 10);
else
RaiseEConvertError(S)
end;
// still enough room in result?
if Result shr 60 > 0 then
RaiseEConvertError(S);
// shift converted digit into result
Result := Result shl 4 + Dig;
// next char
Inc(I);
end;
end
else begin // decimal unsigned 64 bit conversion
// check if not empty
if S[I] = #0 then
RaiseEConvertError(S);
Hi := 0;
Lo := 0;
while S[I] <> #0 do
begin
// Extract the digit from the string and convert it ASCII->Byte
Digit := Ord(S[I]) xor Ord('0');
// Some assembler to perform an unsigned 64 bit integer calculation.
// This asm code runs in D6 and Kylix (PIC code).
// HiLo := (HiLo*10)+Digit
asm
push esi // save register
// calculate: Hi * 10;
mov eax, Hi // Load Hi
mov ecx, 10 // multiplier is 10
mul ecx // EDX:EAX := EAX*ECX
or edx, edx // Overflow?
jnz @TooBig // yes -> bye bye
// calculate: Lo * 10
mov esi, eax // save Hi value
mov eax, Lo // load Lo
mul ecx // EDX:EAX := EAX*ECX
// Combine Hi, Lo, and overflow of Lo to form HiLo result
add edx, esi // EDX:EAX := HiLo*10
// HiLo := HiLo + Digit
add eax, Digit // EDX:EAX := HiLo+Digit
adc edx, 0 // check overflow
jc @TooBig // yes -> bye bye
// save HiLo
mov Hi, edx // Hi := EDX
mov Lo, eax // Lo := EAX
jmp @TheEnd // successfull finish
@TooBig:
mov Digit, 666 // something went wrong: invalidate Digit
@TheEnd:
pop esi // restore register
end;
// Check if digit was legal and if the previous calculation was a success
if not (Digit in [0..9]) then
RaiseEConvertError(S);
// proceed to the next digit
Inc(I);
end;
// Return HiLo as an unsigned 64 bit integer
_UInt64(Result).Lo := Lo;
_UInt64(Result).Hi := Hi;
end;
end;
function UInt64ToStr(Value: UInt64): string;
const
BiggestUInt64Str = '18446744073709551615';
MaxBCD = Length(BiggestUInt64Str);
type
TBCD = array[0..MaxBCD-1] of Integer; { Index 0 is highest BCD digit}
procedure AddBCD(var BCD : TBCD; Pos,Value : Integer);
begin
Inc(BCD[Pos], Value);
if BCD[Pos] > 9 then
begin
Dec(BCD[Pos],10);
AddBCD(BCD,Pos-1, 1);
end;
end;
procedure IncBCD(var A : TBCD; const B : TBCD);
var
I : Integer;
begin
for I := MaxBCD-1 downto 0 do
AddBCD(A, I, B[I]);
end;
var
ValueBCD : TBCD;
BitValue : TBCD;
Tmp : TBCD;
I : Integer;
Ofs : Integer;
begin
// default to zero
FillChar(ValueBCD, SizeOf(ValueBCD), 0);
// set bit value BCD. Lowest bit has value 1
FillChar(BitValue, SizeOf(BitValue), 0);
BitValue[MaxBCD-1] := 1;
// check if there are bits available
while Value <> 0 do
begin
// if current lowest bit is set
// Increment the BCD value with the current bit value
if Value and 1 <> 0 then
IncBCD(ValueBCD, BitValue);
// proceed to the next bit
Value := Value shr 1;
// Double the BitValue
Tmp := BitValue;
IncBCD(BitValue, Tmp);
end;
// Find highest non zero decimal
Ofs := 0;
while (Ofs < MaxBCD) and (ValueBCD[Ofs] = 0) do
Inc(Ofs);
// check if any non zero decimals present
if Ofs < MaxBCD then
begin
// convert BCD result to ASCII result
SetLength(Result, MaxBCD-Ofs);
I := Ofs;
Repeat
Result[I-Ofs+1] := Char(ValueBCD[I]+Ord('0'));
Inc(I);
until I > MaxBCD-1;
end
else
Result := '0'; // nothing set -> value is '0'
end;
end.
Code:
{ }
{ GT Delphi Components }
{ GT Threaded Timer }
{ }
{ Copyright (c) GT Delphi Components }
{ http://www.gtdelphicomponents.gr }
{ }
{ }
unit o_GTTimer;
interface
uses
Classes
;
type
{------------------------------------------------------------------------------}
TgtTimer = class;
{------------------------------------------------------------------------------}
TgtTimerThread = class(TThread)
private
{ Private declarations }
FTimer : TgtTimer;
protected
{ Protected declarations }
procedure DoTimer;
public
{ Public declarations }
constructor Create(ATimer : TgtTimer);
destructor Destroy;override;
procedure Execute;override;
published
{ Published declarations}
end;
{------------------------------------------------------------------------------}
TgtTimer = class(TComponent)
private
FEnabled: Boolean;
FInterval: Cardinal;
FOnTimer: TNotifyEvent;
procedure SetEnabled(const Value: Boolean);
procedure SetInterval(const Value: Cardinal);
{ Private declarations }
protected
{ Protected declarations }
FTimerThread : TgtTimerThread;
procedure UpdateTimer;
public
{ Public declarations }
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
published
{ Published declarations}
property Enabled : Boolean read FEnabled write SetEnabled;
property Interval: Cardinal read FInterval write SetInterval;
published
property OnTimer : TNotifyEvent read FOnTimer write FOnTimer;
end;
{------------------------------------------------------------------------------}
implementation
uses
Windows
,SysUtils
;
{ TgtTimerThread }
{------------------------------------------------------------------------------}
constructor TgtTimerThread.Create(ATimer: TgtTimer);
begin
inherited Create(True);
FreeOnTerminate := True;
FTimer := ATimer;
end;
{------------------------------------------------------------------------------}
destructor TgtTimerThread.Destroy;
begin
inherited;
end;
{------------------------------------------------------------------------------}
procedure TgtTimerThread.DoTimer;
begin
if Assigned(FTimer.OnTimer) then
FTimer.OnTimer(FTimer);
end;
{------------------------------------------------------------------------------}
procedure TgtTimerThread.Execute;
begin
while (not Self.Terminated) and (FTimer.Enabled) do
begin
WaitForSingleObject(Self.Handle,FTimer.Interval);
Synchronize(DoTimer);
end;
end;
{------------------------------------------------------------------------------}
{ TgtTimer }
{------------------------------------------------------------------------------}
constructor TgtTimer.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FEnabled := True;
FInterval := 1000;
end;
{------------------------------------------------------------------------------}
destructor TgtTimer.Destroy;
begin
inherited;
end;
{------------------------------------------------------------------------------}
procedure TgtTimer.UpdateTimer;
begin
if Assigned(FTimerThread) then
begin
FTimerThread.Terminate;
FTimerThread := nil;
end;
if Enabled then
begin
if FInterval > 0 then
begin
FTimerThread := TgtTimerThread.Create(Self);
FTimerThread.Resume;
end
else
Enabled := False;
end;
end;
{------------------------------------------------------------------------------}
//Getters - Setters\\
{------------------------------------------------------------------------------}
procedure TgtTimer.SetEnabled(const Value: Boolean);
begin
FEnabled := Value;
UpdateTimer;
end;
{------------------------------------------------------------------------------}
procedure TgtTimer.SetInterval(const Value: Cardinal);
begin
if Value <> FInterval then
begin
FInterval := Value;
UpdateTimer;
end;
end;
{------------------------------------------------------------------------------}
end.
Yer I know, this offset unit is both ugly, terrible and stuipid, I was cbf changing it once I started
Code:
unit moduleWoWOffsets;
///////////////////////////////////////////////////////////////////////////////
//This unit contains offsets for all WoW modules. Very dodge way of doing it :S//
///////////////////////////////////////////////////////////////////////////////
{To do:
- Add FindPattern methods, for updateable currmgr
- Possibly read currmanager straight from here.
}
interface
type
TWoWOffsets = Class
published
function ClientConnection: Cardinal;
function CurrMgr: Cardinal;
function FirstObject: Cardinal;
function NextObject: Cardinal;
function LocalGUID: Cardinal;
function objGuid: Cardinal;
function objType: Cardinal;
function objXPosition: Cardinal;
function objYPosition: Cardinal;
function objZPosition: Cardinal;
function objRotation: Cardinal;
function objDescriptorFields: Cardinal;
function crPitch1: Cardinal;/////////
function crPitch2: Cardinal;/////////
function crLevel: Cardinal;
function crCurrentHealth: Cardinal;
function crMaxHealth: Cardinal;
function crCurrentMana: Cardinal;
function crMaxMana: Cardinal;
function crTargetGuid: Cardinal;
function npcName1: Cardinal;
function npcName2: Cardinal;
function npcSummonedBy: Cardinal;
function npcAttackingGuid: Cardinal;
function plrCurrentRage: Cardinal;
function plrCurrentEnergy: Cardinal;
function plrMaxEnergy: Cardinal;
function gmeName1: Cardinal;
function gmeName2: Cardinal;
function gmeXPosition: Cardinal;
function gmeYPosition: Cardinal;
function gmeZPosition: Cardinal;
function gmedisplayId: Cardinal;
function dynXPosition: Cardinal;
function dynYPosition: Cardinal;
function dynZPosition: Cardinal;
function cpsXPosition: Cardinal;
function cpsYPosition: Cardinal;
function cpsZPosition: Cardinal;
end;
implementation
{Object Manager Offsets}
function TWoWOffsets.ClientConnection: Cardinal;
begin
result:= $C79CD8; //00BB43F0
end;
function TWoWOffsets.CurrMgr: Cardinal;
begin
result := $2ED0;
end;
function TWoWOffsets.FirstObject : Cardinal;
begin
result:= $AC;
end;
function TWoWOffsets.NextObject : Cardinal;
begin
result:= $3C;
end;
function TWoWOffsets.LocalGUID : Cardinal;
begin
result:= $C0; //Offset from currmanager
end;
{Base object offsets}
function TWoWOffsets.objGuid: Cardinal;
begin
result:= $30;
end;
function TWoWOffsets.objType: Cardinal;
begin
result:= $14;
end;
function TWoWOffsets.objXPosition: Cardinal;
begin
result:= $798; //7D0
end;
function TWoWOffsets.objYPosition: Cardinal;
begin
result:=$79C; //$7D4;
end;
function TWoWOffsets.objZPosition: Cardinal;
begin
result:= $7A0; //$7D8;
end;
function TWoWOffsets.objRotation: Cardinal;
begin
result:= $7A8;
end;
function TWoWOffsets.objDescriptorFields: Cardinal;
begin
result:= $8;
end;
{Creature object offsets}
function TWoWOffsets.crPitch1: Cardinal;/////////
begin
result:= $110;
end;
function TWoWOffsets.crPitch2: Cardinal;/////////
begin
result:= $20;
end;
function TWoWOffsets.crLevel: Cardinal;
begin
result:= $35 * 4;
end;
function TWoWOffsets.crCurrentHealth: Cardinal;
begin
result:= $17 * 4;
end;
function TWoWOffsets.crMaxHealth: Cardinal;
begin
result:= $1F * 4;
end;
function TWoWOffsets.crCurrentMana: Cardinal;
begin
result:= $18 * 4;
end;
function TWoWOffsets.crMaxMana: Cardinal;
begin
result:= $20 * 4;
end;
function TWoWOffsets.crTargetGuid: Cardinal;
begin
result:= $12 * 4;
end;
{NPC object offsets}
function TWoWOffsets.npcName1: Cardinal;
begin
result:= $9B0;
end;
function TWoWOffsets.npcName2: Cardinal;
begin
result:= $3C;
end;
function TWoWOffsets.npcSummonedBy: Cardinal;
begin
result:= $E * 4;
end;
function TWoWOffsets.npcAttackingGuid: Cardinal;
begin
result:= $0A38;
end;
{Player object offsets}
function TWoWOffsets.plrCurrentRage: Cardinal;
begin
result:= $19 * 4;
end;
function TWoWOffsets.plrCurrentEnergy: Cardinal;
begin
result:= $1B * 4;
end;
function TWoWOffsets.plrMaxEnergy: Cardinal;
begin
result:= $23 * 4;
end;
{Game object offsets}
function TWoWOffsets.gmeName1: Cardinal;
begin
result:= $1f4;
end;
function TWoWOffsets.gmeName2: Cardinal;
begin
result:= $078;
end;
function TWoWOffsets.gmeXPosition: Cardinal;
begin
result:= $E8;
end;
function TWoWOffsets.gmeYPosition: Cardinal;
begin
result:= $EC;
end;
function TWoWOffsets.gmeZPosition: Cardinal;
begin
result:= $F0;
end;
function TWoWOffsets.gmedisplayId: Cardinal;
begin
result:= $8 * 4;
end;
{Dynamic object offsets}
function TWoWOffsets.dynXPosition: Cardinal;
begin
result:= $B * 4;
end;
function TWoWOffsets.dynYPosition: Cardinal;
begin
result:= $C * 4;
end;
function TWoWOffsets.dynZPosition: Cardinal;
begin
result:= $D * 4;
end;
{Corpse object offsets}
function TWoWOffsets.cpsXPosition: Cardinal;
begin
result:= $B * 4;
end;
function TWoWOffsets.cpsYPosition: Cardinal;
begin
result:= $C * 4;
end;
function TWoWOffsets.cpsZPosition: Cardinal;
begin
result:= $D * 4;
end;
end.
Code:
unit moduleWoWObjectManager;
///////////////////////////////////////////////////////////////////////////////
//This unit contains the ObjectManager. //
//How to use: //
//- Add unit to uses clause //
//- Create new TWoWObjectManager using constructor CreateObjMgr //
//- Read the arrays of wowobjects, it self updates :D //
///////////////////////////////////////////////////////////////////////////////
{To do:
- Add more descriptors
- Add items and containers
- Make player data easily accessable
- Do Aggro Radius
}
interface
uses
SysUtils, Classes, UInt64Lib, windows, o_GTTimer, Variants, moduleWoWOffsets, math;
type
{Master object, all others decending}
TWoWObject = class
private
protected
public
BaseAddress: Cardinal;
objType: Cardinal;
objGUID: UInt64;
constructor Create(BaseAdd: Cardinal); //Loads all things that dont change
function DescriptorFields: Cardinal;
function xPosition: Single; virtual;
function yPosition: Single; virtual;
function zPosition: Single; virtual;
function Rotation: Single; virtual;
end;
{Creature object, holds the procedures etc similar between
creatures and players}
TWoWCreature = class(TWoWObject)
private
protected
public
function Pitch: Single;
function TargetGUID: Uint64;
function Level: Integer;
function CurrentHealth: Integer;
function MaxHealth: Integer;
function CurrentMana: Integer;
function MaxMana: Integer;
function HealthPercent: Real;
end;
{NPC object, decendant of creature object}
TWoWNPC = class(TWoWCreature)
private
protected
public
function Name: String;
function AttackingGUID: UInt64;
function SummonedBy: UInt64;
function GetAggroRadius(PlayersLevel: Integer): Integer;
end;
{Player object, decendant of creature object}
TWoWPlayer = class(TWoWCreature)
private
protected
public
function CurrentRage: Integer;
function MaxRage: Integer; //wait... didnt need this... always 100
function CurrentEnergy: Integer;
function MaxEnergy: Integer;
end;
{Game Object, nodes etc}
TWoWGame = class(TWoWObject)
private
protected
public
function Name: String;
function xPosition: Single; override;
function yPosition: Single; override;
function zPosition: Single; override;
function DisplayID: Integer;
end;
{Dynamic Object, spells etc}
TWoWDynamic = class(TWoWObject)
private
protected
public
function xPosition: Single; override;
function yPosition: Single; override;
function zPosition: Single; override;
end;
{Corpse Object, dead players etc}
TWoWCorpse = class(TWoWObject)
private
protected
public
end;
{END OF WOW OBJECTS, START OF OBJECT MANAGER TYPE DECLARATIONS}
TWoWObjectManager = class(TComponent)
private
timerUpdate: TgtTimer;
procedure LoadObjects;
procedure timerUpdateOnTimer(Sender : TObject);
function GetLocalPlayerIndex: Integer; //returns the index of the local player, use this later
function GetLocalPlayer: TWoWPlayer;
public
GameObjects: Array of TWoWGame;
PlayerObjects: Array of TWoWPlayer;
NPCObjects: Array of TWoWNPC;
DynamicObjects: Array of TWoWDynamic;
CorpseObjects: Array of TWoWCorpse;
property LocalPlayer: TWoWPlayer
read GetLocalPlayer;
constructor createObjMgr(AOwner: TComponent; wWindow: HWND; RefreshRate: Integer);
function CurrMgr: Cardinal; //returns the currmgr
function Count: integer;
end;
var
WoWWindow: HWND;
Offsets: TWoWOffsets;
implementation
///////////////////////////////////////////////////////////////////////////////
//Utility methods //
//These methods are used in the various components in some way //
///////////////////////////////////////////////////////////////////////////////
{Sets the application privlieage level high enough to be able to read from wow l8r}
function SetPrivilege(privilegeName: string; enable: boolean): boolean;
var tpPrev,
tp : TTokenPrivileges;
token : THandle;
dwRetLen : DWord;
begin
result := False;
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, token);
tp.PrivilegeCount := 1;
if LookupPrivilegeValue(nil, pchar(privilegeName), tp.Privileges[0].LUID) then
begin
if enable then
tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
tp.Privileges[0].Attributes := 0;
dwRetLen := 0;
result := AdjustTokenPrivileges(token, False, tp, SizeOf(tpPrev), tpPrev, dwRetLen);
end;
CloseHandle(token);
end;
function ReadCardinal(Address: Cardinal): Cardinal;
{NOTE: Cardinal is an unsigned 32 bit integer}
var
bytesRead: Cardinal;
Pid, PidHandle: Integer;
begin
bytesRead:= 0;
GetWindowThreadProcessId(WoWWindow,@Pid);
Pidhandle := OpenProcess(PROCESS_VM_READ,False,Pid);
ReadProcessMemory(pidhandle, ptr(address), @result, 4, bytesRead);
closehandle(Pidhandle);
end;
function ReadInt32(Address: Cardinal): Integer;
var
bytesRead: Cardinal;
Pid, PidHandle: Integer;
begin
bytesRead:= 0;
GetWindowThreadProcessId(WoWWindow,@Pid);
Pidhandle := OpenProcess(PROCESS_VM_READ,False,Pid);
ReadProcessMemory(pidhandle, ptr(address), @result, 4, bytesRead);
closehandle(Pidhandle);
end;
function ReadUInt64(Address: Cardinal): UInt64;
var
bytesRead: Cardinal;
Pid, PidHandle: Integer;
begin
bytesRead:= 0;
GetWindowThreadProcessId(WoWWindow,@Pid);
Pidhandle := OpenProcess(PROCESS_VM_READ,False,Pid);
ReadProcessMemory(pidhandle, ptr(address), @result, 8, bytesRead);
closehandle(Pidhandle);
end;
function ReadFloat(Address: Cardinal): Single;
{32 bit float, use for reading coords etc}
var
bytesRead: Cardinal;
Pid, PidHandle: Integer;
begin
bytesRead:= 0;
GetWindowThreadProcessId(WoWWindow,@Pid);
Pidhandle := OpenProcess(PROCESS_VM_READ,False,Pid);
ReadProcessMemory(pidhandle, ptr(address), @result, 4, bytesRead);
closehandle(Pidhandle);
end;
function ReadString(Address: Cardinal): String;
begin
result:= '';
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWObject //
//Base component for all loaded objects. //
///////////////////////////////////////////////////////////////////////////////
constructor TWoWObject.Create(BaseAdd: Cardinal);
{Load all info that doesnt change}
begin
BaseAddress:= BaseAdd;
objType:= ReadCardinal(BaseAddress + Offsets.objType);
objGUID:= ReadUInt64(BaseAddress + Offsets.objGuid);
end;
function TWoWObject.DescriptorFields: Cardinal;
begin
result:= ReadCardinal(BaseAddress + Offsets.objDescriptorFields);
end;
function TWoWObject.xPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.objXPosition);
end;
function TWoWObject.yPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.objYPosition);
end;
function TWoWObject.zPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.objZPosition);
end;
function TWoWObject.Rotation: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.objRotation);
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWCreature //
//Decendant of TWoWObject //
///////////////////////////////////////////////////////////////////////////////
function TWoWCreature.Pitch: Single;
begin
result:= ReadFloat(ReadCardinal(BaseAddress + Offsets.crPitch1) + Offsets.crPitch2);
end;
function TWoWCreature.TargetGUID: UInt64;
begin
result:= ReadUInt64(DescriptorFields + Offsets.crTargetGuid);
end;
function TWoWCreature.Level: Integer;
begin
result:= ReadInt32(DescriptorFields + offsets.crLevel);
end;
function TWoWCreature.CurrentHealth: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.crCurrentHealth);
end;
function TWoWCreature.MaxHealth: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.crMaxHealth);
end;
function TWoWCreature.CurrentMana: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.crCurrentMana);
end;
function TWoWCreature.MaxMana: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.crMaxMana);
end;
function TWoWCreature.HealthPercent: Real;
begin
result:= (CurrentHealth / MaxHealth) * 100;
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWNPC //
//Decendant of TWoWCreature //
///////////////////////////////////////////////////////////////////////////////
function TWoWNPC.Name: String;
begin
result:= ReadString(ReadCardinal(ReadCardinal(BaseAddress + Offsets.npcName1) + Offsets.npcName2));
end;
function TWoWNPC.AttackingGUID: UInt64;
begin
result:= ReadUInt64(BaseAddress + Offsets.npcAttackingGuid);
end;
function TWoWNPC.SummonedBy: UInt64;
begin
result:= ReadUInt64(DescriptorFields + Offsets.npcSummonedBy);
end;
function TWoWNPC.GetAggroRadius(PlayersLevel: Integer): Integer;
{Return the aggro radius of this npc, finish later}
begin
result:= 0;
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWPlayer //
//Decendant of TWoWCreature //
///////////////////////////////////////////////////////////////////////////////
function TWoWPlayer.CurrentRage: Integer;
var
ragetemp: Real;
begin
ragetemp:= ReadInt32(DescriptorFields + Offsets.plrCurrentRage)/10;
result:= Floor(RageTemp);
end;
function TWoWPlayer.MaxRage: Integer;
begin
result:= 100;
end;
function TWoWPlayer.CurrentEnergy: Integer;
begin
result:= ReadInt32(DescriptorFields + offsets.plrCurrentEnergy);
end;
function TWoWPlayer.MaxEnergy: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.plrMaxEnergy);
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWGame //
//Decendant of TWoWObject //
///////////////////////////////////////////////////////////////////////////////
function TWoWGame.Name: String;
begin
result:= ReadString(ReadCardinal(BaseAddress + Offsets.gmeName1) + Offsets.gmeName2);
end;
function TWoWGame.xPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.gmeXPosition);
end;
function TWoWGame.yPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.gmeYPosition);
end;
function TWoWGame.zPosition: Single;
begin
result:= ReadFloat(BaseAddress + Offsets.gmeZPosition);
end;
function TWoWGame.DisplayID: Integer;
begin
result:= ReadInt32(DescriptorFields + Offsets.gmedisplayId);
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWDynamic //
//Decendant of TWoWObject //
///////////////////////////////////////////////////////////////////////////////
function TWoWDynamic.xPosition: Single;
begin
result:= ReadFloat(DescriptorFields + Offsets.dynXPosition);
end;
function TWoWDynamic.yPosition: Single;
begin
result:= ReadFloat(DescriptorFields + Offsets.dynYPosition);
end;
function TWoWDynamic.zPosition: Single;
begin
result:= ReadFloat(DescriptorFields + Offsets.dynZPosition);
end;
///////////////////////////////////////////////////////////////////////////////
//TWoWCorpse //
//Decendant of TWoWObject //
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//TWoWObjectManager //
//Component controlling object manager, self updating, uses object classes //
///////////////////////////////////////////////////////////////////////////////
function TWoWObjectManager.CurrMgr: Cardinal;
{Returns the currmgr}
begin
result:= readcardinal(Offsets.ClientConnection);
result:= ReadCardinal(result + $2ED0);
//result:= ReadCardinal(ReadCardinal(Offsets.ClientConnection)+ Offsets.CurrMgr);
end;
function TWoWObjectManager.Count: integer;
{Returns the number of objects loaded}
var
NextObject: Cardinal;
objType: Integer;
begin
NextObject:= ReadCardinal(CurrMgr + Offsets.FirstObject); //Read the first object
result:= 0; //initialize result
ObjType:= ReadInt32(NextObject + Offsets.objType); //read the type of the first object
//NOTE: if there is an object in the list, objType will = 1 to 7, fix for previous bug
While (ObjType <= 7) and (ObjType > 0) do
begin
result:= result + 1;
NextObject:= ReadCardinal(NextObject + Offsets.NextObject);
ObjType:= ReadInt32(NextObject + Offsets.objType); //read the type of nxtobject
end;
end;
procedure TWoWObjectManager.LoadObjects;
{Completly refreshes the object list, loading all the base addresses into their
array by type}
var
objAddress, myType: Cardinal;
ObjectCount, objIndex: Integer;
begin
//Clear arrays
SetLength(GameObjects, 0);
SetLength(PlayerObjects, 0);
SetLength(NPCObjects, 0);
SetLength(DynamicObjects, 0);
SetLength(CorpseObjects, 0);
ObjectCount:= Count;
if (ObjectCount > 0) then //If is there any objects loaded?
begin
//Loop through the entire loaded list
myType:= 0;
objAddress:= 0;
ObjAddress:= ReadCardinal(CurrMgr + Offsets.FirstObject);
myType:= ReadCardinal(objAddress + Offsets.objType);
for objIndex:= 0 to (ObjectCount-1) do
begin
case myType of //Load a object into whatever array it belongs in
3: //NPCs
begin
SetLength(NPCObjects, (Length(NPCObjects)+1));
NPCObjects[Length(NPCObjects)-1]:= TWoWNPC.Create(objAddress);
end;
4: //Players
begin
SetLength(PlayerObjects, (Length(PlayerObjects)+1));
PlayerObjects[Length(PlayerObjects)-1]:= TWoWPlayer.Create(objAddress);
end;
5: //Gameobjects
begin
SetLength(GameObjects, (Length(GameObjects)+1));
GameObjects[Length(GameObjects)-1]:= TWoWGame.Create(objAddress);
end;
6: //dynamicobjects
begin
SetLength(DynamicObjects, (Length(DynamicObjects)+1));
DynamicObjects[Length(DynamicObjects)-1]:= TWoWDynamic.Create(objAddress);
end;
7: //Corpses
begin
SetLength(CorpseObjects, (Length(CorpseObjects)+1));
CorpseObjects[Length(CorpseObjects)-1]:= TWoWCorpse.Create(objAddress);
end;
end;
ObjAddress:= ReadCardinal(objAddress + Offsets.NextObject);
myType:= ReadCardinal(objAddress + Offsets.objType);
end;
end;
end;
procedure TWoWObjectManager.timerUpdateOnTimer(Sender : TObject);
{TO DO: Add some way to check to see if the objmgr needs updating, then test to
see if it is more efficient.}
begin
LoadObjects;
end;
constructor TWoWObjectManager.createObjMgr(AOwner: TComponent; wWindow: HWND; RefreshRate: Integer);
begin
//The TComponent create constructor
{NOTE ABOUT TComponent: It isn't strictly neccesary however it has a method
that destroys all children on close, and later could be used to make the
component visual drag/drop able}
self:= TWoWObjectManager.create(AOwner);
SetPrivilege('SeDebugPrivilege', true); //sets privlige high enough to access wow
WoWWindow:= wWindow;
//First-run, load object list
LoadObjects;
//Create update loop. This loop runs every interval (the specified refreshRate), keeping the object lists up to date.
timerUpdate:= TgtTimer.Create(Self);
timerUpdate.OnTimer := timerUpdateOnTimer; //the procedure that is run on timer
timerUpdate.Interval:= RefreshRate; //x ms
timerUpdate.Enabled := true;
end;
function TWoWObjectManager.GetLocalPlayerIndex: Integer;
{Returns the index of the local player in the array}
var
LocalGUID: UInt64;//The GUID of the local player
objIndex: Integer;
begin
//Find the local GUID
LocalGUID:= ReadUInt64(CurrMgr + Offsets.LocalGUID);
objIndex:= 0;
result:= 0;
for objIndex:= 0 to (Length(PlayerObjects) - 1) do
begin
if (PlayerObjects[objIndex].objGUID = LocalGUID) then
result:= objIndex;
end;
end;
function TWoWObjectManager.GetLocalPlayer: TWoWPlayer;
begin
result:= PlayerObjects[GetLocalPlayerIndex];
end;
end.