diff options
Diffstat (limited to 'src/server')
52 files changed, 701 insertions, 544 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 977847e60c9..ef3357fa6ed 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -468,7 +468,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e)                      TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Map entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.map);                      return false;                  } -                if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !GetAreaEntryByAreaID(e.event.respawn.area)) +                if (e.event.respawn.type == SMART_SCRIPT_RESPAWN_CONDITION_AREA && !sAreaTableStore.LookupEntry(e.event.respawn.area))                  {                      TC_LOG_ERROR("sql.sql", "SmartAIMgr: Entry %d SourceType %u Event %u Action %u uses non-existent Area entry %u, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.GetActionType(), e.event.respawn.area);                      return false; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 90e61826e35..ac8e0298a44 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -156,7 +156,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)              return true;          }          case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA: -            if (!GetAreaEntryByAreaID(area.id)) +            if (!sAreaTableStore.LookupEntry(area.id))              {                  TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored.",                      criteria->ID, criteria->requiredType, dataType, area.id); @@ -1905,17 +1905,15 @@ bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achie              bool matchFound = false;              for (int j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)              { -                uint32 area_id = worldOverlayEntry->areatableID[j]; -                if (!area_id)                            // array have 0 only in empty tail +                AreaTableEntry const* area = sAreaTableStore.LookupEntry(worldOverlayEntry->areatableID[j]); +                if (!area)                      break; -                int32 exploreFlag = GetAreaFlagByAreaID(area_id); -                if (exploreFlag < 0) +                uint32 playerIndexOffset = uint32(area->exploreFlag) / 32; +                if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)                      continue; -                uint32 playerIndexOffset = uint32(exploreFlag) / 32; -                uint32 mask = 1 << (uint32(exploreFlag) % 32); - +                uint32 mask = 1 << (uint32(area->exploreFlag) % 32);                  if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)                  {                      matchFound = true; diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 9ab96383ed1..1942ac9d648 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -389,6 +389,8 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)          {              if (TotalTime >= BG_SA_ROUNDLENGTH)              { +                CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); +                CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);                  RoundScores[0].winner = Attackers;                  RoundScores[0].time = BG_SA_ROUNDLENGTH;                  TotalTime = 0; @@ -401,8 +403,6 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)                  ToggleTimer();                  ResetObjs();                  GetBgMap()->UpdateAreaDependentAuras(); -                CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); -                CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);                  return;              }          } @@ -410,6 +410,8 @@ void BattlegroundSA::PostUpdateImpl(uint32 diff)          {              if (TotalTime >= EndRoundTimer)              { +                CastSpellOnTeam(SPELL_END_OF_ROUND, ALLIANCE); +                CastSpellOnTeam(SPELL_END_OF_ROUND, HORDE);                  RoundScores[1].time = BG_SA_ROUNDLENGTH;                  RoundScores[1].winner = (Attackers == TEAM_ALLIANCE) ? TEAM_HORDE : TEAM_ALLIANCE;                  if (RoundScores[0].time == RoundScores[1].time) diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 011b68a2bb3..8fe0810f3b9 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -296,11 +296,11 @@ bool ChatHandler::ExecuteCommandInTable(std::vector<ChatCommand> const& table, c                  uint32 areaId = player->GetAreaId();                  std::string areaName = "Unknown";                  std::string zoneName = "Unknown"; -                if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) +                if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))                  {                      int locale = GetSessionDbcLocale();                      areaName = area->area_name[locale]; -                    if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone)) +                    if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))                          zoneName = zone->area_name[locale];                  } diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index d5367e919a3..4215a3a5d02 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -1708,7 +1708,7 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) const          }          case CONDITION_ZONEID:          { -            AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(cond->ConditionValue1); +            AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(cond->ConditionValue1);              if (!areaEntry)              {                  TC_LOG_ERROR("sql.sql", "%s Area (%u) does not exist, skipped.", cond->ToString(true).c_str(), cond->ConditionValue1); diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp index c73350872cc..6c51c71fe7b 100644 --- a/src/server/game/DataStores/DBCStores.cpp +++ b/src/server/game/DataStores/DBCStores.cpp @@ -51,11 +51,9 @@ struct WMOAreaTableTripple  typedef std::map<WMOAreaTableTripple, WMOAreaTableEntry const*> WMOAreaInfoByTripple;  typedef std::multimap<uint32, CharSectionsEntry const*> CharSectionsMap; -DBCStorage <AreaTableEntry> sAreaStore(AreaTableEntryfmt); +DBCStorage <AreaTableEntry> sAreaTableStore(AreaTableEntryfmt);  DBCStorage <AreaGroupEntry> sAreaGroupStore(AreaGroupEntryfmt);  DBCStorage <AreaPOIEntry> sAreaPOIStore(AreaPOIEntryfmt); -static AreaFlagByAreaID sAreaFlagByAreaID; -static AreaFlagByMapID sAreaFlagByMapID;                    // for instances without generated *.map files  static WMOAreaInfoByTripple sWMOAreaInfoByTripple; @@ -286,21 +284,7 @@ void LoadDBCStores(const std::string& dataPath)      StoreProblemList bad_dbc_files;      uint32 availableDbcLocales = 0xFFFFFFFF; -    LoadDBC(availableDbcLocales, bad_dbc_files, sAreaStore,                   dbcPath, "AreaTable.dbc"); - -    // must be after sAreaStore loading -    for (uint32 i = 0; i < sAreaStore.GetNumRows(); ++i)           // areaflag numbered from 0 -    { -        if (AreaTableEntry const* area = sAreaStore.LookupEntry(i)) -        { -            // fill AreaId->DBC records -            sAreaFlagByAreaID.insert(AreaFlagByAreaID::value_type(uint16(area->ID), area->exploreFlag)); - -            // fill MapId->DBC records (skip sub zones and continents) -            if (area->zone == 0 && area->mapid != 0 && area->mapid != 1 && area->mapid != 530 && area->mapid != 571) -                sAreaFlagByMapID.insert(AreaFlagByMapID::value_type(area->mapid, area->exploreFlag)); -        } -    } +    LoadDBC(availableDbcLocales, bad_dbc_files, sAreaTableStore,                   dbcPath, "AreaTable.dbc");      LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementStore,            dbcPath, "Achievement.dbc", &CustomAchievementfmt, &CustomAchievementIndex);      LoadDBC(availableDbcLocales, bad_dbc_files, sAchievementCriteriaStore,    dbcPath, "Achievement_Criteria.dbc"); @@ -721,7 +705,7 @@ void LoadDBCStores(const std::string& dataPath)      }      // Check loaded DBC files proper version -    if (!sAreaStore.LookupEntry(3617)              ||       // last area (areaflag) added in 3.3.5a +    if (!sAreaTableStore.LookupEntry(4987)         ||       // last area added in 3.3.5a          !sCharTitlesStore.LookupEntry(177)         ||       // last char title added in 3.3.5a          !sGemPropertiesStore.LookupEntry(1629)     ||       // last added spell in 3.3.5a          !sItemStore.LookupEntry(56806)             ||       // last gem property added in 3.3.5a @@ -773,41 +757,13 @@ uint32 GetTalentSpellCost(uint32 spellId)      return 0;  } -int32 GetAreaFlagByAreaID(uint32 area_id) -{ -    AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id); -    if (i == sAreaFlagByAreaID.end()) -        return -1; - -    return i->second; -}  WMOAreaTableEntry const* GetWMOAreaTableEntryByTripple(int32 rootid, int32 adtid, int32 groupid)  {      WMOAreaInfoByTripple::iterator i = sWMOAreaInfoByTripple.find(WMOAreaTableTripple(rootid, adtid, groupid)); -        if (i == sWMOAreaInfoByTripple.end()) -            return NULL; -        return i->second; -} - -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id) -{ -    int32 areaflag = GetAreaFlagByAreaID(area_id); -    if (areaflag < 0) +    if (i == sWMOAreaInfoByTripple.end())          return NULL; - -    return sAreaStore.LookupEntry(areaflag); -} - -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id) -{ -    if (area_flag) -        return sAreaStore.LookupEntry(area_flag); - -    if (MapEntry const* mapEntry = sMapStore.LookupEntry(map_id)) -        return GetAreaEntryByAreaID(mapEntry->linked_zone); - -    return NULL; +    return i->second;  }  char const* GetRaceName(uint8 race, uint8 locale) @@ -822,15 +778,6 @@ char const* GetClassName(uint8 class_, uint8 locale)      return classEntry ? classEntry->name[locale] : NULL;  } -uint32 GetAreaFlagByMapId(uint32 mapid) -{ -    AreaFlagByMapID::iterator i = sAreaFlagByMapID.find(mapid); -    if (i == sAreaFlagByMapID.end()) -        return 0; -    else -        return i->second; -} -  uint32 GetVirtualMapForMapAndZone(uint32 mapid, uint32 zoneId)  {      if (mapid != 530 && mapid != 571)                        // speed for most cases diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h index 14f59b04e6d..56ee1f618dd 100644 --- a/src/server/game/DataStores/DBCStores.h +++ b/src/server/game/DataStores/DBCStores.h @@ -33,11 +33,6 @@ char* GetPetName(uint32 petfamily, uint32 dbclang);  uint32 GetTalentSpellCost(uint32 spellId);  TalentSpellPos const* GetTalentSpellPos(uint32 spellId); -int32 GetAreaFlagByAreaID(uint32 area_id);                  // -1 if not found -AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id); -AreaTableEntry const* GetAreaEntryByAreaFlagAndMap(uint32 area_flag, uint32 map_id); -uint32 GetAreaFlagByMapId(uint32 mapid); -  char const* GetRaceName(uint8 race, uint8 locale);  char const* GetClassName(uint8 class_, uint8 locale); @@ -86,7 +81,7 @@ EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uin  extern DBCStorage <AchievementEntry>             sAchievementStore;  extern DBCStorage <AchievementCriteriaEntry>     sAchievementCriteriaStore; -extern DBCStorage <AreaTableEntry>               sAreaStore;// recommend access using functions +extern DBCStorage <AreaTableEntry>               sAreaTableStore;  extern DBCStorage <AreaGroupEntry>               sAreaGroupStore;  extern DBCStorage <AreaPOIEntry>                 sAreaPOIStore;  extern DBCStorage <AreaTriggerEntry>             sAreaTriggerStore; diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 2f4820d0353..b5dc4489148 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -509,7 +509,7 @@ struct AreaTableEntry      uint32  ID;                                             // 0      uint32  mapid;                                          // 1      uint32  zone;                                           // 2 if 0 then it's zone, else it's zone id of this area -    uint32  exploreFlag;                                    // 3, main index +    uint32  exploreFlag;                                    // 3      uint32  flags;                                          // 4, unknown value but 312 for all cities                                                              // 5-9 unused      int32   area_level;                                     // 10 diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 22a01dae9f0..c61ec997bc2 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -23,7 +23,7 @@ char const Achievementfmt[] = "niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxx  const std::string CustomAchievementfmt = "pppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaapapaaaaaaaaaaaaaaaaaapp";  const std::string CustomAchievementIndex = "ID";  char const AchievementCriteriafmt[] = "niiiiiiiixxxxxxxxxxxxxxxxxiiiix"; -char const AreaTableEntryfmt[] = "iiinixxxxxissssssssssssssssxiiiiixxx"; +char const AreaTableEntryfmt[] = "niiiixxxxxissssssssssssssssxiiiiixxx";  char const AreaGroupEntryfmt[] = "niiiiiii";  char const AreaPOIEntryfmt[] = "niiiiiiiiiiifffixixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxix";  char const AreaTriggerEntryfmt[] = "niffffffff"; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 1497eb4922c..5d62b740947 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -369,13 +369,13 @@ bool Creature::InitEntry(uint32 entry, CreatureData const* data /*= nullptr*/)      SetByteValue(UNIT_FIELD_BYTES_0, 2, minfo->gender);      // Load creature equipment -    if (!data || data->equipmentId == 0) -        LoadEquipment(); // use default equipment (if available) -    else if (data && data->equipmentId != 0)                // override, 0 means no equipment +    if (data && data->equipmentId != 0)      {          m_originalEquipmentId = data->equipmentId;          LoadEquipment(data->equipmentId);      } +    else +        LoadEquipment(0, true);      SetName(normalInfo->Name);                              // at normal entry always @@ -1409,6 +1409,7 @@ void Creature::LoadEquipment(int8 id, bool force /*= true*/)                  SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, 0);              m_equipmentId = 0;          } +          return;      } @@ -1417,7 +1418,7 @@ void Creature::LoadEquipment(int8 id, bool force /*= true*/)          return;      m_equipmentId = id; -    for (uint8 i = 0; i < 3; ++i) +    for (uint8 i = 0; i < MAX_EQUIPMENT_ITEMS; ++i)          SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + i, einfo->ItemEntry[i]);  } @@ -2148,6 +2149,11 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool /*force*/) const      if (GetMap()->IsDungeon())          return true; +    // if the mob is actively being damaged, do not reset due to distance unless it's a world boss +    if (!isWorldBoss()) +        if (time(NULL) - GetLastDamagedTime() <= MAX_AGGRO_RESET_TIME) +            return true; +      //Use AttackDistance in distance check if threat radius is lower. This prevents creature bounce in and out of combat every update tick.      float dist = std::max(GetAttackDistance(victim), sWorld->getFloatConfig(CONFIG_THREAT_RADIUS)) + m_CombatDistance; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index b030f42bef7..1acfeacbf83 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1399,7 +1399,10 @@ void GameObject::Use(Unit* user)                  player->SendCinematicStart(info->camera.cinematicId);              if (info->camera.eventID) +            {                  GetMap()->ScriptsStart(sEventScripts, info->camera.eventID, player, this); +                EventInform(info->camera.eventID, user); +            }              return;          } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8ce78f88906..9ae9f21c967 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4682,6 +4682,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness)      // remove death flag + set aura      SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); +    RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);      // This must be called always even on Players with race != RACE_NIGHTELF in case of faction change      RemoveAurasDueToSpell(20584);                           // RACE_NIGHTELF speed bonuses @@ -5102,10 +5103,10 @@ void Player::RepopAtGraveyard()      // note: this can be called also when the player is alive      // for example from WorldSession::HandleMovementOpcodes -    AreaTableEntry const* zone = GetAreaEntryByAreaID(GetAreaId()); +    AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());      // Such zones are considered unreachable as a ghost and the player must be automatically revived -    if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < -500.0f) +    if ((!IsAlive() && zone && zone->flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))      {          ResurrectPlayer(0.5f);          SpawnCorpseBones(); @@ -5142,8 +5143,10 @@ void Player::RepopAtGraveyard()              GetSession()->SendPacket(&data);          }      } -    else if (GetPositionZ() < -500.0f) +    else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))          TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); + +    RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);  }  bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) @@ -5188,7 +5191,7 @@ void Player::UpdateLocalChannels(uint32 newZone)      if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())          return;                                              // The client handles it automatically after loading, but not after teleporting -    AreaTableEntry const* current_zone = GetAreaEntryByAreaID(newZone); +    AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone);      if (!current_zone)          return; @@ -6429,22 +6432,32 @@ void Player::CheckAreaExploreAndOutdoor()          return;      bool isOutdoor; -    uint16 areaFlag = GetBaseMap()->GetAreaFlag(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); +    uint32 areaId = GetBaseMap()->GetAreaId(GetPositionX(), GetPositionY(), GetPositionZ(), &isOutdoor); +    AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);      if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK) && !isOutdoor)          RemoveAurasWithAttribute(SPELL_ATTR0_OUTDOORS_ONLY); -    if (areaFlag == 0xffff) +    if (!areaId)          return; -    int offset = areaFlag / 32; + +    if (!areaEntry) +    { +        TC_LOG_ERROR("entities.player", "Player '%s' (%s) discovered unknown area (x: %f y: %f z: %f map: %u)", +            GetName().c_str(), GetGUID().ToString().c_str(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); +        return; +    } + +    uint32 offset = areaEntry->exploreFlag / 32;      if (offset >= PLAYER_EXPLORED_ZONES_SIZE)      { -        TC_LOG_ERROR("entities.player", "Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", areaFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE); +        TC_LOG_ERROR("entities.player", "Player::CheckAreaExploreAndOutdoor: Wrong area flag %u in map data for (X: %f Y: %f) point to field PLAYER_EXPLORED_ZONES_1 + %u ( %u must be < %u ).", +            areaEntry->exploreFlag, GetPositionX(), GetPositionY(), offset, offset, PLAYER_EXPLORED_ZONES_SIZE);          return;      } -    uint32 val = (uint32)(1 << (areaFlag % 32)); +    uint32 val = (uint32)(1 << (areaEntry->exploreFlag % 32));      uint32 currFields = GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);      if (!(currFields & val)) @@ -6453,19 +6466,11 @@ void Player::CheckAreaExploreAndOutdoor()          UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA); -        AreaTableEntry const* areaEntry = GetAreaEntryByAreaFlagAndMap(areaFlag, GetMapId()); -        if (!areaEntry) -        { -            TC_LOG_ERROR("entities.player", "Player %u discovered unknown area (x: %f y: %f z: %f map: %u", GetGUID().GetCounter(), GetPositionX(), GetPositionY(), GetPositionZ(), GetMapId()); -            return; -        } -          if (areaEntry->area_level > 0)          { -            uint32 area = areaEntry->ID;              if (getLevel() >= sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL))              { -                SendExplorationExperience(area, 0); +                SendExplorationExperience(areaId, 0);              }              else              { @@ -6489,9 +6494,9 @@ void Player::CheckAreaExploreAndOutdoor()                  }                  GiveXP(XP, NULL); -                SendExplorationExperience(area, XP); +                SendExplorationExperience(areaId, XP);              } -            TC_LOG_DEBUG("entities.player", "Player %u discovered a new area: %u", GetGUID().GetCounter(), area); +            TC_LOG_DEBUG("entities.player", "Player '%s' (%s) discovered a new area: %u", GetName().c_str(),GetGUID().ToString().c_str(), areaId);          }      }  } @@ -7061,7 +7066,7 @@ void Player::UpdateArea(uint32 newArea)      // so apply them accordingly      m_areaUpdateId = newArea; -    AreaTableEntry const* area = GetAreaEntryByAreaID(newArea); +    AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);      pvpInfo.IsInFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA);      UpdatePvPState(true); @@ -7109,7 +7114,7 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea)      // zone changed, so area changed as well, update it      UpdateArea(newArea); -    AreaTableEntry const* zone = GetAreaEntryByAreaID(newZone); +    AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone);      if (!zone)          return; @@ -26154,11 +26159,11 @@ std::string Player::GetMapAreaAndZoneString()      uint32 areaId = GetAreaId();      std::string areaName = "Unknown";      std::string zoneName = "Unknown"; -    if (AreaTableEntry const* area = GetAreaEntryByAreaID(areaId)) +    if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))      {          int locale = GetSession()->GetSessionDbcLocale();          areaName = area->area_name[locale]; -        if (AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone)) +        if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone))              zoneName = zone->area_name[locale];      } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 3aed5fde7b3..c224ef78ec8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8328,8 +8328,6 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg          case 52914:          case 52915:          case 52910: -        // Honor Among Thieves -        case 52916:          {              target = triggeredByAura->GetBase()->GetCaster();              if (!target) @@ -12750,7 +12748,7 @@ Unit* Creature::SelectVictim()          }      }      else -        return NULL; +        return nullptr;      if (target && _IsTargetAcceptable(target) && CanCreatureAttack(target))      { @@ -12759,14 +12757,6 @@ Unit* Creature::SelectVictim()          return target;      } -    // Case where mob is being kited. -    // Mob may not be in range to attack or may have dropped target. In any case, -    //  don't evade if damage received within the last 10 seconds -    // Does not apply to world bosses to prevent kiting to cities -    if (!isWorldBoss() && !GetInstanceId()) -        if (time(NULL) - GetLastDamagedTime() <= MAX_AGGRO_RESET_TIME) -            return target; -      // last case when creature must not go to evade mode:      // it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list      // for example at owner command to pet attack some far away creature @@ -12775,12 +12765,12 @@ Unit* Creature::SelectVictim()      {          if ((*itr) && !CanCreatureAttack(*itr) && (*itr)->GetTypeId() != TYPEID_PLAYER          && !(*itr)->ToCreature()->HasUnitTypeMask(UNIT_MASK_CONTROLABLE_GUARDIAN)) -            return NULL; +            return nullptr;      }      /// @todo a vehicle may eat some mob, so mob should not evade      if (GetVehicle()) -        return NULL; +        return nullptr;      // search nearby enemy before enter evade mode      if (HasReactState(REACT_AGGRESSIVE)) @@ -12798,17 +12788,17 @@ Unit* Creature::SelectVictim()          {              if ((*itr)->GetBase()->IsPermanent())              { -                AI()->EnterEvadeMode(); +                AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_OTHER);                  break;              }          } -        return NULL; +        return nullptr;      }      // enter in evade mode in other case      AI()->EnterEvadeMode(CreatureAI::EVADE_REASON_NO_HOSTILES); -    return NULL; +    return nullptr;  }  //====================================================================== diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index d2064092a65..f45634e9684 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1756,7 +1756,7 @@ void ObjectMgr::LoadCreatures()          if (!ok)              continue; -        // -1 random, 0 no equipment, +        // -1 random, 0 no equipment          if (data.equipmentId != 0)          {              if (!GetEquipmentInfo(data.id, data.equipmentId)) @@ -2773,7 +2773,7 @@ void ObjectMgr::LoadItemTemplates()              itemTemplate.ItemSet = 0;          } -        if (itemTemplate.Area && !GetAreaEntryByAreaID(itemTemplate.Area)) +        if (itemTemplate.Area && !sAreaTableStore.LookupEntry(itemTemplate.Area))              TC_LOG_ERROR("sql.sql", "Item (Entry: %u) has wrong Area (%u)", entry, itemTemplate.Area);          if (itemTemplate.Map && !sMapStore.LookupEntry(itemTemplate.Map)) @@ -4143,7 +4143,7 @@ void ObjectMgr::LoadQuests()          // client quest log visual (area case)          if (qinfo->ZoneOrSort > 0)          { -            if (!GetAreaEntryByAreaID(qinfo->ZoneOrSort)) +            if (!sAreaTableStore.LookupEntry(qinfo->ZoneOrSort))              {                  TC_LOG_ERROR("sql.sql", "Quest %u has `ZoneOrSort` = %u (zone case) but zone with this id does not exist.",                      qinfo->GetQuestId(), qinfo->ZoneOrSort); @@ -5956,7 +5956,7 @@ void ObjectMgr::LoadGraveyardZones()              continue;          } -        AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); +        AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);          if (!areaEntry)          {              TC_LOG_ERROR("sql.sql", "Table `game_graveyard_zone` has a record for not existing zone id (%u), skipped.", zoneId); @@ -7796,7 +7796,7 @@ void ObjectMgr::LoadFishingBaseSkillLevel()          uint32 entry  = fields[0].GetUInt32();          int32 skill   = fields[1].GetInt16(); -        AreaTableEntry const* fArea = GetAreaEntryByAreaID(entry); +        AreaTableEntry const* fArea = sAreaTableStore.LookupEntry(entry);          if (!fArea)          {              TC_LOG_ERROR("sql.sql", "AreaId %u defined in `skill_fishing_base_level` does not exist", entry); diff --git a/src/server/game/Grids/GridDefines.h b/src/server/game/Grids/GridDefines.h index 162c39b951b..24c9100b222 100644 --- a/src/server/game/Grids/GridDefines.h +++ b/src/server/game/Grids/GridDefines.h @@ -226,7 +226,7 @@ namespace Trinity      inline bool IsValidMapCoord(float x, float y, float z)      { -        return IsValidMapCoord(x, y) && std::isfinite(z); +        return IsValidMapCoord(x, y) && IsValidMapCoord(z);      }      inline bool IsValidMapCoord(float x, float y, float z, float o) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.cpp b/src/server/game/Grids/Notifiers/GridNotifiers.cpp index c48d1947eec..571d56b618e 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.cpp +++ b/src/server/game/Grids/Notifiers/GridNotifiers.cpp @@ -131,7 +131,7 @@ inline void CreatureUnitRelocationWorker(Creature* c, Unit* u)      if (!u->IsAlive() || !c->IsAlive() || c == u || u->IsInFlight())          return; -    if (c->HasReactState(REACT_AGGRESSIVE) && !c->HasUnitState(UNIT_STATE_SIGHTLESS)) +    if ((c->HasReactState(REACT_AGGRESSIVE) || c->IsTrigger()) && !c->HasUnitState(UNIT_STATE_SIGHTLESS))      {          if (c->IsAIEnabled && c->CanSeeOrDetect(u, false, true))              c->AI()->MoveInLineOfSight_Safe(u); diff --git a/src/server/game/Handlers/ChannelHandler.cpp b/src/server/game/Handlers/ChannelHandler.cpp index 976860e8cc0..9285f4247b2 100644 --- a/src/server/game/Handlers/ChannelHandler.cpp +++ b/src/server/game/Handlers/ChannelHandler.cpp @@ -39,7 +39,7 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)          if (!channel)              return; -        AreaTableEntry const* zone = GetAreaEntryByAreaID(GetPlayer()->GetZoneId()); +        AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());          if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))              return;      } diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 6cd8bfc014e..5f5a66e7b20 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -319,7 +319,7 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData)              continue;          std::string aname; -        if (AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(pzoneid)) +        if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(pzoneid))              aname = areaEntry->area_name[GetSessionDbcLocale()];          bool s_show = true; @@ -1753,7 +1753,7 @@ void WorldSession::HandleHearthAndResurrect(WorldPacket& /*recvData*/)          return;      } -    AreaTableEntry const* atEntry = GetAreaEntryByAreaID(_player->GetAreaId()); +    AreaTableEntry const* atEntry = sAreaTableStore.LookupEntry(_player->GetAreaId());      if (!atEntry || !(atEntry->flags & AREA_FLAG_WINTERGRASP_2))          return; diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index eea5c62fbd1..02702fc5622 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -386,7 +386,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)          plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); -        if (movementInfo.pos.GetPositionZ() < -500.0f) +        if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))          {              if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player)))              { @@ -395,6 +395,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)                  /// @todo discard movement packets after the player is rooted                  if (plrMover->IsAlive())                  { +                    plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS);                      plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());                      // player can be alive if GM/etc                      // change the death state to CORPSE to prevent the death timer from diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 530bcd2902c..19dc210ea5b 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -1580,8 +1580,8 @@ void LoadLootTemplates_Fishing()      uint32 count = LootTemplates_Fishing.LoadAndCollectLootIds(lootIdSet);      // remove real entries and check existence loot -    for (uint32 i = 1; i < sAreaStore.GetNumRows(); ++i) -        if (AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(i)) +    for (uint32 i = 1; i < sAreaTableStore.GetNumRows(); ++i) +        if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i))              if (lootIdSet.find(areaEntry->ID) != lootIdSet.end())                  lootIdSet.erase(areaEntry->ID); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index a2cb84359f2..1560d4bdd08 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -37,7 +37,7 @@  #include "VMapFactory.h"  u_map_magic MapMagic        = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','3'} }; +u_map_magic MapVersionMagic = { {'v','1','.','7'} };  u_map_magic MapAreaMagic    = { {'A','R','E','A'} };  u_map_magic MapHeightMagic  = { {'M','H','G','T'} };  u_map_magic MapLiquidMagic  = { {'M','L','I','Q'} }; @@ -1644,13 +1644,15 @@ GridMap::GridMap()      _flags = 0;      // Area data      _gridArea = 0; -    _areaMap = NULL; +    _areaMap = nullptr;      // Height level data      _gridHeight = INVALID_HEIGHT;      _gridGetHeight = &GridMap::getHeightFromFlat;      _gridIntHeightMultiplier = 0; -    m_V9 = NULL; -    m_V8 = NULL; +    m_V9 = nullptr; +    m_V8 = nullptr; +    _maxHeight = nullptr; +    _minHeight = nullptr;      // Liquid data      _liquidType    = 0;      _liquidOffX   = 0; @@ -1658,9 +1660,9 @@ GridMap::GridMap()      _liquidWidth  = 0;      _liquidHeight = 0;      _liquidLevel = INVALID_HEIGHT; -    _liquidEntry = NULL; -    _liquidFlags = NULL; -    _liquidMap  = NULL; +    _liquidEntry = nullptr; +    _liquidFlags = nullptr; +    _liquidMap  = nullptr;  }  GridMap::~GridMap() @@ -1723,15 +1725,19 @@ void GridMap::unloadData()      delete[] _areaMap;      delete[] m_V9;      delete[] m_V8; +    delete[] _maxHeight; +    delete[] _minHeight;      delete[] _liquidEntry;      delete[] _liquidFlags;      delete[] _liquidMap; -    _areaMap = NULL; -    m_V9 = NULL; -    m_V8 = NULL; -    _liquidEntry = NULL; -    _liquidFlags = NULL; -    _liquidMap  = NULL; +    _areaMap = nullptr; +    m_V9 = nullptr; +    m_V8 = nullptr; +    _maxHeight = nullptr; +    _minHeight = nullptr; +    _liquidEntry = nullptr; +    _liquidFlags = nullptr; +    _liquidMap  = nullptr;      _gridGetHeight = &GridMap::getHeightFromFlat;  } @@ -1746,7 +1752,7 @@ bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/)      _gridArea = header.gridArea;      if (!(header.flags & MAP_AREA_NO_AREA))      { -        _areaMap = new uint16 [16*16]; +        _areaMap = new uint16[16 * 16];          if (fread(_areaMap, sizeof(uint16), 16*16, in) != 16*16)              return false;      } @@ -1796,6 +1802,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)      }      else          _gridGetHeight = &GridMap::getHeightFromFlat; + +    if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) +    { +        _maxHeight = new float[16 * 16]; +        _minHeight = new float[16 * 16]; +        if (fread(_maxHeight, sizeof(float), 16 * 16, in) != 16 * 16 || +            fread(_minHeight, sizeof(float), 16 * 16, in) != 16 * 16) +            return false; +    } +      return true;  } @@ -2066,6 +2082,18 @@ float GridMap::getHeightFromUint16(float x, float y) const      return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;  } +float GridMap::getMinHeight(float x, float y) const +{ +    if (!_minHeight) +        return -500.0f; + +    x = 16 * (CENTER_GRID_ID - x / SIZE_OF_GRIDS); +    y = 16 * (CENTER_GRID_ID - y / SIZE_OF_GRIDS); +    int lx = (int)x & 15; +    int ly = (int)y & 15; +    return _minHeight[lx * 16 + ly]; +} +  float GridMap::getLiquidLevel(float x, float y) const  {      if (!_liquidMap) @@ -2125,12 +2153,12 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R              uint32 liqTypeIdx = liquidEntry->Type;              if (entry < 21)              { -                if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(getArea(x, y), MAPID_INVALID)) +                if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y)))                  {                      uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];                      if (!overrideLiquid && area->zone)                      { -                        area = GetAreaEntryByAreaID(area->zone); +                        area = sAreaTableStore.LookupEntry(area->zone);                          if (area)                              overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type];                      } @@ -2266,6 +2294,14 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float      return mapHeight;                               // explicitly use map data  } +float Map::GetMinHeight(float x, float y) const +{ +    if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y)) +        return grid->getMinHeight(x, y); + +    return -500.0f; +} +  inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)  {      bool outdoor = true; @@ -2304,7 +2340,7 @@ bool Map::IsOutdoors(float x, float y, float z) const      if (wmoEntry)      {          TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId); -        atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); +        atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);      }      return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);  } @@ -2328,7 +2364,7 @@ bool Map::GetAreaInfo(float x, float y, float z, uint32 &flags, int32 &adtId, in      return false;  } -uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const +uint32 Map::GetAreaId(float x, float y, float z, bool *isOutdoors) const  {      uint32 mogpFlags;      int32 adtId, rootId, groupId; @@ -2341,20 +2377,20 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const          haveAreaInfo = true;          wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);          if (wmoEntry) -            atEntry = GetAreaEntryByAreaID(wmoEntry->areaId); +            atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);      } -    uint16 areaflag; +    uint32 areaId;      if (atEntry) -        areaflag = atEntry->exploreFlag; +        areaId = atEntry->ID;      else      {          if (GridMap* gmap = const_cast<Map*>(this)->GetGrid(x, y)) -            areaflag = gmap->getArea(x, y); +            areaId = gmap->getArea(x, y);          // this used while not all *.map files generated (instances)          else -            areaflag = GetAreaFlagByMapId(i_mapEntry->MapID); +            areaId = i_mapEntry->linked_zone;      }      if (isOutdoors) @@ -2364,8 +2400,31 @@ uint16 Map::GetAreaFlag(float x, float y, float z, bool *isOutdoors) const          else              *isOutdoors = true;      } -    return areaflag; - } +    return areaId; +} + +uint32 Map::GetAreaId(float x, float y, float z) const +{ +    return GetAreaId(x, y, z, nullptr); +} + +uint32 Map::GetZoneId(float x, float y, float z) const +{ +    uint32 areaId = GetAreaId(x, y, z); +    if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) +        if (area->zone) +            return area->zone; + +    return areaId; +} + +void Map::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const +{ +    areaid = zoneid = GetAreaId(x, y, z); +    if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid)) +        if (area->zone) +            zoneid = area->zone; +}  uint8 Map::GetTerrainType(float x, float y) const  { @@ -2401,12 +2460,12 @@ ZLiquidStatus Map::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidTyp                  if (liquid_type && liquid_type < 21)                  { -                    if (AreaTableEntry const* area = GetAreaEntryByAreaFlagAndMap(GetAreaFlag(x, y, z), GetId())) +                    if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(x, y, z)))                      {                          uint32 overrideLiquid = area->LiquidTypeOverride[liquidFlagType];                          if (!overrideLiquid && area->zone)                          { -                            area = GetAreaEntryByAreaID(area->zone); +                            area = sAreaTableStore.LookupEntry(area->zone);                              if (area)                                  overrideLiquid = area->LiquidTypeOverride[liquidFlagType];                          } @@ -2468,34 +2527,6 @@ float Map::GetWaterLevel(float x, float y) const          return 0;  } -uint32 Map::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ -    AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - -    if (entry) -        return entry->ID; -    else -        return 0; -} - -uint32 Map::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id) -{ -    AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - -    if (entry) -        return (entry->zone != 0) ? entry->zone : entry->ID; -    else -        return 0; -} - -void Map::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id) -{ -    AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id); - -    areaid = entry ? entry->ID : 0; -    zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0; -} -  bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask) const  {      return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 01db38d9c30..13d48db0f9d 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -98,9 +98,10 @@ struct map_areaHeader      uint16 gridArea;  }; -#define MAP_HEIGHT_NO_HEIGHT  0x0001 -#define MAP_HEIGHT_AS_INT16   0x0002 -#define MAP_HEIGHT_AS_INT8    0x0004 +#define MAP_HEIGHT_NO_HEIGHT            0x0001 +#define MAP_HEIGHT_AS_INT16             0x0002 +#define MAP_HEIGHT_AS_INT8              0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS    0x0008  struct map_heightHeader  { @@ -166,6 +167,8 @@ class GridMap          uint16* m_uint16_V8;          uint8* m_uint8_V8;      }; +    float* _maxHeight; +    float* _minHeight;      // Height level data      float _gridHeight;      float _gridIntHeightMultiplier; @@ -206,6 +209,7 @@ public:      uint16 getArea(float x, float y) const;      inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} +    float getMinHeight(float x, float y) const;      float getLiquidLevel(float x, float y) const;      uint8 getTerrainType(float x, float y) const;      ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); @@ -326,11 +330,15 @@ class Map : public GridRefManager<NGridType>          // some calls like isInWater should not use vmaps due to processor power          // can return INVALID_HEIGHT if under z+2 z coord not found height          float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; +        float GetMinHeight(float x, float y) const;          ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; -        uint16 GetAreaFlag(float x, float y, float z, bool *isOutdoors=nullptr) const; -        bool GetAreaInfo(float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId) const; +        uint32 GetAreaId(float x, float y, float z, bool *isOutdoors) const; +        bool GetAreaInfo(float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; +        uint32 GetAreaId(float x, float y, float z) const; +        uint32 GetZoneId(float x, float y, float z) const; +        void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const;          bool IsOutdoors(float x, float y, float z) const; @@ -339,25 +347,6 @@ class Map : public GridRefManager<NGridType>          bool IsInWater(float x, float y, float z, LiquidData* data = nullptr) const;          bool IsUnderWater(float x, float y, float z) const; -        static uint32 GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id); -        static uint32 GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id); -        static void GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id); - -        uint32 GetAreaId(float x, float y, float z) const -        { -            return GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); -        } - -        uint32 GetZoneId(float x, float y, float z) const -        { -            return GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), GetId()); -        } - -        void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const -        { -            GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), GetId()); -        } -          void MoveAllCreaturesInMoveList();          void MoveAllGameObjectsInMoveList();          void MoveAllDynamicObjectsInMoveList(); diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h index 51bb418bdf5..7f9621593d4 100644 --- a/src/server/game/Maps/MapManager.h +++ b/src/server/game/Maps/MapManager.h @@ -42,22 +42,20 @@ class MapManager          Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId=0);          Map* FindMap(uint32 mapId, uint32 instanceId) const; -        uint16 GetAreaFlag(uint32 mapid, float x, float y, float z) const -        { -            Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); -            return m->GetAreaFlag(x, y, z); -        }          uint32 GetAreaId(uint32 mapid, float x, float y, float z) const          { -            return Map::GetAreaIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); +            Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); +            return m->GetAreaId(x, y, z);          }          uint32 GetZoneId(uint32 mapid, float x, float y, float z) const          { -            return Map::GetZoneIdByAreaFlag(GetAreaFlag(mapid, x, y, z), mapid); +            Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); +            return m->GetZoneId(x, y, z);          }          void GetZoneAndAreaId(uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)          { -            Map::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(mapid, x, y, z), mapid); +            Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid); +            m->GetZoneAndAreaId(zoneid, areaid, x, y, z);          }          void Initialize(void); diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index 868cba9a5b9..d329ab27de9 100644 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -687,7 +687,7 @@ void OutdoorPvP::BroadcastWorker(Worker& _worker, uint32 zoneId)  void OutdoorPvP::SetMapFromZone(uint32 zone)  { -    AreaTableEntry const* areaTable = GetAreaEntryByAreaID(zone); +    AreaTableEntry const* areaTable = sAreaTableStore.LookupEntry(zone);      ASSERT(areaTable);      Map* map = sMapMgr->CreateBaseMap(areaTable->mapid);      ASSERT(!map->Instanceable()); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 6a10d113553..207908c6d51 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -4683,11 +4683,6 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool                      if (target->GetTypeId() == TYPEID_PLAYER)                          target->ToPlayer()->RemoveAmmo();      // not use ammo and not allow use                      break; -                case 52916: // Honor Among Thieves -                    if (target->GetTypeId() == TYPEID_PLAYER) -                        if (Unit* spellTarget = ObjectAccessor::GetUnit(*target, target->ToPlayer()->GetComboTarget())) -                            target->CastSpell(spellTarget, 51699, true); -                   break;                  case 71563:                      if (Aura* newAura = target->AddAura(71564, target))                          newAura->SetStackAmount(newAura->GetSpellInfo()->StackAmount); @@ -5619,25 +5614,6 @@ void AuraEffect::HandlePeriodicTriggerSpellAuraTick(Unit* target, Unit* caster)                              target->RemoveAurasDueToSpell(28820);                          return;                      } -                    // Totemic Mastery (Skyshatter Regalia (Shaman Tier 6) - bonus) -                    case 38443: -                    { -                        bool all = true; -                        for (int i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) -                        { -                            if (!target->m_SummonSlot[i]) -                            { -                                all = false; -                                break; -                            } -                        } - -                        if (all) -                            target->CastSpell(target, 38437, true, NULL, this); -                        else -                            target->RemoveAurasDueToSpell(38437); -                        return; -                    }                  }                  break;              } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 63fe148dd93..7c1ccbdb463 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5477,7 +5477,7 @@ SpellCastResult Spell::CheckCast(bool strict)                  if (m_originalCaster && m_originalCaster->GetTypeId() == TYPEID_PLAYER && m_originalCaster->IsAlive())                  {                      Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId()); -                    if (AreaTableEntry const* area = GetAreaEntryByAreaID(m_originalCaster->GetAreaId())) +                    if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))                          if (area->flags & AREA_FLAG_NO_FLY_ZONE  || (Bf && !Bf->CanFlyIn()))                              return (_triggeredCastFlags & TRIGGERED_DONT_REPORT_CAST_ERROR) ? SPELL_FAILED_DONT_REPORT : SPELL_FAILED_NOT_HERE;                  } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index f961654f279..b2aa44e28df 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4137,14 +4137,14 @@ void Spell::EffectDuel(SpellEffIndex effIndex)          return;      // Players can only fight a duel in zones with this flag -    AreaTableEntry const* casterAreaEntry = GetAreaEntryByAreaID(caster->GetAreaId()); +    AreaTableEntry const* casterAreaEntry = sAreaTableStore.LookupEntry(caster->GetAreaId());      if (casterAreaEntry && !(casterAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))      {          SendCastResult(SPELL_FAILED_NO_DUELING);            // Dueling isn't allowed here          return;      } -    AreaTableEntry const* targetAreaEntry = GetAreaEntryByAreaID(target->GetAreaId()); +    AreaTableEntry const* targetAreaEntry = sAreaTableStore.LookupEntry(target->GetAreaId());      if (targetAreaEntry && !(targetAreaEntry->flags & AREA_FLAG_ALLOW_DUELS))      {          SendCastResult(SPELL_FAILED_NO_DUELING);            // Dueling isn't allowed here diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ff8fc4539ff..40e8f2d4e24 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -1159,7 +1159,7 @@ bool SpellArea::IsFitToRequirements(Player const* player, uint32 newZone, uint32              if (!player)                  return false; -            AreaTableEntry const* pArea = GetAreaEntryByAreaID(player->GetAreaId()); +            AreaTableEntry const* pArea = sAreaTableStore.LookupEntry(player->GetAreaId());              if (!(pArea && pArea->flags & AREA_FLAG_NO_FLY_ZONE))                  return false;              if (!player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) && !player->HasAuraType(SPELL_AURA_FLY)) @@ -2618,7 +2618,7 @@ void SpellMgr::LoadSpellAreas()              }          } -        if (spellArea.areaId && !GetAreaEntryByAreaID(spellArea.areaId)) +        if (spellArea.areaId && !sAreaTableStore.LookupEntry(spellArea.areaId))          {              TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_area` have wrong area (%u) requirement", spell, spellArea.areaId);              continue; diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 8d3ee939e2c..499f0c9cbf0 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -191,7 +191,6 @@ void CreatureTextMgr::LoadCreatureTextLocales()      } while (result->NextRow());      TC_LOG_INFO("server.loading", ">> Loaded %u creature localized texts in %u ms", textCount, GetMSTimeDiffToNow(oldMSTime)); -  }  uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject const* whisperTarget /*= nullptr*/, ChatMsg msgType /*= CHAT_MSG_ADDON*/, Language language /*= LANG_ADDON*/, CreatureTextRange range /*= TEXT_RANGE_NORMAL*/, uint32 sound /*= 0*/, Team team /*= TEAM_OTHER*/, bool gmOnly /*= false*/, Player* srcPlr /*= nullptr*/) @@ -228,42 +227,10 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject          tempGroup = textGroupContainer;      } -    uint8 count = 0; -    float lastChance = -1; -    bool isEqualChanced = true; - -    float totalChance = 0; - -    for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) +    auto iter = Trinity::Containers::SelectRandomWeightedContainerElement(tempGroup, [](CreatureTextEntry const& t) -> double      { -        if (lastChance >= 0 && lastChance != iter->probability) -            isEqualChanced = false; - -        lastChance = iter->probability; -        totalChance += iter->probability; -        ++count; -    } - -    int32 offset = -1; -    if (!isEqualChanced) -    { -        for (CreatureTextGroup::const_iterator iter = tempGroup.begin(); iter != tempGroup.end(); ++iter) -        { -            uint32 chance = uint32(iter->probability); -            uint32 r = urand(0, 100); -            ++offset; -            if (r <= chance) -                break; -        } -    } - -    uint32 pos = 0; -    if (isEqualChanced || offset < 0) -        pos = urand(0, count - 1); -    else if (offset >= 0) -        pos = offset; - -    CreatureTextGroup::const_iterator iter = tempGroup.begin() + pos; +        return t.probability; +    });      ChatMsg finalType = (msgType == CHAT_MSG_ADDON) ? iter->type : msgType;      Language finalLang = (language == LANG_ADDON) ? iter->lang : language; @@ -293,9 +260,7 @@ uint32 CreatureTextMgr::SendChat(Creature* source, uint8 textGroup, WorldObject          SendChatPacket(finalSource, builder, finalType, whisperTarget, range, team, gmOnly);      } -    if (isEqualChanced || totalChance == 100.0f) -        SetRepeatId(source, textGroup, iter->id); - +    SetRepeatId(source, textGroup, iter->id);      return iter->duration;  } diff --git a/src/server/scripts/Commands/cs_go.cpp b/src/server/scripts/Commands/cs_go.cpp index b7acfb85f50..039af61c010 100644 --- a/src/server/scripts/Commands/cs_go.cpp +++ b/src/server/scripts/Commands/cs_go.cpp @@ -424,7 +424,7 @@ public:          uint32 areaId = id ? (uint32)atoi(id) : player->GetZoneId(); -        AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); +        AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);          if (x < 0 || x > 100 || y < 0 || y > 100 || !areaEntry)          { @@ -434,7 +434,7 @@ public:          }          // update to parent zone if exist (client map show only zones without parents) -        AreaTableEntry const* zoneEntry = areaEntry->zone ? GetAreaEntryByAreaID(areaEntry->zone) : areaEntry; +        AreaTableEntry const* zoneEntry = areaEntry->zone ? sAreaTableStore.LookupEntry(areaEntry->zone) : areaEntry;          ASSERT(zoneEntry);          Map const* map = sMapMgr->CreateBaseMap(zoneEntry->mapid); diff --git a/src/server/scripts/Commands/cs_group.cpp b/src/server/scripts/Commands/cs_group.cpp index 5e8952ce881..9f2bc86f9c0 100644 --- a/src/server/scripts/Commands/cs_group.cpp +++ b/src/server/scripts/Commands/cs_group.cpp @@ -348,10 +348,10 @@ public:                  phase = (!p->IsGameMaster() ? p->GetPhaseMask() : -1);                  uint32 locale = handler->GetSessionDbcLocale(); -                AreaTableEntry const* area = GetAreaEntryByAreaID(p->GetAreaId()); +                AreaTableEntry const* area = sAreaTableStore.LookupEntry(p->GetAreaId());                  if (area)                  { -                    AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone); +                    AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);                      if (zone)                          zoneName = zone->area_name[locale];                  } diff --git a/src/server/scripts/Commands/cs_lookup.cpp b/src/server/scripts/Commands/cs_lookup.cpp index 4e749d33fcf..61e6acfb4d8 100644 --- a/src/server/scripts/Commands/cs_lookup.cpp +++ b/src/server/scripts/Commands/cs_lookup.cpp @@ -97,9 +97,9 @@ public:          wstrToLower(wNamePart);          // Search in AreaTable.dbc -        for (uint32 areaflag = 0; areaflag < sAreaStore.GetNumRows(); ++areaflag) +        for (uint32 i = 0; i < sAreaTableStore.GetNumRows(); ++i)          { -            AreaTableEntry const* areaEntry = sAreaStore.LookupEntry(areaflag); +            AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(i);              if (areaEntry)              {                  int locale = handler->GetSessionDbcLocale(); diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 6ae509af443..c70246f7fb5 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -198,8 +198,8 @@ public:          uint32 mapId = object->GetMapId();          MapEntry const* mapEntry = sMapStore.LookupEntry(mapId); -        AreaTableEntry const* zoneEntry = GetAreaEntryByAreaID(zoneId); -        AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(areaId); +        AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId); +        AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);          float zoneX = object->GetPositionX();          float zoneY = object->GetPositionY(); @@ -961,7 +961,7 @@ public:          uint32 zoneId = player->GetZoneId(); -        AreaTableEntry const* areaEntry = GetAreaEntryByAreaID(zoneId); +        AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(zoneId);          if (!areaEntry || areaEntry->zone !=0)          {              handler->PSendSysMessage(LANG_COMMAND_GRAVEYARDWRONGZONE, graveyardId, zoneId); @@ -1052,17 +1052,23 @@ public:              return false;          } -        int32 area = GetAreaFlagByAreaID(atoi((char*)args)); -        int32 offset = area / 32; +        AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); +        if (!area) +        { +            handler->SendSysMessage(LANG_BAD_VALUE); +            handler->SetSentErrorMessage(true); +            return false; +        } -        if (area<0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) +        int32 offset = area->exploreFlag / 32; +        if (offset >= PLAYER_EXPLORED_ZONES_SIZE)          {              handler->SendSysMessage(LANG_BAD_VALUE);              handler->SetSentErrorMessage(true);              return false;          } -        uint32 val = uint32((1 << (area % 32))); +        uint32 val = uint32((1 << (area->exploreFlag % 32)));          uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);          playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields | val))); @@ -1083,17 +1089,23 @@ public:              return false;          } -        int32 area = GetAreaFlagByAreaID(atoi((char*)args)); -        int32 offset = area / 32; +        AreaTableEntry const* area = sAreaTableStore.LookupEntry(atoi(args)); +        if (!area) +        { +            handler->SendSysMessage(LANG_BAD_VALUE); +            handler->SetSentErrorMessage(true); +            return false; +        } -        if (area < 0 || offset >= PLAYER_EXPLORED_ZONES_SIZE) +        int32 offset = area->exploreFlag / 32; +        if (offset >= PLAYER_EXPLORED_ZONES_SIZE)          {              handler->SendSysMessage(LANG_BAD_VALUE);              handler->SetSentErrorMessage(true);              return false;          } -        uint32 val = uint32((1 << (area % 32))); +        uint32 val = uint32((1 << (area->exploreFlag % 32)));          uint32 currFields = playerTarget->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset);          playerTarget->SetUInt32Value(PLAYER_EXPLORED_ZONES_1 + offset, uint32((currFields ^ val))); @@ -1737,12 +1749,12 @@ public:          // Position data          MapEntry const* map = sMapStore.LookupEntry(mapId); -        AreaTableEntry const* area = GetAreaEntryByAreaID(areaId); +        AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);          if (area)          {              areaName = area->area_name[locale]; -            AreaTableEntry const* zone = GetAreaEntryByAreaID(area->zone); +            AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->zone);              if (zone)                  zoneName = zone->area_name[locale];          } diff --git a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp index b23b9e645d0..b725f421c8f 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp +++ b/src/server/scripts/EasternKingdoms/Karazhan/instance_karazhan.cpp @@ -44,6 +44,13 @@ EndScriptData */  11 - Nightbane  */ +const Position OptionalSpawn[] = +{ +    { -10960.981445f, -1940.138428f, 46.178097f, 4.12f  }, // Hyakiss the Lurker +    { -10899.903320f, -2085.573730f, 49.474449f, 1.38f  }, // Rokad the Ravager +    { -10945.769531f, -2040.153320f, 49.474438f, 0.077f } // Shadikith the Glider +}; +  class instance_karazhan : public InstanceMapScript  {  public: @@ -64,6 +71,7 @@ public:              // 1 - OZ, 2 - HOOD, 3 - RAJ, this never gets altered.              m_uiOperaEvent = urand(1, 3);              m_uiOzDeathCount = 0; +            OptionalBossCount = 0;          }          uint32 m_auiEncounter[MAX_ENCOUNTER]; @@ -71,6 +79,7 @@ public:          uint32 m_uiOperaEvent;          uint32 m_uiOzDeathCount; +        uint32 OptionalBossCount;          ObjectGuid m_uiCurtainGUID;          ObjectGuid m_uiStageDoorLeftGUID; @@ -107,6 +116,29 @@ public:              }          } +        void OnUnitDeath(Unit* unit) override +        { +            Creature* creature = unit->ToCreature(); +            if (!creature) +                return; + +            switch (creature->GetEntry()) +            { +                case NPC_COLDMIST_WIDOW: +                case NPC_COLDMIST_STALKER: +                case NPC_SHADOWBAT: +                case NPC_VAMPIRIC_SHADOWBAT: +                case NPC_GREATER_SHADOWBAT: +                case NPC_PHASE_HOUND: +                case NPC_DREADBEAST: +                case NPC_SHADOWBEAST: +                    SetData(TYPE_OPTIONAL_BOSS, NOT_STARTED); +                    break; +                default: +                    break; +            } +        } +          void SetData(uint32 type, uint32 uiData) override          {              switch (type) @@ -118,7 +150,28 @@ public:                      m_auiEncounter[1] = uiData;                      break;                  case TYPE_MAIDEN:               m_auiEncounter[2] = uiData; break; -                case TYPE_OPTIONAL_BOSS:        m_auiEncounter[3] = uiData; break; +                case TYPE_OPTIONAL_BOSS: +                    m_auiEncounter[3] = uiData; +                    if (uiData == NOT_STARTED) +                    { +                        ++OptionalBossCount; +                        if (OptionalBossCount == 50) +                        { +                            switch (urand(0, 2)) +                            { +                                case 0: +                                    instance->SummonCreature(NPC_HYAKISS_THE_LURKER, OptionalSpawn[0]); +                                    break; +                                case 1: +                                    instance->SummonCreature(NPC_ROKAD_THE_RAVAGER, OptionalSpawn[1]); +                                    break; +                                case 2: +                                    instance->SummonCreature(NPC_SHADIKITH_THE_GLIDER, OptionalSpawn[2]); +                                    break; +                            } +                        } +                    } +                    break;                  case TYPE_OPERA:                      m_auiEncounter[4] = uiData;                      if (uiData == DONE) diff --git a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h index db68484c4a8..4d86492257c 100644 --- a/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h +++ b/src/server/scripts/EasternKingdoms/Karazhan/karazhan.h @@ -64,4 +64,20 @@ enum OperaEvents      EVENT_RAJ                       = 3  }; +enum MiscCreatures +{ +    NPC_HYAKISS_THE_LURKER          = 16179, +    NPC_ROKAD_THE_RAVAGER           = 16181, +    NPC_SHADIKITH_THE_GLIDER        = 16180, + +    // Trash +    NPC_COLDMIST_WIDOW              = 16171, +    NPC_COLDMIST_STALKER            = 16170, +    NPC_SHADOWBAT                   = 16173, +    NPC_VAMPIRIC_SHADOWBAT          = 16175, +    NPC_GREATER_SHADOWBAT           = 16174, +    NPC_PHASE_HOUND                 = 16178, +    NPC_DREADBEAST                  = 16177, +    NPC_SHADOWBEAST                 = 16176 +};  #endif diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp index b48f0edec25..6386bb50e1a 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/instance_magisters_terrace.cpp @@ -16,8 +16,10 @@   */  #include "ScriptMgr.h" +#include "ScriptedCreature.h"  #include "InstanceScript.h"  #include "magisters_terrace.h" +#include "EventMap.h"  /*  0  - Selin Fireheart @@ -36,6 +38,8 @@ DoorData const doorData[] =      { 0,                       0,             DOOR_TYPE_ROOM } // END  }; +Position const KalecgosSpawnPos = { 164.3747f, -397.1197f, 2.151798f, 1.66219f }; +  class instance_magisters_terrace : public InstanceMapScript  {      public: @@ -93,6 +97,10 @@ class instance_magisters_terrace : public InstanceMapScript                      case NPC_DELRISSA:                          DelrissaGUID = creature->GetGUID();                          break; +                    case NPC_KALECGOS: +                    case NPC_HUMAN_KALECGOS: +                        KalecgosGUID = creature->GetGUID(); +                        break;                      default:                          break;                  } @@ -139,6 +147,25 @@ class instance_magisters_terrace : public InstanceMapScript                  }              } +            void ProcessEvent(WorldObject* obj, uint32 eventId) override +            { +                if (eventId == EVENT_SPAWN_KALECGOS) +                    if (!ObjectAccessor::GetCreature(*obj, KalecgosGUID) && Events.Empty()) +                       Events.ScheduleEvent(EVENT_SPAWN_KALECGOS, Minutes(1)); +            } + +            void Update(uint32 diff) override +            { +                Events.Update(diff); + +                if (Events.ExecuteEvent() == EVENT_SPAWN_KALECGOS) +                    if (Creature* kalecgos = instance->SummonCreature(NPC_KALECGOS, KalecgosSpawnPos)) +                    { +                        kalecgos->GetMotionMaster()->MovePath(PATH_KALECGOS_FLIGHT, false); +                        kalecgos->AI()->Talk(SAY_KALECGOS_SPAWN); +                    } +            } +              bool SetBossState(uint32 type, EncounterState state) override              {                  if (!InstanceScript::SetBossState(type, state)) @@ -177,10 +204,12 @@ class instance_magisters_terrace : public InstanceMapScript              }          protected: +            EventMap Events;              ObjectGuid SelinGUID;              ObjectGuid DelrissaGUID;              ObjectGuid KaelStatue[2];              ObjectGuid EscapeOrbGUID; +            ObjectGuid KalecgosGUID;              uint32 DelrissaDeathCount;          }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp index e216a024468..5b90ac8ccf4 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.cpp @@ -31,7 +31,8 @@ EndContentData */  #include "ScriptedCreature.h"  #include "ScriptedGossip.h"  #include "Player.h" -#include "SpellInfo.h" +#include "magisters_terrace.h" +#include "EventMap.h"  /*######  ## npc_kalecgos @@ -39,30 +40,29 @@ EndContentData */  enum Spells  { -    SPELL_TRANSFORM_TO_KAEL     = 44670, +    SPELL_KALECGOS_TRANSFORM    = 44670, +    SPELL_TRANSFORM_VISUAL      = 24085, +    SPELL_CAMERA_SHAKE          = 44762,      SPELL_ORB_KILL_CREDIT       = 46307  }; -enum Creatures +enum MovementPoints  { -    NPC_KAEL                    = 24848 //human form entry +    POINT_ID_PREPARE_LANDING    = 6  }; -enum Misc +enum EventIds  { -    POINT_ID_LAND               = 1 +    EVENT_KALECGOS_TRANSFORM         = 1, +    EVENT_KALECGOS_LANDING           = 2  }; -const float afKaelLandPoint[] = {225.045f, -276.236f, -5.434f}; -  #define GOSSIP_ITEM_KAEL_1      "Who are you?"  #define GOSSIP_ITEM_KAEL_2      "What can we do to assist you?"  #define GOSSIP_ITEM_KAEL_3      "What brings you to the Sunwell?"  #define GOSSIP_ITEM_KAEL_4      "You're not alone here?"  #define GOSSIP_ITEM_KAEL_5      "What would Kil'jaeden want with a mortal woman?" -// This is friendly keal that appear after used Orb. -// If we assume DB handle summon, summon appear somewhere outside the platform where Orb is  class npc_kalecgos : public CreatureScript  {  public: @@ -115,52 +115,46 @@ public:      struct npc_kalecgosAI : public ScriptedAI      { -        npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) -        { -            Initialize(); -        } +        npc_kalecgosAI(Creature* creature) : ScriptedAI(creature) { } -        void Initialize() +        void MovementInform(uint32 type, uint32 pointId) override          { -            m_uiTransformTimer = 0; -        } - -        uint32 m_uiTransformTimer; - -        void Reset() override -        { -            Initialize(); - -            // we must assume he appear as dragon somewhere outside the platform of orb, and then move directly to here -            if (me->GetEntry() != NPC_KAEL) -                me->GetMotionMaster()->MovePoint(POINT_ID_LAND, afKaelLandPoint[0], afKaelLandPoint[1], afKaelLandPoint[2]); -        } - -        void MovementInform(uint32 uiType, uint32 uiPointId) override -        { -            if (uiType != POINT_MOTION_TYPE) +            if (type != WAYPOINT_MOTION_TYPE)                  return; -            if (uiPointId == POINT_ID_LAND) -                m_uiTransformTimer = MINUTE*IN_MILLISECONDS; +            if (pointId == POINT_ID_PREPARE_LANDING) +            { +                me->HandleEmoteCommand(EMOTE_ONESHOT_LAND); +                me->SetDisableGravity(false); +                me->SetHover(false); +                events.ScheduleEvent(EVENT_KALECGOS_LANDING, Seconds(2)); +            }          } -        void UpdateAI(uint32 uiDiff) override +        void UpdateAI(uint32 diff) override          { -            if (m_uiTransformTimer) +            events.Update(diff); + +            switch (events.ExecuteEvent())              { -                if (m_uiTransformTimer <= uiDiff) -                { +                case EVENT_KALECGOS_LANDING: +                    DoCastAOE(SPELL_CAMERA_SHAKE); +                    me->SetObjectScale(0.6f); +                    events.ScheduleEvent(EVENT_KALECGOS_TRANSFORM, Seconds(1)); +                    break; +                case EVENT_KALECGOS_TRANSFORM:                      DoCast(me, SPELL_ORB_KILL_CREDIT, true); - -                    // Transform and update entry, now ready for quest/read gossip -                    DoCast(me, SPELL_TRANSFORM_TO_KAEL, false); -                    me->UpdateEntry(NPC_KAEL); - -                    m_uiTransformTimer = 0; -                } else m_uiTransformTimer -= uiDiff; +                    DoCast(me, SPELL_TRANSFORM_VISUAL, false); +                    DoCast(me, SPELL_KALECGOS_TRANSFORM, false); +                    me->UpdateEntry(NPC_HUMAN_KALECGOS); +                    break; +                default: +                    break;              }          } + +        private: +            EventMap events;      };  }; diff --git a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h index 917ad0eb50b..05718dfc1dd 100644 --- a/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h +++ b/src/server/scripts/EasternKingdoms/MagistersTerrace/magisters_terrace.h @@ -42,7 +42,9 @@ enum CreatureIds  {      NPC_SELIN               = 24723,      NPC_DELRISSA            = 24560, -    NPC_FEL_CRYSTAL         = 24722 +    NPC_FEL_CRYSTAL         = 24722, +    NPC_KALECGOS            = 24844, +    NPC_HUMAN_KALECGOS      = 24848  };  enum GameObjectIds @@ -57,4 +59,19 @@ enum GameObjectIds      GO_ESCAPE_ORB           = 188173  }; +enum InstanceEventIds +{ +    EVENT_SPAWN_KALECGOS    = 16547 +}; + +enum InstanceText +{ +    SAY_KALECGOS_SPAWN      = 0 +}; + +enum MovementData +{ +    PATH_KALECGOS_FLIGHT    = 248440 +}; +  #endif diff --git a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp index b1a00f35bb5..a01b93a140b 100644 --- a/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp +++ b/src/server/scripts/EasternKingdoms/zone_western_plaguelands.cpp @@ -25,7 +25,6 @@ EndScriptData */  /* ContentData  npcs_dithers_and_arbington -npc_myranda_the_hag  npc_the_scourge_cauldron  npc_andorhal_tower  EndContentData */ @@ -33,7 +32,6 @@ EndContentData */  #include "ScriptMgr.h"  #include "ScriptedCreature.h"  #include "ScriptedGossip.h" -#include "ScriptedEscortAI.h"  #include "Player.h"  #include "WorldSession.h" @@ -120,54 +118,6 @@ public:  };  /*###### -## npc_myranda_the_hag -######*/ - -enum Myranda -{ -    ILLUSION_GOSSIP         = 4773, -    QUEST_SUBTERFUGE        = 5862, -    QUEST_IN_DREAMS         = 5944, -    SPELL_SCARLET_ILLUSION  = 17961 -}; - -class npc_myranda_the_hag : public CreatureScript -{ -public: -    npc_myranda_the_hag() : CreatureScript("npc_myranda_the_hag") { } - -    bool OnGossipSelect(Player* player, Creature* /*creature*/, uint32 /*sender*/, uint32 action) override -    { -        player->PlayerTalkClass->ClearMenus(); -        if (action == GOSSIP_ACTION_INFO_DEF + 1) -        { -            player->CLOSE_GOSSIP_MENU(); -            player->CastSpell(player, SPELL_SCARLET_ILLUSION, false); -        } -        return true; -    } - -    bool OnGossipHello(Player* player, Creature* creature) override -    { -        if (creature->IsQuestGiver()) -            player->PrepareQuestMenu(creature->GetGUID()); - -        if (player->GetQuestStatus(QUEST_SUBTERFUGE) == QUEST_STATUS_COMPLETE && -            player->GetQuestStatus(QUEST_IN_DREAMS) != QUEST_STATUS_COMPLETE && -            !player->HasAura(SPELL_SCARLET_ILLUSION)) -        { -            player->ADD_GOSSIP_ITEM_DB(Player::GetDefaultGossipMenuForSource(creature), 0, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + 1); -            player->SEND_GOSSIP_MENU(ILLUSION_GOSSIP, creature->GetGUID()); -            return true; -        } -        else -            player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - -        return true; -    } -}; - -/*######  ## npc_the_scourge_cauldron  ######*/ @@ -195,7 +145,7 @@ public:              me->DealDamage(me, me->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false);              //override any database `spawntimesecs` to prevent duplicated summons              uint32 rTime = me->GetRespawnDelay(); -            if (rTime<600) +            if (rTime < 600)                  me->SetRespawnDelay(600);          } @@ -274,7 +224,6 @@ public:          }          void MoveInLineOfSight(Unit* who) override -          {              if (!who || who->GetTypeId() != TYPEID_PLAYER)                  return; @@ -286,14 +235,9 @@ public:      };  }; -/*###### -## -######*/ -  void AddSC_western_plaguelands()  {      new npcs_dithers_and_arbington(); -    new npc_myranda_the_hag();      new npc_the_scourge_cauldron();      new npc_andorhal_tower();  } diff --git a/src/server/scripts/Kalimdor/zone_ashenvale.cpp b/src/server/scripts/Kalimdor/zone_ashenvale.cpp index 52a83c02a8a..50730507b8f 100644 --- a/src/server/scripts/Kalimdor/zone_ashenvale.cpp +++ b/src/server/scripts/Kalimdor/zone_ashenvale.cpp @@ -31,6 +31,7 @@ EndContentData */  #include "ScriptedCreature.h"  #include "ScriptedEscortAI.h"  #include "Player.h" +#include "SpellScript.h"  /*####  # npc_ruul_snowhoof @@ -344,9 +345,42 @@ class go_naga_brazier : public GameObjectScript          }  }; +enum KingoftheFoulwealdMisc +{ +    GO_BANNER = 178205 +}; + +class spell_destroy_karangs_banner : public SpellScriptLoader +{ +    public: +        spell_destroy_karangs_banner() : SpellScriptLoader("spell_destroy_karangs_banner") { } + +        class spell_destroy_karangs_banner_SpellScript : public SpellScript +        { +            PrepareSpellScript(spell_destroy_karangs_banner_SpellScript); + +            void HandleAfterCast() +            { +                if (GameObject* banner = GetCaster()->FindNearestGameObject(GO_BANNER, GetSpellInfo()->GetMaxRange(true))) +                    banner->Delete(); +            } + +            void Register() override +            { +                AfterCast += SpellCastFn(spell_destroy_karangs_banner_SpellScript::HandleAfterCast); +            } +        }; + +        SpellScript* GetSpellScript() const override +        { +            return new spell_destroy_karangs_banner_SpellScript(); +        } +}; +  void AddSC_ashenvale()  {      new npc_ruul_snowhoof();      new npc_muglash();      new go_naga_brazier(); +    new spell_destroy_karangs_banner();  } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp index b8e7dcc91d5..f59701b9c25 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_blood_prince_council.cpp @@ -1222,7 +1222,6 @@ class npc_kinetic_bomb : public CreatureScript                  _x = 0.f;                  _y = 0.f;                  _groundZ = 0.f; -                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);              }              void Reset() override diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp index 0f721148b72..2db9d206a00 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_professor_putricide.cpp @@ -317,14 +317,12 @@ class boss_professor_putricide : public CreatureScript                          // no possible aura seen in sniff adding the aurastate                          summon->ModifyAuraState(AURA_STATE_UNKNOWN22, true);                          summon->CastSpell(summon, SPELL_GASEOUS_BLOAT_PROC, true); -                        summon->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);                          summon->SetReactState(REACT_PASSIVE);                          break;                      case NPC_VOLATILE_OOZE:                          // no possible aura seen in sniff adding the aurastate                          summon->ModifyAuraState(AURA_STATE_UNKNOWN19, true);                          summon->CastSpell(summon, SPELL_OOZE_ERUPTION_SEARCH_PERIODIC, true); -                        summon->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);                          summon->SetReactState(REACT_PASSIVE);                          break;                      case NPC_CHOKING_GAS_BOMB: diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp index fd945db4604..89868fc7bf2 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_algalon_the_observer.cpp @@ -980,7 +980,7 @@ class go_celestial_planetarium_access : public GameObjectScript              bool GossipHello(Player* player) override              {                  if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_IN_USE)) -                    return false; +                    return true;                  bool hasKey = true;                  if (LockEntry const* lock = sLockStore.LookupEntry(go->GetGOInfo()->goober.lockId)) diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp index df5877d9220..05beacca638 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_freya.cpp @@ -222,7 +222,6 @@ class npc_iron_roots : public CreatureScript              {                  SetCombatMovement(false); -                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);                  me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip                  me->setFaction(14);                  me->SetReactState(REACT_PASSIVE); diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index 385f7d6a69d..09d95b34521 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -380,7 +380,6 @@ class npc_saronite_vapors : public CreatureScript              {                  Talk(EMOTE_VAPORS);                  instance = me->GetInstanceScript(); -                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);                  me->ApplySpellImmune(0, IMMUNITY_ID, 49560, true); // Death Grip jump effect                  me->SetReactState(REACT_PASSIVE);              } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index 4d6aa046d10..f435c669935 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -1637,7 +1637,7 @@ class go_mimiron_hardmode_button : public GameObjectScript          bool OnGossipHello(Player* /*player*/, GameObject* go) override          {              if (go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE)) -                return false; +                return true;              InstanceScript* instance = go->GetInstanceScript();              if (!instance) diff --git a/src/server/scripts/Northrend/zone_icecrown.cpp b/src/server/scripts/Northrend/zone_icecrown.cpp index 88217cb384e..1e020edd10a 100644 --- a/src/server/scripts/Northrend/zone_icecrown.cpp +++ b/src/server/scripts/Northrend/zone_icecrown.cpp @@ -213,7 +213,6 @@ class npc_tournament_training_dummy : public CreatureScript              void Reset() override              {                  me->SetControlled(true, UNIT_STATE_STUNNED); -                me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);                  Initialize();                  // Cast Defend spells to max stack size diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp index 5c3ee1d7f4a..abde43ef952 100644 --- a/src/server/scripts/Spells/spell_generic.cpp +++ b/src/server/scripts/Spells/spell_generic.cpp @@ -1930,10 +1930,7 @@ class spell_gen_mount : public SpellScriptLoader                      if (map == 530 || (map == 571 && target->HasSpell(SPELL_COLD_WEATHER_FLYING)))                          canFly = true; -                    float x, y, z; -                    target->GetPosition(x, y, z); -                    uint32 areaFlag = target->GetBaseMap()->GetAreaFlag(x, y, z); -                    AreaTableEntry const* area = sAreaStore.LookupEntry(areaFlag); +                    AreaTableEntry const* area = sAreaTableStore.LookupEntry(target->GetAreaId());                      if (!area || (canFly && (area->flags & AREA_FLAG_NO_FLY_ZONE)))                          canFly = false; diff --git a/src/server/scripts/Spells/spell_rogue.cpp b/src/server/scripts/Spells/spell_rogue.cpp index 3ca2db40d65..9b577d4e140 100644 --- a/src/server/scripts/Spells/spell_rogue.cpp +++ b/src/server/scripts/Spells/spell_rogue.cpp @@ -41,6 +41,9 @@ enum RogueSpells      SPELL_ROGUE_SHIV_TRIGGERED                  = 5940,      SPELL_ROGUE_TRICKS_OF_THE_TRADE_DMG_BOOST   = 57933,      SPELL_ROGUE_TRICKS_OF_THE_TRADE_PROC        = 59628, +    SPELL_ROGUE_HONOR_AMONG_THIEVES             = 51698, +    SPELL_ROGUE_HONOR_AMONG_THIEVES_PROC        = 52916, +    SPELL_ROGUE_HONOR_AMONG_THIEVES_2           = 51699  };  // 13877, 33735, (check 51211, 65956) - Blade Flurry @@ -703,6 +706,143 @@ class spell_rog_tricks_of_the_trade_proc : public SpellScriptLoader          }  }; +// 51698,51700,51701 - Honor Among Thieves +class spell_rog_honor_among_thieves : public SpellScriptLoader +{ +public: +    spell_rog_honor_among_thieves() : SpellScriptLoader("spell_rog_honor_among_thieves") { } + +    class spell_rog_honor_among_thieves_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_rog_honor_among_thieves_AuraScript); + +        bool CheckProc(ProcEventInfo& /*eventInfo*/) +        { +            Unit* caster = GetCaster(); +            if (!caster) +                return false; + +            if (!caster->GetSpellHistory()->HasCooldown(GetSpellInfo()->Effects[EFFECT_0].TriggerSpell)) +                return true; + +            return false; +        } + +        void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/) +        { +            PreventDefaultAction(); + +            Unit* caster = GetCaster(); +            if (!caster) +                return; + +            Unit* target = GetTarget(); +            target->CastSpell(target, GetSpellInfo()->Effects[EFFECT_0].TriggerSpell, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD), nullptr, aurEff, caster->GetGUID()); +        } + +        void Register() override +        { +            DoCheckProc += AuraCheckProcFn(spell_rog_honor_among_thieves_AuraScript::CheckProc); +            OnEffectProc += AuraEffectProcFn(spell_rog_honor_among_thieves_AuraScript::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_rog_honor_among_thieves_AuraScript(); +    } +}; + +// 52916 - Honor Among Thieves (Proc) +class spell_rog_honor_among_thieves_proc : public SpellScriptLoader +{ +public: +    spell_rog_honor_among_thieves_proc() : SpellScriptLoader("spell_rog_honor_among_thieves_proc") { } + +    class spell_rog_honor_among_thieves_proc_SpellScript : public SpellScript +    { +        PrepareSpellScript(spell_rog_honor_among_thieves_proc_SpellScript); + +        bool Validate(SpellInfo const* /*spellInfo*/) override +        { +            if (!sSpellMgr->GetSpellInfo(SPELL_ROGUE_HONOR_AMONG_THIEVES_PROC)) +                return false; + +            return true; +        } + +        void FilterTargets(std::list<WorldObject*>& targets) +        { +            targets.clear(); + +            Unit* target = GetOriginalCaster(); +            if (!target) +                return; + +            targets.push_back(target); +        } + +        void HandleBeforeHit() +        { +            Unit* target = GetHitUnit(); +            if (!target) +                return; + +            /* +             * The applied aura has a duration of 8 seconds +             * This prevents new applications while its active +             * Removing it on each new proc enables the application from different sources (different grouped players) +             * and on new procs after the source cooldown is finished (1 second) +             */ +            if (target->HasAura(GetSpellInfo()->Id)) +                target->RemoveAura(GetSpellInfo()->Id); +        } + +        void TriggerCooldown() +        { +            Unit* target = GetHitUnit(); +            if (!target) +                return; + +            target->GetSpellHistory()->AddCooldown(GetSpellInfo()->Id, 0, std::chrono::seconds(1)); +        } + +        void Register() override +        { +            OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_rog_honor_among_thieves_proc_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_CASTER_AREA_PARTY); +            BeforeHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::HandleBeforeHit); +            AfterHit += SpellHitFn(spell_rog_honor_among_thieves_proc_SpellScript::TriggerCooldown); +        } +    }; + +    SpellScript* GetSpellScript() const override +    { +        return new spell_rog_honor_among_thieves_proc_SpellScript(); +    } + +    class spell_rog_honor_among_thieves_proc_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_rog_honor_among_thieves_proc_AuraScript); + +        void HandleEffectApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) +        { +            if (Player* player = GetTarget()->ToPlayer()) +                if (Unit* spellTarget = ObjectAccessor::GetUnit(*player, player->GetTarget())) +                    player->CastSpell(spellTarget, SPELL_ROGUE_HONOR_AMONG_THIEVES_2, true); +        } + +        void Register() override +        { +            AfterEffectApply += AuraEffectApplyFn(spell_rog_honor_among_thieves_proc_AuraScript::HandleEffectApply, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_rog_honor_among_thieves_proc_AuraScript(); +    } +}; +  void AddSC_rogue_spell_scripts()  {      new spell_rog_blade_flurry(); @@ -716,4 +856,6 @@ void AddSC_rogue_spell_scripts()      new spell_rog_shiv();      new spell_rog_tricks_of_the_trade();      new spell_rog_tricks_of_the_trade_proc(); +    new spell_rog_honor_among_thieves(); +    new spell_rog_honor_among_thieves_proc();  } diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index c8b0264995b..41e72b1388b 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -55,7 +55,8 @@ enum ShamanSpells      SPELL_SHAMAN_TOTEM_EARTHBIND_EARTHGRAB      = 64695,      SPELL_SHAMAN_TOTEM_EARTHBIND_TOTEM          = 6474,      SPELL_SHAMAN_TOTEM_EARTHEN_POWER            = 59566, -    SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL      = 52042 +    SPELL_SHAMAN_TOTEM_HEALING_STREAM_HEAL      = 52042, +    SPELL_SHAMAN_TOTEMIC_MASTERY                = 38437  };  enum ShamanSpellIcons @@ -1025,6 +1026,46 @@ class spell_sha_thunderstorm : public SpellScriptLoader          }  }; +// 38443 - Totemic Mastery (Tier 6 - 2P) +class spell_sha_totemic_mastery : public SpellScriptLoader +{ +public: +    spell_sha_totemic_mastery() : SpellScriptLoader("spell_sha_totemic_mastery") { } + +    class spell_sha_totemic_mastery_AuraScript : public AuraScript +    { +        PrepareAuraScript(spell_sha_totemic_mastery_AuraScript); + +        bool Validate(SpellInfo const* /*spellInfo*/) override +        { +            if (!sSpellMgr->GetSpellInfo(SPELL_SHAMAN_TOTEMIC_MASTERY)) +                return false; +            return true; +        } + +        void HandleDummy(AuraEffect const* /*aurEff*/) +        { +            Unit* target = GetTarget(); +            for (uint8 i = SUMMON_SLOT_TOTEM; i < MAX_TOTEM_SLOT; ++i) +                if (!target->m_SummonSlot[i]) +                    return; + +            target->CastSpell(target, SPELL_SHAMAN_TOTEMIC_MASTERY, true); +            PreventDefaultAction(); +        } + +        void Register() override +        { +            OnEffectPeriodic += AuraEffectPeriodicFn(spell_sha_totemic_mastery_AuraScript::HandleDummy, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); +        } +    }; + +    AuraScript* GetAuraScript() const override +    { +        return new spell_sha_totemic_mastery_AuraScript(); +    } +}; +  void AddSC_shaman_spell_scripts()  {      new spell_sha_ancestral_awakening_proc(); @@ -1048,4 +1089,5 @@ void AddSC_shaman_spell_scripts()      new spell_sha_mana_tide_totem();      new spell_sha_sentry_totem();      new spell_sha_thunderstorm(); +    new spell_sha_totemic_mastery();  } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 40f9e63f4f6..56d48949fac 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -1485,7 +1485,6 @@ public:          void Reset() override          {              me->SetControlled(true, UNIT_STATE_STUNNED);//disable rotate -            me->ApplySpellImmune(0, IMMUNITY_EFFECT, SPELL_EFFECT_KNOCK_BACK, true);//imune to knock aways like blast wave              _events.Reset();              _damageTimes.clear(); @@ -2635,6 +2634,97 @@ public:      }  }; +enum PandarenMonkMisc +{ +    SPELL_PANDAREN_MONK = 69800, +    EVENT_FOCUS = 1, +    EVENT_EMOTE = 2, +    EVENT_FOLLOW = 3, +    EVENT_DRINK = 4 +}; + +class npc_pandaren_monk : public CreatureScript +{ +public: +    npc_pandaren_monk() : CreatureScript("npc_pandaren_monk") {} + +    struct npc_pandaren_monkAI : public NullCreatureAI +    { +        npc_pandaren_monkAI(Creature* creature) : NullCreatureAI(creature) { } + +        void Reset() override +        { +            _events.Reset(); +            _events.ScheduleEvent(EVENT_FOCUS, 1000); +        } + +        void EnterEvadeMode(EvadeReason why) override +        { +            if (!_EnterEvadeMode(why)) +                return; + +            Reset(); +        } + +        void ReceiveEmote(Player* /*player*/, uint32 emote) override +        { +            me->InterruptSpell(CURRENT_CHANNELED_SPELL); +            me->StopMoving(); + +            switch (emote) +            { +                case TEXT_EMOTE_BOW: +                    _events.ScheduleEvent(EVENT_FOCUS, 1000); +                    break; +                case TEXT_EMOTE_DRINK: +                    _events.ScheduleEvent(EVENT_DRINK, 1000); +                    break; +            } +        } + +        void UpdateAI(uint32 diff) override +        { +            _events.Update(diff); + +            if (Unit* owner = me->GetCharmerOrOwner()) +                if (!me->IsWithinDist(owner, 30.f)) +                    me->InterruptSpell(CURRENT_CHANNELED_SPELL); + +            while (uint32 eventId = _events.ExecuteEvent()) +            { +                switch (eventId) +                { +                    case EVENT_FOCUS: +                        if (Unit* owner = me->GetCharmerOrOwner()) +                            me->SetFacingToObject(owner); +                        _events.ScheduleEvent(EVENT_EMOTE, 1000); +                        break; +                    case EVENT_EMOTE: +                        me->HandleEmoteCommand(EMOTE_ONESHOT_BOW); +                        _events.ScheduleEvent(EVENT_FOLLOW, 1000); +                        break; +                    case EVENT_FOLLOW: +                        if (Unit* owner = me->GetCharmerOrOwner()) +                            me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, PET_FOLLOW_ANGLE); +                        break; +                    case EVENT_DRINK: +                        me->CastSpell(me, SPELL_PANDAREN_MONK, false); +                        break; +                    default: +                        break; +                } +            } +        } +    private: +        EventMap _events; +    }; + +    CreatureAI* GetAI(Creature* creature) const +    { +        return new npc_pandaren_monkAI(creature); +    } +}; +  void AddSC_npcs_special()  {      new npc_air_force_bots(); @@ -2661,4 +2751,5 @@ void AddSC_npcs_special()      new npc_stable_master();      new npc_train_wrecker();      new npc_egbert(); +    new npc_pandaren_monk();  } diff --git a/src/server/shared/Containers.h b/src/server/shared/Containers.h deleted file mode 100644 index c2ebbf58a1e..00000000000 --- a/src/server/shared/Containers.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef TRINITY_CONTAINERS_H -#define TRINITY_CONTAINERS_H - -#include "Define.h" -#include <list> - -//! Because circular includes are bad -extern uint32 urand(uint32 min, uint32 max); - -namespace Trinity -{ -    namespace Containers -    { -        template<class T> -        void RandomResizeList(std::list<T> &list, uint32 size) -        { -            size_t list_size = list.size(); - -            while (list_size > size) -            { -                typename std::list<T>::iterator itr = list.begin(); -                std::advance(itr, urand(0, list_size - 1)); -                list.erase(itr); -                --list_size; -            } -        } - -        template<class T, class Predicate> -        void RandomResizeList(std::list<T> &list, Predicate& predicate, uint32 size) -        { -            //! First use predicate filter -            std::list<T> listCopy; -            for (typename std::list<T>::iterator itr = list.begin(); itr != list.end(); ++itr) -                if (predicate(*itr)) -                    listCopy.push_back(*itr); - -            if (size) -                RandomResizeList(listCopy, size); - -            list = listCopy; -        } - -        /* Select a random element from a container. Note: make sure you explicitly empty check the container */ -        template <class C> typename C::value_type const& SelectRandomContainerElement(C const& container) -        { -            typename C::const_iterator it = container.begin(); -            std::advance(it, urand(0, container.size() - 1)); -            return *it; -        } - -        /** -        * @fn bool Trinity::Containers::Intersects(Iterator first1, Iterator last1, Iterator first2, Iterator last2) -        * -        * @brief Checks if two SORTED containers have a common element -        * -        * @param first1 Iterator pointing to start of the first container -        * @param last1 Iterator pointing to end of the first container -        * @param first2 Iterator pointing to start of the second container -        * @param last2 Iterator pointing to end of the second container -        * -        * @return true if containers have a common element, false otherwise. -        */ -        template<class Iterator1, class Iterator2> -        bool Intersects(Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) -        { -            while (first1 != last1 && first2 != last2) -            { -                if (*first1 < *first2) -                    ++first1; -                else if (*first2 < *first1) -                    ++first2; -                else -                    return true; -            } - -            return false; -        } - -        template<class K, class V, template<class, class, class...> class M, class... Rest> -        void MultimapErasePair(M<K, V, Rest...>& multimap, K const& key, V const& value) -        { -            auto range = multimap.equal_range(key); -            for (auto itr = range.first; itr != range.second;) -            { -                if (itr->second == value) -                    itr = multimap.erase(itr); -                else -                    ++itr; -            } -        } - -    } -    //! namespace Containers -} -//! namespace Trinity - -#endif //! #ifdef TRINITY_CONTAINERS_H  | 
