Monday, August 16, 2021

Tip - Sit and Rest Together For Maximum Recovery (and cancel the resting early)


Twitch streamer Djackzz asked me to look at how Resting and Sitting On Ground work together.

He likes so sit on the ground next to a chair, and then rest.  He believes this increases how much endurance he recovers.

He's right.

It's because they are two independent activities.  Resting is a TimedAction, and doesn't affect the normal endurance recovery code where the sitting benefit is applied.  So you can do both at the same time, and get both benefits.

Resting is handled in the ISRestAction.lua file

The actual recovery during rest is handled in update()

function ISRestAction:update()
    if self.character then
        local endurance = self.character:getStats():getEndurance() + ((ZomboidGlobals.ImobileEnduranceIncrease * self.character:getRecoveryMod() * self.mul) * getGameTime():getMultiplier())
        if endurance > 1 then endurance = 1 end
        if endurance < 0 then endurance = 0 end
        self.character:getStats():setEndurance(endurance)

        self.character:setMetabolicTarget(Metabolics.SeatedResting);
    end
end

This is a timed action, and update gets called frequently (multiple times per second).

You can see it takes the current endurance, and then adds a value based on some settings and how much time has passed.  No mention of whether or not the character is sitting, because that is separate and independent.

When you sit, your endurance recovers at an increased rate, and that is handled in IsoPlayer.class (in the updateEndurance method).

This code is also called regularly - it is called by updateInternal2, which is called by updateInternal1, which is called by update().  Update() is inherited from its parent, and it looks like it goes up the ancestors to some of Project Zomboid's base classes.  

    private void updateEndurance(float f) {
        if (this.isSitOnGround()) {
            float f2 = (float)ZomboidGlobals.SittingEnduranceMultiplier;
            f2 *= 1.0f - this.stats.fatigue;
            this.stats.endurance = (float)((double)this.stats.endurance + ZomboidGlobals.ImobileEnduranceReduce * SandboxOptions.instance.getEnduranceRegenMultiplier() * (double)this.getRecoveryMod() * (double)(f2 *= GameTime.instance.getMultiplier()));
            this.stats.endurance = PZMath.clamp(this.stats.endurance, 0.0f, 1.0f);
            return;
        }
        // Code for if you aren't sitting follows

Here, if you are sitting your endurance goes up as time passes, affected by some modifiers.

What is particularly interesting about this code is that FATIGUE plays a role.  If you are fatigued at all (drowsy, sleepy, etc.), sitting doesn't update your endurance as effectively!  This is mentioned in the wiki:  "As the character's tiredness rises, their stamina regeneration also gets worse."  So if you are about to sit down and rest, and you are sleepy at all, having some coffee or vitamins will increase the rate at which you recover your fatigue.

One important note - if you do this you may want to cancel your rest action early.  Resting is a Timed Action.  When it initializes it sets up how long the action should take:

o.maxTime = (1 - character:getStats():getEndurance()) * 16000;

This is a calculation based on the character's current endurance.  It stands to reason that if your endurance increases in a way not expected by the ISRestAction code (for example, if you are recovering extra endurance because you are sitting on the ground), you may max out your endurance early.

You can see what happens in update() if your endurance maxes out early:

function ISRestAction:update()
    if self.character then
        local endurance = self.character:getStats():getEndurance() + ((ZomboidGlobals.ImobileEnduranceIncrease * self.character:getRecoveryMod() * self.mul) * getGameTime():getMultiplier())
        if endurance > 1 then endurance = 1 end
        if endurance < 0 then endurance = 0 end
        self.character:getStats():setEndurance(endurance)

        self.character:setMetabolicTarget(Metabolics.SeatedResting);
    end
end

If your endurance is > 1 then it is set to 1 (maximum endurance).

Unfortunately, there is nothing in ISRestAction that automatically exits the action if you max out your endurance before your action is complete.  So you may be spending some time resting when you've already fully recovered.  I don't really consider this a hard bug, but it would be nice if they allowed for the early exit.  Even if you aren't sitting while resting, if the code's calculation of how long you need to rest is not accurate, you may still be performing the rest action after you hit maximum endurance.

So yes, if you are exhausted from running/fighting and it's not time to sleep yet, rest by first sitting on the ground next to a chair or bed, then rest in the chair/bed.  Better yet, have some coffee or vitamins right before you rest.  You'll get credit for both resting and sitting and the same time, and will maximize your endurance recovery.  And don't wait for the rest action to complete - you will probably be fully recovered before that is done.


No comments:

Post a Comment

Do Gloves Protect You From Broken Glass?

Yes, gloves protect you from handling broken glass - any pair of gloves.  But gloves are not needed when removing broken glass from a smashe...