Skip to content

Commit

Permalink
Player: Fix Power Sync between Client & Server
Browse files Browse the repository at this point in the history
Closes #470
  • Loading branch information
insunaa authored and killerwife committed Jan 11, 2024
1 parent 7ecbb10 commit 5111706
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 48 deletions.
69 changes: 39 additions & 30 deletions src/game/Entities/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1625,8 +1625,9 @@ void Player::Update(const uint32 diff)
if (IsAlive())
{
m_regenTimer += diff;
if (m_regenTimer >= REGEN_TIME_FULL)
RegenerateAll(m_regenTimer / 100 * 100);
m_healthRegenTimer += diff;
if (m_regenTimer >= REGEN_TIME_PRECISE)
RegenerateAll(m_regenTimer);
}

if (m_deathState == JUST_DIED)
Expand Down Expand Up @@ -2433,32 +2434,40 @@ void Player::RewardRage(uint32 damage, uint32 weaponSpeedHitFactor, bool attacke

void Player::RegenerateAll(uint32 diff)
{
// Not in combat or they have regeneration
if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) ||
HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT))
if (m_healthRegenTimer >= REGEN_TIME_FULL)
{
RegenerateHealth(diff);
if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
{
Regenerate(POWER_RAGE, diff);
if (getClass() == CLASS_DEATH_KNIGHT)
Regenerate(POWER_RUNIC_POWER, diff);
}
if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT))
RegenerateHealth(REGEN_TIME_FULL);
m_healthRegenTimer -= REGEN_TIME_FULL;
}

Regenerate(POWER_ENERGY, diff);

Regenerate(POWER_MANA, diff);

if (getClass() == CLASS_DEATH_KNIGHT)
Regenerate(POWER_RUNE, diff);
switch (getClass())
{
case CLASS_DRUID:
Regenerate(POWER_ENERGY, diff);
Regenerate(POWER_MANA, diff);
case CLASS_WARRIOR:
if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
Regenerate(POWER_RAGE, diff);
break;
case CLASS_ROGUE:
Regenerate(POWER_ENERGY, diff);
break;
case CLASS_DEATH_KNIGHT:
if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN))
Regenerate(POWER_RUNIC_POWER, diff);
Regenerate(POWER_RUNE, diff);
break;
default:
Regenerate(POWER_MANA, diff);
}

m_regenTimer -= diff;
}

void Player::Regenerate(Powers power, uint32 diff)
{
uint32 curValue = GetPower(power);
float curValue = GetRealPower(power);
uint32 maxValue = GetMaxPower(power);

float addvalue = 0.0f;
Expand All @@ -2475,17 +2484,17 @@ void Player::Regenerate(Powers power, uint32 diff)
if (recentCast)
{
// Mangos Updates Mana in intervals of 2s, which is correct
addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * uint32(float(diff) / 1000);
addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * (float(diff) / 1000);
}
else
{
addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * uint32(float(diff) / 1000);
addvalue = GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * (float(diff) / 1000);
}
} break;
case POWER_RAGE: // Regenerate rage
{
float RageDecreaseRate = sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_RAGE_LOSS);
addvalue = uint32(float(diff) / 200) * 2.5 * RageDecreaseRate; // decay 2.5 rage per 2 seconds
addvalue = (float(diff) / 200) * 2.5 * RageDecreaseRate; // decay 2.5 rage per 2 seconds

AuraList const& ModPowerRegenPCTAuras = GetAurasByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT);
for (auto ModPowerRegenPCTAura : ModPowerRegenPCTAuras)
Expand All @@ -2495,13 +2504,13 @@ void Player::Regenerate(Powers power, uint32 diff)
case POWER_ENERGY: // Regenerate energy
{
float EnergyRate = sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_ENERGY);
addvalue = uint32(float(diff) / 100) * EnergyRate * m_energyRegenRate;
addvalue = (float(diff) / 100) * EnergyRate * m_energyRegenRate;
break;
}
case POWER_RUNIC_POWER:
{
float RunicPowerDecreaseRate = sWorld.getConfig(CONFIG_FLOAT_RATE_POWER_RUNICPOWER_LOSS);
addvalue = uint32(float(diff) / 200) * 2.5 * RunicPowerDecreaseRate; // decay 2.5 runic power per 2 seconds
addvalue = (float(diff) / 200) * 2.5 * RunicPowerDecreaseRate; // decay 2.5 runic power per 2 seconds
} break;
case POWER_RUNE:
{
Expand Down Expand Up @@ -2530,23 +2539,23 @@ void Player::Regenerate(Powers power, uint32 diff)

if (power != POWER_RAGE && power != POWER_RUNIC_POWER)
{
curValue += uint32(addvalue);
curValue += addvalue;
if (curValue > maxValue)
curValue = maxValue;
}
else
{
if (curValue <= uint32(addvalue))
curValue = 0;
if (curValue <= addvalue)
curValue = 0.f;
else
curValue -= uint32(addvalue);
curValue -= addvalue;
}
SetPower(power, curValue, false);
}

void Player::RegenerateHealth(uint32 diff)
{
uint32 curValue = GetHealth();
float curValue = GetRealHealth();
uint32 maxValue = GetMaxHealth();

if (curValue >= maxValue) return;
Expand Down Expand Up @@ -2578,7 +2587,7 @@ void Player::RegenerateHealth(uint32 diff)
if (addvalue < 0)
addvalue = 0;

ModifyHealth(int32(addvalue * float(diff) / 1000));
ModifyHealth(addvalue * float(diff) / 1000);
}

Creature* Player::GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask)
Expand Down
26 changes: 17 additions & 9 deletions src/game/Entities/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ Unit::Unit() :
m_charmInfo(nullptr),
i_motionMaster(this),
m_regenTimer(0),
m_healthRegenTimer(0),
m_unitHealth(0),
m_vehicleInfo(nullptr),
m_combatData(new CombatData(this)),
m_guardianPetsIterator(m_guardianPets.end()),
Expand Down Expand Up @@ -319,6 +321,10 @@ Unit::Unit() :
m_createResistance = 0;

m_attacking = nullptr;

for (float& i : m_unitPower)
i = 0.0f;

m_modMeleeHitChance = 0.0f;
m_modRangedHitChance = 0.0f;
m_modSpellHitChance = 0.0f;
Expand Down Expand Up @@ -9071,14 +9077,14 @@ void Unit::HandleExitCombat(bool pvpCombat)
CallForAllControlledUnits([](Unit* unit) { unit->HandleExitCombat(); }, CONTROLLED_PET | CONTROLLED_GUARDIANS | CONTROLLED_CHARM | CONTROLLED_TOTEMS);
}

int32 Unit::ModifyHealth(int32 dVal)
float Unit::ModifyHealth(float dVal)
{
if (dVal == 0)
return 0;

int32 curHealth = (int32)GetHealth();
float curHealth = GetRealHealth();

int32 val = dVal + curHealth;
float val = dVal + curHealth;
if (val <= 0)
{
SetHealth(0);
Expand All @@ -9087,7 +9093,7 @@ int32 Unit::ModifyHealth(int32 dVal)

int32 maxHealth = (int32)GetMaxHealth();

int32 gain;
float gain;
if (val < maxHealth)
{
SetHealth(val);
Expand Down Expand Up @@ -10373,13 +10379,14 @@ void Unit::SetLevel(uint32 lvl)
((Player*)this)->SetGroupUpdateFlag(GROUP_UPDATE_FLAG_LEVEL);
}

void Unit::SetHealth(uint32 val)
void Unit::SetHealth(float val)
{
uint32 maxHealth = GetMaxHealth();
if (maxHealth < val)
val = maxHealth;

SetUInt32Value(UNIT_FIELD_HEALTH, val);
SetUInt32Value(UNIT_FIELD_HEALTH, uint32(val));
m_unitHealth = val;

// group update
if (GetTypeId() == TYPEID_PLAYER)
Expand Down Expand Up @@ -10423,16 +10430,17 @@ void Unit::SetHealthPercent(float percent)
SetHealth(newHealth);
}

void Unit::SetPower(Powers power, uint32 val, bool withPowerUpdate /*= true*/)
void Unit::SetPower(Powers power, float val, bool withPowerUpdate /*= true*/)
{
if (GetPower(power) == val)
if (GetRealPower(power) == val)
return;

uint32 maxPower = GetMaxPower(power);
if (maxPower < val)
val = maxPower;

SetStatInt32Value(UNIT_FIELD_POWER1 + power, val);
SetStatInt32Value(UNIT_FIELD_POWER1 + power, int32(val));
m_unitPower[power] = val;

if (withPowerUpdate)
{
Expand Down
12 changes: 9 additions & 3 deletions src/game/Entities/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1411,22 +1411,24 @@ class Unit : public WorldObject
inline void SetResistance(SpellSchools school, int32 val) { SetInt32Value(UNIT_FIELD_RESISTANCES + school, val); }

uint32 GetHealth() const { return GetUInt32Value(UNIT_FIELD_HEALTH); }
float GetRealHealth() const { return m_unitHealth; }
uint32 GetMaxHealth() const { return GetUInt32Value(UNIT_FIELD_MAXHEALTH); }
float GetHealthPercent() const { return (GetHealth() * 100.0f) / GetMaxHealth(); }
void SetHealth(uint32 val);
void SetHealth(float val);
void SetMaxHealth(uint32 val);
void SetHealthPercent(float percent);
int32 ModifyHealth(int32 dVal);
float ModifyHealth(float dVal);
float OCTRegenHPPerSpirit() const;
float OCTRegenMPPerSpirit() const;

Powers GetPowerType() const { return Powers(GetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE)); }
void SetPowerType(Powers new_powertype, bool sendUpdate = true);
uint32 GetPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_POWER1 + power); }
float GetRealPower(Powers power) const { return m_unitPower[power]; }
uint32 GetMaxPower(Powers power) const { return GetUInt32Value(UNIT_FIELD_MAXPOWER1 + power); }
float GetPowerPercent() const { return (GetMaxPower(GetPowerType()) == 0) ? 0.0f : (GetPower(GetPowerType()) * 100.0f) / GetMaxPower(GetPowerType()); }
float GetPowerPercent(Powers power) const { return (GetMaxPower(power) == 0) ? 0.0f : (GetPower(power) * 100.0f) / GetMaxPower(power); }
void SetPower(Powers power, uint32 val, bool withPowerUpdate = true);
void SetPower(Powers power, float val, bool withPowerUpdate = true);
void SetMaxPower(Powers power, uint32 val);
int32 ModifyPower(Powers power, int32 dVal);
void ApplyPowerMod(Powers power, uint32 val, bool apply);
Expand Down Expand Up @@ -2098,6 +2100,9 @@ class Unit : public WorldObject
form != FORM_SHADOW && form != FORM_STEALTH;
}

float m_unitHealth;
float m_unitPower[POWER_RUNIC_POWER + 1];

float m_modMeleeHitChance;
float m_modRangedHitChance;
float m_modSpellHitChance;
Expand Down Expand Up @@ -2694,6 +2699,7 @@ class Unit : public WorldObject

uint32 m_reactiveTimer[MAX_REACTIVE];
uint32 m_regenTimer;
uint32 m_healthRegenTimer;
uint32 m_lastManaUseTimer;

bool m_canDodge;
Expand Down
9 changes: 7 additions & 2 deletions src/game/Maps/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ void Map::LoadMapAndVMap(int gx, int gy)

Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
: i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0), m_clientUpdateTimer(0),
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_persistentState(nullptr),
m_activeNonPlayersIter(m_activeNonPlayers.end()), m_onEventNotifiedIter(m_onEventNotifiedObjects.end()),
i_gridExpiry(expiry), m_TerrainData(sTerrainMgr.LoadTerrain(id)),
Expand Down Expand Up @@ -874,7 +874,12 @@ void Map::Update(const uint32& t_diff)
#endif

// Send world objects and item update field changes
SendObjectUpdates();
m_clientUpdateTimer += t_diff;
if (m_clientUpdateTimer >= 333)
{
m_clientUpdateTimer -= 333;
SendObjectUpdates();
}

// Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
// This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
Expand Down
1 change: 1 addition & 0 deletions src/game/Maps/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,7 @@ class Map : public GridRefManager<NGridType>
uint32 i_id;
uint32 i_InstanceId;
uint32 m_unloadTimer;
uint32 m_clientUpdateTimer;
float m_VisibleDistance;
MapPersistentState* m_persistentState;

Expand Down
7 changes: 3 additions & 4 deletions src/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7609,12 +7609,11 @@ SpellCastResult Spell::CheckPower(bool strict)
return SPELL_CAST_OK;

// Do precise power regen on spell cast
if (m_powerCost > 0 && m_caster->GetTypeId() == TYPEID_PLAYER)
if (m_powerCost > 0 && m_caster->IsPlayer())
{
Player* playerCaster = (Player*)m_caster;
Player* playerCaster = static_cast<Player*>(m_caster);
uint32 diff = m_caster->GetRegenTimer();
if (diff >= REGEN_TIME_PRECISE)
playerCaster->RegenerateAll(diff);
playerCaster->RegenerateAll(diff);
}

m_powerCost = CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem, !strict);
Expand Down

0 comments on commit 5111706

Please sign in to comment.