Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
// v1.08 remove all reference to actorinfo structure.
// v1.07 changed way to setup plugin to operates. variable autofeed
// and autodrink in INI file will be used to determine at what
// level you want plugin to eat or drink. 0=off. Also added a
// new command to plugin autodrink as requested.
// /autodrink 3500 (set point where plugin should drink, 0=off
// /autofeed 3500 (set point where plugin should eat, 0=off
// v1.06 Major updates to make it compatible to recent game change
// structures.
// v1.05 Setting ON/OFF will be save under autofeed section in ini
// as numerical value (0=off,1=on).
// v1.04 It will consume last found norent food/drink even if not
// in inifile before any regular food types defined.
// v1.03 Change approach for searching in inventory for food/drink
// to try to consume the smallest stack first.
// v1.02 Cosmetic fix trying to eat with merchant window open.
// v1.01 Fixed problems with pack8 and qty window popping up while
// code try to move back food to their original spot.
// v1.00 Initial write up.
//****************************************************************//
// MQ2FeedMe v1.08
// based on snippet FeedMe 2.3 from A_Druid_00
// by s0rCieR 2005.12.10
//****************************************************************//
// I was real bored this morning and wake up, checking mq2 forums
// snippet by A_Druid_00 then i see a comment from hendrix04 that
// say that this would be an awsome plugin. Well here it is ...
//
// It will eat food and drink you specify in the ini (MQ2FeedMe.ini)
// if your hunger or thirst level fall below 5000. (GAGE_HUNGER and
// GAGE_THIRST to change those threshold). Threshold level is check
// every 15 seconds or so (SKIP_PULSES).
//
// Lots of code stolen, credits goes to the author of those.
//****************************************************************//
// Usage: /autodrink -> Force manual drinking
// /autodrink 0 -> Turn off autodrinking
// /autodrink 3500 -> Set Level where plugin should drink
//
// /autofeed -> Force manual feeding
// /autofeed 0 -> Turn off autofeeding
// /autofeed 3500 -> Set Level where plugin should eat
//****************************************************************//
#include "../MQ2Plugin.h"
#include <list>
#include <string>
PreSetup("MQ2FeedMe");
#define SKIP_PULSES 500
#define SLOT_MAX 30
#define NOID -1
bool Loaded=0; // List Loaded?
long Pulses=0; // Pulses Skipped Counter
long FeedAt=0; // Feed Level
long DrnkAt=0; // Drnk Level
char Buffer[16];
list<string> Hunger; // Hunger Fix List
list<string> Thirst; // Thirst Fix List
char FindName[ITEM_NAME_LEN]; // Find Food/Drink Name
DWORD FindPile; // Find Qty in Stack
DWORD FindSlot; // Find Inventory Slot
BOOL WindowOpen(PCHAR WindowName) {
PCSIDLWND pWnd=(PCSIDLWND)FindMQ2Window(WindowName);
return (!pWnd)?false:(BOOL)pWnd->Show;
}
void SendModClick(PCHAR WindowName, PCHAR ScreenID, PCHAR ClickNotification, DWORD KeyState) {
bool KeyboardFlags[4];
*(DWORD*)&KeyboardFlags=*(DWORD*)&((PCXWNDMGR)pWndMgr)->KeyboardFlags;
*(DWORD*)&((PCXWNDMGR)pWndMgr)->KeyboardFlags=KeyState;
SendWndClick(WindowName,ScreenID,ClickNotification);
*(DWORD*)&((PCXWNDMGR)pWndMgr)->KeyboardFlags=*(DWORD*)&KeyboardFlags;
}
void ReadList(list<string> *MyList, PCHAR fSec) {
char Buffer[MAX_STRING*10];
MyList->clear();
if(GetPrivateProfileString(fSec,NULL,"",Buffer,MAX_STRING*10,INIFileName)) {
char szTemp[MAX_STRING];
PCHAR pBuffer=Buffer;
while (pBuffer[0]!=0) {
GetPrivateProfileString(fSec,pBuffer,"",szTemp,MAX_STRING,INIFileName);
if(szTemp[0]!=0) MyList->push_back(string(szTemp));
pBuffer+=strlen(pBuffer)+1;
}
}
}
bool GoodToFeed() {
if(MQ2Globals::gGameState==GAMESTATE_INGAME) // currently ingame
if(GetCharInfo2()) // get charinfo
if(!GetCharInfo2()->Cursor) // nothing on cursor
if(GetCharInfo()->pSpawn->CastingSpellID==NOID)// not casting
if(GetCharInfo()->pSpawn->SpellETA==0) // not using abilities
if(!WindowOpen("SpellBookWnd")) // not medding a spell
if(!WindowOpen("MerchantWnd")) // not interacting with vendor
if(!WindowOpen("TradeWnd")) // not trading with someone
if(!WindowOpen("BigBankWnd")) // not banking
if(!WindowOpen("BankWnd")) // not banking
if(!WindowOpen("LootWnd")) // not looting
return true; // then return true
return false; // otherwise false
}
void FindFood(DWORD fTYPE, list<string> fLIST, DWORD fSLOT, PCONTENTS fITEM) {
if(fITEM) if(fITEM->Item->ItemType==fTYPE) {
if(fITEM->Item->NoRent) {
list<string>::iterator pLIST;
pLIST=(fITEM->StackCount<FindPile)?fLIST.begin():fLIST.end();
while(pLIST!=fLIST.end()) if(!stricmp(fITEM->Item->Name,pLIST->c_str())) break; else pLIST++;
if(pLIST==fLIST.end()) return;
}
strcpy(FindName,fITEM->Item->Name);
FindSlot=fSLOT;
FindPile=(fITEM->Item->NoRent)?fITEM->StackCount:0;
}
}
void Consume(DWORD fTYPE, list<string> fLIST) {
FindPile=99999;
for(int iSlot=22; iSlot<SLOT_MAX; iSlot++) if(PCONTENTS pSlot=GetCharInfo2()->InventoryArray[iSlot]) {
if(pSlot->Item->Type!=ITEMTYPE_PACK) FindFood(fTYPE,fLIST,iSlot,pSlot);
else for(int bSlot=0; bSlot<pSlot->Item->Slots; bSlot++) FindFood(fTYPE,fLIST,251+(iSlot-22)*10+bSlot,pSlot->Contents[bSlot]);
}
if(FindPile<99999) {
WriteChatf("MQ2FeedMe::Consuming -> %s.",FindName);
if(FindSlot<SLOT_MAX) {
sprintf(FindName,"InvSlot%d",FindSlot);
SendModClick("InventoryWindow",FindName,"rightmouseup",0);
} else {
pInvSlotMgr->MoveItem(FindSlot,0x1E,1,1);
SendModClick("InventoryWindow","InvSlot29","leftmouseup",0);
SendModClick("InventoryWindow","InvSlot29","rightmouseup",0);
SendModClick("InventoryWindow","InvSlot29","leftmouseup",1);
if(GetCharInfo2()->Cursor) pInvSlotMgr->MoveItem(0x1E,FindSlot,1,1);
}
}
}
void AutoFeedCmd(PSPAWNINFO pChar, PCHAR zLine) {
if(zLine[0]!=0) {
FeedAt=atoi(zLine); if(FeedAt<0) FeedAt=0; else if(FeedAt>5000) FeedAt=5000;
sprintf(Buffer,"%d",FeedAt);
WritePrivateProfileString(GetCharInfo()->Name,"AutoFeed",Buffer,INIFileName);
WriteChatf("MQ2FeedMe::AutoFeed (\ag%s\ax).",(FeedAt)?Buffer:"\aroff");
} else if(GoodToFeed()) Consume(ITEMITEMTYPE_FOOD,Hunger);
}
void AutoDrinkCmd(PSPAWNINFO pCHAR, PCHAR zLine) {
if(zLine[0]!=0) {
DrnkAt=atoi(zLine); if(DrnkAt<0) DrnkAt=0; else if(DrnkAt>5000) DrnkAt=5000;
sprintf(Buffer,"%d",DrnkAt);
WritePrivateProfileString(GetCharInfo()->Name,"AutoDrink",Buffer,INIFileName);
WriteChatf("MQ2FeedMe::AutoDrink (\ag%s\ax).",(DrnkAt)?Buffer:"\aroff");
} else if(GoodToFeed()) Consume(ITEMITEMTYPE_WATER,Thirst);
}
PLUGIN_API void InitializePlugin(void) {
DebugSpewAlways("Initializing MQ2FeedMe");
AddCommand("/autofeed",AutoFeedCmd);
AddCommand("/autodrink",AutoDrinkCmd);
}
PLUGIN_API void OnPulse(void) {
if(++Pulses<SKIP_PULSES) return; Pulses=0;
if(!GoodToFeed()) return;
if(DrnkAt && GetCharInfo2()->thirstlevel<DrnkAt) Consume(ITEMITEMTYPE_WATER,Thirst);
if(FeedAt && GetCharInfo2()->hungerlevel<FeedAt) Consume(ITEMITEMTYPE_FOOD,Hunger);
}
PLUGIN_API void SetGameState(DWORD GameState) {
if(MQ2Globals::gGameState==GAMESTATE_INGAME)
if(GetCharInfo2()) {
DrnkAt=GetPrivateProfileInt(GetCharInfo()->Name,"AutoDrink",0,INIFileName);
FeedAt=GetPrivateProfileInt(GetCharInfo()->Name,"AutoFeed" ,0,INIFileName);
if(!Loaded) {
ReadList(&Hunger,"FOOD");
ReadList(&Thirst,"DRINK");
Loaded=true;
}
}
}
PLUGIN_API void ShutdownPlugin(void) {
DebugSpewAlways("Shutting down MQ2FeedMe");
RemoveCommand("/autofeed");
RemoveCommand("/autodrink");
}