diff --git a/D2Hackit/Modules/autoSell/Resources/AutoSell_items.txt b/D2Hackit/Modules/autoSell/Resources/AutoSell_items.txt
index a76f9d1..614f46f 100644
--- a/D2Hackit/Modules/autoSell/Resources/AutoSell_items.txt
+++ b/D2Hackit/Modules/autoSell/Resources/AutoSell_items.txt
@@ -1,3 +1 @@
fkn Fake Note
-po3 Mountain Dew
-po4 Nirvana Grass
\ No newline at end of file
diff --git a/D2Hackit/Modules/autoStocker/AutoStocker.cpp b/D2Hackit/Modules/autoStocker/AutoStocker.cpp
index a76ae64..e2bd29a 100644
--- a/D2Hackit/Modules/autoStocker/AutoStocker.cpp
+++ b/D2Hackit/Modules/autoStocker/AutoStocker.cpp
@@ -54,6 +54,9 @@ bool AutoStocker::Init(bool useChat)
IsTransmutingUnidentifiedSmallCharms = (GetPrivateProfileInt("Autostocker", "NonIDSmallCharms", 0, CONFIG_FILE) == 1);
IsTransmutingUnidentifiedLargeCharms = (GetPrivateProfileInt("Autostocker", "NonIDLargeCharms", 0, CONFIG_FILE) == 1);
IsTransmutingUnidentifiedGrandCharms = (GetPrivateProfileInt("Autostocker", "NonIDGrandCharms", 0, CONFIG_FILE) == 1);
+ IgnoreIdentifiedSetRingsAndAmulets = (GetPrivateProfileInt("Autostocker", "IgnoreIdentifiedSetRingsAndAmulets", 0, CONFIG_FILE) == 1);
+ MinPrefixCount = GetPrivateProfileInt("Autostocker", "PrefixCount", 0, CONFIG_FILE);
+ MinSuffixCount = GetPrivateProfileInt("Autostocker", "SuffixCount", 0, CONFIG_FILE);
return true;
}
@@ -800,6 +803,9 @@ bool AutoStocker::ReadAffixConfig(const std::string &configPath, std::unordered_
return true;
}
+#include "../../Includes/itemPrefix.h"
+#include "../../Includes/ItemSuffix.h"
+
///
/// Determines if this item has a good affix and should be kept
///
@@ -817,19 +823,60 @@ bool AutoStocker::CheckItemAffix(const ITEM &item)
if(goodPrefix.count(item.wPrefix[i]) > 0)
{
goodPrefixCount++;
- //server->GameStringf("�c;Prefix�c0 %s: %s", Prefix[item.wPrefix[i]], PrefixDetails[item.wPrefix[i]]);
+ //server->GameStringf("�c;AS Prefix�c0 %s: %s", Prefix[item.wPrefix[i]], PrefixDetails[item.wPrefix[i]]);
}
if(goodSuffix.count(item.wSuffix[i]) > 0)
{
goodSuffixCount++;
- //server->GameStringf("�c:Suffix�c0 %s: %s", Suffix[item.wSuffix[i]], SuffixDetails[item.wSuffix[i]]);
+ //server->GameStringf("�c:AS Suffix�c0 %s: %s", Suffix[item.wSuffix[i]], SuffixDetails[item.wSuffix[i]]);
}
}
}
+ if (IsRingAmulet(item.szItemCode))
+ {
+ if (item.iSocketed)
+ {
+ return true;
+ }
+ if (item.iPersonalized)
+ {
+ return true;
+ }
+
+ //server->GameStringf("Suffix=%d Prefix=%d Result=(%d)", goodPrefixCount, goodSuffixCount, (goodPrefixCount + goodSuffixCount) >= 2);
+ return (goodPrefixCount + goodSuffixCount) >= 2;
+ }
+
return goodPrefixCount >= 1 || goodSuffixCount >= 1;
}
+bool AutoStocker::IsRingAmulet(LPCSTR itemCode)
+{
+ if(strcmp(itemCode, "amu") == 0 ||
+ strcmp(itemCode, "rin") == 0 ||
+ strcmp(itemCode, "zrn") == 0 ||
+ strcmp(itemCode, "srn") == 0 ||
+ strcmp(itemCode, "nrn") == 0 ||
+ strcmp(itemCode, "prn") == 0 ||
+ strcmp(itemCode, "brg") == 0 ||
+ strcmp(itemCode, "drn") == 0 ||
+ strcmp(itemCode, "arn") == 0 ||
+ strcmp(itemCode, "zam") == 0 ||
+ strcmp(itemCode, "sam") == 0 ||
+ strcmp(itemCode, "nam") == 0 ||
+ strcmp(itemCode, "pam") == 0 ||
+ strcmp(itemCode, "bam") == 0 ||
+ strcmp(itemCode, "dam") == 0 ||
+ strcmp(itemCode, "aam") == 0)
+
+ {
+ return true;
+ }
+
+ return false;
+}
+
///
/// Determines if specified item should be stored in the gem can
///
@@ -915,7 +962,7 @@ bool AutoStocker::IsCrystalItem(LPCSTR itemCode)
/// Determines if specified item should be stored in the rerolling orb
///
/// Item being checked.
-/// true if item should be cubed a stocker.
+/// true if item should be destroyed
bool AutoStocker::IsRerollItem(const ITEM &item)
{
if(!item.iIdentified)
@@ -953,6 +1000,14 @@ bool AutoStocker::IsRerollItem(const ITEM &item)
}
}
+ if (item.iIdentified)
+ {
+ if (item.iQuality == ITEM_LEVEL_SET && IgnoreIdentifiedSetRingsAndAmulets && IsRingAmulet(item.szItemCode))
+ {
+ return false;
+ }
+ }
+
if(item.iQuality == ITEM_LEVEL_MAGIC ||
(item.iQuality == ITEM_LEVEL_SET && transmuteSet) ||
(item.iQuality == ITEM_LEVEL_RARE && transmuteRare) ||
diff --git a/D2Hackit/Modules/autoStocker/AutoStocker.h b/D2Hackit/Modules/autoStocker/AutoStocker.h
index d75d2c7..de9a9a3 100644
--- a/D2Hackit/Modules/autoStocker/AutoStocker.h
+++ b/D2Hackit/Modules/autoStocker/AutoStocker.h
@@ -77,6 +77,7 @@ class AutoStocker
bool IsCrystalItem(LPCSTR itemCode);
bool IsGemCanItem(LPCSTR itemCode);
bool IsRerollItem(const ITEM &item);
+ bool AutoStocker::IsRingAmulet(LPCSTR itemCode);
std::vector> itemsToTransmute;
std::vector restockers;
@@ -93,9 +94,12 @@ class AutoStocker
bool IsTransmutingUnidentifiedSmallCharms;
bool IsTransmutingUnidentifiedLargeCharms;
bool IsTransmutingUnidentifiedGrandCharms;
+ bool IgnoreIdentifiedSetRingsAndAmulets;
int MaxUnidentifiedSCharmLevel;
int MaxUnidentifiedLCharmLevel;
int MaxUnidentifiedGCharmLevel;
+ int MinPrefixCount;
+ int MinSuffixCount;
unsigned int currentItem;
unsigned int currentStocker;
diff --git a/D2Hackit/Modules/autoStocker/Resources/autostockerMisc.ini b/D2Hackit/Modules/autoStocker/Resources/autostockerMisc.ini
index c090878..e51f8cd 100644
--- a/D2Hackit/Modules/autoStocker/Resources/autostockerMisc.ini
+++ b/D2Hackit/Modules/autoStocker/Resources/autostockerMisc.ini
@@ -8,4 +8,5 @@ MaxUnidentifiedLCharmLvl=44
MaxUnidentifiedGCharmLvl=44
NonIDSmallCharms = 0
NonIDLargeCharms = 0
-NonIDGrandCharms = 0
\ No newline at end of file
+NonIDGrandCharms = 0
+IgnoreIdentifiedSetRingsAndAmulets = 1
diff --git a/D2Hackit/Modules/filter/ItemFilter.cpp b/D2Hackit/Modules/filter/ItemFilter.cpp
index 3279a93..438cf66 100644
--- a/D2Hackit/Modules/filter/ItemFilter.cpp
+++ b/D2Hackit/Modules/filter/ItemFilter.cpp
@@ -191,6 +191,7 @@ bool ItemFilter::LoadItemMap(const std::string &fileName, std::unordered_mapGameErrorf("�c:Filter�c0: �c1failed to read the follow item table:�c0 %s", fileName.c_str());
return false;
}
diff --git a/D2Hackit/Modules/filter/main.cpp b/D2Hackit/Modules/filter/main.cpp
index e2daae7..88f659b 100644
--- a/D2Hackit/Modules/filter/main.cpp
+++ b/D2Hackit/Modules/filter/main.cpp
@@ -78,8 +78,7 @@ BOOL EXPORT OnClientStart()
{
if(!ItemFilter.LoadItems())
{
- server->GameErrorf("Failed to load item tables. Do you have filterTable.txt");
- server->GameErrorf(" in the plugin directory?");
+ server->GameErrorf("Failed to load all item tables.");
return FALSE;
}
diff --git a/D2Hackit/Modules/goto/Main.cpp b/D2Hackit/Modules/goto/Main.cpp
index c71e192..4f78328 100644
--- a/D2Hackit/Modules/goto/Main.cpp
+++ b/D2Hackit/Modules/goto/Main.cpp
@@ -97,6 +97,24 @@ bool isLeftHandCasting = false;
#include "../../Core/definitions.h"
+void Abort()
+{
+ if (currentState == STATE_Idle)
+ {
+ return;
+ }
+
+
+ server->GameStringf("�c5Goto�c0: Complete");
+ currentState = STATE_Idle;
+
+ auto fleeModule = GetModuleHandle("Flee.d2h");
+ if (fleeModule != NULL)
+ {
+ server->GameCommandf("flee SuppressAutoTp 0");
+ }
+}
+
void SetState(States newState)
{
/*
@@ -471,14 +489,12 @@ void NextRoomTransition()
{
//server->GameStringf("NextRoomTransition()");
- SetState(STATE_Idle);
-
if(currentTravelData->CurrentStep + 1 < currentTravelData->NumSteps)
{
currentTravelData->CurrentStep++;
}
else {
- server->GameStringf("Done");
+ Abort();
return;
}
@@ -552,7 +568,7 @@ void CalculatePathToStairsRoom()
}
}
- SetState(States::STATE_Idle);
+ Abort();
server->GameStringf("Failed to find path to stairs. Returning to town");
server->GameCommandf(".flee tp");
}
@@ -612,6 +628,12 @@ BOOL PRIVATE Start(char** argv, int argc)
return TRUE;
}
+ auto fleeModule = GetModuleHandle("Flee.d2h");
+ if (fleeModule != NULL)
+ {
+ server->GameCommandf("flee SuppressAutoTp 1");
+ }
+
currentState = STATE_UsingWaypoint;
server->GameCommandf("load wp");
server->GameCommandf("wp start %d", currentTravelData->WaypointDestination);
@@ -628,17 +650,17 @@ BOOL PRIVATE Start(char** argv, int argc)
VOID EXPORT OnGameJoin(THISGAMESTRUCT* thisgame)
{
- SetState(STATE_Idle);
+ Abort();
}
VOID EXPORT OnClientStop(THISGAMESTRUCT *thisgame)
{
server->GameStringf("OnClientStop");
- SetState(STATE_Idle);
+ Abort();
}
VOID EXPORT OnGameLeave(THISGAMESTRUCT* thisgame)
{
- SetState(STATE_Idle);
+ Abort();
}
BOOL EXPORT OnClientStart()
@@ -763,7 +785,8 @@ DWORD EXPORT OnGamePacketBeforeSent(BYTE* aPacket, DWORD aLen)
{
if(strcmp(chatMessage, "�c5Waypoint�c0: Complete") != 0)
{
- SetState(STATE_Idle);
+ Abort();
+ return 0;
}
return 0;
@@ -828,7 +851,7 @@ VOID EXPORT OnThisPlayerMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
if (me->IsInTown())
{
server->GameStringf("Unexpected map change. Aborting.");
- SetState(STATE_Idle);
+ Abort();
return;
}
@@ -848,16 +871,17 @@ VOID EXPORT OnThisPlayerMessage(UINT nMessage, WPARAM wParam, LPARAM lParam)
{
GoBackToTown();
}
- SetState(STATE_Idle);
+ Abort();
}
}
}
+
BYTE EXPORT OnGameKeyDown(BYTE iKeyCode)
{
if(iKeyCode == VK_SPACE)
{
- currentState = STATE_Idle;
+ Abort();
}
return iKeyCode;
}
diff --git a/D2Hackit/Modules/pick/ItemWatcher.cpp b/D2Hackit/Modules/pick/ItemWatcher.cpp
index e1dbfe6..214a6a4 100644
--- a/D2Hackit/Modules/pick/ItemWatcher.cpp
+++ b/D2Hackit/Modules/pick/ItemWatcher.cpp
@@ -59,6 +59,8 @@ BOOL CALLBACK searchForTomesItemProc(LPCITEM item, LPARAM lParam)
void ItemWatcher::CheckWatchedItems()
{
+ bool needToResortWatchedItems = false;
+
if(!destroyedItemsSinceLastCheck.empty())
{
for (auto watchedItemIter = watchedItems.begin(); watchedItemIter != watchedItems.end();)
@@ -66,8 +68,9 @@ void ItemWatcher::CheckWatchedItems()
if (destroyedItemsSinceLastCheck.find(watchedItemIter->id) != destroyedItemsSinceLastCheck.end())
{
watchedItemIter = watchedItems.erase(watchedItemIter);
+ needToResortWatchedItems = true;
}
- else
+ else
{
++watchedItemIter;
}
@@ -78,30 +81,25 @@ void ItemWatcher::CheckWatchedItems()
// same thread (Proc_OnGameTimerTick() server20.cpp)
destroyedItemsSinceLastCheck.clear();
- if(me->GetOpenedUI() != 0)
+ if(std::chrono::system_clock::now() < nextPickAttemptTime)
{
return;
}
- if (watchedItems.empty())
+ if(me->GetOpenedUI() != 0)
{
return;
}
- const auto myPosition = me->GetPosition();
- for(auto &item: watchedItems)
+ if(watchedItems.empty())
{
- item.distanceToItem = sqrt(
- (myPosition.x - item.x) *(myPosition.x - item.x) +
- (myPosition.y - item.y) * (myPosition.y - item.y)
- );
+ return;
}
- std::sort(watchedItems.begin(), watchedItems.end(), [](const WatchedItemData &left, const WatchedItemData &right) {
- return left.distanceToItem < right.distanceToItem;
- });
+ SortWatchedItems();
- for(auto itemIter = watchedItems.begin(); itemIter != watchedItems.end(); )
+ int numPickAttemptsThisFrame = 0;
+ for (auto itemIter = watchedItems.begin(); itemIter != watchedItems.end(); )
{
GAMEUNIT itemUnit;
itemUnit.dwUnitType = UNIT_TYPE_ITEM;
@@ -112,28 +110,17 @@ void ItemWatcher::CheckWatchedItems()
continue;
}
- const auto myPos = me->GetPosition();
- if (server->GetDistance(myPos.x, myPos.y, itemIter->x, itemIter->y) > radius || me->GetMode() == MODE_CAST)
+ if(itemIter->distanceToItem > radius || numPickAttemptsThisFrame > 5)
{
- ++itemIter;
- continue;
+ break;
}
- //server->GameStringf("Picking %X... [%d]", i->id, watchedItems.size());
if(itemIter->isGold)
{
+ numPickAttemptsThisFrame++;
me->PickGroundItem(itemIter->id, this->isWalkToGold);
-
- goldPicksThisFrame++;
- if (goldPicksThisFrame > goldSpeed) {
- return;
- }
- ++itemIter;
- continue;
}
-
-
- if (itemIter->isIdScroll)
+ else if(itemIter->isIdScroll)
{
TomeInfo info{ 0, 0, 0 };
me->EnumStorageItems(STORAGE_INVENTORY, searchForTomesItemProc, (LPARAM)&info);
@@ -141,17 +128,16 @@ void ItemWatcher::CheckWatchedItems()
const auto numCharges = me->GetSpellCharges(D2S_TOMEOFIDENTIFY);
const auto maxCharges = info.totalTomesOfIdentify * 40;
- if (maxCharges - numCharges < 2)
+ if(maxCharges - numCharges < 2)
{
itemIter = watchedItems.erase(itemIter);
continue;
}
+ numPickAttemptsThisFrame++;
me->PickGroundItem(itemIter->id, this->isWalkToItems);
- return;
}
-
- if (itemIter->isTpScroll)
+ else if(itemIter->isTpScroll)
{
TomeInfo info{ 0, 0, 0 };
me->EnumStorageItems(STORAGE_INVENTORY, searchForTomesItemProc, (LPARAM)&info);
@@ -159,40 +145,51 @@ void ItemWatcher::CheckWatchedItems()
const auto numCharges = me->GetSpellCharges(D2S_TOMEOFTOWNPORTAL);
const auto maxCharges = info.totalTomesOfTownPortal * 40;
- if (maxCharges - numCharges < 2)
+ if(maxCharges - numCharges < 2)
{
itemIter = watchedItems.erase(itemIter);
continue;
}
+ numPickAttemptsThisFrame++;
me->PickGroundItem(itemIter->id, this->isWalkToItems);
- return;
}
-
- if (itemIter->keyCount > 0)
+ else if(itemIter->keyCount > 0)
{
- TomeInfo info{ 0, 0, 0};
+ TomeInfo info{ 0, 0, 0 };
me->EnumStorageItems(STORAGE_INVENTORY, searchForTomesItemProc, (LPARAM)&info);
- if ((info.totalKeys + itemIter->keyCount) > 20)
+ if((info.totalKeys + itemIter->keyCount) > 20)
{
itemIter = watchedItems.erase(itemIter);
continue;
}
+ numPickAttemptsThisFrame++;
me->PickGroundItem(itemIter->id, this->isWalkToItems);
- return;
}
-
- if(me->FindFirstStorageSpace(STORAGE_INVENTORY, itemIter->itemSize, NULL))
+ else if(me->FindFirstStorageSpace(STORAGE_INVENTORY, itemIter->itemSize, NULL))
{
+ numPickAttemptsThisFrame++;
me->PickGroundItem(itemIter->id, this->isWalkToItems);
+ }
+ else
+ {
+ server->GameStringf("�c1Pick�c0: �c:Not enough room for item, skipping");
+ itemIter = watchedItems.erase(itemIter);
+ continue;
+ }
+
+ if(radius > 5 && itemIter->distanceToItem > 5)
+ {
+ // We're likely walking somewhere, give it 200ms unless something new drops
+ // nextPickAttemptTime = std::chrono::system_clock::now() + std::chrono::milliseconds(200);
return;
}
- server->GameStringf("�c1Pick�c0: �c:Not enough room for item, skipping");
- itemIter = watchedItems.erase(itemIter);
- return;
+ ++itemIter;
}
+
+ nextPickAttemptTime = std::chrono::system_clock::now() + std::chrono::milliseconds(10);
}
////////////////////////////////////////////
@@ -316,7 +313,7 @@ bool ItemWatcher::loadItemMap(const std::string &fileName, std::unordered_mapGetItemSize(itemCode.c_str());
- watchedItems.push_back(itemData);
+ SortWatchedItems();
}
}
}
+ watchedItems.push_back(itemData);
AnnounceItem(item);
}
-void ItemWatcher::AnnounceItem(const ITEM &item)
+float ItemWatcher::Distance(float x1, float x2, float y1, float y2) const
{
- if (isMute)
+ return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
+}
+
+void ItemWatcher::SortWatchedItems()
+{
+ auto myPosition = me->GetPosition();
+
+ for (auto& item : watchedItems)
+ {
+ item.distanceToItem = Distance(myPosition.x, item.x, myPosition.y, item.y);
+ }
+
+ std::sort(watchedItems.begin(), watchedItems.end(), [](const WatchedItemData& left, const WatchedItemData& right) {
+ return left.distanceToItem < right.distanceToItem;
+ });
+}
+
+void ItemWatcher::AnnounceItem(const ITEM& item)
+{
+ if(isMute)
{
return;
}
std::string outputMessage;
outputMessage.reserve(128);
-
+
bool overrideAnnouncment = false;
const auto itemCode = std::string(item.szItemCode);
diff --git a/D2Hackit/Modules/pick/ItemWatcher.h b/D2Hackit/Modules/pick/ItemWatcher.h
index 13a0cb4..0bfc162 100644
--- a/D2Hackit/Modules/pick/ItemWatcher.h
+++ b/D2Hackit/Modules/pick/ItemWatcher.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "../../Includes/D2Client.h"
//#include "_item.h"
@@ -46,6 +47,8 @@ class ItemWatcher
void CheckWatchedItems();
void Cleanup();
bool loadItemMap(const std::string &fileName, std::unordered_map &itemMap);
+ void SortWatchedItems();
+ float Distance(float x1, float x2, float y1, float y2) const;
const char *GetItemDesc(const ITEM &item);
const char *GetDirectionFrom(WORD sourceX, WORD sourceY, WORD targetX, WORD targetY);
@@ -60,6 +63,9 @@ class ItemWatcher
std::unordered_map itemsToAnnounce;
std::unordered_map itemsToPick;
+ std::chrono::system_clock::time_point nextPickAttemptTime;
+
+ int itemWatcherTicksToSkip;
unsigned int radius;
unsigned int minGold;
bool townPickup;