diff --git a/src/game/Object/LootMgr.h b/src/game/Object/LootMgr.h index 1e585200c..be623decc 100644 --- a/src/game/Object/LootMgr.h +++ b/src/game/Object/LootMgr.h @@ -89,7 +89,7 @@ struct LootStoreItem uint8 type; // 0 = item, 1 = currency float chance; // always positive, chance to drop for both quest and non-quest items, chance to be used for refs int32 mincountOrRef; // mincount for drop items (positive) or minus referenced TemplateleId (negative) - uint32 maxcount; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative) + uint8 maxcount; // max drop count for the item (mincountOrRef positive) or Ref multiplicator (mincountOrRef negative) uint8 group : 7; bool needs_quest : 1; // quest drop (negative ChanceOrQuestChance in DB) uint16 conditionId : 16; // additional loot condition Id diff --git a/src/game/Object/SpellMgr.cpp b/src/game/Object/SpellMgr.cpp index 5bda503e3..d016f1b79 100644 --- a/src/game/Object/SpellMgr.cpp +++ b/src/game/Object/SpellMgr.cpp @@ -120,18 +120,18 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell) return 0; } - int32 castTime = 0; + uint32 castTime = 0; SpellScalingEntry const* spellScalingEntry = spellInfo->GetSpellScaling(); if (spell && spellScalingEntry && (spell->GetCaster()->GetTypeId() == TYPEID_PLAYER || spell->GetCaster()->GetObjectGuid().IsPet())) { uint32 level = spell->GetCaster()->getLevel(); if (level == 1) - castTime = int32(spellScalingEntry->castTimeMin); - else if (level < spellScalingEntry->castScalingMaxLevel) - castTime = int32(spellScalingEntry->castTimeMin + float(level - 1) * + castTime = uint32(spellScalingEntry->castTimeMin); + else if (level < uint32(spellScalingEntry->castScalingMaxLevel)) + castTime = uint32(spellScalingEntry->castTimeMin + float(level - 1) * (spellScalingEntry->castTimeMax - spellScalingEntry->castTimeMin) / (spellScalingEntry->castScalingMaxLevel - 1)); else - castTime = int32(spellScalingEntry->castTimeMax); + castTime = uint32(spellScalingEntry->castTimeMax); } else if (SpellCastTimesEntry const* spellCastTimeEntry = sSpellCastTimesStore.LookupEntry(spellInfo->CastingTimeIndex)) { @@ -146,13 +146,13 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell) } // currently only profession spells have CastTimePerLevel data filled, always negative - castTime = spellCastTimeEntry->CastTime + spellCastTimeEntry->CastTimePerLevel * level; + castTime = uint32(spellCastTimeEntry->CastTime + spellCastTimeEntry->CastTimePerLevel * level); } else - castTime = spellCastTimeEntry->CastTime; + castTime = uint32(spellCastTimeEntry->CastTime); - if (castTime < spellCastTimeEntry->MinCastTime) - castTime = spellCastTimeEntry->MinCastTime; + if (castTime < uint32(spellCastTimeEntry->MinCastTime)) + castTime = uint32(spellCastTimeEntry->MinCastTime); } else // not all spells have cast time index and this is all is pasiive abilities @@ -164,18 +164,18 @@ uint32 GetSpellCastTime(SpellEntry const* spellInfo, Spell const* spell) modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_CASTING_TIME, castTime, spell); if (!spellInfo->HasAttribute(SPELL_ATTR_UNK4) && !spellInfo->HasAttribute(SPELL_ATTR_TRADESPELL)) - castTime = int32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED)); + castTime = uint32(castTime * spell->GetCaster()->GetFloatValue(UNIT_MOD_CAST_SPEED)); else { if (spell->IsRangedSpell() && !spell->IsAutoRepeat()) - castTime = int32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]); + castTime = uint32(castTime * spell->GetCaster()->m_modAttackSpeedPct[RANGED_ATTACK]); } } if (spellInfo->HasAttribute(SPELL_ATTR_RANGED) && (!spell || !spell->IsAutoRepeat())) castTime += 500; - return (castTime > 0) ? uint32(castTime) : 0; + return (castTime > 0) ? castTime : 0; } uint32 GetSpellCastTimeForBonus(SpellEntry const* spellProto, DamageEffectType damagetype) diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index 836ca5a46..ebf979560 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -3887,7 +3887,10 @@ void Unit::SetCurrentCastedSpell(Spell* pSpell) m_currentSpells[CSpellType] = pSpell; pSpell->SetReferencedFromCurrent(true); - pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]); + pSpell->SetSelfContainer(&(m_currentSpells[pSpell->GetCurrentContainer()])); // this works, but is not safe - + + // original and faulty code - delete once the above has been proven to work + // pSpell->m_selfContainer = &(m_currentSpells[pSpell->GetCurrentContainer()]); // m_selfContainer is not accessible, due to being a protected member } void Unit::InterruptSpell(CurrentSpellTypes spellType, bool withDelayed, bool sendAutoRepeatCancelToClient) @@ -9526,9 +9529,9 @@ int32 Unit::CalculateSpellDamage(Unit const* target, SpellEntry const* spellProt if (gtScalingEntry) { float scale = gtScalingEntry->value; - if (scalingEntry->castTimeMax > 0 && scalingEntry->castScalingMaxLevel > level) + if (uint32(scalingEntry->castTimeMax) > 0 && uint32(scalingEntry->castScalingMaxLevel) > level) scale *= float(scalingEntry->castTimeMin + float(level - 1) * (scalingEntry->castTimeMax - scalingEntry->castTimeMin) / (scalingEntry->castScalingMaxLevel - 1)) / float(scalingEntry->castTimeMax); - if (scalingEntry->coefLevelBase > level) + if (uint32(scalingEntry->coefLevelBase) > level) scale *= (1.0f - scalingEntry->coefBase) * (level - 1) / (scalingEntry->coefLevelBase - 1) + scalingEntry->coefBase; basePoints = int32(scalingEntry->coeff1[effect_index] * scale); diff --git a/src/game/WorldHandlers/Map.cpp b/src/game/WorldHandlers/Map.cpp index 31f5471ac..fb013f96c 100644 --- a/src/game/WorldHandlers/Map.cpp +++ b/src/game/WorldHandlers/Map.cpp @@ -43,6 +43,7 @@ #include "VMapFactory.h" #include "MoveMap.h" #include "BattleGround/BattleGroundMgr.h" +#include "Weather.h" #include "Calendar.h" Map::~Map() @@ -1056,6 +1057,20 @@ void Map::SendToPlayers(WorldPacket const* data) const itr->getSource()->GetSession()->SendPacket(data); } +bool Map::SendToPlayersInZone(WorldPacket const* data, uint32 zoneId) const +{ + bool foundPlayer = false; + for (MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + { + if (itr->getSource()->GetZoneId() == zoneId) + { + itr->getSource()->GetSession()->SendPacket(data); + foundPlayer = true; + } + } + return foundPlayer; +} + bool Map::ActiveObjectsNearGrid(uint32 x, uint32 y) const { MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS); @@ -1217,6 +1232,12 @@ void Map::CreateInstanceData(bool load) } } +void Map::SetWeather(uint32 zoneId, WeatherType type, float grade, bool permanently) +{ + Weather* wth = m_weatherSystem->FindOrCreateWeather(zoneId); + wth->SetWeather(WeatherType(type), grade, this, permanently); +} + template void Map::Add(Corpse*); template void Map::Add(Creature*); template void Map::Add(GameObject*); diff --git a/src/game/WorldHandlers/Map.h b/src/game/WorldHandlers/Map.h index d216326d6..2a999dddc 100644 --- a/src/game/WorldHandlers/Map.h +++ b/src/game/WorldHandlers/Map.h @@ -62,6 +62,7 @@ struct ScriptInfo; class BattleGround; class GridMap; class GameObjectModel; +class WeatherSystem; // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push,N), also any gcc version not support it at some platform #if defined( __GNUC__ ) @@ -220,6 +221,7 @@ class Map : public GridRefManager bool ActiveObjectsNearGrid(uint32 x, uint32 y) const; void SendToPlayers(WorldPacket const* data) const; + bool SendToPlayersInZone(WorldPacket const* data, uint32 zoneId) const; typedef MapRefManager PlayerList; PlayerList const& GetPlayers() const { return m_mapRefManager; } @@ -290,6 +292,8 @@ class Map : public GridRefManager // Get Holder for Creature Linking CreatureLinkingHolder* GetCreatureLinkingHolder() { return &m_creatureLinkingHolder; } + void SetWeather(uint32 zoneId, WeatherType type, float grade, bool permanently); + private: void LoadMapAndVMap(int gx, int gy); @@ -383,6 +387,9 @@ class Map : public GridRefManager // Dynamic Map tree object DynamicMapTree m_dyn_tree; + + // WeatherSystem + WeatherSystem* m_weatherSystem; }; class WorldMap : public Map diff --git a/src/game/WorldHandlers/Spell.h b/src/game/WorldHandlers/Spell.h index 0ea061e54..6ac37c6b1 100644 --- a/src/game/WorldHandlers/Spell.h +++ b/src/game/WorldHandlers/Spell.h @@ -518,6 +518,9 @@ class Spell typedef std::list UnitList; + void SetSelfContainer(Spell** pCurrentContainer) { m_selfContainer = pCurrentContainer; } + Spell** GetSelfContainer() { return m_selfContainer; } + protected: bool HasGlobalCooldown(); void TriggerGlobalCooldown(); diff --git a/src/game/WorldHandlers/Weather.cpp b/src/game/WorldHandlers/Weather.cpp index e16ff78ec..850eb183f 100644 --- a/src/game/WorldHandlers/Weather.cpp +++ b/src/game/WorldHandlers/Weather.cpp @@ -33,6 +33,9 @@ #include "Log.h" #include "ObjectMgr.h" #include "Util.h" +#ifdef ENABLE_ELUNA +#include "LuaEngine.h" +#endif /* ENABLE_ELUNA */ /// Create the Weather object Weather::Weather(uint32 zone, WeatherZoneChances const* weatherChances) : m_zone(zone), m_weatherChances(weatherChances) @@ -196,6 +199,31 @@ void Weather::SendWeatherUpdateToPlayer(Player* player) player->GetSession()->SendPacket(&data); } +// Send the new weather to all players in the zone +bool Weather::SendWeatherForPlayersInZone(Map const* _map) +{ + NormalizeGrade(); + + WeatherState state = GetWeatherState(); + + WorldPacket data(SMSG_WEATHER, 4 + 4 + 1); + data << uint32(state); + data << float(m_grade); + data << uint8(0); // 1 = instant change, 0 = smooth change + + ///- Send the weather packet to all players in this zone + if (!_map->SendToPlayersInZone(&data, m_zone)) + return false; + + ///- Log the event + LogWeatherState(state); +#ifdef ENABLE_ELUNA + sEluna->OnChange(this, m_zone, GetWeatherState(), m_grade); +#endif /* ENABLE_ELUNA */ + + return true; +} + void Weather::SendFineWeatherUpdateToPlayer(Player* player) { WorldPacket data(SMSG_WEATHER, (4 + 4 + 1)); @@ -271,7 +299,21 @@ bool Weather::UpdateWeather() return true; } +// Set the weather +void Weather::SetWeather(WeatherType type, float grade, Map const* _map, bool isPermanent) +{ + m_isPermanentWeather = isPermanent; + + if (m_type == type && m_grade == grade) + return; + + m_type = type; + m_grade = grade; + SendWeatherForPlayersInZone(_map); +} + /// Set the weather +// pre Dev21 version - delete if not required ? void Weather::SetWeather(WeatherType type, float grade) { if (m_type == type && m_grade == grade) @@ -320,3 +362,64 @@ WeatherState Weather::GetWeatherState() const return WEATHER_STATE_FINE; } } + +void Weather::NormalizeGrade() +{ + if (m_grade >= 1) + { + m_grade = 0.9999f; + } + else if (m_grade < 0) + { + m_grade = 0.0001f; + } +} + +// Helper to log recent state +void Weather::LogWeatherState(WeatherState state) const +{ + char const* wthstr; + switch (state) + { + case WEATHER_STATE_LIGHT_RAIN: + wthstr = "light rain"; + break; + case WEATHER_STATE_MEDIUM_RAIN: + wthstr = "medium rain"; + break; + case WEATHER_STATE_HEAVY_RAIN: + wthstr = "heavy rain"; + break; + case WEATHER_STATE_LIGHT_SNOW: + wthstr = "light snow"; + break; + case WEATHER_STATE_MEDIUM_SNOW: + wthstr = "medium snow"; + break; + case WEATHER_STATE_HEAVY_SNOW: + wthstr = "heavy snow"; + break; + case WEATHER_STATE_LIGHT_SANDSTORM: + wthstr = "light sandstorm"; + break; + case WEATHER_STATE_MEDIUM_SANDSTORM: + wthstr = "medium sandstorm"; + break; + case WEATHER_STATE_HEAVY_SANDSTORM: + wthstr = "heavy sandstorm"; + break; + case WEATHER_STATE_THUNDERS: + wthstr = "thunders"; + break; + case WEATHER_STATE_BLACKRAIN: + wthstr = "black rain"; + break; + case WEATHER_STATE_FINE: + default: + wthstr = "fine"; + break; + } + + DETAIL_FILTER_LOG(LOG_FILTER_WEATHER, "Change the weather of zone %u (type %u, grade %f) to state %s.", m_zone, m_type, m_grade, wthstr); +} + diff --git a/src/game/WorldHandlers/Weather.h b/src/game/WorldHandlers/Weather.h index 614797a3e..e4e75ea57 100644 --- a/src/game/WorldHandlers/Weather.h +++ b/src/game/WorldHandlers/Weather.h @@ -59,20 +59,66 @@ class Weather public: Weather(uint32 zone, WeatherZoneChances const* weatherChances); ~Weather() { }; + bool ReGenerate(); bool UpdateWeather(); void SendWeatherUpdateToPlayer(Player* player); + bool SendWeatherForPlayersInZone(Map const* _map); static void SendFineWeatherUpdateToPlayer(Player* player); + void SetWeather(WeatherType type, float grade, Map const* _map, bool isPermanent); void SetWeather(WeatherType type, float grade); /// For which zone is this weather? uint32 GetZone() { return m_zone; }; bool Update(time_t diff); + static bool IsValidWeatherType(uint32 type) + { + switch (type) + { + case WEATHER_TYPE_FINE: + case WEATHER_TYPE_RAIN: + case WEATHER_TYPE_SNOW: + case WEATHER_TYPE_STORM: + case WEATHER_TYPE_THUNDERS: + case WEATHER_TYPE_BLACKRAIN: + return true; + default: + return false; + } + } + private: + // Helper to get the grade between 0..1 + void NormalizeGrade(); + // Helper to log recent state + void LogWeatherState(WeatherState state) const; + WeatherState GetWeatherState() const; uint32 m_zone; WeatherType m_type; float m_grade; ShortIntervalTimer m_timer; WeatherZoneChances const* m_weatherChances; + bool m_isPermanentWeather; +}; + +// --------------------------------------------------------- +// Weather information hold on one map +// --------------------------------------------------------- + +/// Weathers for one map +class WeatherSystem +{ +public: + WeatherSystem(Map const* _map); + ~WeatherSystem(); + + Weather* FindOrCreateWeather(uint32 zoneId); + void UpdateWeathers(uint32 diff); + +private: + Map const* const m_map; + + typedef UNORDERED_MAP WeatherMap; + WeatherMap m_weathers; }; #endif