Jump to content

[SOLVED] Check if player is eating/drinking.


grumpypoo
 Share

Recommended Posts

Currently working on a mod.
I'm a little lost and hope someone can point me in the right direction..
(C++)

Is there a native function that checks whenever the player is eating/drinking?
I've checked the scenarios (for drinking) to see if it'll return for me, but no luck.

I've thought about checking the animation, but before I dig deep into that figured i'd ask first.

Any help is much appreciated.

------------------------------------------------------------------------------------------------------------------------------------------

Here is the solution - 
 

Alright i've figured this out - 
Here is the code i'm using to check if someone drinks anything

 

int tAnimationSet = 0;
static int getGameTime() 
{
	return invoke<int>(0x4F67E8ECA7D3F667);
}
bool refillThirstCoreScenario()
{
	const char* animations[] = {
		"face_human@gen_male@scenario@drinkbottle",
		"face_human@gen_male@scenario@drinkshot",
		"face_human@gen_male@scenario@drinkmug",
		"face_human@gen_male@scenario@drinkhand"
	};
	for (const char* animation : animations)
	{
		if (STREAMING::HAS_ANIM_DICT_LOADED(animation))
		{
			return true;
			tAnimationSet = getGameTime();
			break;
		}
	}
	return false;
}
void update()
{
  // Core refilling actions 
  if (TASK::GET_IS_TASK_ACTIVE(PLAYER::PLAYER_PED_ID(), 471))
  {
    // Thirst
    if (refillThirstCoreScenario())
    {
      if (getGameTime() - tAnimationSet > 5000)
      {
        PrintSubtitle("You drank!");
      }
    }
  }
}


This is a reliable way to check if someone has drank a liquid.
For eating you can check the eating animation like I did with drinking.

Feel free to copy/paste this code - If you do use it, give yourself a high five in my honor.

Edited by grumpypoo
Link to comment
Share on other sites

I don't think there's a native for that.

 

There's a scenario for pouring coffee at camp, probably one for taking stew, too, or you can check if you have a coffee mug or plate in your hand, but I doubt you can detect just normally eating something from your inventory that way.

 

Checking your core values might be another way, when they're being refilled and the player is not sleeping then probably eating or drinking... I don't know if it's possible to do it reliably.

 

Let me know if you find a way, I'd be interested, too 😄

Link to comment
Share on other sites

Well I have discovered something yesterday - 

Whenever the cores get refilled it uses TASK 471.
I haven't tested this against sleep, but eating/drinking from your provisions work.

So I figured that would be my first check - 
Then I moved on to just seeing if an object was in the players hand (This went terribly)
So I went through OpenIV looking for elixir because that's one of the drinks I have.

I ended up finding the prop in
levels_3\rdr3\props\lev_des\s_pickups.rpf
I realized these were all the props that you use for provisions + other stuff.

I got the bright idea to test
IS_ENTITY_TOUCHING_MODEL(entity, hash)

entity = PLAYER_PED_ID()
hash = GET_HASH_KEY("s_ginsengelixir01x")

Whenever I drank the elixir nothing happened, but once he dropped the bottle and the players foot touched it - The function actually returned true?
So now i'm back to being confused, but I have a few more things I want to try.

 

bool refillThirstCoreScenario()
{
	const char* objs[] =
	{
		"s_brandy01x",
		"s_brandy_used01x",
		"s_ginsengelixir01x"
	};
	for (const char* obj : objs)
	{
		if (ENTITY::IS_ENTITY_TOUCHING_MODEL(PLAYER::PLAYER_PED_ID(), MISC::GET_HASH_KEY(obj)))
		{
			//if (TASK::GET_IS_TASK_ACTIVE(PLAYER::PLAYER_PED_ID(), 471))
			//{
				return true;
				break;
			//}
		}
	}
	return false;
}



Here is the code i'm using to check if anyone is interested

Edited by grumpypoo
Link to comment
Share on other sites

Maybe you could use GET_CLOSEST_OBJECT_OF_TYPE(float x, float y, float z, float radius, Hash modelHash, BOOL isMission, BOOL p6, BOOL p7)

or one of script hook's 'get all' functions.

worldGetAllPickups(pickups, pickupsArraySize); 
worldGetAllObjects(objects, objectsArraySize);

Something like:

const int arrSize{ 512 };
Object objects[arrSize];	
int objCount = worldGetAllObjects(objects, arrSize);
for (int i = 0; i < objCount; ++i)
	if (ENTITY::GET_ENTITY_MODEL(pickups[i]) == MISC::GET_HASH_KEY("s_brandy01x"))
	{
		// if bottle found
		// check distance to player ??
	}

I mean it's pretty convoluted, but if it finds the object while it's in the players hand then it could be used reliably.

Edited by crossed99
Link to comment
Share on other sites

Yea I tried that method to see if it was near the players hand/face etc, but nothing returned 😕
It seems like the object doesn't actually exist during the animation - Almost as if it is hidden.
I found the animations but of course there were no objects (Ironically none of the animations I found actually load during the drinking animation?)

I did find a reliable animation dictionary however - face_human@gen_male@scenario@drinkbottle
This animation dictionary gets loaded whenever the player drinks from a bottle.
The downside is - It doesn't ever seem to unload (So nothing as simple as "Oh well i'll just run a check for TASK 471 then check if the animation dictionary loaded"


So now i'm looking if the player is actually using the animation - 
I have no idea what the taskflag is supposed to be for ENTITY::IS_ENTITY_PLAYING_ANIM
I've tried the GTAV 3 flag or 2, but I fear this is not the case.

I also found something about getting off a horse animation that used 1 << 18 (262144)
I think I might just have to spawn a bunch of bottles and have a loop going to see if the animation hits

Here is my current debug code for those that care
 

const char* scenarios[] = {
			"loop_short",
			"loop_long",
			"opengulp",
			"enter",
			"strain_enter",
			"closegulp",
			"strain_gasp",
			"strain_loop_long",
			"strain_exit",
			"enter_short",
			"strain_loop_short",
			"exit"
		};
		for (const char* scenario : scenarios)
		{
			if (ENTITY::IS_ENTITY_PLAYING_ANIM(PLAYER::PLAYER_PED_ID(), "face_human@gen_male@scenario@drinkbottle", scenario, 1 << 18))
			{
				PrintSubtitle("Works");
				break;
			}
		}

 

Link to comment
Share on other sites

Oh I'm silly

2 hours ago, grumpypoo said:

I did find a reliable animation dictionary however - face_human@gen_male@scenario@drinkbottle
This animation dictionary gets loaded whenever the player drinks from a bottle.
The downside is - It doesn't ever seem to unload (So nothing as simple as "Oh well i'll just run a check for TASK 471 then check if the animation dictionary loaded"


This turned out to be a false statement.

I got frustrated by checking individual animations and decided to revisit this idea

2 hours ago, grumpypoo said:

(So nothing as simple as "Oh well i'll just run a check for TASK 471 then check if the animation dictionary loaded")


I tested this code -

if (STREAMING::HAS_ANIM_DICT_LOADED("face_human@gen_male@scenario@drinkbottle"))
		{
			PrintSubtitle("DICT_LOADED");
		}
		else
		{
			PrintSubtitle("DICT_NOT_LOADED");
		}


Turns out R* does remove the Animation Dictionary.
A few things that are confusing -

  • The DICT doesn't immediately unload
    • I tried to force this by waiting say 10 seconds and running STREAMING::REMOVE_ANIM_DICT("face_human@gen_male@scenario@drinkbottle");
      • This lead to animations for drinking to be completely broken
    • So you have to drink then do anything other than drink again
      • At that point R* unloads the dict


So how can we take advantage of this?

We know the following information

  • TASK ID 471 = Cores getting filled
    • This works with drinking and eating - Sleeping is unknown
  • Drinking from a bottle uses the following animation dictionary
    • face_human@gen_male@scenario@drinkbottle
  • The animation doesn't get unloaded until something other than drinking is done after the animation completes


An initial check could look like this

if (TASK::GET_IS_TASK_ACTIVE(PLAYER::PLAYER_PED_ID(), 471)) // Check that the core task is running
{
	if (STREAMING::HAS_ANIM_DICT_LOADED("face_human@gen_male@scenario@drinkbottle")) // Is the Animation dictionary loaded?
    {
      // Do something here
    }
}


What this doesn't solve is the animation dictionary doesn't get unloaded until the player does something else

Possible solutions?

  • Force another animation after like 5 seconds
    • This will need to be tested and it needs to be from another DICT outside of what we are trying to check


I will continue to test this and once I come up with a final solution I will post the code here.

Link to comment
Share on other sites

Alright i've figured this out - 
Here is the code i'm using to check if someone drinks anything

 

int tAnimationSet = 0;
static int getGameTime() 
{
	return invoke<int>(0x4F67E8ECA7D3F667);
}
bool refillThirstCoreScenario()
{
	const char* animations[] = {
		"face_human@gen_male@scenario@drinkbottle",
		"face_human@gen_male@scenario@drinkshot",
		"face_human@gen_male@scenario@drinkmug",
		"face_human@gen_male@scenario@drinkhand"
	};
	for (const char* animation : animations)
	{
		if (STREAMING::HAS_ANIM_DICT_LOADED(animation))
		{
			return true;
			tAnimationSet = getGameTime();
			break;
		}
	}
	return false;
}
void update()
{
  // Core refilling actions 
  if (TASK::GET_IS_TASK_ACTIVE(PLAYER::PLAYER_PED_ID(), 471))
  {
    // Thirst
    if (refillThirstCoreScenario())
    {
      if (getGameTime() - tAnimationSet > 5000)
      {
        PrintSubtitle("You drank!");
      }
    }
  }
}


This is a reliable way to check if someone has drank a liquid.
For eating you can check the eating animation like I did with drinking.

Feel free to copy/paste this code - If you do use it, give yourself a high five in my honor.

  • Like 1
Link to comment
Share on other sites

  • grumpypoo changed the title to [SOLVED] Check if player is eating/drinking.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...