Gotcha: Very nice and interesting! Thank you for this.
Thanks!
dtgreene: Worth noting that this may differ from how the original Ultima 7 handles it.
It is, as I note in the beginning of the text. I didn't touch on HP/MP regen in this, but did read about it in the code. Here's the function mend_wounds in actors.cc:
/*
* Restore HP's on the hour.
*/
void Actor::mend_wounds(
bool mendmana
) {
int hp = properties[static_cast<int>(health)];
bool starving = (get_property(static_cast<int>(food_level)) <= 9
&& is_in_party() && !get_info().does_not_eat());
// It should be okay to leave is_cold_immune out.
// It blocks raising temperature in the first place.
bool freezing = (is_in_party() && temperature >= 50 &&
!(gear_powers & Frame_flags::cold_immune));
if (is_dead() || get_flag(Obj_flags::poisoned) || (starving && hp > 0) ||
freezing)
return;
int maxhp = properties[static_cast<int>(strength)];
if (maxhp > 0 && hp < maxhp) {
// first case doesn't seem to be used in the original - will keep for npcs
if (maxhp >= 3 && !starving && get_schedule_type() == Schedule::sleep)
hp += 1 + rand() % (maxhp / 3);
else
hp += 1;
if (hp > maxhp)
hp = maxhp;
properties[static_cast<int>(health)] = hp;
}
if (!mendmana)
return;
// Restore some mana also.
int maxmana = properties[static_cast<int>(magic)];
int curmana = properties[static_cast<int>(mana)];
clear_flag(Obj_flags::no_spell_casting);
if (maxmana > 0 && curmana < maxmana) {
if (maxmana >= 3)
curmana += 1 + rand() % (maxmana / 3);
else
curmana += 1;
properties[static_cast<int>(mana)] = curmana <= maxmana ? curmana
: maxmana;
}
}
As you mentioned, HP regens 1 per call, or more if sleeping. If mana is greater than 3, it regens from 1 up to a third of the max mana. If it's 0-2, it regens 1. This function is called for every npc every hour, in gameclk.cc.
Those changes you mentioned should be fairly easy to implement. You could open an issue and bring attention to the Exult team.