EDIT: seems like the code format is cluttered - and the URL to my site filtered. Send me a PM if you want the correct link to the source!
Well, if you expected the NTPK source-code - you're wrong! Nevertheless, I wrote a pretty cool autoaim for a friend tonight, and I'm sure the source-code will be of "some" interest to a few module developers (difficulty: intermediate). It's *not* the most optimal way to solve an autoaim, but touches on a few things, like reading some playerinfo directly from memory and handling a gamelist structure.
You can download the source-code directly here: http://www.****************/files/aa.zip (the compiled binary version/full project-file is included, aswell as a readme on how to use it)
It's a simple autoaim that allows you to swap through a list of players and attack them either with left or right button (attacks hide graphics, i.e. you can run while attacking). The main source code (4 main files, 2 excluded) is appended in ASCII format:
I suggest you download the .zip packed file from the link above, since "framework.h" and "framework.cpp" have been excluded from this post to save you from the clutter ;p. Also, this code will not work without the d2hackit framework below version 0.61!
Have fun and don't hesitate to ask questions.
-Jan
Well, if you expected the NTPK source-code - you're wrong! Nevertheless, I wrote a pretty cool autoaim for a friend tonight, and I'm sure the source-code will be of "some" interest to a few module developers (difficulty: intermediate). It's *not* the most optimal way to solve an autoaim, but touches on a few things, like reading some playerinfo directly from memory and handling a gamelist structure.
You can download the source-code directly here: http://www.****************/files/aa.zip (the compiled binary version/full project-file is included, aswell as a readme on how to use it)
It's a simple autoaim that allows you to swap through a list of players and attack them either with left or right button (attacks hide graphics, i.e. you can run while attacking). The main source code (4 main files, 2 excluded) is appended in ASCII format:
Code:
//---
//mem.h (declares unitstructure and related functions)
//---
#ifndef MEM_H
#define MEM_H
#include "aa.h"
#define GET_UNIT_RVA 0x869F0 // offset in d2client.dll
#define GET_MY_UNIT_RVA 0x883D0 // offset in d2client.dll
struct pUnit
{
DWORD unk[3];
DWORD dwId; // our player id (+0x0c)
DWORD unk2;
char* PlayerName; // ptr to charname (+0x14)
};
typedef pUnit * (__fastcall * GetUnitFunc) (DWORD dwID, DWORD dwTYPE);
typedef pUnit * (__fastcall * GetMyUnitFunc) (void);
namespace mem {
// prototypes
extern BOOL init(void);
extern char* GetPNAME(DWORD dwID);
extern char* GetMyPNAME(VOID);
extern DWORD GetMyPID(VOID);
};
#endif // MEM_H
Code:
//---
//mem.cpp (defines memory functions)
//---
#include "mem.h"
#include "aa.h"
// define funcs (local to mem.cpp)
GetUnitFunc GetUnit;
GetMyUnitFunc GetMyUnit;
namespace mem { // experimental ;p (zoidOr elitOr)
BOOL init(void) // some messy ptr initialization
{
static bInstalled=FALSE;
if(bInstalled) return TRUE;
HANDLE ghD2Client = LoadLibrary("D2CLIENT.DLL");
if (!ghD2Client) return FALSE;
GetUnit=(GetUnitFunc)(LPDWORD)((LPBYTE)ghD2Client+GET_UNIT_RVA);
GetMyUnit=(GetMyUnitFunc)(LPDWORD)((LPBYTE)ghD2Client+GET_MY_UNIT_RVA);
bInstalled=TRUE;
return TRUE;
}
char* GetPNAME(DWORD dwID) // get name by id (print target name)
{
pUnit * p = GetUnit(dwID,0);
return p ? p->PlayerName : "Unknown";
}
char* GetMyPNAME(VOID) // get our name (greeting message)
{
pUnit * p = GetMyUnit();
return p ? p->PlayerName : "Unknown";
}
DWORD GetMyPID(VOID) // get our id (prevent adding ourself)
{
pUnit * p = GetMyUnit();
return p ? p->dwId : 0;
}
};
Code:
//---
//aa.h (global stuff&framework declarations)
//---
#ifndef AA_H
#define AA_H
#include <windows.h>
#include "mem.h"
#include "framework.h"
#define MAX_PLAYER_PER_GAME 8
struct pGameStruct;
// prototypes
extern BOOL AddPlayer(DWORD dwID);
extern BOOL RemovePlayer(DWORD dwID);
#endif // AA_H
Code:
//---
//aa.cpp (defines module functions & other)
//---
#include "aa.h"
int currTarget; // index of current target
char szMsg[256]; // message buffer
bool bButton; // TRUE: right button, FALSE: left button
BYTE attackTarget[9] = {0};
struct pGameStruct // our game structure (holds player infos)
{
DWORD pID;
bool bUsed;
}; pGameStruct gs[MAX_PLAYER_PER_GAME];
BOOL PRIVATE OnGameCommandToggle(char** argv, int argc)
{
if(argc!=2)return FALSE;
bButton=1-bButton; // might produce performance-warning
sprintf(szMsg,"Autoaim set to ÿc2%sÿc0 button.",bButton ? "RIGHT" : "LEFT");
server->GamePrintString(szMsg);
return TRUE;
}
BOOL PRIVATE OnGameCommandAttack(char** argv, int argc)
{
if(argc!=2)return FALSE;
if(currTarget<0)
{
server->GamePrintString("Error: No target set.");
return TRUE;
}
bButton ? attackTarget[0]=0x0d : attackTarget[0]=0x07; // set button type
memcpy(&attackTarget[5],&gs[currTarget].pID,sizeof(DWORD)); // set id
server->GameSendPacketToServer(attackTarget,sizeof(attackTarget)); // send attack
return TRUE;
}
BOOL PRIVATE OnGameCommandPrevious(char** argv, int argc)
{
if(argc!=2)return FALSE;
int buf=currTarget;
for(int i=1;i<MAX_PLAYER_PER_GAME;i++)
{
if(--buf<0) // prevent out-of-bounds
buf=MAX_PLAYER_PER_GAME-1;
if(gs[buf].bUsed)
{
currTarget=buf;
sprintf(szMsg,"Now aiming at: %s",(const char*)mem::GetPNAME(gs[buf].pID));
server->GamePrintString(szMsg);
return TRUE;
}
}
server->GamePrintString("Could not set previous target, because no target is set.");
return TRUE;
}
BOOL PRIVATE OnGameCommandNext(char** argv, int argc)
{
if(argc!=2)return FALSE;
int buf=currTarget;
for(int i=1;i<MAX_PLAYER_PER_GAME;i++)
{
if(++buf>MAX_PLAYER_PER_GAME-1) // prevent out-of-bounds
buf=0;
if(gs[buf].bUsed)
{
currTarget=buf;
sprintf(szMsg,"Now aiming at: %s",(const char*)mem::GetPNAME(gs[buf].pID));
server->GamePrintString(szMsg);
return TRUE;
}
}
server->GamePrintString("Could not set next target, because no target is set.");
return TRUE;
}
BOOL PRIVATE OnGameCommandTarget(char** argv, int argc)
{
if(argc!=2)return FALSE;
if(currTarget<0)
{
server->GamePrintString("Error: No target set.");
return TRUE;
}
sprintf(szMsg,"Current target is: %s",(const char*)mem::GetPNAME(gs[currTarget].pID));
server->GamePrintString(szMsg);
return TRUE;
}
BOOL EXPORT OnClientStart()
{
mem::init(); // initializes function ptr
return TRUE;
}
VOID EXPORT OnGameJoin(THISGAMESTRUCT* thisgame)
{
currTarget=-1;
for(int i=0;i<MAX_PLAYER_PER_GAME;i++) // init gamestruct
{
gs[i].pID=0;
gs[i].bUsed=FALSE;
}
// print greeting
sprintf(szMsg,"Hello %s. Welcome to the world of autoaim!",(const char*)mem::GetMyPNAME());
server->GamePrintString(szMsg);
server->GamePrintString("Type ''.aa'' for help!");
}
DWORD EXPORT OnGamePacketBeforeReceived(BYTE* aPacket, DWORD aLen)
{
// player joins (note: module has to be loaded when player joins)
if(aPacket[0] == 0x5b)
{
if(!AddPlayer(*(DWORD*)(&aPacket[3])))
server->GamePrintString("Error: Could not add player to list.");
return aLen;
}
// player leaves (03: usual - 00: timeout)
if (aPacket[0]==0x5a && (aPacket[1]==0x03 || aPacket[1]==0x00))
{
if(!RemovePlayer(*(DWORD*)(&aPacket[3])))
server->GamePrintString("Error: Could not remove player from list.");
return aLen;
}
return aLen;
}
BOOL AddPlayer(DWORD dwID)
{
if(dwID==mem::GetMyPID()) // make sure we don't add ourself
return TRUE; // prevent error msg
bool bFoundSlot=FALSE;
for(int i=0;i<MAX_PLAYER_PER_GAME;i++)
{
if(!gs[i].bUsed)
{
gs[i].pID=dwID;
gs[i].bUsed=TRUE;
bFoundSlot=TRUE;
break;
}
}
if(!bFoundSlot) return FALSE; // shouldn't happen
return TRUE;
}
BOOL RemovePlayer(DWORD dwID)
{
for(int i=0;i<MAX_PLAYER_PER_GAME;i++)
{
if(gs[i].pID==dwID && gs[i].bUsed)
{
gs[i].pID=0;
gs[i].bUsed=FALSE;
return TRUE;
}
}
return FALSE;
}
Have fun and don't hesitate to ask questions.
-Jan