Skip to content

Commit

Permalink
Merge pull request #3 from nooperation/better_ore_extraction
Browse files Browse the repository at this point in the history
Better ore extraction
  • Loading branch information
nooperation authored Apr 30, 2021
2 parents 18c002b + b5e0603 commit bdfce36
Show file tree
Hide file tree
Showing 19 changed files with 346 additions and 183 deletions.
160 changes: 118 additions & 42 deletions D2Hackit/Modules/autoExtractor/AutoExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,22 @@ bool AutoExtractor::Start(int itemCount, bool useChat)
/// <returns>true if success.</returns>
bool AutoExtractor::StartExtraction()
{
currentState = STATE_START;

if(!me->OpenCube())
{
if(useChat)
me->Say("ÿc:AutoExtractorÿc0: Cube not opened");
else
server->GameStringf("ÿc:AutoExtractorÿc0: Cube not opened");

Abort();
return false;
}

if(numberOfRunsRemaining-- <= 0)
{
currentState = STATE_COMPLETE;
Abort();
return true;
}

Expand All @@ -110,8 +113,12 @@ bool AutoExtractor::StartExtraction()
me->EnumStorageItems(STORAGE_CUBE, enumFindExtractors, (LPARAM)&extractors);
if (extractors.empty())
{
if (useChat)
me->Say("ÿc:AutoExtractorÿc0: Nothing found to extract");
else
server->GameStringf("ÿc:AutoExtractorÿc0: Nothing found to extract");

Abort();
server->GameStringf("ÿc:AutoExtractorÿc0: Nothing found to extract");
return true;
}

Expand All @@ -121,12 +128,59 @@ bool AutoExtractor::StartExtraction()
{
extractedItemIDs.pop();
}
itemsExpectedToCube = GetNumberOfExpectredOutputs();

auto expectedOutputSize = GetExpectedOutputSize();
if (expectedOutputSize.cx == 1 && expectedOutputSize.cy == 1)
{
itemsExpectedToCube = GetNumberOfExpectedOutputs();
if (itemsExpectedToCube > me->GetNumberOfFreeStorageSlots(STORAGE_INVENTORY))
{
if (useChat)
me->Say("ÿc:AutoExtractorÿc0: No more room");
else
server->GameStringf("ÿc:AutoExtractorÿc0: No more room");

Abort();
return true;
}
}
else
{
POINT buffer;

// Make sure our oddly shaped output will fit in our inventory
if (!me->FindFirstStorageSpace(STORAGE_INVENTORY, expectedOutputSize, &buffer))
{
if (useChat)
me->Say("ÿc:AutoExtractorÿc0: No more room");
else
server->GameStringf("ÿc:AutoExtractorÿc0: No more room");

Abort();
return true;
}

// Also make sure our extractors will too
itemsExpectedToCube = GetNumberOfExpectedOutputs() - 1; // exclude our oddly shaped item
if (itemsExpectedToCube > me->GetNumberOfFreeStorageSlots(STORAGE_INVENTORY))
{
if (useChat)
me->Say("ÿc:AutoExtractorÿc0: No more room");
else
server->GameStringf("ÿc:AutoExtractorÿc0: No more room");

Abort();
return true;
}
}

// Make sure we still have the cube open, slightly lessens the chance of being kicked if user closes
// it during the extraction process
if(!CheckCubeUI())
if (!CheckCubeUI())
{
Abort();
return false;
}

// 3000ms timeout
ticksTillTransmuteTimeout = 3 * (1000 / server->GetTickRate());
Expand All @@ -146,8 +200,8 @@ bool AutoExtractor::CheckCubeUI()
{
if(useChat)
me->Say("ÿc:AutoExtractorÿc0: Cube UI closed, aborting");

server->GameStringf("ÿc:AutoExtractorÿc0: Cube UI closed, aborting");
else
server->GameStringf("ÿc:AutoExtractorÿc0: Cube UI closed, aborting");

Abort();
return false;
Expand Down Expand Up @@ -323,40 +377,22 @@ void AutoExtractor::OnItemToInventory(const ITEM &item)
return;
}

// All of the extracted items are 1x1, so make sure we have room for it
SIZE itemSize = server->GetItemSize(item.szItemCode);;
POINT emptySpot = {0, 0};

bool foundSpot = false;

// We check 3 times to make sure there's room for the output + extractors (e.g: rare ring, key, rerolling orb).
// when calling FindFirstStorageSpaceEx, it checks starting right after the previously found spot
for(int i = 0; i < 3; i++)
{
if(!me->FindFirstStorageSpaceEx(STORAGE_INVENTORY, itemSize, &emptySpot, emptySpot))
{
if(useChat)
{
me->Say("ÿc:AutoExtractorÿc0: No more room");
}
else
{
server->GameStringf("ÿc:AutoExtractorÿc0: No more room");
}

Abort();
return;
}

// Increment the current inventory spot so next time we check for an empty spot it will be right
// after the previous one.
emptySpot.x++;
if(emptySpot.x >= INV_COL)
{
emptySpot.x = 0;
emptySpot.y++;
}
}
//// TODO: this assumes all extracted items are 1x1
//auto freeSpotsRemaining = me->GetNumberOfFreeStorageSlots(STORAGE_INVENTORY);
//if (GetNumberOfExpectredOutputs() > freeSpotsRemaining)
//{
// if (useChat)
// {
// me->Say("ÿc:AutoExtractorÿc0: No more room");
// }
// else
// {
// server->GameStringf("ÿc:AutoExtractorÿc0: No more room");
// }

// Abort();
// return;
//}

extractedItemIDs.pop();
if (!extractedItemIDs.empty())
Expand Down Expand Up @@ -398,7 +434,7 @@ void AutoExtractor::OnItemToCube(const ITEM &item)
{
// reset the expected item count back to the number of extractors we use plus 1 for the output
// (e.g: key + rerollingOrb + rare ring = 3 items expected)
itemsExpectedToCube = GetNumberOfExpectredOutputs();
itemsExpectedToCube = GetNumberOfExpectedOutputs();

if(!CheckCubeUI())
{
Expand All @@ -412,7 +448,16 @@ void AutoExtractor::OnItemToCube(const ITEM &item)
void AutoExtractor::PickupNextExtractedItem()
{
currentState = STATE_PICKUPEXTRACTEDITEM;

if (extractedItemIDs.empty())
{
// TODO: Figure out why this is happening... Possible feedback from other modules
StartExtraction();
return;
}

auto extractedItemId = extractedItemIDs.front();

if (!me->PickStorageItemToCursor(extractedItemId))
{
if (useChat)
Expand All @@ -425,7 +470,38 @@ void AutoExtractor::PickupNextExtractedItem()
}
}

int AutoExtractor::GetNumberOfExpectredOutputs() const
SIZE AutoExtractor::GetExpectedOutputSize() const
{
SIZE expectedSize = { 1,1 };

for (auto &item : this->extractors)
{
if (
item.itemCode == "t16" || // magic large charm -> magic large charm
item.itemCode == "t17" || // rare large charm -> magic large charm
item.itemCode == "t18" // rare large charm -> rare large charm
)
{
expectedSize.cy = 2;
return expectedSize;
}
else if (
item.itemCode == "t19" || // magic grand charm -> magic grand charm
item.itemCode == "t20" || // magic grand charm -> rare grand charm
item.itemCode == "t21" || // rare grand charm -> rare grand charm
item.itemCode == "t24" || // rare->rare arrow
item.itemCode == "t25" // rare->unique arrow
)
{
expectedSize.cy = 3;
return expectedSize;
}
}

return expectedSize;
}

int AutoExtractor::GetNumberOfExpectedOutputs() const
{
// Ore has a special case for determining number of outputs. See 'enumFindExtractors'
if (this->extractors.size() == 1 && this->extractors[0].itemCode == "ore")
Expand Down
4 changes: 3 additions & 1 deletion D2Hackit/Modules/autoExtractor/AutoExtractor.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
enum States
{
STATE_UNINITIALIZED = 0,
STATE_START,
STATE_COMPLETE,
STATE_TRANSMUTE,
STATE_PICKUPEXTRACTEDITEM,
Expand Down Expand Up @@ -44,7 +45,8 @@ class AutoExtractor
bool IsGoodSuffix(int suffixId);
bool IsItemAnExtractor(const ITEM &item);
bool ReadAffixFile(const std::string &configPath, std::unordered_set<int> &readTo);
int GetNumberOfExpectredOutputs() const;
int GetNumberOfExpectedOutputs() const;
SIZE GetExpectedOutputSize() const;
void PickupNextExtractedItem();

bool useChat;
Expand Down
62 changes: 54 additions & 8 deletions D2Hackit/Modules/autoOre/AutoOre.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,25 @@ AutoOre::AutoOre()

void AutoOre::SetState(State newState)
{
if (false)
{
const char *const stateNames[] = {
"Uninitialized",
"PickupNextItemToDrop",
"DropNextItemToDrop",
"PickupNextOre",
"DropNextOreToCube",
"WaitingToRunAutoExtractor",
"RunAutoExtractor",
"RunEmptyCube",
"RunAutoStocker",
};
server->GameStringf("ÿc:ÿc5AutoOreÿc0: State %s -> %s", stateNames[(int)this->currentState], stateNames[(int)newState]);
}

this->currentState = newState;
}

void AutoOre::Start()
{
this->itemsToDrop.clear();
Expand Down Expand Up @@ -40,10 +57,10 @@ void AutoOre::Start()
server->GameCommandLine("load emptycube");
}

StartAsAe();
StartAutoOre();
}

void AutoOre::StartAsAe()
void AutoOre::StartAutoOre()
{
if (!me->OpenCube())
{
Expand Down Expand Up @@ -84,7 +101,7 @@ void AutoOre::PickupNextItemToDrop()
if (this->itemsToDrop.empty())
{
server->GameStringf("ÿc:ÿc5AutoOreÿc0: No more items to drop");
this->StartAsAe();
this->StartAutoOre();
return;
}

Expand Down Expand Up @@ -157,7 +174,9 @@ void AutoOre::OnItemDroppedToCube(DWORD itemId)
return;
}

this->RunAutoExtractor();
// NOTE: We cannot run extractor yet. If we do then it will also see this item 'to cube' and
// will think it was part of its extraction process
SetState(State::WaitingToRunAutoExtractor);
}
}

Expand Down Expand Up @@ -185,10 +204,15 @@ void AutoOre::DropNextOreToCube()
me->DropCursorItemToStorage(STORAGE_CUBE);
}

void AutoOre::RunAutoExtractor()
void AutoOre::OnTick()
{
SetState(State::RunAutoExtractor);
server->GameCommandLine("ae start chat");
if (currentState == State::WaitingToRunAutoExtractor)
{
// HACK: AE must be delayed a full tick so the autoextract module does not process the item we
// just put in the cube as a transmute result
SetState(State::RunAutoExtractor);
server->GameCommandLine("ae start chat");
}
}

bool AutoOre::OnAutoExtractorMessage(const std::string_view &message)
Expand All @@ -199,9 +223,31 @@ bool AutoOre::OnAutoExtractorMessage(const std::string_view &message)
}

if (message == "AutoExtractor Ended")
{
this->RunEmptyCube();
}

return true;
}

void AutoOre::RunEmptyCube()
{
SetState(State::RunEmptyCube);
server->GameCommandLine("emptycube start chat");
}

bool AutoOre::OnEmptyCubeMessage(const std::string_view &message)
{
if (currentState != State::RunEmptyCube)
{
return false;
}

if (message == "EmptyCube Ended")
{
this->RunAutoStocker();
}

return true;
}

Expand All @@ -220,7 +266,7 @@ bool AutoOre::OnAutoStockerMessage(const std::string_view &message)

if (message == "Autostocker Ended")
{
StartAsAe();
StartAutoOre();
}
return true;
}
Expand Down
Loading

0 comments on commit bdfce36

Please sign in to comment.