Skip to content

Commit

Permalink
AutoSell now auto refills your tp tomes if they're not full
Browse files Browse the repository at this point in the history
Flee has a CreatePortalWhenLeavingTown option that auto creates a portal whenever you leave town
BuffMe has a useless chat mode (so it can be used with other d2h modules)
  • Loading branch information
nooperation committed Sep 17, 2022
1 parent 7c7a0cc commit bf48504
Show file tree
Hide file tree
Showing 9 changed files with 198 additions and 17 deletions.
9 changes: 9 additions & 0 deletions D2Hackit/Core/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,15 @@ BOOL D2ParseItem(const BYTE *aPacket, DWORD aLen, ITEM& item)
item.iSocketNumber = (BYTE)iPacket.GetField(4);
}

// Useless because d2hackit doesn't update quantity of inventory items on use. Keeping for a future note though.
//if(strcmp(item.szItemCode, "tbk") == 0)
//{
// auto unknown = iPacket.GetField(5);
// auto amount = iPacket.GetField(9);
// item.iQuantity = amount;
// return TRUE;
//}

if(D2IsStackable(item.szItemCode))
{
item.iQuantity = (WORD)iPacket.GetField(9);
Expand Down
120 changes: 114 additions & 6 deletions D2Hackit/Modules/autoSell/AutoSell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,67 @@ bool AutoSell::SellItem(DWORD dwItemID) const
return server->GameSendPacketToServer(aPacket, 17);
}


#pragma pack(push, 1)
struct D2GS_NPC_BUY
{
uint8_t PacketId;
uint32_t UnitId;
uint32_t ItemId;
uint32_t BuyType;
uint32_t Cost;
};
#pragma pack(pop)

bool AutoSell::BuyItemInQuantity(DWORD dwItemID) const
{
if (!me->IsUIOpened(UI_NPCSHOP))
{
server->GameErrorf("ÿc:AutoSellÿc0: You must first open the trade interface with a merchant");
return false;
}

const auto vendorId = server->GetInteractedNPCUniqueID();
if (vendorId == 0)
{
server->GameErrorf("ÿc:AutoSellÿc0: No merchant found");
return false;
}

const auto vendorClassId = server->GetInteractedNPCClassID();
if (GetNpcTradeMenuID(vendorClassId) == -1)
{
server->GameErrorf("ÿc:AutoSellÿc0: Currently selected npc is not a merchant");
return false;
}

GAMEUNIT unit;
unit.dwUnitID = vendorId;
unit.dwUnitType = UNIT_TYPE_MONSTER;
if (!server->VerifyUnit(&unit))
{
server->GameErrorf("ÿc:AutoSellÿc0: could not verify merchant");
return FALSE;
}

D2GS_NPC_BUY packet;
packet.PacketId = 0x32;
packet.UnitId = vendorId;
packet.ItemId = dwItemID;
packet.BuyType = 0x80000000;
packet.Cost = 0;

return server->GameSendPacketToServer((uint8_t*)&packet, sizeof(packet));
}

bool AutoSell::Start(bool silentStart)
{
if (currentState != State::Uninitialized)
{
this->Stop();
}

numTPTomesToRefill = 0;
while (!itemsToSell.empty())
{
itemsToSell.pop();
Expand All @@ -133,8 +187,9 @@ bool AutoSell::Start(bool silentStart)
return false;
}

this->numTPTomesToRefill = 0;
me->EnumStorageItems(STORAGE_INVENTORY, FindStuffToSellCallback, (LPARAM)this);
if (this->itemsToSell.empty())
if (this->itemsToSell.empty() && this->numTPTomesToRefill == 0)
{
if (!silentStart)
{
Expand Down Expand Up @@ -167,15 +222,53 @@ void AutoSell::Stop()
}
}

void AutoSell::RestockScrolls()
{
if (numTPTomesToRefill == 0)
{
this->Stop();
return;
}

if (this->merchantTpScrollId == 0)
{
return;
}

for (auto i = 0; i < this->numTPTomesToRefill; i++)
{
BuyItemInQuantity(this->merchantTpScrollId);
}

this->numTPTomesToRefill = 0;
}


// Called when NPC is listing items up for gamble, before NPC_SESSION message
void AutoSell::OnNpcItemList(const ITEM& merchantItem)
{
if (strcmp(merchantItem.szItemCode, "tsc") != 0)
{
return;
}

this->merchantTpScrollId = merchantItem.dwItemID;

if (this->currentState == State::Uninitialized)
{
Start(true);
}
}

void AutoSell::SellQueuedItems()
{
currentState = State::SellingItem;
if (itemsToSell.empty())
{
this->Stop();
RestockScrolls();
return;
}

currentState = State::SellingItem;
const auto itemToSell = itemsToSell.front();
itemsToSell.pop();

Expand All @@ -200,12 +293,13 @@ void AutoSell::OnItemSold()
{
return;
}

SellQueuedItems();
}

void AutoSell::OnNPCShopScreenOpened()
{
this->merchantTpScrollId = 0;
if (!this->isFullyAutomatic)
{
return;
Expand All @@ -214,7 +308,7 @@ void AutoSell::OnNPCShopScreenOpened()
Start(true);
}

void AutoSell::ProcessInventoryItem(const ITEM *item)
void AutoSell::ProcessInventoryItem(const ITEM* item)
{
if (item == nullptr)
{
Expand All @@ -223,6 +317,20 @@ void AutoSell::ProcessInventoryItem(const ITEM *item)

if (this->targetItems.find(item->szItemCode) == this->targetItems.end())
{
if (strcmp(item->szItemCode, "tbk") == 0)
{
// TODO: d2hackit doesn't update item->iQuantity, never trust it...
GAMEUNIT unit;
unit.dwUnitID = item->dwItemID;
unit.dwUnitType = UNIT_TYPE_ITEM;

auto charges = server->GetUnitStat(&unit, STAT_AMMOQUANTITY);
if (charges < 40)
{
this->numTPTomesToRefill++;
}
}

return;
}

Expand All @@ -235,4 +343,4 @@ BOOL CALLBACK FindStuffToSellCallback(LPCITEM item, LPARAM lParam)
instance->ProcessInventoryItem(item);

return TRUE;
}
}
5 changes: 5 additions & 0 deletions D2Hackit/Modules/autoSell/AutoSell.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,22 @@ class AutoSell
void OnItemSold();
void OnNPCShopScreenOpened();
void ProcessInventoryItem(const ITEM *item);
void OnNpcItemList(const ITEM &merchantItem);

private:
bool LoadItemMap(const std::string &fileName, std::unordered_map<std::string, std::string> &itemMap);
void SellQueuedItems();
void RestockScrolls();
bool SellItem(DWORD dwItemID) const;
bool BuyItemInQuantity(DWORD dwItemID) const;

std::queue<ItemToSell> itemsToSell;

bool isFullyAutomatic;
bool isAnnouncingSoldItems;
long startingGold;
int numTPTomesToRefill;
int merchantTpScrollId;

State currentState;
std::unordered_map<std::string, std::string> targetItems;
Expand Down
20 changes: 20 additions & 0 deletions D2Hackit/Modules/autoSell/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,26 @@ BYTE EXPORT OnGameKeyDown(BYTE iKeyCode)
return iKeyCode;
}

DWORD EXPORT OnGamePacketBeforeReceived(BYTE* aPacket, DWORD aLen)
{
if(aPacket[0] == 0x9c)
{
ITEM currentItem;

if(!server->ParseItem(aPacket, aLen, currentItem))
{
return aLen;
}

if(currentItem.iStore)
{
autoSell.OnNpcItemList(currentItem);
}
}

return aLen;
}

MODULECOMMANDSTRUCT ModuleCommands[]=
{
{
Expand Down
13 changes: 12 additions & 1 deletion D2Hackit/Modules/buffMe/BuffMe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ bool BuffMe::ReadBuffs(const std::string &fileName)
/// <summary>
/// Starts the buff process with the first buff
/// </summary>
void BuffMe::Start()
void BuffMe::Start(bool useChat)
{
this->useChat = useChat;
currentBuffIndex = 0;
currentState = STATE_SENDING;
startingSkill = me->GetSelectedSpell(FALSE);
Expand All @@ -75,6 +76,11 @@ void BuffMe::OnCompletion()
{
me->SelectSpell(startingSkill, FALSE);
currentState = STATE_IDLE;

if(useChat)
{
me->Say("ÿc5BuffMeÿc0: Done");
}
}

/// <summary>
Expand All @@ -93,6 +99,11 @@ void BuffMe::OnDisAffect(size_t affectID)
{
if(item.affectId == affectID)
{
if(useChat)
{
me->Say("ÿc5BuffMeÿc0: Rebuff needed");
}

server->GameStringf("ÿc3Warningÿc0: ÿc2Rebuff needed");
needsRebuff = true;
return;
Expand Down
3 changes: 2 additions & 1 deletion D2Hackit/Modules/buffMe/BuffMe.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class BuffMe
{
public:
BuffMe();
void Start();
void Start(bool useChat);
void OnAffect(size_t affectID);
void OnDisAffect(size_t affectID);
void OnTick();
Expand All @@ -45,6 +45,7 @@ class BuffMe

BuffStates currentState;
bool needsRebuff;
bool useChat;
int startingSkill;
};

Expand Down
18 changes: 15 additions & 3 deletions D2Hackit/Modules/buffMe/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ bool isShowingSelectedSkill = false;

CLIENTINFO
(
1,0,
1,1,
"",
"",
"buffMe",
Expand All @@ -20,8 +20,20 @@ CLIENTINFO

BOOL PRIVATE Buff(char** argv, int argc)
{
buff.Start();
bool useChat = false;

if(argc >= 3)
{
for(int i = 2; i < argc; i++)
{
if(_stricmp(argv[i], "chat") == 0)
{
useChat = true;
}
}
}

buff.Start(useChat);
return TRUE;
}

Expand Down Expand Up @@ -86,7 +98,7 @@ BYTE EXPORT OnGameKeyDown(BYTE iKeyCode)
if(iKeyCode == VK_DELETE)
{
tickCount = 0;
buff.Start();
buff.Start(false);
}

return iKeyCode;
Expand Down
1 change: 1 addition & 0 deletions D2Hackit/Modules/flee/Resources/flee.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ HotkeyInTown=0
HpPercentage=0
PortalKey=8
FleeKey=0
CreatePortalWhenLeavingTown=0
Loading

0 comments on commit bf48504

Please sign in to comment.