-
AlexSpl
имя: Александр
- Эксперт
-
- Сообщения: 5587
- Зарегистрирован: 17 сен 2010, 12:58
- Пол:
- Награды: 14
-
-
- Поблагодарили: 2185 раз.
|
AlexSpl » 12 июн 2014, 11:24
Исходники LMOracle.SkillTreeAPI.dll SkillTreeAPI.h - Код: Выделить всё
#include <windows.h>
#define DllExport extern "C" __declspec(dllexport)
struct THero { BYTE Class; BYTE Level; BYTE TreeNumber; BYTE LastWisdom; BYTE LastMagic; BYTE Attack; BYTE Defense; BYTE SpellPower; BYTE Knowledge; BYTE SkillCount; BYTE Skill[28]; };
struct TWeights { BYTE PW[4]; BYTE PW10[4]; BYTE SW[28]; bool SR[28]; };
struct TSecondary { BYTE Left; BYTE Right; };
struct TSkillOffer { BYTE Primary; TSecondary Secondary; };
struct TSkillExcept { BYTE Last_Wisdom; BYTE Last_Magic; BYTE Delta_Wisdom; BYTE Delta_Magic; };
enum {ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
enum { PATHFINDING, ARCHERY, LOGISTICS, SCOUTING, DIPLOMACY, NAVIGATION, LEADERSHIP, WISDOM, MYSTICISM, LUCK, BALLISTICS, EAGLE_EYE, NECROMANCY, ESTATES, FIRE_MAGIC, AIR_MAGIC, WATER_MAGIC, EARTH_MAGIC, SCHOLAR, TACTICS, ARTILLERY, LEARNING, OFFENSE, ARMORER, INTELLIGENCE, SORCERY, RESISTANCE, FIRST_AID, NONE };
enum {BASIC = 1, ADVANCED, EXPERT};
const DWORD HAddr[4] = {0x0069CC88, 0x006994E8, 0x00699538, 0x006388D8}; const DWORD WAddr[4] = {0x0067EFDC, 0x0067DCEC, 0x0067DCEC, 0x0061C194}; const DWORD BB_CFAddr[3] = {0x0069AEEC, 0x0069774C, 0x0069774C}; const DWORD BB_SRAddr[3] = {0x0067AF90, 0x00679CA0, 0x00679CA0};
DllExport DWORD GetProcessID(const wchar_t *Title); DllExport DWORD GetHStartPoint(const HANDLE hProcess, const BYTE Version); DllExport int RAMHero(const HANDLE hProcess, const DWORD HStartPoint, const BYTE ID, void *HeroRecord); DllExport int RAMWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord); DllExport int LevelUp(void *HeroRecord, const void *WeightsRecord, void *SkillOfferRecord, const BYTE Option); DllExport bool isStandardWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE ID); DllExport int RAMBBWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord);
SkillTreeAPI.cpp - Код: Выделить всё
#include "SkillTreeAPI.h"
DWORD GetProcessID(const wchar_t *Title) { HWND HWindow = FindWindow(NULL, Title); DWORD PID = 0; GetWindowThreadProcessId(HWindow, &PID); return PID; }
DWORD GetHStartPoint(const HANDLE hProcess, const BYTE Version) { DWORD HStartPoint = 0; if ( Version < 4 ) { DWORD BR; ReadProcessMemory(hProcess, LPCVOID(HAddr[Version]), &HStartPoint, 4, &BR); HStartPoint += ( Version == 3 ) ? 0x21608 : 0x21620; } return HStartPoint; }
int RAMHero(const HANDLE hProcess, const DWORD HStartPoint, const BYTE ID, void *HeroRecord) { if ( ID < 156 ) { DWORD BR; DWORD BAddr = HStartPoint + ID * 0x492;
ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x30), (BYTE *)HeroRecord, 1, &BR); ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x55), (BYTE *)HeroRecord + 1, 1, &BR); ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x8F), (BYTE *)HeroRecord + 2, 2, &BR); ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x3F), (BYTE *)HeroRecord + 4, 1, &BR);
ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x476), (BYTE *)HeroRecord + 5, 4, &BR); ReadProcessMemory(hProcess, LPCVOID(BAddr + 0x101), (BYTE *)HeroRecord + 9, 1, &BR); ReadProcessMemory(hProcess, LPCVOID(BAddr + 0xC9), (BYTE *)HeroRecord + 10, 28, &BR); } return 0; }
bool isStandardWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE ID) { bool StandardWeights = true; if ( Version < 3 ) { DWORD BR; BYTE CF, SF, HF;
ReadProcessMemory(hProcess, LPCVOID(BB_CFAddr[Version]), &CF, 1, &BR); ReadProcessMemory(hProcess, LPCVOID(HStartPoint - 0x21C4), &SF, 1, &BR); ReadProcessMemory(hProcess, LPCVOID(HStartPoint + ID * 0x492 + 0x1A), &HF, 1, &BR);
StandardWeights = !( (CF) && (SF == 0x0E) && (HF == 0x2D) ); } return StandardWeights; }
int RAMBBWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord) { if ( (Version < 3) && (Class < 18) ) { DWORD BR; DWORD WeightsAddr; ReadProcessMemory(hProcess, LPCVOID(WAddr[Version]), &WeightsAddr, 4, &BR); ReadProcessMemory(hProcess, LPCVOID(WeightsAddr + 0x310), (BYTE *)WeightsRecord, 8, &BR); ReadProcessMemory(hProcess, LPCVOID(WeightsAddr + (Class << 6) + 0x18), (BYTE *)WeightsRecord + 8, 28, &BR); ReadProcessMemory(hProcess, LPCVOID(BB_SRAddr[Version]), (bool *)WeightsRecord + 36, 28, &BR); } return 0; }
int RAMWeights(const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord) { if ( (Version < 4) && (Class < 18) ) { DWORD BR; DWORD WeightsAddr; ReadProcessMemory(hProcess, LPCVOID(WAddr[Version]), &WeightsAddr, 4, &BR); ReadProcessMemory(hProcess, LPCVOID(WeightsAddr + (Class << 6) + 0x10), (BYTE *)WeightsRecord, 36, &BR); ReadProcessMemory(hProcess, LPCVOID(HStartPoint + 0x2D038), (bool *)WeightsRecord + 36, 28, &BR); } return 0; }
int Rand(const DWORD Seed, DWORD &R) { R = 0x343FD * Seed + 0x269EC3; return ( (R >> 0x10) & 0x7FFF ); }
BYTE GetSkillOffer(const THero *Hero, const TWeights *Weights, const BYTE Level, const TSkillExcept *SkillExcept, const BYTE MinLevel, const BYTE MaxLevel, const BYTE LeftSkill, DWORD &R) { if ( MinLevel >= MaxLevel ) return NONE; // Wisdom if ( ((*SkillExcept).Last_Wisdom + (*SkillExcept).Delta_Wisdom <= Level) && ((*Hero).Skill[WISDOM] >= MinLevel) && ((*Hero).Skill[WISDOM] < MaxLevel) && (!(*Weights).SR[WISDOM]) && (LeftSkill != WISDOM) ) return WISDOM;
int SUM_W = 0; int Q; // Magic if ( ((*SkillExcept).Last_Magic + (*SkillExcept).Delta_Magic <= Level) && (LeftSkill != FIRE_MAGIC) && (LeftSkill != AIR_MAGIC) && (LeftSkill != WATER_MAGIC) && (LeftSkill != EARTH_MAGIC) ) { for (int i = FIRE_MAGIC; i <= EARTH_MAGIC; ++i) if ( ((*Hero).Skill[i] >= MinLevel) && ((*Hero).Skill[i] < MaxLevel) && (!(*Weights).SR[i]) ) (*Hero).Skill[i] ? ++SUM_W : SUM_W += (*Weights).SW[i]; if ( SUM_W ) { if ( SUM_W > 1 ) { Q = Rand(R, R); ++(Q %= SUM_W); } else Q = 1;
SUM_W = Q; for (int i = FIRE_MAGIC; i <= EARTH_MAGIC; ++i) { if ( ((*Hero).Skill[i] >= MinLevel) && ((*Hero).Skill[i] < MaxLevel) && (!(*Weights).SR[i]) ) (*Hero).Skill[i] ? --SUM_W : SUM_W -= (*Weights).SW[i];
if ( SUM_W <= 0 ) return (BYTE)i; } } }
// Other Skills SUM_W = 0; for (int i = PATHFINDING; i < NONE; ++i) if ( ((*Hero).Skill[i] >= MinLevel) && ((*Hero).Skill[i] < MaxLevel) && (i != LeftSkill) ) if ( (!(*Weights).SR[i]) && ((*Weights).SW[i]) ) SUM_W += (*Weights).SW[i]; else if ( (*Hero).Skill[i] > 0 ) ++SUM_W; if ( SUM_W ) { if ( SUM_W > 1 ) { Q = Rand(R, R); ++(Q %= SUM_W); } else Q = 1;
SUM_W = Q; for (int i = PATHFINDING; i < NONE; ++i) { if ( ((*Hero).Skill[i] >= MinLevel) && ((*Hero).Skill[i] < MaxLevel) && (i != LeftSkill) ) if ( (!(*Weights).SR[i]) && ((*Weights).SW[i]) ) SUM_W -= (*Weights).SW[i]; else if ( (*Hero).Skill[i] > 0 ) --SUM_W; if ( SUM_W <= 0 ) return (BYTE)i; } }
return NONE; }
int LevelUp(void *HeroRecord, const void *WeightsRecord, void *SkillOfferRecord, const BYTE Option) { THero *Hero; TWeights *Weights; TSkillOffer *SkillOffer;
Hero = (THero *)HeroRecord; Weights = (TWeights *)WeightsRecord; SkillOffer = (TSkillOffer *)SkillOfferRecord; BYTE Level = (*Hero).Level; BYTE Slot = Option & 3;
Slot ? Level = ++(*Hero).Level : ++Level; DWORD R = 0; int Q = Rand(0x343FD * Level + 0x26497 * (*Hero).TreeNumber + 0x259DF, R); ++(Q %= 100); // BB Campaign if ( Option & 4 ) { int SUM = (Level > 9) ? (*Weights).PW10[ATTACK] + (*Weights).PW10[DEFENSE] : (*Weights).PW[ATTACK] + (*Weights).PW[DEFENSE]; if ( SUM > 1 ) { Q = Rand(R, R); ++(Q %= SUM); } else Q = SUM; } // Primary Skills int Primary_ID = 0; int W; do { W = ( Level > 9 ) ? (*Weights).PW10[Primary_ID] : (*Weights).PW[Primary_ID]; if ( Q <= W ) break; Q -= W; ++Primary_ID; } while ( true ); (*SkillOffer).Primary = Primary_ID; if ( Slot ) ++*((BYTE *)HeroRecord + 5 + Primary_ID);
// Secondary Skills TSkillExcept SkillExcept = { (*Hero).LastWisdom, (*Hero).LastMagic, 6, 4 }; BYTE MinLevel = (*Hero).SkillCount > 7; if ( ((*Hero).Class & 0x11) == 1 ) SkillExcept.Delta_Wisdom = SkillExcept.Delta_Magic = 3; BYTE LeftSkill = GetSkillOffer(Hero, Weights, Level, &SkillExcept, BASIC, EXPERT, NONE, R); if ( LeftSkill == NONE ) LeftSkill = GetSkillOffer(Hero, Weights, Level, &SkillExcept, MinLevel, EXPERT, NONE, R);
if ( LeftSkill == WISDOM ) SkillExcept.Last_Wisdom = Level; if ( (LeftSkill >= FIRE_MAGIC) && (LeftSkill <= EARTH_MAGIC) ) SkillExcept.Last_Magic = Level;
BYTE RightSkill = GetSkillOffer(Hero, Weights, Level, &SkillExcept, MinLevel, BASIC, LeftSkill, R); if ( RightSkill == NONE ) RightSkill = GetSkillOffer(Hero, Weights, Level, &SkillExcept, MinLevel, EXPERT, LeftSkill, R);
if ( RightSkill == WISDOM ) SkillExcept.Last_Wisdom = Level; if ( (RightSkill >= FIRE_MAGIC) && (RightSkill <= EARTH_MAGIC) ) SkillExcept.Last_Magic = Level; (*SkillOffer).Secondary.Left = LeftSkill; (*SkillOffer).Secondary.Right = RightSkill; if ( Slot ) { (*Hero).LastWisdom = SkillExcept.Last_Wisdom; (*Hero).LastMagic = SkillExcept.Last_Magic; } else return 0;
BYTE Skill_ID = ( Slot == 1 ) ? LeftSkill : RightSkill;
if ( Skill_ID < NONE ) { if ( !(*Hero).Skill[Skill_ID] ) ++(*Hero).SkillCount; ++(*Hero).Skill[Skill_ID]; } return 0; }
А вот так можно потестить получившуюся DLL-ку: Test.h - Код: Выделить всё
#include <iostream> #include <windows.h>
using namespace std;
struct THero { BYTE Class; BYTE Level; BYTE TreeNumber; BYTE LastWisdom; BYTE LastMagic; BYTE Attack; BYTE Defense; BYTE SpellPower; BYTE Knowledge; BYTE SkillCount; BYTE Skill[28]; };
struct TWeights { BYTE PW[4]; BYTE PW10[4]; BYTE SW[28]; bool SR[28]; };
struct TSecondary { BYTE Left; BYTE Right; };
struct TSkillOffer { BYTE Primary; TSecondary Secondary; };
enum {ATTACK, DEFENSE, SPELL_POWER, KNOWLEDGE};
enum { PATHFINDING, ARCHERY, LOGISTICS, SCOUTING, DIPLOMACY, NAVIGATION, LEADERSHIP, WISDOM, MYSTICISM, LUCK, BALLISTICS, EAGLE_EYE, NECROMANCY, ESTATES, FIRE_MAGIC, AIR_MAGIC, WATER_MAGIC, EARTH_MAGIC, SCHOLAR, TACTICS, ARTILLERY, LEARNING, OFFENSE, ARMORER, INTELLIGENCE, SORCERY, RESISTANCE, FIRST_AID, NONE };
const char *PrimSkillName[4] = {"ATTACK", "DEFENSE", "SPELL_POWER", "KNOWLEDGE"};
const char *SecSkillName[29] = { "PATHFINDING", "ARCHERY", "LOGISTICS", "SCOUTING", "DIPLOMACY", "NAVIGATION", "LEADERSHIP", "WISDOM", "MYSTICISM", "LUCK", "BALLISTICS", "EAGLE_EYE", "NECROMANCY", "ESTATES", "FIRE_MAGIC", "AIR_MAGIC", "WATER_MAGIC", "EARTH_MAGIC", "SCHOLAR", "TACTICS", "ARTILLERY", "LEARNING", "OFFENSE", "ARMORER", "INTELLIGENCE", "SORCERY", "RESISTANCE", "FIRST_AID", "NONE" };
Test.cpp - Код: Выделить всё
#include "Test.h"
int main() { // Объявляем указатели на импортируемые функции. DWORD (*GetProcessID) (const wchar_t *Title); DWORD (*GetHStartPoint) (const HANDLE hProcess, const BYTE Version); int (*RAMHero) (const HANDLE hProcess, const DWORD HStartPoint, const BYTE ID, void *HeroRecord); int (*RAMWeights) (const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord); int (*LevelUp) (void *HeroRecord, const void *WeightsRecord, void *SkillOfferRecord, const BYTE Option); // Специальные функции для кампании "Рождение варвара" ("Birth of a Barbarian"). bool (*isStandardWeights) (const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE ID); int (*RAMBBWeights) (const HANDLE hProcess, const DWORD HStartPoint, const BYTE Version, const BYTE Class, void *WeightsRecord);
// Загружаем библиотеку и получаем адреса функций. HINSTANCE hDLL = LoadLibrary(L"LMOracle.SkillTreeAPI.dll"); if ( !hDLL ) return -1;
GetProcessID = (DWORD (*) (const wchar_t *)) GetProcAddress(hDLL, "GetProcessID"); GetHStartPoint = (DWORD (*) (const HANDLE, const BYTE)) GetProcAddress(hDLL, "GetHStartPoint"); RAMHero = (int (*) (const HANDLE, const DWORD, const BYTE, void *)) GetProcAddress(hDLL, "RAMHero"); RAMWeights = (int (*) (const HANDLE, const DWORD, const BYTE, const BYTE, void *)) GetProcAddress(hDLL, "RAMWeights"); LevelUp = (int (*) (void *, const void *, void *, const BYTE)) GetProcAddress(hDLL, "LevelUp"); isStandardWeights = (bool (*) (const HANDLE, const DWORD, const BYTE, const BYTE)) GetProcAddress(hDLL, "isStandardWeights"); RAMBBWeights = (int (*) (const HANDLE, const DWORD, const BYTE, const BYTE, void *)) GetProcAddress(hDLL, "RAMBBWeights");
// Получаем PID и открываем процесс для чтения. DWORD ProcessID = GetProcessID(L"Heroes of Might and Magic III"); HANDLE hProcess = OpenProcess(PROCESS_VM_READ, false, ProcessID);
// Определяем адрес в памяти процесса, по которому хранятся структуры героев: GetHStartPoint(<хендл процесса>, <версия игры>), где // <версия игры> = 0 для 4.0 RU, // <версия игры> = 1 для 4.0 EN, // <версия игры> = 2 для 3.2 EN, // <версия игры> = 3 для Heroes Chronicles 1.0 RU. DWORD HStartPoint = GetHStartPoint(hProcess, 2); // Объявляем экземпляры структур THero, TWeights и TSkillOffer. THero Hero; TWeights Weights; TSkillOffer SkillOffer; // Вводим идентификатор героя ID и количество уровней MaxLevel, на которое будем прокачивать героя. int ID, MaxLevel, Slot; cout << "Enter ID and MaxLevel: "; cin >> ID >> MaxLevel; cout << endl;
// Читаем данные из структуры героя с идентификатором ID. RAMHero(hProcess, HStartPoint, ID, &Hero); // Читаем веса первичных и вторичных навыков для класса, к которому принадлежит герой Hero, // с учётом особенностей прокачки Йога в кампании "Рождение варвара" ("Birth of a Barbarian"). // Для этого определим флаг BBFlag, который будет равен 0 для стандартной прокачки и 4 - для исключения BYTE BBFlag = isStandardWeights(hProcess, HStartPoint, 2, ID) ? 0 : 4; BBFlag ? RAMBBWeights(hProcess, HStartPoint, 2, Hero.Class, &Weights) : RAMWeights(hProcess, HStartPoint, 2, Hero.Class, &Weights); // Тестируем for (int i = 0; i < MaxLevel; ++i) { // Option = 000b = 0 - получить SkillOffer, не повышая уровень героя Hero; // Option = 001b = 1 - получить SkillOffer и повысить уровень героя Hero, выбрав навык из левого слота; // Option = 010b = 2 - получить SkillOffer и повысить уровень героя Hero, выбрав навык из правого слота; // Option = 1xxb - получить SkillOffer c учётом особенностей кампании "Рождение варвара" ("Birth of a Barbarian"), // где xx = 00, 01 или 10 (см. выше). // Пример. // Option = 110b = 6 - получить SkillOffer c учётом особенностей кампании "Рождение варвара" ("Birth of a Barbarian") // и повысить уровень героя Hero, выбрав навык из правого слота. LevelUp(&Hero, &Weights, &SkillOffer, BBFlag); // Option = 000b OR BBFlag
// Выводим предлагаемые при повышении уровня навыки cout << "SkillOffer = [" << PrimSkillName[SkillOffer.Primary] << ", [" << SecSkillName[SkillOffer.Secondary.Left] << ", " << SecSkillName[SkillOffer.Secondary.Right] << "]]" << endl << endl;
// Выбираем навык: 1 - левый, 2 - правый cout << "Slot = "; cin >> Slot; cout << endl;
LevelUp(&Hero, &Weights, &SkillOffer, Slot | BBFlag); // Option = Slot OR BBFlag // Наблюдаем за изменениями характеристик героя. cout << "Level = " << (int)Hero.Level << endl << "LastWisdom = " << (int)Hero.LastWisdom << endl << "LastMagic = " << (int)Hero.LastMagic << endl << "Primary = " << (int)Hero.Attack << " " << (int)Hero.Defense << " " << (int)Hero.SpellPower << " " << (int)Hero.Knowledge << endl << endl; cout << "SkillCount = " << (int)Hero.SkillCount << endl << "Secondary = "; for (int i = PATHFINDING; i < NONE; ++i) cout << (int)Hero.Skill[i] << " "; cout << endl << endl; system("Pause"); cout << endl; } // Закрываем хендл, выгружаем библиотеку и выходим. CloseHandle(hProcess); FreeLibrary(hDLL); return 0; }
|