Skip to content

Commit

Permalink
Added AutoTinker
Browse files Browse the repository at this point in the history
  • Loading branch information
nooperation committed Apr 26, 2021
1 parent 9b05f83 commit 8bd960d
Show file tree
Hide file tree
Showing 7 changed files with 654 additions and 0 deletions.
7 changes: 7 additions & 0 deletions D2Hackit/D2Hackit/D2hackit.sln
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoAncientScroll", "..\Mod
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutoOre", "..\Modules\autoOre\AutoOre.vcxproj", "{832CCF50-B3EA-4201-9FFF-90C6FD82FF3A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoTinker", "..\Modules\autoTinker\autoTinker.vcxproj", "{117F3113-ACE4-4FC4-BF9E-80FE8827BB69}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Expand Down Expand Up @@ -163,6 +165,10 @@ Global
{832CCF50-B3EA-4201-9FFF-90C6FD82FF3A}.Debug|Win32.Build.0 = Debug|Win32
{832CCF50-B3EA-4201-9FFF-90C6FD82FF3A}.Release|Win32.ActiveCfg = Release|Win32
{832CCF50-B3EA-4201-9FFF-90C6FD82FF3A}.Release|Win32.Build.0 = Release|Win32
{117F3113-ACE4-4FC4-BF9E-80FE8827BB69}.Debug|Win32.ActiveCfg = Debug|Win32
{117F3113-ACE4-4FC4-BF9E-80FE8827BB69}.Debug|Win32.Build.0 = Debug|Win32
{117F3113-ACE4-4FC4-BF9E-80FE8827BB69}.Release|Win32.ActiveCfg = Release|Win32
{117F3113-ACE4-4FC4-BF9E-80FE8827BB69}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -193,6 +199,7 @@ Global
{D92FD3C9-082F-4DFB-B414-3538D1F9DE28} = {B633F61A-62D5-4159-BA82-8C17FFE77E9C}
{FF4D7C7F-7217-4447-F996-98DBF93EF41C} = {B633F61A-62D5-4159-BA82-8C17FFE77E9C}
{832CCF50-B3EA-4201-9FFF-90C6FD82FF3A} = {B633F61A-62D5-4159-BA82-8C17FFE77E9C}
{117F3113-ACE4-4FC4-BF9E-80FE8827BB69} = {B633F61A-62D5-4159-BA82-8C17FFE77E9C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7DAE5C20-C224-4A1A-8147-796AF2BFCA24}
Expand Down
14 changes: 14 additions & 0 deletions D2Hackit/Modules/autoTinker/Resources/autoTinker.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
1 hrt ÿc1Heart
1 sol ÿc3Soul
1 fng ÿc5Fang
1 hrn ÿc:Horn
1 spe ÿc;Spleen
1 tal ÿc8Tail
2 jaw ÿc7Jawbone
1 scz ÿc:Scalp
1 qll ÿc5Quill
1 00g Griswold's Hand
1 00t Treehead WoodFist's Arm
1 00r Radament's Head
1 00h Hephasto's Hand
2 xt7 ÿc1Enigmatic Cinnabar
327 changes: 327 additions & 0 deletions D2Hackit/Modules/autoTinker/autoTinker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,327 @@
#include "../../Includes/D2Client.h"
#include "AutoTinker.h"
#include <string>
#include <sstream>
#include <fstream>

AutoTinker::AutoTinker()
{
currentState = State::Uninitialized;
}

void AutoTinker::SetState(State newState)
{
if (false)
{
const char * const stateNames[] = {
"Uninitialized",
"PickupOrganFromInventory",
"DropOrganToCube",
"TransmuteTargetAndOrgan"
};
server->GameStringf("ÿc:AutoTinkerÿc0: State %s -> %s", stateNames[(int)this->currentState], stateNames[(int)newState]);
}

this->currentState = newState;
}

bool AutoTinker::Start()
{
ReadRecipes(".//plugin//autoTinker.txt");

// Clear previous settings
this->itemWaitingOn = 0;
this->itemsBeingMovedToCube.clear();

// Notify the user about the current settings
server->GameStringf("ÿc:AutoTinkerÿc0: Starting");

// Open the player's cube
if (!OpenCube())
{
Abort();
return false;
}

if (IsCubeEmpty())
{
server->GameStringf("ÿc:AutoTinkerÿc0: Please place an item in your cube that you want to tinker");
Abort();
return false;
}

FindRecipe();

return true;
}

bool AutoTinker::ReadRecipes(const std::string &fileName)
{
this->requiredOrganCounts.clear();

std::ifstream inFile(fileName.c_str());
if (!inFile)
{
return false;
}

while (inFile.good())
{
std::string readBuff;
std::getline(inFile, readBuff);

if (readBuff.length() <= 0)
{
continue;
}

if (!isdigit(readBuff[0]))
{
continue;
}

int itemCount;
std::string itemCode;

std::stringstream ss(readBuff);
ss >> itemCount >> itemCode;

this->requiredOrganCounts[itemCode] = itemCount;
}

inFile.close();
return true;
}

void AutoTinker::FindRecipe()
{
this->organsIdsByType.clear();
this->itemsBeingMovedToCube.clear();

me->EnumStorageItems(STORAGE_INVENTORY, enumItemProc, (LPARAM)this);

if (this->organsIdsByType.empty())
{
Abort();
return;
}

for (auto &item : this->organsIdsByType)
{
const auto requiredAmountIter = this->requiredOrganCounts.find(item.first);
if (requiredAmountIter == this->requiredOrganCounts.end())
{
continue;
}

if (item.second.size() >= requiredAmountIter->second)
{
for (auto i = 0; i < requiredAmountIter->second; ++i)
{
const auto organId = item.second.back();
item.second.pop_back();

this->itemsBeingMovedToCube.push_back(organId);
}

PickupOrganFromInventory();
return;
}
}

// No more valid organs/recpies were found
Abort();
}

void AutoTinker::PickupOrganFromInventory()
{
if (this->itemsBeingMovedToCube.empty())
{
server->GameStringf("ÿc:AutoTinkerÿc0: No more organs to move");
Abort();
return;
}

this->itemWaitingOn = itemsBeingMovedToCube.back();
this->itemsBeingMovedToCube.pop_back();

SetState(State::PickupOrganFromInventory);
if (!me->PickStorageItemToCursor(itemWaitingOn))
{
server->GameStringf("ÿc:AutoTinkerÿc0: Failed to pick up organ");

Abort();
return;
}
}

void AutoTinker::DropOrganToCube()
{
if (me->GetCursorItem() != this->itemWaitingOn)
{
server->GameStringf("ÿc:AutoTinkerÿc0: DropOrganToCube - Unknown cursor item. Expected the organ");
return;
}

SetState(State::DropOrganToCube);
if(!me->DropCursorItemToStorage(STORAGE_CUBE))
{
server->GameStringf("ÿc:AutoTinkerÿc0: Failed to drop the organ");

Abort();
return;
}
}

void AutoTinker::TransmuteTargetAndOrgan()
{
// TODO: Check cube items for organs ?
SetState(State::TransmuteTargetAndOrgan);
if(!me->Transmute())
{
server->GameStringf("ÿc:AutoTinkerÿc0: Failed to transmute");

Abort();
return;
}
}


/// <summary>
/// Called whenever an item is pickedup to the cursor from the player's inventory
/// </summary>
/// <param name="item">Item picked up from the player's inventory.</param>
void AutoTinker::OnItemFromInventory(const ITEM &item)
{
if (this->currentState == State::Uninitialized)
{
return;
}

const auto itemCode = std::string_view(item.szItemCode);

if (this->currentState == State::PickupOrganFromInventory)
{
if (!this->IsOrgan(itemCode))
{
server->GameStringf("ÿc:AutoTinkerÿc0: I was expecting to pickup an organ, but got a %s instead", itemCode.data());
return;
}

this->DropOrganToCube();
return;
}
}

/// <summary>
/// Called whenever an item is moved to the cube
/// </summary>
/// <param name="item">The item that was moved to the cube.</param>
void AutoTinker::OnItemToCube(const ITEM &item)
{
if (this->currentState == State::Uninitialized)
{
return;
}

const auto itemCode = std::string_view(item.szItemCode);

if (this->currentState == State::DropOrganToCube)
{
if (!IsOrgan(itemCode))
{
server->GameStringf("ÿc:AutoTinkerÿc0: Cube was expecting an organ, but got a %s instead", itemCode.data());
return;
}

if (this->itemsBeingMovedToCube.empty())
{
TransmuteTargetAndOrgan();
}
else
{
PickupOrganFromInventory();
}
return;
}
else if (currentState == State::TransmuteTargetAndOrgan)
{
FindRecipe();
return;
}
}

bool AutoTinker::OpenCube()
{
if (!me->OpenCube())
{
server->GameStringf("ÿc:AutoTinkerÿc0: You must open your cube before using");

Abort();
return false;
}

return true;
}

bool AutoTinker::CheckCubeUI()
{
if (!me->IsUIOpened(UI_CUBE))
{
server->GameStringf("ÿc:AutoTinkerÿc0: Cube UI closed, aborting");
Abort();
}

return true;
}

void AutoTinker::Abort()
{
if (currentState != State::Uninitialized)
{
server->GameStringf("ÿc:AutoTinkerÿc0: Done");
SetState(State::Uninitialized);
}
}

bool AutoTinker::IsCubeEmpty()
{
int itemCount = 0;
me->EnumStorageItems(STORAGE_CUBE, enumItemCountProc, (LPARAM)&itemCount);

if (itemCount != 0)
{
return false;
}

return true;
}

bool AutoTinker::IsOrgan(const std::string_view &itemCode) const
{
return this->requiredOrganCounts.find(itemCode.data()) != this->requiredOrganCounts.end();
}

void AutoTinker::ProcessInventoryItem(const ITEM *item)
{
if (IsOrgan(item->szItemCode))
{
this->organsIdsByType[item->szItemCode].push_back(item->dwItemID);
}
}

BOOL CALLBACK enumItemProc(LPCITEM item, LPARAM lParam)
{
auto autoStocker = (AutoTinker *)lParam;
autoStocker->ProcessInventoryItem(item);

return TRUE;
}

BOOL CALLBACK enumItemCountProc(LPCITEM item, LPARAM lParam)
{
auto pItemCount = (int *)lParam;
(*pItemCount)++;

return TRUE;
}
Loading

0 comments on commit 8bd960d

Please sign in to comment.