Pet Battles: Wire state-driven weather system from DB2
Replace dead hardcoded PetBattleWeatherType enum with a data-driven weather system that reads BattlePetAbilityState entries from DB2. The old system had SetWeather/GetWeatherDamageModifier/GetWeatherHealingModifier functions but SetWeather was never called, so weather abilities fired visually (aura icon appeared) but had zero gameplay effect. Now weather modifiers (damage %, healing %, accuracy, speed) are loaded from BattlePetAbilityState DB2 onto the environment slot when a weather aura is applied, and read back during combat calculations. Elemental pets remain immune to all weather effects.
This commit is contained in:
@@ -109,6 +109,7 @@ namespace BattlePets
|
||||
STATE_STAT_POWER = 18,
|
||||
STATE_STAT_STAMINA = 19,
|
||||
STATE_STAT_SPEED = 20,
|
||||
STATE_STAT_ACCURACY = 22,
|
||||
STATE_MOD_DAMAGE_DEALT_PERCENT = 23,
|
||||
STATE_MOD_DAMAGE_TAKEN_PERCENT = 24,
|
||||
STATE_MOD_SPEED_PERCENT = 25,
|
||||
|
||||
@@ -445,11 +445,12 @@ namespace PetBattles
|
||||
_needsFrontPetSwap.fill(false);
|
||||
|
||||
// Recalculate effective stats for all living pets (includes passive bonuses, weather speed)
|
||||
PetBattleWeatherType activeWeather = _environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType;
|
||||
auto const* envStates = _environments[PET_BATTLE_WEATHER_ENV_SLOT].IsActive()
|
||||
? &_environments[PET_BATTLE_WEATHER_ENV_SLOT].States : nullptr;
|
||||
for (uint8 t = 0; t < MAX_PET_BATTLE_PLAYERS; ++t)
|
||||
for (uint8 p = 0; p < _teams[t].PetCount; ++p)
|
||||
if (_teams[t].Pets[p].IsAlive())
|
||||
_teams[t].Pets[p].RecalculateEffectiveStats(activeWeather);
|
||||
_teams[t].Pets[p].RecalculateEffectiveStats(envStates);
|
||||
|
||||
// Apply passive round-start effects (Humanoid heal, Dragonkin reset, etc.)
|
||||
ApplyPassiveRoundStart();
|
||||
@@ -953,6 +954,14 @@ namespace PetBattles
|
||||
int16 basePower = effect->Param[0];
|
||||
int16 accuracy = effect->Param[1];
|
||||
|
||||
// Weather accuracy modifier (Elemental passive: ignores weather)
|
||||
if (accuracy > 0 && attacker.PetType != PET_TYPE_ELEMENTAL)
|
||||
{
|
||||
int32 envAccMod = _environments[PET_BATTLE_WEATHER_ENV_SLOT].GetState(BattlePets::STATE_STAT_ACCURACY);
|
||||
if (envAccMod != 0)
|
||||
accuracy = std::max(int16(0), int16(accuracy + envAccMod));
|
||||
}
|
||||
|
||||
// Check accuracy (if specified and > 0, roll for hit)
|
||||
if (accuracy > 0 && accuracy < 100)
|
||||
{
|
||||
@@ -1043,7 +1052,7 @@ namespace PetBattles
|
||||
effect->ID, abilityID, weatherAuraAbilityID, auraDuration);
|
||||
|
||||
// Cancel existing weather on weather slot (PetbattleEnviros::Weather = 2, PBOID 8)
|
||||
if (_environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID != 0 && _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID != 0)
|
||||
if (_environments[PET_BATTLE_WEATHER_ENV_SLOT].IsActive())
|
||||
{
|
||||
PetBattleRoundEffect cancelEffect;
|
||||
cancelEffect.EffectType = PET_BATTLE_EFFECT_AURA_CANCEL;
|
||||
@@ -1051,16 +1060,19 @@ namespace PetBattles
|
||||
cancelEffect.Param1 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID;
|
||||
cancelEffect.Param2 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID;
|
||||
_roundEffects.push_back(cancelEffect);
|
||||
ClearWeatherStates();
|
||||
}
|
||||
|
||||
// Set up weather environment slot with the weather aura
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID = weatherAuraAbilityID;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType = PET_BATTLE_WEATHER_NONE; // Gameplay mods come from SET_STATE effects
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].RemainingRounds = auraDuration;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CasterTeam = attackerTeam;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID = _nextAuraInstanceID++;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CurrentRound = _currentRound;
|
||||
|
||||
// Load weather modifier states from BattlePetAbilityState DB2
|
||||
ApplyWeatherStates(weatherAuraAbilityID);
|
||||
|
||||
// Emit AURA_APPLY targeting environment PBOID 8 (PetbattleEnviros::Weather)
|
||||
PetBattleRoundEffect applyEffect;
|
||||
applyEffect.AbilityEffectID = effect->ID;
|
||||
@@ -1158,7 +1170,7 @@ namespace PetBattles
|
||||
TC_LOG_DEBUG("server.loading", "PetBattle WEATHER_PERIODIC: effectID={} castAbility={} auraAbilityID={} duration={}",
|
||||
effect->ID, abilityID, weatherAuraAbilityID, auraDuration);
|
||||
|
||||
if (_environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID != 0 && _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID != 0)
|
||||
if (_environments[PET_BATTLE_WEATHER_ENV_SLOT].IsActive())
|
||||
{
|
||||
PetBattleRoundEffect cancelEffect;
|
||||
cancelEffect.EffectType = PET_BATTLE_EFFECT_AURA_CANCEL;
|
||||
@@ -1166,15 +1178,18 @@ namespace PetBattles
|
||||
cancelEffect.Param1 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID;
|
||||
cancelEffect.Param2 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID;
|
||||
_roundEffects.push_back(cancelEffect);
|
||||
ClearWeatherStates();
|
||||
}
|
||||
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID = weatherAuraAbilityID;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType = PET_BATTLE_WEATHER_NONE;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].RemainingRounds = auraDuration;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CasterTeam = attackerTeam;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID = _nextAuraInstanceID++;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CurrentRound = _currentRound;
|
||||
|
||||
// Load weather modifier states from BattlePetAbilityState DB2
|
||||
ApplyWeatherStates(weatherAuraAbilityID);
|
||||
|
||||
PetBattleRoundEffect applyEffect;
|
||||
applyEffect.AbilityEffectID = effect->ID;
|
||||
applyEffect.EffectType = PET_BATTLE_EFFECT_AURA_APPLY;
|
||||
@@ -1352,6 +1367,9 @@ namespace PetBattles
|
||||
TC_LOG_DEBUG("server.loading", "PetBattle WEATHER_SET_STATE: effectID={} stateID={} stateValue={}",
|
||||
effect->ID, stateID, stateValue);
|
||||
|
||||
// Store the state on the environment for gameplay use
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].States[stateID] = stateValue;
|
||||
|
||||
// Emit SET_STATE targeting environment PBOID (slot 0)
|
||||
PetBattleRoundEffect roundEffect;
|
||||
roundEffect.AbilityEffectID = effect->ID;
|
||||
@@ -1554,9 +1572,19 @@ namespace PetBattles
|
||||
result.TypeMod = GetTypeEffectiveness(abilityType, PetBattlePetType(defender.PetType));
|
||||
rawDamage *= result.TypeMod;
|
||||
|
||||
// Weather damage modifier (Elemental passive: ignores all weather effects)
|
||||
// Weather damage modifiers from environment states (Elemental passive: ignores weather)
|
||||
if (attacker.PetType != PET_TYPE_ELEMENTAL)
|
||||
rawDamage *= (1.0f + GetWeatherDamageModifier(abilityType));
|
||||
{
|
||||
int32 envDmgDealMod = _environments[PET_BATTLE_WEATHER_ENV_SLOT].GetState(BattlePets::STATE_MOD_DAMAGE_DEALT_PERCENT);
|
||||
if (envDmgDealMod != 0)
|
||||
rawDamage *= (1.0f + envDmgDealMod / 100.0f);
|
||||
}
|
||||
if (defender.PetType != PET_TYPE_ELEMENTAL)
|
||||
{
|
||||
int32 envDmgTakeMod = _environments[PET_BATTLE_WEATHER_ENV_SLOT].GetState(BattlePets::STATE_MOD_DAMAGE_TAKEN_PERCENT);
|
||||
if (envDmgTakeMod != 0)
|
||||
rawDamage *= (1.0f + envDmgTakeMod / 100.0f);
|
||||
}
|
||||
|
||||
// Beast passive: +25% damage when below 50% HP
|
||||
if (attacker.PetType == PET_TYPE_BEAST && attacker.Health <= attacker.MaxHealth / 2)
|
||||
@@ -1601,8 +1629,13 @@ namespace PetBattles
|
||||
{
|
||||
float rawHealing = healPower * (attackerPower / 20.0f);
|
||||
|
||||
// Weather healing modifier
|
||||
rawHealing *= (1.0f + GetWeatherHealingModifier());
|
||||
// Weather healing modifier from environment states (Elemental passive: ignores weather)
|
||||
if (healer.PetType != PET_TYPE_ELEMENTAL)
|
||||
{
|
||||
int32 envHealMod = _environments[PET_BATTLE_WEATHER_ENV_SLOT].GetState(BattlePets::STATE_MOD_HEALING_DEALT_PERCENT);
|
||||
if (envHealMod != 0)
|
||||
rawHealing *= (1.0f + envHealMod / 100.0f);
|
||||
}
|
||||
|
||||
// State-based healing modifiers
|
||||
for (auto const& [stateID, stateValue] : healer.States)
|
||||
@@ -1829,64 +1862,26 @@ namespace PetBattles
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Environment / Weather system
|
||||
// Environment / Weather system (state-driven from BattlePetAbilityState DB2)
|
||||
// ============================================================================
|
||||
|
||||
void PetBattle::SetWeather(PetBattleWeatherType weatherType, uint32 abilityID, int8 duration, uint8 casterTeam)
|
||||
void PetBattle::ApplyWeatherStates(uint32 abilityID)
|
||||
{
|
||||
if (weatherType == PET_BATTLE_WEATHER_CLEANSING)
|
||||
// Load BattlePetAbilityState entries for this weather ability onto the environment
|
||||
if (auto const* states = sPetBattleMgr->GetWeatherAbilityStates(abilityID))
|
||||
{
|
||||
// Clear all weather ? emit AURA_CANCEL for any active environment auras
|
||||
for (uint8 i = 0; i < MAX_PET_BATTLE_ENVIRONMENTS; ++i)
|
||||
for (auto const& [stateID, value] : *states)
|
||||
{
|
||||
if (_environments[i].WeatherType != PET_BATTLE_WEATHER_NONE && _environments[i].AuraInstanceID != 0)
|
||||
{
|
||||
PetBattleRoundEffect cancelEffect;
|
||||
cancelEffect.EffectType = PET_BATTLE_EFFECT_AURA_CANCEL;
|
||||
cancelEffect.TargetEnvSlot = static_cast<int8>(i);
|
||||
cancelEffect.Param1 = _environments[i].AuraInstanceID;
|
||||
cancelEffect.Param2 = _environments[i].AbilityID;
|
||||
_roundEffects.push_back(cancelEffect);
|
||||
}
|
||||
_environments[i].WeatherType = PET_BATTLE_WEATHER_NONE;
|
||||
_environments[i].AbilityID = 0;
|
||||
_environments[i].RemainingRounds = 0;
|
||||
_environments[i].AuraInstanceID = 0;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].States[stateID] = value;
|
||||
TC_LOG_DEBUG("server.loading", "PetBattle ApplyWeatherStates: abilityID={} stateID={} value={}",
|
||||
abilityID, stateID, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel existing weather on weather slot (PetbattleEnviros::Weather = 2, PBOID 8)
|
||||
if (_environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType != PET_BATTLE_WEATHER_NONE && _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID != 0)
|
||||
{
|
||||
PetBattleRoundEffect cancelEffect;
|
||||
cancelEffect.EffectType = PET_BATTLE_EFFECT_AURA_CANCEL;
|
||||
cancelEffect.TargetEnvSlot = PET_BATTLE_WEATHER_ENV_SLOT;
|
||||
cancelEffect.Param1 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID;
|
||||
cancelEffect.Param2 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID;
|
||||
_roundEffects.push_back(cancelEffect);
|
||||
}
|
||||
|
||||
// Weather slot (PetbattleEnviros::Weather = 2) is the shared battlefield weather
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AbilityID = abilityID;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType = weatherType;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].RemainingRounds = duration;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CasterTeam = casterTeam;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID = _nextAuraInstanceID++;
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].CurrentRound = _currentRound;
|
||||
|
||||
// Emit AURA_APPLY targeting environment PBOID 8 (EnvWeather)
|
||||
PetBattleRoundEffect applyEffect;
|
||||
applyEffect.AbilityEffectID = abilityID;
|
||||
applyEffect.EffectType = PET_BATTLE_EFFECT_AURA_APPLY;
|
||||
applyEffect.SourceTeam = casterTeam;
|
||||
applyEffect.SourcePet = _teams[casterTeam].FrontPetIndex;
|
||||
applyEffect.TargetEnvSlot = PET_BATTLE_WEATHER_ENV_SLOT;
|
||||
applyEffect.Param1 = _environments[PET_BATTLE_WEATHER_ENV_SLOT].AuraInstanceID;
|
||||
applyEffect.Param2 = abilityID;
|
||||
applyEffect.Param3 = duration;
|
||||
applyEffect.Param4 = _currentRound;
|
||||
_roundEffects.push_back(applyEffect);
|
||||
void PetBattle::ClearWeatherStates()
|
||||
{
|
||||
_environments[PET_BATTLE_WEATHER_ENV_SLOT].States.clear();
|
||||
}
|
||||
|
||||
void PetBattle::TickWeather()
|
||||
@@ -1894,7 +1889,7 @@ namespace PetBattles
|
||||
for (uint8 envSlot = 0; envSlot < MAX_PET_BATTLE_ENVIRONMENTS; ++envSlot)
|
||||
{
|
||||
PetBattleEnvironment& env = _environments[envSlot];
|
||||
if (env.WeatherType == PET_BATTLE_WEATHER_NONE)
|
||||
if (!env.IsActive())
|
||||
continue;
|
||||
|
||||
// Emit AURA_CHANGE for environment aura (updates round counter in client)
|
||||
@@ -1915,35 +1910,6 @@ namespace PetBattles
|
||||
|
||||
env.RemainingRounds--;
|
||||
|
||||
// Weather deals periodic damage/effects
|
||||
if (env.WeatherType == PET_BATTLE_WEATHER_SANDSTORM ||
|
||||
env.WeatherType == PET_BATTLE_WEATHER_BLIZZARD ||
|
||||
env.WeatherType == PET_BATTLE_WEATHER_LIGHTNING)
|
||||
{
|
||||
for (uint8 t = 0; t < MAX_PET_BATTLE_PLAYERS; ++t)
|
||||
{
|
||||
PetBattlePetData& frontPet = _teams[t].Pets[_teams[t].FrontPetIndex];
|
||||
if (!frontPet.IsAlive())
|
||||
continue;
|
||||
|
||||
// Elemental passive: ignores all weather effects
|
||||
if (frontPet.PetType == PET_TYPE_ELEMENTAL)
|
||||
continue;
|
||||
|
||||
int32 weatherDamage = std::max(1, frontPet.MaxHealth / 20); // 5% max HP per tick
|
||||
|
||||
frontPet.Health = std::max(0, frontPet.Health - weatherDamage);
|
||||
|
||||
PetBattleRoundEffect roundEffect;
|
||||
roundEffect.AbilityEffectID = env.AbilityID;
|
||||
roundEffect.EffectType = PET_BATTLE_EFFECT_SET_HEALTH;
|
||||
roundEffect.TargetTeam = t;
|
||||
roundEffect.TargetPet = _teams[t].FrontPetIndex;
|
||||
roundEffect.Param1 = frontPet.Health;
|
||||
_roundEffects.push_back(roundEffect);
|
||||
}
|
||||
}
|
||||
|
||||
if (env.RemainingRounds <= 0)
|
||||
{
|
||||
// Emit AURA_CANCEL so client removes the weather icon
|
||||
@@ -1956,49 +1922,14 @@ namespace PetBattles
|
||||
cancelEffect.Param2 = env.AbilityID;
|
||||
_roundEffects.push_back(cancelEffect);
|
||||
}
|
||||
env.WeatherType = PET_BATTLE_WEATHER_NONE;
|
||||
env.AbilityID = 0;
|
||||
env.AuraInstanceID = 0;
|
||||
if (envSlot == PET_BATTLE_WEATHER_ENV_SLOT)
|
||||
ClearWeatherStates();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float PetBattle::GetWeatherDamageModifier(PetBattlePetType abilityType) const
|
||||
{
|
||||
PetBattleWeatherType weather = _environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType;
|
||||
|
||||
switch (weather)
|
||||
{
|
||||
case PET_BATTLE_WEATHER_RAIN:
|
||||
return (abilityType == PET_TYPE_AQUATIC) ? 0.25f : 0.0f;
|
||||
case PET_BATTLE_WEATHER_ARCANE:
|
||||
case PET_BATTLE_WEATHER_MOONLIGHT:
|
||||
return (abilityType == PET_TYPE_MAGIC) ? 0.25f : 0.0f;
|
||||
case PET_BATTLE_WEATHER_LIGHTNING:
|
||||
return (abilityType == PET_TYPE_MECHANICAL) ? 0.25f : 0.0f;
|
||||
case PET_BATTLE_WEATHER_SCORCHED:
|
||||
return (abilityType == PET_TYPE_DRAGONKIN) ? 0.25f : 0.0f;
|
||||
case PET_BATTLE_WEATHER_SANDSTORM:
|
||||
return -0.10f; // Sandstorm reduces all damage slightly
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
float PetBattle::GetWeatherHealingModifier() const
|
||||
{
|
||||
PetBattleWeatherType weather = _environments[PET_BATTLE_WEATHER_ENV_SLOT].WeatherType;
|
||||
|
||||
switch (weather)
|
||||
{
|
||||
case PET_BATTLE_WEATHER_SUNNY:
|
||||
case PET_BATTLE_WEATHER_MOONLIGHT:
|
||||
return 0.25f;
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Passive family abilities
|
||||
// ============================================================================
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "BattlePetMgr.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
class Creature;
|
||||
@@ -59,11 +60,18 @@ namespace PetBattles
|
||||
struct PetBattleEnvironment
|
||||
{
|
||||
uint32 AbilityID = 0;
|
||||
PetBattleWeatherType WeatherType = PET_BATTLE_WEATHER_NONE;
|
||||
int8 RemainingRounds = 0;
|
||||
uint8 CasterTeam = 0;
|
||||
uint32 AuraInstanceID = 0; // Unique ID for the environment aura (sent to client)
|
||||
int32 CurrentRound = 0; // Round when weather was applied
|
||||
std::unordered_map<uint32, int32> States; // BattlePetState modifiers from DB2
|
||||
|
||||
bool IsActive() const { return AbilityID != 0 && AuraInstanceID != 0; }
|
||||
int32 GetState(uint32 stateID) const
|
||||
{
|
||||
auto it = States.find(stateID);
|
||||
return it != States.end() ? it->second : 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct PetBattlePetData
|
||||
@@ -124,7 +132,7 @@ namespace PetBattles
|
||||
// State values for the pet
|
||||
std::vector<std::pair<uint32, int32>> States;
|
||||
|
||||
void RecalculateEffectiveStats(PetBattleWeatherType activeWeather = PET_BATTLE_WEATHER_NONE)
|
||||
void RecalculateEffectiveStats(std::unordered_map<uint32, int32> const* envStates = nullptr)
|
||||
{
|
||||
EffectivePower = Power;
|
||||
EffectiveSpeed = Speed;
|
||||
@@ -163,11 +171,12 @@ namespace PetBattles
|
||||
if (PetType == PET_TYPE_FLYING && Health > MaxHealth / 2)
|
||||
EffectiveSpeed = int32(EffectiveSpeed * (1.0f + PASSIVE_FLYING_SPEED_BONUS));
|
||||
|
||||
// Weather speed penalties (Elemental passive: ignores all weather effects)
|
||||
if (PetType != PET_TYPE_ELEMENTAL)
|
||||
// Weather speed modifier from environment states (Elemental passive: ignores weather)
|
||||
if (PetType != PET_TYPE_ELEMENTAL && envStates)
|
||||
{
|
||||
if (activeWeather == PET_BATTLE_WEATHER_BLIZZARD || activeWeather == PET_BATTLE_WEATHER_MUD)
|
||||
EffectiveSpeed = int32(EffectiveSpeed * 0.75f); // -25% speed
|
||||
auto it = envStates->find(BattlePets::STATE_MOD_SPEED_PERCENT);
|
||||
if (it != envStates->end() && it->second != 0)
|
||||
EffectiveSpeed = int32(EffectiveSpeed * (1.0f + it->second / 100.0f));
|
||||
}
|
||||
|
||||
if (EffectivePower < 1) EffectivePower = 1;
|
||||
@@ -309,11 +318,10 @@ namespace PetBattles
|
||||
void RemoveAura(uint8 targetTeam, uint8 targetPet, uint32 abilityID);
|
||||
void TickAuras();
|
||||
|
||||
// Environment/weather
|
||||
void SetWeather(PetBattleWeatherType weatherType, uint32 abilityID, int8 duration, uint8 casterTeam);
|
||||
// Environment/weather (state-driven from BattlePetAbilityState DB2)
|
||||
void ApplyWeatherStates(uint32 abilityID);
|
||||
void ClearWeatherStates();
|
||||
void TickWeather();
|
||||
float GetWeatherDamageModifier(PetBattlePetType abilityType) const;
|
||||
float GetWeatherHealingModifier() const;
|
||||
|
||||
// Passive family abilities
|
||||
void ApplyPassiveRoundStart();
|
||||
|
||||
@@ -191,21 +191,9 @@ namespace PetBattles
|
||||
PET_BATTLE_AURA_SLEEP = 6,
|
||||
};
|
||||
|
||||
// Weather/environment effect types
|
||||
enum PetBattleWeatherType : uint8
|
||||
{
|
||||
PET_BATTLE_WEATHER_NONE = 0,
|
||||
PET_BATTLE_WEATHER_SUNNY = 1, // +25% healing
|
||||
PET_BATTLE_WEATHER_MOONLIGHT = 2, // +25% healing, +10% magic damage
|
||||
PET_BATTLE_WEATHER_RAIN = 3, // +25% aquatic damage
|
||||
PET_BATTLE_WEATHER_SANDSTORM = 4, // Damage reduction shield, deals damage
|
||||
PET_BATTLE_WEATHER_BLIZZARD = 5, // Deals frost damage, -25% speed
|
||||
PET_BATTLE_WEATHER_MUD = 6, // -25% speed
|
||||
PET_BATTLE_WEATHER_CLEANSING = 7, // removes all weather
|
||||
PET_BATTLE_WEATHER_ARCANE = 8, // +25% magic damage
|
||||
PET_BATTLE_WEATHER_LIGHTNING = 9, // +25% mechanical damage, deals damage
|
||||
PET_BATTLE_WEATHER_SCORCHED = 10, // +25% dragonkin damage
|
||||
};
|
||||
// Weather effects are now fully state-driven from BattlePetAbilityState DB2 data.
|
||||
// Each weather ability defines its own modifiers (damage %, healing %, accuracy, speed)
|
||||
// via BattlePetAbilityState entries, stored on the environment slot at runtime.
|
||||
|
||||
// DB2 effect property IDs - these correspond to BattlePetEffectPropertiesEntry::ID
|
||||
// The actual effect behavior is determined by the effect properties ID
|
||||
|
||||
@@ -177,12 +177,13 @@ namespace PetBattles
|
||||
for (BattlePetAbilityStateEntry const* entry : sBattlePetAbilityStateStore)
|
||||
abilityStates[entry->BattlePetAbilityID].push_back({ entry->BattlePetStateID, entry->Value });
|
||||
|
||||
// Diagnostic: log states for abilities already found as weather
|
||||
// Store BattlePetAbilityState entries for weather abilities (used at runtime for modifiers)
|
||||
for (uint32 abilID : _weatherAbilityIDs)
|
||||
{
|
||||
auto it = abilityStates.find(abilID);
|
||||
if (it != abilityStates.end())
|
||||
{
|
||||
_weatherAbilityStates[abilID] = it->second;
|
||||
for (auto const& [stateID, value] : it->second)
|
||||
TC_LOG_INFO("server.loading", " WeatherAbil {} has AbilityState: stateID={} value={}", abilID, stateID, value);
|
||||
}
|
||||
@@ -379,6 +380,12 @@ namespace PetBattles
|
||||
return _weatherAbilityIDs.count(abilityID) > 0;
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint32, int32>> const* PetBattleMgr::GetWeatherAbilityStates(uint32 abilityID) const
|
||||
{
|
||||
auto it = _weatherAbilityStates.find(abilityID);
|
||||
return it != _weatherAbilityStates.end() ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
void PetBattleMgr::Update(uint32 diff)
|
||||
{
|
||||
// Update all active battles
|
||||
|
||||
@@ -102,8 +102,9 @@ namespace PetBattles
|
||||
// Effect action mapping (DB2 PropsID -> abstract action type)
|
||||
PetBattleAbilityEffectAction GetEffectAction(uint16 propsID) const;
|
||||
|
||||
// Weather ability detection
|
||||
// Weather ability detection and state lookup
|
||||
bool IsWeatherAbility(uint32 abilityID) const;
|
||||
std::vector<std::pair<uint32, int32>> const* GetWeatherAbilityStates(uint32 abilityID) const;
|
||||
|
||||
// PvP Queue
|
||||
void JoinQueue(ObjectGuid playerGUID);
|
||||
@@ -141,6 +142,9 @@ namespace PetBattles
|
||||
// Weather ability IDs (abilities whose effects set weatherState on environment)
|
||||
std::unordered_set<uint32> _weatherAbilityIDs;
|
||||
|
||||
// Weather ability states: abilityID -> BattlePetAbilityState entries (stateID, value)
|
||||
std::unordered_map<uint32, std::vector<std::pair<uint32, int32>>> _weatherAbilityStates;
|
||||
|
||||
// PvP Queue
|
||||
std::vector<PvPQueueEntry> _pvpQueue;
|
||||
std::unique_ptr<PvPMatchProposal> _pendingProposal;
|
||||
|
||||
@@ -205,7 +205,7 @@ static void BuildPetBattleEnviros(std::array<WorldPackets::BattlePet::PetBattleE
|
||||
for (uint8 i = 0; i < PetBattles::MAX_PET_BATTLE_ENVIRONMENTS; ++i)
|
||||
{
|
||||
PetBattles::PetBattleEnvironment const& env = battle->GetEnvironment(i);
|
||||
if (env.WeatherType != PetBattles::PET_BATTLE_WEATHER_NONE && env.AuraInstanceID != 0)
|
||||
if (env.IsActive())
|
||||
{
|
||||
WorldPackets::BattlePet::PetBattleAuraInfo auraInfo;
|
||||
auraInfo.AbilityID = env.AbilityID;
|
||||
|
||||
Reference in New Issue
Block a user