Hunger/Thirst information

A forum for the general posts relating to MacroQuest. *DEPRECATED: This forum is no longer in public use, but remains here for your reading pleasure. Enjoy

Moderator: MacroQuest Developers

visar
orc pawn
orc pawn
Posts: 10
Joined: Fri Jan 09, 2004 10:58 am
Location: USA

Hunger/Thirst information

Post by visar » Sun Feb 15, 2004 3:00 pm

Been lurking for several months, I'm not much of a poster. I would like to first say that MQ2 KICKS ASS! Great job by the devs. I don't do a lot of macroing but I still find that I don't like to play EQ nearly as much when MQ isn't working because it enhances the game play so much.

Anyway, I'd been thinking recently about the way hunger and thirst works and the various "nutritional" values of food and drink items to help with not eating that expensive stat food that you have to keep first in your inventory.

I did some research and wanted to post what I found out. If I'm posting something that the devs and many users know already or if it goes too far beyond the enhancement of EQ into the realm of cheating, or just if nobody gives a damn :), then I apologize and mods please delete the thread. If not, I hope it ends up of use to some people.

I noticed two heartbeats in the game relating to food/drink. The first one is, your hungerlevel and thirstlevel decrease by 32 every 45 seconds. It appears this timer starts over when you zone, so if you start zoning at 44 seconds then you get a freebie tick. There are also zone modifiers at least for thirst. In North Ro for instance, I lost 64 thirstlevel every tick instead of 32. Wouldn't be surprised if there are zone modifiers for food as well. I couldn't tell a difference though for sitting vs. standing, running vs. standing still, or meleeing vs. not. Still need to check for effects of stuff like disease, poison, buffs, etc.

The second timer seems to be on a 30 second schedule, and it checks your current hunger and thirst levels. If either one is below 3000, you will eat or drink the first appropriate item found in your inventory. This doesn't restart the decrement timer though -- the two timers run independently.

This info could probably be used in some kind of general purpose include snippet having a timer that kicks off every 45 seconds or minute or so, and if either of your levels get below say 3500, it could throw up warnings that you need to eat or drink so you don't end up consuming your stat stuff by accident. Or it could be just a macro that serves the same purpose running anytime you're not running something else. I wrote one like that to aid in my research.

I also found that in the _ITEMINFO struct, the nourishment value of food/drink items is stored in the CastTime field (so CastTime and Nourishment are a union in that struct). Whenever you eat or drink, the value in that field for the item you consumed is multiplied by 100 and added back to your level.

For instance you have Fruit as the top food item in your inventory, and Fruit contains the value 8 in the CastTime/Nourishment field. When your hungerlevel falls below 3000 and the check timer notices this, your stack of Fruit will decrease by 1 and your hungerlevel will increase by 800. Other items of course have varying values (one interesting thing is that a foraged Pod of Water has the value 0x10 while a Water Flask has 0x0F, even though it takes 4 Pods in a brew barrel to make one flask. Weird).

I had to add some stuff to EQData.h and MQ2Parms.cpp to help me figure all this out, and if anyone's interested I'll post the diffs. I added the nourish value printout function to both $cursor and $item, though for some reason I couldn't get /selectitem to select anything in my own inventory -- probably my own stupidity.

Anyway, once again THANKS to the devs for MQ2 -- keep up the good work!

-visar

GD
a snow griffon
a snow griffon
Posts: 353
Joined: Sat Jun 29, 2002 11:57 pm

Post by GD » Sun Feb 15, 2004 7:58 pm

Wow, that's pretty damn cool. you may want to post the code, as it's something that will probably come in handy.
Opinions are like assholes, everyone has one, but most of them stink.

Teh_ish
UI Guru
Posts: 168
Joined: Wed Nov 05, 2003 12:18 am

Post by Teh_ish » Mon Feb 16, 2004 12:54 am

Excellent work. Please post
OMGWTFBBQ

User avatar
Schark
orc pawn
orc pawn
Posts: 28
Joined: Sat Nov 29, 2003 5:37 am

Post by Schark » Mon Feb 16, 2004 4:56 am

Yes, good work. Please post this! :)

Would also be great to have the nourishment value shown when you inspected a food/drink item.

daerck
a ghoul
a ghoul
Posts: 134
Joined: Mon Jan 12, 2004 8:44 pm

Post by daerck » Mon Feb 16, 2004 10:33 am

Awesome! Yes please!!

visar
orc pawn
orc pawn
Posts: 10
Joined: Fri Jan 09, 2004 10:58 am
Location: USA

Post by visar » Mon Feb 16, 2004 1:20 pm

Good to see some folks found this info useful.

First a couple of clarifications. After some further playing around with this I am no longer sure that the timer checking for below 3000 hunger/thirst level, which causes automatic eating/drinking, happens on a 30-second schedule. Some stuff I saw last night led me to believe it might be on 45 seconds or even a minute. There may be one each for hunger and thirst, or they may be be together. Damfino. I'm still sure though that the hunger/thirst decrement runs on a 45-second schedule and that at least its effects are independent from the level checker. I'll post more as I do more research, but not being sure about that one aspect won't affect how this can be used.

Now for the diffs. All these involve only the addition of lines. For those not familiar with context diffs, what you'll need to do is find the spot in the affected file (either through the line numbers listed at the top of each diff section, or from the surrounding context) and add the lines that have a plus sign in the front. Don't include the plus sign itself though when you add the line. These diffs are from the MQ2-20040215.zip but you should be able to use the context information to find where to add the lines in the previous version. If anyone has problems, PM me and I'll try to help you. MAKE BACKUPS OF THE ORIGINAL FILES (yeah I know you can get them back out of the zip, but I'm anal that way)!

MQ2Main\EQData.h (needed for the stuff in MQ2Parms.cpp to work):

Code: Select all

*** EQData.h.orig       2004-02-15 13:49:40.000000000 -0500
--- EQData.h    2004-02-16 10:35:46.000000000 -0500
***************
*** 322,328 ****
--- 322,331 ----
  /*0x1c8*/  DWORD              SpellShield;
  /*0x1cc*/  DWORD              Avoidance;
  /*0x1d0*/  BYTE                       Unknown0x1d0[0xc];
+    union {
  /*0x1dc*/  DWORD              CastTime;
+ /*0x1dc*/  DWORD              Nourishment;
+    };
     union {
  /*0x1e0*/  BYTE                       MaxCharges;
  /*0x1e0*/  BYTE                       Stackable;
MQ2Main\MQ2Parms.cpp (allows you to use $char(hunger), $char(thirst), $cursor(nourish) and $item(nourish). $item(nourish) is untested due to my /selectitem troubles but the others work):

Code: Select all

*** MQ2Parms.cpp.orig   2004-02-13 22:41:54.000000000 -0500
--- MQ2Parms.cpp        2004-02-16 10:46:12.000000000 -0500
***************
*** 200,205 ****
--- 200,212 ----
                i+=19;
                strcat(szOutput,szDmgBonusType[pItem->DmgBonusType]);
   
+     // $cursor(nourish)
+     } else if (!strncmp("cursor(nourish)",szVar,15)) {
+         i+=14;
+         CHAR szTemp[MAX_STRING] = {0};
+         itoa(pItem->Nourishment*100,szTemp,10);
+         strcat(szOutput,szTemp);
+
      // $cursor(unknown)
      } else {
          DebugSpewNoFile("PMP - Bad $cursor() '%s'",szVar);
***************
*** 400,405 ****
--- 407,419 ----
                  strcat(szOutput, "Book");
              }
   
+         // $item(nourish)
+         } else if (!strncmp("nourish)",szVar+Offset,8)) {
+             i+=Offset+7;
+             CHAR szTemp[MAX_STRING] = {0};
+             itoa(pItem->Item->Nourishment*100,szTemp,10);
+             strcat(szOutput,szTemp);
+
          // $item(unknown)
          } else {
              DebugSpewNoFile("PMP - Bad $item() '%s'",szVar);
***************
*** 3086,3091 ****
--- 3100,3119 ----
          itoa(pCharInfo->CareerFavor,szTemp,10);
          strcat(szOutput,szTemp);
   
+     // $char(hunger)
+     } else if (!strncmp("char(hunger)",szVar,12)) {
+         CHAR szTemp[MAX_STRING] = {0};
+         i+=11;
+         itoa(pCharInfo->hungerlevel,szTemp,10);
+         strcat(szOutput,szTemp);
+
+     // $char(thirst)
+     } else if (!strncmp("char(thirst)",szVar,12)) {
+         CHAR szTemp[MAX_STRING] = {0};
+         i+=11;
+         itoa(pCharInfo->thirstlevel,szTemp,10);
+         strcat(szOutput,szTemp);
+
        // $char(unknown)
      } else {
          DebugSpewNoFile("PMP - Bad $char() '%s'",szVar);
After doing this, rebuild MQ2Main.dll. I didn't have to rebuild the rest of the app, but it shouldn't hurt if you do. Also, you can't have MQ2 running when you rebuild the dll or you'll get a error trying to overwrite the file (unless you make a separate working directory to try this out).

Obviously when later versions of the zip are released you'll have to make these changes again unless the devs decide to include them.

I'll do some more research, write and test an include snippet, and if/when it works I'll make another post.

-visar

ubatch
a ghoul
a ghoul
Posts: 93
Joined: Tue Nov 18, 2003 3:57 pm

Post by ubatch » Tue Feb 17, 2004 6:45 pm

You're the man. Keep up the good research!

Teh_ish
UI Guru
Posts: 168
Joined: Wed Nov 05, 2003 12:18 am

Post by Teh_ish » Tue Feb 17, 2004 8:08 pm

Question.. Nourishment is only a single struct entry.. Yet the $char stuff references hungerlevel and thirstlevel.. One would think that it doesn't work with just that..Believe we need the structs for hunger and thirst :)
Last edited by Teh_ish on Tue Feb 17, 2004 8:43 pm, edited 1 time in total.
OMGWTFBBQ

User avatar
FreQuency
a hill giant
a hill giant
Posts: 215
Joined: Tue Sep 23, 2003 6:03 pm

Post by FreQuency » Tue Feb 17, 2004 8:17 pm

Question.. Nourishment is only a single struct entry.. Yet the $char stuff references hungerlevel and thirstlevel.. One would think that it doesn't work with just that..
Nourishment is single entry for that particular item i believe either a food or a drink.

daerck
a ghoul
a ghoul
Posts: 134
Joined: Mon Jan 12, 2004 8:44 pm

Post by daerck » Tue Feb 17, 2004 8:50 pm

thirstlevel and hungerlevel is already in the Charinfo struct.

Teh_ish
UI Guru
Posts: 168
Joined: Wed Nov 05, 2003 12:18 am

Post by Teh_ish » Tue Feb 17, 2004 9:48 pm

Silly me :P
OMGWTFBBQ

Teh_ish
UI Guru
Posts: 168
Joined: Wed Nov 05, 2003 12:18 am

Post by Teh_ish » Tue Feb 17, 2004 11:32 pm

Removed due to bugs.
OMGWTFBBQ

visar
orc pawn
orc pawn
Posts: 10
Joined: Fri Jan 09, 2004 10:58 am
Location: USA

Post by visar » Wed Feb 18, 2004 11:01 am

No Teh_ish put the code back! :) I was going to use it for experimentation. Maybe PM it to me please...

What you had said about the extra -1 comparison -- I noticed some items had 0xFFFF in the CastTime/Nourishment union and I wondered why. I think all normal food/drink items had a positive non-zero value though, so maybe instead of checking for not -1 we could just check if item type was food or drink. Doing it that way would prevent non food/drink items that have a CastTime from showing a Nourishment value in the inspection box.

I can't remember for sure but I think some alcoholic drinks had -1 as their Nourishment value. If that's the case and their item type is drink instead of something special just for alcohol, it's possible that consuming them might actually make you more thirsty (just like IRL lol). So we might want to show the -100 impact to thirstlevel for them. More research :P

Now for what I think is the last info on the timers. I know you guys are probably tired of hearing about it and I'm tired of researching it :).

The hunger/thirst level check timer is definitely on a 45-second pulse just like the decrement timer. They're staggered though. The level checker fires first. It's the one that generates all the "You are hungry" or "You are out of food" etc. messages. I found that if I let my levels fall below 3000 (the point at which "You are hungry" messages start appearing) and zoned with no food in my inventory, I got a hungry message maybe 30 seconds before my levels were decremented again. It's almost like the level checker is running all the time (maybe from the moment you select your char and start to enter the world), but the level decrement timer only starts when you actually appear in the world. Who cares really :roll:

Anyway, when I get home tonight I'll try to post my little macro for watching your levels, even though you guys have probably come up with your own by now. I found I couldn't make it a general-purpose include since it depends on a timer and would thus interfere with any macros that already use Event_Timer (or maybe I'm just not smart enough about MQ yet). But it would be easy enough to manually include it in other macros. I'll post it in this thread instead of the depot since it requires the changes above before it will work.

This is the first time I've messed with C since I quit going to my systems class in college a *long* time ago. This is a lot more fun than I remember the class being!

-visar

visar
orc pawn
orc pawn
Posts: 10
Joined: Fri Jan 09, 2004 10:58 am
Location: USA

Post by visar » Fri Feb 20, 2004 7:30 pm

Alcohol drinks with a nourishment value of -100 (0xFFFF in Nourish field) have no effect on thirstlevel when consumed.

The following was fun to use in the bazaar. Misty Thicket Picnic 12000, Qeynos Afternoon Tea 8500, Kaladim Constitutional 12000.

MQ2ItemDisplay\MQ2ItemDisplay.cpp:

Code: Select all

*** orig/MQ2ItemDisplay/MQ2ItemDisplay.cpp      Wed Feb 11 02:05:44 2004
--- new/MQ2ItemDisplay/MQ2ItemDisplay.cpp       Fri Feb 20 09:57:35 2004
***************
*** 66,71 ****
--- 66,77 ----
        strcat(out,temp);
       }

+      // visar 2004/02/20
+      if (Item->ItemType==/*Food*/14 || Item->ItemType==/*Drink*/15) {
+        sprintf(temp,"Nourishment: %d<BR>",Item->Nourishment*100);
+        strcat(out,temp);
+      }
+
       // This really should be a compare against some field in the item...
       if (strstr(This->ItemInfo->Text,"(Combat)")) {
           if (Item->Level == 0 )