Latest stable.

This commit is contained in:
Hash Borgir 2024-05-05 10:41:26 -06:00
parent 6141cc0a7b
commit 3a7be104d9
8 changed files with 233 additions and 74 deletions

View File

@ -243,6 +243,10 @@ namespace d2_tweaks {
bool removeFromBag;
int prop;
int val;
int tmog;
int x;
int y;
item_move_cs() : item_guid(0), target_page(0) {
message_type = MESSAGE_TYPE_ITEM_MOVE;

View File

@ -1046,5 +1046,10 @@ namespace diablo2 {
//D2Common.0x6FD57720 (#10602)
//int __stdcall DATATBLS_GetItemIdFromItemCode(uint32_t dwCode)
static int get_item_id_from_item_code(uint32_t dwCode);
//D2Common.0x6FD576D0 (#10601)
// D2ItemsTxt* __stdcall DATATBLS_GetItemRecordFromItemCode(uint32_t dwCode, int* pItemId)
static structures::items_line* get_item_record_from_item_code(uint32_t dwCode, int* pItemId);
};
}

View File

@ -49,8 +49,10 @@ namespace diablo2 {
static uint32_t __fastcall diablo2::d2_game::transmogrify(diablo2::structures::game* game, diablo2::structures::unit* player);
//D2Game.0x6FC4ED80
structures::unit* __fastcall D2GAME_CreateItemEx_6FC4ED80(structures::game* pGame, structures::D2ItemDropStrc* pItemDrop, int32_t a3);
static structures::unit* __fastcall D2GAME_CreateItemEx_6FC4ED80(structures::game* pGame, structures::D2ItemDropStrc* pItemDrop, int32_t a3);
//D2Game.0x6FC4A660
static int32_t __fastcall D2GAME_Transmogrify_6FC4A660(structures::game* pGame, structures::unit* pPlayer, structures::unit* pItem);
static int32_t __fastcall D2GAME_Transmogrify_6FC4A660(structures::game* pGame, structures::unit* pUnit, structures::unit* pItem);
};
}

View File

@ -89,6 +89,12 @@ namespace diablo2 {
};
};
struct D2CoordStrc //sizeof 0x08
{
int nX; //0x00
int nY; //0x04
};
struct D2ItemDropStrc
{
diablo2::structures::unit* pUnit; //0x00

View File

@ -26,6 +26,20 @@
#include <iomanip> // For std::setw
enum D2C_ItemQualities
{
ITEMQUAL_INFERIOR = 0x01, //0x01 Inferior
ITEMQUAL_NORMAL = 0x02, //0x02 Normal
ITEMQUAL_SUPERIOR = 0x03, //0x03 Superior
ITEMQUAL_MAGIC = 0x04, //0x04 Magic
ITEMQUAL_SET = 0x05, //0x05 Set
ITEMQUAL_RARE = 0x06, //0x06 Rare
ITEMQUAL_UNIQUE = 0x07, //0x07 Unique
ITEMQUAL_CRAFT = 0x08, //0x08 Crafted
ITEMQUAL_TEMPERED = 0x09 //0x09 Tempered
};
void serialize_item(const std::string& itemcode, const diablo2::structures::unit& item, std::ofstream& file) {
// Write item code
file << itemcode << ":";
@ -72,69 +86,98 @@ bool d2_tweaks::server::modules::item_move::handle_packet(diablo2::structures::g
const char* itemcode = itemMove->item_code;
const auto bag = instance.get_server_unit(game, itemMove->bag_guid, diablo2::structures::unit_type_t::UNIT_TYPE_ITEM); //0x4 = item
D2PropertyStrc itemProperty = {};
itemProperty.nProperty = itemMove->prop;
itemProperty.nLayer = 0;
itemProperty.nMin = itemMove->val;
itemProperty.nMax = itemMove->val;
diablo2::d2_common::add_property(bag, &itemProperty, 1);
if (item == nullptr)
return true; //block further packet processing
const auto inventoryIndex = diablo2::d2_common::get_inventory_index(player, itemMove->target_page, game->item_format == 101);
uint32_t tx, ty;
if (!find_free_space(player->inventory, item, inventoryIndex, itemMove->target_page, tx, ty))
return true; //block further packet processing
//diablo2::d2_common::set_unit_mode(item, 0); // mode 4 - ïðåäìåò íåëüçÿ âçÿòü ìûøêîé èç èíâåíòàðÿ, mode 0 - îáû÷íûé ðåæèì
item->item_data->page = itemMove->target_page;
diablo2::d2_common::inv_add_item(player->inventory, item, tx, ty, inventoryIndex, false, item->item_data->page);
diablo2::d2_common::inv_update_item(player->inventory, item, false);
diablo2::d2_game::update_inventory_items(game, player);
//send update packet
resp.item_guid = itemMove->item_guid;
resp.target_page = itemMove->target_page;
resp.tx = tx;
resp.ty = ty;
const auto client = player->player_data->net_client;
diablo2::d2_net::send_to_client(1, client->client_id, &resp, sizeof resp);
if (itemMove->removeFromBag == 1) {
if (itemMove->tmog == 1) {
// here we need to add item to inventory
diablo2::structures::unit* item;
const auto item = instance.get_server_unit(game, itemMove->item_guid, diablo2::structures::unit_type_t::UNIT_TYPE_ITEM); //0x4 = item
// or I can do something like this,
// when extractor is clicked, send the bag and extractor to cube,
diablo2::d2_game::D2GAME_Transmogrify_6FC4A660(game, player, item);
//auto gemCode = diablo2::d2_common::get_item_id_from_item_code(' vfg');
//diablo2::structures::D2ItemDropStrc itemDrop = {};
//diablo2::structures::D2CoordStrc pReturnCoords = {};
//auto player = diablo2::d2_client::get_local_player();
//itemDrop.pSeed = nullptr;
//itemDrop.nX = pReturnCoords.nX;
//itemDrop.nY = pReturnCoords.nY;
//itemDrop.wItemFormat = game->item_format;
//itemDrop.pRoom = 0;
//itemDrop.nQuality = ITEMQUAL_NORMAL;
//itemDrop.pUnit = player;
//itemDrop.pGame = game;
//itemDrop.nId = gemCode;
//itemDrop.nSpawnType = 4;
//itemDrop.wUnitInitFlags = 1;
//itemDrop.nItemLvl = 1;
//diablo2::structures::unit* nItem = diablo2::d2_game::D2GAME_CreateItemEx_6FC4ED80(game, &itemDrop, 0);
//Display nITem->guid in a messagebox
//std::string guid = std::to_string(nItem->guid);
//MessageBox(NULL, guid.c_str(), "Item GUID", MB_OK | MB_ICONINFORMATION);
//const auto inventoryIndex = diablo2::d2_common::get_inventory_index(player, 0, game->item_format == 101);
//uint32_t tx, ty;
//if (!find_free_space(player->inventory, nItem, inventoryIndex, 0, tx, ty))
// return true; //block further packet processing
//
//nItem->item_data->page = 0;
//diablo2::d2_common::inv_add_item(player->inventory, nItem, tx, ty, inventoryIndex, false, nItem->item_data->page);
//diablo2::d2_common::inv_update_item(player->inventory, nItem, false);
//diablo2::d2_game::update_inventory_items(game, player);
////send update packet
//resp.item_guid = nItem->guid;
//resp.target_page = 0;
//resp.tx = tx;
//resp.ty = ty;
//const auto client = player->player_data->net_client;
//diablo2::d2_net::send_to_client(1, client->client_id, &resp, sizeof resp);
const auto player = diablo2::d2_client::get_local_player();
}
else {
D2PropertyStrc itemProperty = {};
itemProperty.nProperty = itemMove->prop;
itemProperty.nLayer = 0;
itemProperty.nMin = itemMove->val;
itemProperty.nMax = itemMove->val;
diablo2::d2_common::add_property(bag, &itemProperty, 1);
if (itemMove->updateBag == 1) {
// Serialize item data into binary file
std::string playerName = player->player_data->name;
std::string fileName = "./Save/" + playerName + ".boh";
// Open file in append mode
std::ofstream outFile(fileName, std::ios::binary | std::ios::app);
if (!outFile) {
std::cerr << "Error opening file: " << fileName << std::endl;
return false;
}
if (item == nullptr)
return true; //block further packet processing
serialize_item(itemcode, *item, outFile);
outFile.close();
const auto inventoryIndex = diablo2::d2_common::get_inventory_index(player, itemMove->target_page, game->item_format == 101);
uint32_t tx, ty;
if (!find_free_space(player->inventory, item, inventoryIndex, itemMove->target_page, tx, ty))
return true; //block further packet processing
//diablo2::d2_common::set_unit_mode(item, 0); // mode 4 - ïðåäìåò íåëüçÿ âçÿòü ìûøêîé èç èíâåíòàðÿ, mode 0 - îáû÷íûé ðåæèì
item->item_data->page = itemMove->target_page;
diablo2::d2_common::inv_add_item(player->inventory, item, tx, ty, inventoryIndex, false, item->item_data->page);
diablo2::d2_common::inv_update_item(player->inventory, item, false);
diablo2::d2_game::update_inventory_items(game, player);
//send update packet
resp.item_guid = itemMove->item_guid;
resp.target_page = itemMove->target_page;
resp.tx = tx;
resp.ty = ty;
const auto client = player->player_data->net_client;
diablo2::d2_net::send_to_client(1, client->client_id, &resp, sizeof resp);
return true;
}
return true;
}
bool d2_tweaks::server::modules::item_move::find_free_space(diablo2::structures::inventory* inv,

View File

@ -150,7 +150,29 @@ const char* ITEMS_armor_and_weapons[] = {
"pa8", "pa9", "paa", "ne6", "ne7", "ne8", "ne9", "nea", "drb", "drc",
"drd", "dre", "drf", "bab", "bac", "bad", "bae", "baf", "pab", "pac",
"pad", "pae", "paf", "neb", "neg", "ned", "nee", "nef", "tor", "ooc",
"eaq", "ebq", "ib1", "ib3"
"eaq", "ebq", "ib1", "ib3",
// stones
"abc", "abd", "abe", "abf", "abg", "abh", "abi", "abj", "abk", "abl",
"abm", "abn", "abo", "abp", "abq", "abr", "abs", "abt", "abu", "abv",
"abw", "abx", "aby", "abz", "ab0", "ab1", "ab2", "ab3", "ab4", "ab5",
"ab6", "ab7", "ab8", "ab9", "acb", "acd", "ace", "acf", "acg", "ach",
"aci", "acj", "ack", "acl", "acm", "acn", "aco", "acp", "acq", "acr",
"acs", "act", "acu", "acv", "acw", "acx", "acy", "acz", "ac0", "ac1",
"ac2", "ac3", "ac4", "ac5", "ac6", "ac7", "ac8", "ac9", "adb", "adc",
"ade", "adf", "adg", "adh", "adi", "adj", "adk", "adl", "adm", "adn",
"ado", "adp", "adq", "adr", "ads", "adt", "adu", "adv", "adw", "adx",
"ady", "adz", "ad0", "ad1", "ad2", "ad3", "ad4", "ad5", "ad6", "ad7",
"ad8", "ad9", "aeb", "aec", "aed", "aef", "aeg", "aeh", "aei", "aej",
"aek", "ael", "aem", "aen", "aeo", "aep", "aeq", "aer", "aes", "aet",
"aeu", "aev", "aew", "aex", "aey", "aez", "ae0", "ae1", "ae2", "ae3",
"ae4", "ae5", "ae6",
// demon keys/chests
"dkr1", "dkr2", "dkr3", "dkr4", "dkr5", "da1", "db1", "dc1"
// crafting items
"afr", "afy", "afp", "af0", "afx", "afh", "afq", "afj", "aft", "afi",
"afe", "afg", "afk", "ae7", "afn", "ae8", "afl", "ae9", "afv", "afz",
"af3", "af1", "afm", "af5", "afc", "afo", "afw", "afs", "af2", "afd",
"afb", "af4", "afu"
};
const char* ITEMS_gems_and_runes[] = {
@ -160,7 +182,8 @@ const char* ITEMS_gems_and_runes[] = {
"gpg", "gpr", "gpb", "skz", "gpy", "ib1", "r01", "r02", "r03", "r04",
"r05", "r06", "r07", "r08", "r09", "r10", "r11", "r12", "r13", "r14",
"r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24",
"r25", "r26", "r27", "r28", "r29", "r30", "r31", "r32", "r33", "ib2"
"r25", "r26", "r27", "r28", "r29", "r30", "r31", "r32", "r33", "ib2",
};
// Define a structure named GemType
@ -490,7 +513,6 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
case WM_RBUTTONDOWN:
{
// Get the local player object from the Diablo 2 client
const auto player = diablo2::d2_client::get_local_player();
@ -566,7 +588,9 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
// Declare a pointer to store the string key
const char* key;
// Check if the current page is the stash or inventory
// Check if the current page is the stash or inventory, right click on gem/rune will
// add it to the cube and send it to page 99 which is non existent
// (hope it doesn't bloat save file size and actualy disappears from memory)
if (currentPage == 0 || currentPage == 4) {
// Check if the stash or inventory window is open
if (diablo2::d2_client::get_ui_window_state(diablo2::UI_WINDOW_STASH) ||
@ -610,7 +634,8 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
}
}
// Check if the cube window is open and the current page is 3
// Check if the cube window is open and the current page is 3 (gen/rune is in cube)
// move the item back to inventory
else if (diablo2::d2_client::get_ui_window_state(diablo2::UI_WINDOW_CUBE) && currentPage == 3) {
// Iterate through each gem type in the gemTypes map
for (const auto& gem : gemTypes) {
@ -636,7 +661,8 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
}
}
// Check if the cube window is open and the current page is 0
// Check if the cube window is open and the current page is 0 (gem/rune is in inventory)
// on right click add it to the gembag and send the original gem/rune to page 99
else if (diablo2::d2_client::get_ui_window_state(diablo2::UI_WINDOW_CUBE) && currentPage == 0) {
// Iterate through each gem type in the gemTypes map
for (const auto& gem : gemTypes) {
@ -679,6 +705,7 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
}
// For gem/rune extractors, on right click, move the bag and extractor to the cube, send transmute packet
// Check if the current page is the inventory, cube, or stash
if (currentPage == 0 || currentPage == 3 || currentPage == 4) {
// Check if the stash, cube, or inventory window is open
@ -737,7 +764,7 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
}
// Move items from the cube to the inventory
// Move gems/runes from the cube to the inventory
if (isGemOrRuneCode(normCode)) {
// Get the local player object
const auto player = diablo2::d2_client::get_local_player();
@ -768,7 +795,10 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
}
if (isArmorOrWeaponCode(normCode)
// For armor and weapon codes, right click will move the item to the stash or cube and transmute
if (isArmorOrWeaponCode(normCode)
|| record->type == 61 - 3 // jewel
|| record->type == 43 - 3 // key
|| record->type == 109
|| record->type == 111
|| record->type == 112
@ -777,7 +807,10 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
|| record->type == 113
|| record->type == 122
|| record->type == 123
|| record->type == 123 - 3 // sum0
|| record->type == 125
|| record->type == 126 - 3
|| record->type == 128 - 3
|| record->type == 4 - 3
|| record->type == 5 - 3
|| record->type == 17 - 3
@ -815,7 +848,7 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
diablo2::d2_client::send_to_server(&packet, sizeof packet);
// Send a packet to activate the transmute button in the cube
diablo2::d2_client::send_to_server_7(0x4F, 0x18, 0, 0);
// diablo2::d2_client::send_to_server_7(0x4F, 0x18, 0, 0);
// Clear the hovered item after processing
(*reinterpret_cast<diablo2::structures::unit**>(diablo2::d2_client::get_base() + 0x1158F4)) = nullptr;
@ -826,8 +859,6 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
break;
}
case WM_RBUTTONUP:
{
block = instance.process_right_mouse(true);
@ -838,17 +869,69 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
case WM_MOUSEWHEEL:
{
// Extract the distance the wheel is rotated from the message
short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
short zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
// Check if the wheel is scrolled upwards
if (zDelta > 0) {
// Process the mouse wheel input by scrolling upwards
// Calculate the memory address of the hover item in the game
// by adding an offset to the base address of the client
const auto g_hoverItem = *reinterpret_cast<diablo2::structures::unit**>(diablo2::d2_client::get_base() + 0x1158F4);
// Get the local player object from the Diablo 2 client
const auto player = diablo2::d2_client::get_local_player();
// Obtain a pointer to the player's inventory
auto pInventory = player->inventory;
if (g_hoverItem != nullptr) {
// Obtain the item record associated with the hovered item
const auto record = diablo2::d2_common::get_item_record(g_hoverItem->data_record_index);
// Extract the string code of the item record
char* normCode = record->string_code;
// Create the packet
static d2_tweaks::common::item_move_cs packet;
packet.item_guid = g_hoverItem->guid;
packet.target_page = 0;
packet.tmog = 1;
packet.item_code = normCode;
diablo2::d2_client::send_to_server(&packet, sizeof packet);
}
block = instance.process_mouse_wheel(true);
}
// Check if the wheel is scrolled downwards
else if (zDelta < 0) {
// Process the mouse wheel input by scrolling downwards
block = instance.process_mouse_wheel(false);
// Calculate the memory address of the hover item in the game
// by adding an offset to the base address of the client
const auto g_hoverItem = *reinterpret_cast<diablo2::structures::unit**>(diablo2::d2_client::get_base() + 0x1158F4);
// Get the local player object from the Diablo 2 client
const auto player = diablo2::d2_client::get_local_player();
// Obtain a pointer to the player's inventory
auto pInventory = player->inventory;
if (g_hoverItem != nullptr) {
// Obtain the item record associated with the hovered item
const auto record = diablo2::d2_common::get_item_record(g_hoverItem->data_record_index);
// Extract the string code of the item record
char* normCode = record->string_code;
// Create the packet
static d2_tweaks::common::item_move_cs packet;
packet.item_guid = g_hoverItem->guid;
packet.target_page = 0;
packet.tmog = 1;
packet.item_code = normCode;
diablo2::d2_client::send_to_server(&packet, sizeof packet);
}
block = instance.process_mouse_wheel(true);
}
break;
}
@ -928,6 +1011,8 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
}
if (isArmorOrWeaponCode(normCode)
|| record->type == 61 - 3 // jewel
|| record->type == 43 - 3 // key
|| record->type == 109
|| record->type == 111
|| record->type == 112
@ -936,7 +1021,10 @@ LRESULT d2_tweaks::ui::ui_manager::wnd_proc(HWND hWnd, UINT msg, WPARAM wParam,
|| record->type == 113
|| record->type == 122
|| record->type == 123
|| record->type == 123 - 3 // sum0
|| record->type == 125
|| record->type == 126 - 3
|| record->type == 128 - 3
|| record->type == 4 - 3
|| record->type == 5 - 3
|| record->type == 17 - 3

View File

@ -266,4 +266,11 @@ diablo2::structures::D2ItemStatCostTxt* diablo2::d2_common::get_item_stat_cost_r
int32_t diablo2::d2_common::get_item_id_from_item_code(uint32_t dwCode) {
static wrap_func_std_import<int32_t(uint32_t)> get_item_id_from_item_code(10602, get_base());
return get_item_id_from_item_code(dwCode);
}
//D2Common.0x6FD576D0 (#10601)
//D2ItemsTxt* __stdcall DATATBLS_GetItemRecordFromItemCode(uint32_t dwCode, int* pItemId)
diablo2::structures::items_line* diablo2::d2_common::get_item_record_from_item_code(uint32_t dwCode, int* pItemId) {
static wrap_func_std_import<diablo2::structures::items_line* (uint32_t, int*)> get_item_record_from_item_code(10601, get_base());
return get_item_record_from_item_code(dwCode, pItemId);
}

View File

@ -147,7 +147,11 @@ diablo2::structures::unit* __fastcall diablo2::d2_game::D2GAME_CreateItemEx_6FC4
// Add a wrapper for the following function:
//D2Game.0x6FC4A660
//int32_t __fastcall D2GAME_Transmogrify_6FC4A660(D2GameStrc* pGame, D2UnitStrc* pUnit, D2UnitStrc* pItem)
int32_t __fastcall diablo2::d2_game::D2GAME_Transmogrify_6FC4A660(diablo2::structures::game* pGame, diablo2::structures::unit* pUnit, diablo2::structures::unit* pItem) {
static wrap_func_fast<int32_t(diablo2::structures::game*, diablo2::structures::unit*, diablo2::structures::unit* item)> D2GAME_Transmogrify_6FC4A660(0x1a660, get_base());
return D2GAME_Transmogrify_6FC4A660(pGame, pUnit, pItem);
}
int32_t __fastcall diablo2::d2_game::D2GAME_Transmogrify_6FC4A660(diablo2::structures::game* pGame, diablo2::structures::unit* pPlayer, diablo2::structures::unit* pItem) {
static wrap_func_fast<int32_t(diablo2::structures::game*, diablo2::structures::unit*, diablo2::structures::unit*)> D2GAME_Transmogrify_6FC4A660(0x1a660, get_base());
return D2GAME_Transmogrify_6FC4A660(pGame, pPlayer, pItem);
}