Sign in to follow this  
Ostentatio

Certain food effects (Fill, good food, Opulence) can lower nutrition drastically

Recommended Posts

It's well-known at this point that there are some oddities concerning how certain food effects interact with nutrition:

  • Path of Insanity "Fill" has been said to give random nutrition, or give bad nutrition if your food bar is low.
  • Opulence has been said to sometimes cause food to lower your nutrition for some reason.
  • Eating just before you would fast has been said to lower your nutrition as well.

 

I'm pretty sure I've figured out why.

 

Before getting into the code involved, here's the gist of it: If a hunger-reducing effect restores too much food compared to how full the character already was, nutrition is not calculated properly and will generally be much lower than expected.

 

Note that this does not apply to refresh, dying, and possibly some other things, since those use their own methods for altering nutrition and hunger.

 

 

Now to the dry, annoying stuff.

 

The problem is in CreatureStatus.modifyHunger(). Here, have a code snippet:

final int oldHunger = this.hunger;
this.hunger = Math.min(65535, Math.max(1, this.hunger + hungerModification));
if (this.hunger < 65535) {
	final int realHungerModification = Math.max(hungerModification, this.hunger - oldHunger);
	if (realHungerModification < ) {
		if (this.nutrition > 0.0f) {
			final float oldnutritionFraction = Math.max(1.0f, 65535 - oldHunger) / (Math.max(1.0f, 65535 - oldHunger) - realHungerModification);
			// ^^^ percentage of new food bar that was already full
			final float newnutritionFraction = Math.min(65535 - oldHunger, -realHungerModification) / (Math.max(1.0f, 65535 - oldHunger) - realHungerModification);
			// ^^^ is probably SUPPOSED to be percentage of new food bar that was not full before?
			// but caps food gain at value of old food bar for some reason
			this.nutrition = oldnutritionFraction * this.nutrition + newnutritionFraction * newNutritionLevel;
		}
		else {
			this.nutrition = newNutritionLevel;
		}
	}
}

Comments mine.

 

The intent of this nutrition-related bit, as I interpret it, is to average the nutrition of what you're eating into your food bar. So let's say you're at 25% food bar and 50% nutrition, and eat 99% nutrition food that brings you up to a 50% food bar. Half your new food bar is the result of the food you ate, and half is what you had at 50% nutrition, so it uses 50% of the old nutrition value and 50% of the new nutrition value, leaving you with roughly 75% nutrition. Basically, it's just a weighted average of your old nutrition and new nutrition, weighted based on your food bar before and the increase to your food bar.

 

However, the way it's implemented is very strange, and the newnutritionFraction calculation uses your old food bar value instead of -realHungerModification (the amount of food bar you just had restored) if the former is higher than the latter. I have no idea what the purpose of that is, but essentially, this means that if you're restoring more food bar in one step than the food bar you already had, things screw up and your nutrition gets tanked. There are situations where you use something that restores a lot of food at once, like Fill, and instead of the calculation saying "let's weight nutrition as 12% from the existing food stock and 88% from what the player just received" (as these must total 100% to make sense, as it is a weighted average), it instead says something like "let's weight nutrition as 12% from the existing food stock and 12% from what the player just received", with the end result that your nutrition is atrocious.

 

This can also happen with high-QL meals when you're very very hungry, especially if you use Opulence.

 

What I don't understand is why the weighted average is implemented in such a strange way. At the very least, the min() statement in the newnutritionFraction assignment is causing the problem here and doesn't serve a purpose that I can figure out.

 

Really, the whole thing could be simplified a bit. Hunger is already recalculated at this point, and you know some food bar has been restored, so you could just do something like:

final int oldHunger = this.hunger;
this.hunger = Math.min(65535, Math.max(1, this.hunger + hungerModification));
if (this.hunger < 65535) {
	final int realHungerModification = Math.max(hungerModification, this.hunger - oldHunger);
	if (realHungerModification < ) {
		if (this.nutrition > 0.0f) {
			final float oldnutritionFraction = Math.max(1.0f, 65535 - oldHunger) / Math.max(1.0f, 65535 - this.hunger);
			// ^^^ percentage of new food bar that was already full
			final float newnutritionFraction = -realHungerModification / Math.max(1.0,65535 - this.hunger);
			// ^^^ percentage of new food bar that is the result of eating
			this.nutrition = oldnutritionFraction * this.nutrition + newnutritionFraction * newNutritionLevel;
		}
		else {
			this.nutrition = newNutritionLevel;
		}
	}
}

 

Of course, there may be things I'm unaware of that would explain some of this, but the newnutritionFraction calculation is definitely a bit of a mess and is definitely causing the problem.

Edited by Ostentatio
  • Like 2

Share this post


Link to post
Share on other sites

That was way too fast, Alectrys. You're starting to scare me.

 

Thanks for the response!

Edited by Ostentatio

Share this post


Link to post
Share on other sites

Hire this guy.

Edited by zigozag
  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this