diff options
Diffstat (limited to 'src')
31 files changed, 519 insertions, 384 deletions
diff --git a/src/server/authserver/Server/AuthSocket.cpp b/src/server/authserver/Server/AuthSocket.cpp index 8a2a6c67496..c7bb600024a 100644 --- a/src/server/authserver/Server/AuthSocket.cpp +++ b/src/server/authserver/Server/AuthSocket.cpp @@ -321,7 +321,7 @@ bool AuthSocket::_HandleLogonChallenge() socket().recv((char *)&buf[0], 4); - EndianConvert(*((uint16*)(buf[0]))); + EndianConvertPtr<uint16>(&buf[0]); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; TC_LOG_DEBUG("server.authserver", "[AuthChallenge] got header, body is %#04x bytes", remaining); @@ -341,11 +341,11 @@ bool AuthSocket::_HandleLogonChallenge() // BigEndian code, nop in little endian case // size already converted - EndianConvert(*((uint32*)(&ch->gamename[0]))); + EndianConvertPtr<uint32>(&ch->gamename[0]); EndianConvert(ch->build); - EndianConvert(*((uint32*)(&ch->platform[0]))); - EndianConvert(*((uint32*)(&ch->os[0]))); - EndianConvert(*((uint32*)(&ch->country[0]))); + EndianConvertPtr<uint32>(&ch->platform[0]); + EndianConvertPtr<uint32>(&ch->os[0]); + EndianConvertPtr<uint32>(&ch->country[0]); EndianConvert(ch->timezone_bias); EndianConvert(ch->ip); @@ -779,7 +779,7 @@ bool AuthSocket::_HandleReconnectChallenge() socket().recv((char *)&buf[0], 4); - EndianConvert(*((uint16*)(buf[0]))); + EndianConvertPtr<uint16>(&buf[0]); uint16 remaining = ((sAuthLogonChallenge_C *)&buf[0])->size; TC_LOG_DEBUG("server.authserver", "[ReconnectChallenge] got header, body is %#04x bytes", remaining); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 7d53f481fe8..8d0f6938532 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -97,6 +97,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS: case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL: + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: break; default: if (dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT) @@ -111,6 +112,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) { case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: case ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT: + case ACHIEVEMENT_CRITERIA_REQUIRE_NTH_BIRTHDAY: return true; case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE: if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id)) @@ -292,6 +294,16 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) return false; } return true; + case ACHIEVEMENT_CRITERIA_REQUIRE_KNOWN_TITLE: + { + if (!sCharTitlesStore.LookupEntry(known_title.title_id)) + { + TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_requirement` (Entry: %u Type: %u) for requirement ACHIEVEMENT_CRITERIA_REQUIRE_KNOWN_TITLE (%u) have unknown title_id in value1 (%u), ignore.", + criteria->ID, criteria->requiredType, dataType, known_title.title_id); + return false; + } + return true; + } default: TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored.", criteria->ID, criteria->requiredType, dataType); return false; @@ -410,6 +422,26 @@ bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, Un } case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID: return source->GetMapId() == map_id.mapId; + case ACHIEVEMENT_CRITERIA_REQUIRE_NTH_BIRTHDAY: + { + time_t birthday_start = time_t(sWorld->getIntConfig(CONFIG_BIRTHDAY_TIME)); + tm birthday_tm; + ACE_OS::localtime_r(&birthday_start, &birthday_tm); + + // exactly N birthday + birthday_tm.tm_year += birthday_login.nth_birthday; + + time_t birthday = mktime(&birthday_tm); + time_t now = sWorld->GetGameTime(); + return now <= birthday + DAY && now >= birthday; + } + case ACHIEVEMENT_CRITERIA_REQUIRE_KNOWN_TITLE: + { + if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(known_title.title_id)) + return source && source->HasTitle(titleInfo->bit_index); + + return false; + } default: break; } @@ -1562,6 +1594,20 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; } + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + { + // This criteria is only called directly after login - with expected miscvalue1 == 1 + if (!miscValue1) + continue; + + // They have no proper requirements in dbc + AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria); + if (!data || !data->Meets(GetPlayer(), unit)) + continue; + + SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); + break; + } // std case: not exist in DBC, not triggered in code as result case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH: case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER: @@ -1574,7 +1620,6 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID: case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA: case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK: - case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE: break; // Not implemented yet :( } @@ -1717,6 +1762,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= achievementCriteria->get_killing_blow.killCount; case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: return achievementCriteria->win_arena.count && progress->counter >= achievementCriteria->win_arena.count; + case ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN: + return true; // handle all statistic-only criteria here case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 1a6777d1055..26270cdec80 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -68,10 +68,12 @@ enum AchievementCriteriaDataType ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT = 18, // 0 0 maker instance script call for check current criteria requirements fit ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM = 19, // item_level item_quality for equipped item in slot to check item level and quality ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID = 20, // map_id 0 player must be on map with id in map_id - ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21 // class_id race_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE = 21, // class_id race_id + ACHIEVEMENT_CRITERIA_REQUIRE_NTH_BIRTHDAY = 22, // N login on day of N-th Birthday + ACHIEVEMENT_CRITERIA_REQUIRE_KNOWN_TITLE = 23, // title_id known (pvp) title, values from dbc }; -#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 22 // maximum value in AchievementCriteriaDataType enum +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 24 // maximum value in AchievementCriteriaDataType enum struct AchievementCriteriaData { @@ -173,6 +175,16 @@ struct AchievementCriteriaData { uint32 mapId; } map_id; + // ACHIEVEMENT_CRITERIA_REQUIRE_NTH_BIRTHDAY = 21 + struct + { + uint32 nth_birthday; + } birthday_login; + // ACHIEVEMENT_CRITERIA_REQUIRE_KNOWN_TITLE = 22 + struct + { + uint32 title_id; + } known_title; // ... struct { diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index 87397c6685b..8d8b7c89a5c 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -91,9 +91,9 @@ enum AchievementCriteriaFlags { ACHIEVEMENT_CRITERIA_FLAG_SHOW_PROGRESS_BAR = 0x00000001, // Show progress as bar ACHIEVEMENT_CRITERIA_FLAG_HIDDEN = 0x00000002, // Not show criteria in client - ACHIEVEMENT_CRITERIA_FLAG_UNK3 = 0x00000004, // BG related?? - ACHIEVEMENT_CRITERIA_FLAG_UNK4 = 0x00000008, // - ACHIEVEMENT_CRITERIA_FLAG_UNK5 = 0x00000010, // not used + ACHIEVEMENT_CRITERIA_FLAG_FAIL_ACHIEVEMENT = 0x00000004, // BG related?? + ACHIEVEMENT_CRITERIA_FLAG_RESET_ON_START = 0x00000008, // + ACHIEVEMENT_CRITERIA_FLAG_IS_DATE = 0x00000010, // not used ACHIEVEMENT_CRITERIA_FLAG_MONEY_COUNTER = 0x00000020 // Displays counter as money }; @@ -174,7 +174,7 @@ enum AchievementCriteriaTypes ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL = 70, ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT = 72, /// @todo 73: Achievements 1515, 1241, 1103 (Name: Mal'Ganis) - ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE = 74, /// @todo title id is not mentioned in dbc + ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN = 74, ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS = 75, ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL = 76, ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL = 77, diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 2dcba7b6a76..1665eae0fcc 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -405,7 +405,9 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) lockData = LFG_LOCKSTATUS_NOT_IN_SEASON; else if (AccessRequirement const* ar = sObjectMgr->GetAccessRequirement(dungeon->map, Difficulty(dungeon->difficulty))) { - if (ar->achievement && !player->HasAchieved(ar->achievement)) + if (player->GetAverageItemLevel() < ar->item_level) + lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; + else if (ar->achievement && !player->HasAchieved(ar->achievement)) lockData = LFG_LOCKSTATUS_MISSING_ACHIEVEMENT; else if (player->GetTeam() == ALLIANCE && ar->quest_A && !player->GetQuestRewardStatus(ar->quest_A)) lockData = LFG_LOCKSTATUS_QUEST_NOT_COMPLETED; @@ -422,7 +424,6 @@ void LFGMgr::InitializeLockedDungeons(Player* player, uint8 level /* = 0 */) } /* @todo VoA closed if WG is not under team control (LFG_LOCKSTATUS_RAID_LOCKED) - lockData = LFG_LOCKSTATUS_TOO_LOW_GEAR_SCORE; lockData = LFG_LOCKSTATUS_TOO_HIGH_GEAR_SCORE; lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_LOW_LEVEL; lockData = LFG_LOCKSTATUS_ATTUNEMENT_TOO_HIGH_LEVEL; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6b7fbebcfb5..9ea9c153f36 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -687,7 +687,7 @@ Player::Player(WorldSession* session): Unit(true) m_regenTimerCount = 0; m_weaponChangeTimer = 0; - m_zoneUpdateId = 0; + m_zoneUpdateId = uint32(-1); m_zoneUpdateTimer = 0; m_areaUpdateId = 0; @@ -18494,6 +18494,9 @@ void Player::_LoadGroup(PreparedQueryResult result) { if (Group* group = sGroupMgr->GetGroupByDbStoreId((*result)[0].GetUInt32())) { + if (group->IsLeader(GetGUID())) + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER); + uint8 subgroup = group->GetMemberGroup(GetGUID()); SetGroup(group, subgroup); if (getLevel() >= LEVELREQUIREMENT_HEROIC) @@ -18504,6 +18507,9 @@ void Player::_LoadGroup(PreparedQueryResult result) } } } + + if (!GetGroup() || !GetGroup()->IsLeader(GetGUID())) + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER); } void Player::_LoadBoundInstances(PreparedQueryResult result) @@ -23609,7 +23615,7 @@ uint32 Player::GetResurrectionSpellId() } // Used in triggers for check "Only to targets that grant experience or honor" req -bool Player::isHonorOrXPTarget(Unit* victim) +bool Player::isHonorOrXPTarget(Unit* victim) const { uint8 v_level = victim->getLevel(); uint8 k_grey = Trinity::XP::GetGrayLevel(getLevel()); @@ -24314,7 +24320,7 @@ bool Player::isTotalImmune() return false; } -bool Player::HasTitle(uint32 bitIndex) +bool Player::HasTitle(uint32 bitIndex) const { if (bitIndex > MAX_TITLE_INDEX) return false; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1f5f9fee7d4..5026489daff 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -840,6 +840,7 @@ struct AccessRequirement { uint8 levelMin; uint8 levelMax; + uint16 item_level; uint32 item; uint32 item2; uint32 quest_A; @@ -1894,7 +1895,7 @@ class Player : public Unit, public GridObject<Player> bool IsAtRecruitAFriendDistance(WorldObject const* pOther) const; void RewardPlayerAndGroupAtKill(Unit* victim, bool isBattleGround); void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject* pRewardSource); - bool isHonorOrXPTarget(Unit* victim); + bool isHonorOrXPTarget(Unit* victim) const; bool GetsRecruitAFriendBonus(bool forXP); uint8 GetGrantableLevels() { return m_grantableLevels; } @@ -2263,8 +2264,8 @@ class Player : public Unit, public GridObject<Player> void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry); void CompletedAchievement(AchievementEntry const* entry); - bool HasTitle(uint32 bitIndex); - bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); } + bool HasTitle(uint32 bitIndex) const; + bool HasTitle(CharTitlesEntry const* title) const { return HasTitle(title->bit_index); } void SetTitle(CharTitlesEntry const* title, bool lost = false); //bool isActiveObject() const { return true; } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e0bf7019acb..ff402488c2c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -8716,13 +8716,28 @@ ReputationRank Unit::GetReactionTo(Unit const* target) const if (GetCharmerOrOwnerOrSelf() == target->GetCharmerOrOwnerOrSelf()) return REP_FRIENDLY; + Player const* selfPlayerOwner = GetAffectingPlayer(); + Player const* targetPlayerOwner = target->GetAffectingPlayer(); + + // check forced reputation to support SPELL_AURA_FORCE_REACTION + if (selfPlayerOwner) + { + if (FactionTemplateEntry const* targetFactionTemplateEntry = target->GetFactionTemplateEntry()) + if (ReputationRank const* repRank = selfPlayerOwner->GetReputationMgr().GetForcedRankIfAny(targetFactionTemplateEntry)) + return *repRank; + } + else if (targetPlayerOwner) + { + if (FactionTemplateEntry const* selfFactionTemplateEntry = GetFactionTemplateEntry()) + if (ReputationRank const* repRank = targetPlayerOwner->GetReputationMgr().GetForcedRankIfAny(selfFactionTemplateEntry)) + return *repRank; + } + + if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) { if (target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE)) { - Player const* selfPlayerOwner = GetAffectingPlayer(); - Player const* targetPlayerOwner = target->GetAffectingPlayer(); - if (selfPlayerOwner && targetPlayerOwner) { // always friendly to other unit controlled by player, or to the player himself diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 04f3395653d..ff87f41ae78 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -705,12 +705,6 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) cInfo->Entry, cInfo->type, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->type); } - if (cInfo->type_flags != difficultyInfo->type_flags) - { - TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, type_flags %u) has different `type_flags` in difficulty %u mode (Entry: %u, type_flags %u).", - cInfo->Entry, cInfo->type_flags, diff + 1, cInfo->DifficultyEntry[diff], difficultyInfo->type_flags); - } - if (!cInfo->VehicleId && difficultyInfo->VehicleId) { TC_LOG_ERROR("sql.sql", "Creature (Entry: %u, VehicleId %u) has different `VehicleId` in difficulty %u mode (Entry: %u, VehicleId %u).", @@ -6012,8 +6006,9 @@ void ObjectMgr::LoadAccessRequirements() _accessRequirementStore.clear(); // need for reload case } - // 0 1 2 3 4 5 6 7 8 9 - QueryResult result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text FROM access_requirement"); + // 0 1 2 3 4 5 6 7 8 9 10 + QueryResult result = WorldDatabase.Query("SELECT mapid, difficulty, level_min, level_max, item_level, item, item2, quest_done_A, quest_done_H, completed_achievement, quest_failed_text FROM access_requirement"); + if (!result) { TC_LOG_INFO("server.loading", ">> Loaded 0 access requirement definitions. DB table `access_requirement` is empty."); @@ -6036,12 +6031,13 @@ void ObjectMgr::LoadAccessRequirements() ar->levelMin = fields[2].GetUInt8(); ar->levelMax = fields[3].GetUInt8(); - ar->item = fields[4].GetUInt32(); - ar->item2 = fields[5].GetUInt32(); - ar->quest_A = fields[6].GetUInt32(); - ar->quest_H = fields[7].GetUInt32(); - ar->achievement = fields[8].GetUInt32(); - ar->questFailedText = fields[9].GetString(); + ar->item_level = fields[4].GetUInt16(); + ar->item = fields[5].GetUInt32(); + ar->item2 = fields[6].GetUInt32(); + ar->quest_A = fields[7].GetUInt32(); + ar->quest_H = fields[8].GetUInt32(); + ar->achievement = fields[9].GetUInt32(); + ar->questFailedText = fields[10].GetString(); if (ar->item) { diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 354f00a9e91..a3fee2d52aa 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -99,6 +99,7 @@ bool Group::Create(Player* leader) m_guid = MAKE_NEW_GUID(lowguid, 0, HIGHGUID_GROUP); m_leaderGuid = leaderGuid; m_leaderName = leader->GetName(); + leader->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER); if (isBGGroup() || isBFGroup()) m_groupType = GROUPTYPE_BGRAID; @@ -666,6 +667,10 @@ void Group::ChangeLeader(uint64 newLeaderGuid) CharacterDatabase.CommitTransaction(trans); } + if (Player* oldLeader = ObjectAccessor::FindPlayer(m_leaderGuid)) + oldLeader->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER); + + newLeader->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GROUP_LEADER); m_leaderGuid = newLeader->GetGUID(); m_leaderName = newLeader->GetName(); ToggleGroupMemberFlag(slot, MEMBER_FLAG_ASSISTANT, false); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 4c7d1669233..333d4d893cd 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1027,6 +1027,9 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) m_playerLoading = false; + // Handle Login-Achievements (should be handled after loading) + _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); + sScriptMgr->OnPlayerLogin(pCurrChar); delete holder; } diff --git a/src/server/game/Handlers/ChatHandler.cpp b/src/server/game/Handlers/ChatHandler.cpp index 17b5974d1ca..fbc78564ea5 100644 --- a/src/server/game/Handlers/ChatHandler.cpp +++ b/src/server/game/Handlers/ChatHandler.cpp @@ -55,6 +55,14 @@ void WorldSession::HandleMessagechatOpcode(WorldPacket& recvData) return; } + if (lang == LANG_UNIVERSAL && type != CHAT_MSG_AFK && type != CHAT_MSG_DND) + { + TC_LOG_ERROR("network", "CMSG_MESSAGECHAT: Possible hacking-attempt: %s tried to send a message in universal language", GetPlayerInfo().c_str()); + SendNotification(LANG_UNKNOWN_LANGUAGE); + recvData.rfinish(); + return; + } + Player* sender = GetPlayer(); //TC_LOG_DEBUG("CHAT: packet received. type %u, lang %u", type, lang); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index fcec4f38852..60f4fb09c28 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1135,7 +1135,6 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData) void WorldSession::HandleSetActionBarToggles(WorldPacket& recvData) { uint8 actionBar; - recvData >> actionBar; if (!GetPlayer()) // ignore until not logged (check needed because STATUS_AUTHED) diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index 4d78064423c..fc14797ea94 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -390,7 +390,6 @@ void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket& recvData) TC_LOG_DEBUG("network", "WORLD: CMSG_SPIRIT_HEALER_ACTIVATE"); uint64 guid; - recvData >> guid; Creature* unit = GetPlayer()->GetNPCIfCanInteractWith(guid, UNIT_NPC_FLAG_SPIRITHEALER); @@ -410,7 +409,6 @@ void WorldSession::HandleSpiritHealerActivateOpcode(WorldPacket& recvData) void WorldSession::SendSpiritResurrect() { _player->ResurrectPlayer(0.5f, true); - _player->DurabilityLossAll(0.25f, true); // get corpse nearest graveyard diff --git a/src/server/game/Movement/MotionMaster.cpp b/src/server/game/Movement/MotionMaster.cpp index d224c21efe8..55f745d993b 100644 --- a/src/server/game/Movement/MotionMaster.cpp +++ b/src/server/game/Movement/MotionMaster.cpp @@ -337,6 +337,9 @@ void MotionMaster::MoveKnockbackFrom(float srcX, float srcY, float speedXY, floa if (_owner->GetTypeId() == TYPEID_PLAYER) return; + if (speedXY <= 0.1f) + return; + float x, y, z; float moveTimeHalf = speedZ / Movement::gravity; float dist = 2 * moveTimeHalf * speedXY; @@ -370,6 +373,8 @@ void MotionMaster::MoveJumpTo(float angle, float speedXY, float speedZ) void MotionMaster::MoveJump(float x, float y, float z, float speedXY, float speedZ, uint32 id) { TC_LOG_DEBUG("misc", "Unit (GUID: %u) jump to point (X: %f Y: %f Z: %f)", _owner->GetGUIDLow(), x, y, z); + if (speedXY <= 0.1f) + return; float moveTimeHalf = speedZ / Movement::gravity; float max_height = -Movement::computeFallElevation(moveTimeHalf, false, -speedZ); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index c769a0b6aea..b7aabcc7589 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -5843,6 +5843,13 @@ void AuraEffect::HandlePeriodicDamageAurasTick(Unit* target, Unit* caster) const else damage = uint32(target->CountPctFromMaxHealth(damage)); + if (m_spellInfo->Effects[m_effIndex].IsTargetingArea() || m_spellInfo->Effects[m_effIndex].IsAreaAuraEffect() || m_spellInfo->Effects[m_effIndex].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) + { + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + if (caster->GetTypeId() != TYPEID_PLAYER) + damage = int32(float(damage) * target->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); + } + bool crit = IsPeriodicTickCrit(target, caster); if (crit) damage = caster->SpellCriticalDamageBonus(m_spellInfo, damage, target); diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index e72a1da563e..9098ac96376 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1171,77 +1171,6 @@ void Spell::SelectImplicitAreaTargets(SpellEffIndex effIndex, SpellImplicitTarge float radius = m_spellInfo->Effects[effIndex].CalcRadius(m_caster) * m_spellValue->RadiusMod; SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), m_spellInfo->Effects[effIndex].ImplicitTargetConditions); - // Custom entries - /// @todo remove those - switch (m_spellInfo->Id) - { - case 46584: // Raise Dead - { - if (Player* playerCaster = m_caster->ToPlayer()) - { - for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - switch ((*itr)->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - { - Unit* unitTarget = (*itr)->ToUnit(); - if (unitTarget->IsAlive() || !playerCaster->isHonorOrXPTarget(unitTarget) - || ((unitTarget->GetCreatureTypeMask() & (1 << (CREATURE_TYPE_HUMANOID-1))) == 0) - || (unitTarget->GetDisplayId() != unitTarget->GetNativeDisplayId())) - break; - AddUnitTarget(unitTarget, effMask, false); - // no break; - } - case TYPEID_CORPSE: // wont work until corpses are allowed in target lists, but at least will send dest in packet - m_targets.SetDst(*(*itr)); - return; // nothing more to do here - default: - break; - } - } - } - return; // don't add targets to target map - } - // Corpse Explosion - case 49158: - case 51325: - case 51326: - case 51327: - case 51328: - // check if our target is not valid (spell can target ghoul or dead unit) - if (!(m_targets.GetUnitTarget() && m_targets.GetUnitTarget()->GetDisplayId() == m_targets.GetUnitTarget()->GetNativeDisplayId() && - ((m_targets.GetUnitTarget()->GetEntry() == 26125 && m_targets.GetUnitTarget()->GetOwnerGUID() == m_caster->GetGUID()) - || m_targets.GetUnitTarget()->isDead()))) - { - // remove existing targets - CleanupTargetList(); - - for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr) - { - switch ((*itr)->GetTypeId()) - { - case TYPEID_UNIT: - case TYPEID_PLAYER: - if (!(*itr)->ToUnit()->isDead()) - break; - AddUnitTarget((*itr)->ToUnit(), 1 << effIndex, false); - return; - default: - break; - } - } - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); - SendCastResult(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); - finish(false); - } - return; - default: - break; - } - CallScriptObjectAreaTargetSelectHandlers(targets, effIndex); if (!targets.empty()) @@ -4866,8 +4795,7 @@ SpellCastResult Spell::CheckCast(bool strict) uint32 zone, area; m_caster->GetZoneAndAreaId(zone, area); - SpellCastResult locRes= m_spellInfo->CheckLocation(m_caster->GetMapId(), zone, area, - m_caster->GetTypeId() == TYPEID_PLAYER ? m_caster->ToPlayer() : NULL); + SpellCastResult locRes = m_spellInfo->CheckLocation(m_caster->GetMapId(), zone, area, m_caster->ToPlayer()); if (locRes != SPELL_CAST_OK) return locRes; } @@ -6722,10 +6650,10 @@ void Spell::DoAllEffectOnLaunchTarget(TargetInfo& targetInfo, float* multiplier) if (m_damage > 0) { - if (m_spellInfo->Effects[i].IsTargetingArea()) + if (m_spellInfo->Effects[i].IsTargetingArea() || m_spellInfo->Effects[i].IsAreaAuraEffect() || m_spellInfo->Effects[i].IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) { m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); - if (m_caster->GetTypeId() == TYPEID_UNIT) + if (m_caster->GetTypeId() != TYPEID_PLAYER) m_damage = int32(float(m_damage) * unit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CREATURE_AOE_DAMAGE_AVOIDANCE, m_spellInfo->SchoolMask)); if (m_caster->GetTypeId() == TYPEID_PLAYER) diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 76be075e94d..031311f2749 100644 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -557,7 +557,7 @@ class Spell GameObject* focusObject; // Damage and healing in effects need just calculate - int32 m_damage; // Damge in effects count here + int32 m_damage; // Damage in effects count here int32 m_healing; // Healing in effects count here // ****************************************** diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b2b4690f893..19cc2fe95c5 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -682,11 +682,6 @@ void Spell::EffectDummy(SpellEffIndex effIndex) if (!unitTarget && !gameObjTarget && !itemTarget) return; - uint32 spell_id = 0; - int32 bp = 0; - bool triggered = true; - SpellCastTargets targets; - // selection by spell family switch (m_spellInfo->SpellFamilyName) { @@ -723,60 +718,10 @@ void Spell::EffectDummy(SpellEffIndex effIndex) } } break; - case SPELLFAMILY_DEATHKNIGHT: - switch (m_spellInfo->Id) - { - case 46584: // Raise Dead - if (m_caster->GetTypeId() != TYPEID_PLAYER) - return; - - // Do we have talent Master of Ghouls? - if (m_caster->HasAura(52143)) - // summon as pet - bp = 52150; - else - // or guardian - bp = 46585; - - if (m_targets.HasDst()) - targets.SetDst(*m_targets.GetDstPos()); - else - { - targets.SetDst(*m_caster); - // Corpse not found - take reagents (only not triggered cast can take them) - triggered = false; - } - // Remove cooldown - summon spellls have category - m_caster->ToPlayer()->RemoveSpellCooldown(m_spellInfo->Id, true); - spell_id = 48289; - break; - // Raise dead - take reagents and trigger summon spells - case 48289: - if (m_targets.HasDst()) - targets.SetDst(*m_targets.GetDstPos()); - spell_id = CalculateDamage(0, NULL); - break; - } + default: break; } - //spells triggered by dummy effect should not miss - if (spell_id) - { - SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id); - - if (!spellInfo) - { - TC_LOG_ERROR("spells", "EffectDummy of spell %u: triggering unknown spell id %i\n", m_spellInfo->Id, spell_id); - return; - } - - targets.SetUnitTarget(unitTarget); - Spell* spell = new Spell(m_caster, spellInfo, triggered ? TRIGGERED_FULL_MASK : TRIGGERED_NONE, m_originalCasterGUID, true); - if (bp) spell->SetSpellValue(SPELLVALUE_BASE_POINT0, bp); - spell->prepare(&targets); - } - // pet auras if (PetAura const* petSpell = sSpellMgr->GetPetAura(m_spellInfo->Id, effIndex)) { @@ -910,7 +855,7 @@ void Spell::EffectTriggerSpell(SpellEffIndex effIndex) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!spellInfo) { - TC_LOG_DEBUG("spells", "Spell::EffectTriggerSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); + TC_LOG_ERROR("spells", "Spell::EffectTriggerSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); return; } @@ -962,7 +907,7 @@ void Spell::EffectTriggerMissileSpell(SpellEffIndex effIndex) SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(triggered_spell_id); if (!spellInfo) { - TC_LOG_DEBUG("spells", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); + TC_LOG_ERROR("spells", "Spell::EffectTriggerMissileSpell spell %u tried to trigger unknown spell %u", m_spellInfo->Id, triggered_spell_id); return; } diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index 8b31e749c62..93f264d2d61 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -2714,8 +2714,39 @@ void SpellMgr::UnloadSpellInfoImplicitTargetConditionLists() void SpellMgr::LoadSpellInfoCustomAttributes() { uint32 oldMSTime = getMSTime(); - + uint32 oldMSTime2 = oldMSTime; SpellInfo* spellInfo = NULL; + + QueryResult result = WorldDatabase.Query("SELECT entry, attributes FROM spell_custom_attr"); + + if (!result) + TC_LOG_INFO("server.loading", ">> Loaded 0 spell custom attributes from DB. DB table `spell_custom_attr` is empty."); + else + { + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 spellId = fields[0].GetUInt32(); + uint32 attributes = fields[1].GetUInt32(); + + spellInfo = _GetSpellInfo(spellId); + if (!spellInfo) + { + TC_LOG_ERROR("sql.sql", "Table `spell_custom_attr` has wrong spell (entry: %u), ignored.", spellId); + continue; + } + + // TODO: validate attributes + + spellInfo->AttributesCu |= attributes; + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u spell custom attributes from DB in %u ms", count, GetMSTimeDiffToNow(oldMSTime2)); + } + for (uint32 i = 0; i < GetSpellInfoStoreSize(); ++i) { spellInfo = mSpellInfoMap[i]; @@ -2826,171 +2857,6 @@ void SpellMgr::LoadSpellInfoCustomAttributes() if (spellInfo->SpellVisual[0] == 3879) spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_BACK; - switch (spellInfo->Id) - { - case 1776: // Gouge - case 1777: - case 8629: - case 11285: - case 11286: - case 12540: - case 13579: - case 24698: - case 28456: - case 29425: - case 34940: - case 36862: - case 38764: - case 38863: - case 52743: // Head Smack - spellInfo->AttributesCu |= SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER; - break; - case 53: // Backstab - case 2589: - case 2590: - case 2591: - case 7159: - case 8627: - case 8721: - case 11279: - case 11280: - case 11281: - case 15582: - case 15657: - case 22416: - case 25300: - case 26863: - case 37685: - case 48656: - case 48657: - case 703: // Garrote - case 8631: - case 8632: - case 8633: - case 11289: - case 11290: - case 26839: - case 26884: - case 48675: - case 48676: - case 5221: // Shred - case 6800: - case 8992: - case 9829: - case 9830: - case 27001: - case 27002: - case 48571: - case 48572: - case 8676: // Ambush - case 8724: - case 8725: - case 11267: - case 11268: - case 11269: - case 27441: - case 48689: - case 48690: - case 48691: - case 6785: // Ravage - case 6787: - case 9866: - case 9867: - case 27005: - case 48578: - case 48579: - case 21987: // Lash of Pain - case 23959: // Test Stab R50 - case 24825: // Test Backstab - case 58563: // Assassinate Restless Lookout - spellInfo->AttributesCu |= SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET; - break; - case 26029: // Dark Glare - case 37433: // Spout - case 43140: // Flame Breath - case 43215: // Flame Breath - case 70461: // Coldflame Trap - case 72133: // Pain and Suffering - case 73788: // Pain and Suffering - case 73789: // Pain and Suffering - case 73790: // Pain and Suffering - spellInfo->AttributesCu |= SPELL_ATTR0_CU_CONE_LINE; - break; - case 24340: // Meteor - case 26558: // Meteor - case 28884: // Meteor - case 36837: // Meteor - case 38903: // Meteor - case 41276: // Meteor - case 57467: // Meteor - case 26789: // Shard of the Fallen Star - case 31436: // Malevolent Cleave - case 35181: // Dive Bomb - case 40810: // Saber Lash - case 43267: // Saber Lash - case 43268: // Saber Lash - case 42384: // Brutal Swipe - case 45150: // Meteor Slash - case 64688: // Sonic Screech - case 72373: // Shared Suffering - case 71904: // Chaos Bane - case 70492: // Ooze Eruption - case 72505: // Ooze Eruption - case 72624: // Ooze Eruption - case 72625: // Ooze Eruption - // ONLY SPELLS WITH SPELLFAMILY_GENERIC and EFFECT_SCHOOL_DAMAGE - spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; - break; - case 18500: // Wing Buffet - case 33086: // Wild Bite - case 49749: // Piercing Blow - case 52890: // Penetrating Strike - case 53454: // Impale - case 59446: // Impale - case 62383: // Shatter - case 64777: // Machine Gun - case 65239: // Machine Gun - case 65919: // Impale - case 67858: // Impale - case 67859: // Impale - case 67860: // Impale - case 69293: // Wing Buffet - case 74439: // Machine Gun - case 63278: // Mark of the Faceless (General Vezax) - case 62544: // Thrust (Argent Tournament) - case 64588: // Thrust (Argent Tournament) - case 66479: // Thrust (Argent Tournament) - case 68505: // Thrust (Argent Tournament) - case 62709: // Counterattack! (Argent Tournament) - case 62626: // Break-Shield (Argent Tournament, Player) - case 64590: // Break-Shield (Argent Tournament, Player) - case 64342: // Break-Shield (Argent Tournament, NPC) - case 64686: // Break-Shield (Argent Tournament, NPC) - case 65147: // Break-Shield (Argent Tournament, NPC) - case 68504: // Break-Shield (Argent Tournament, NPC) - case 62874: // Charge (Argent Tournament, Player) - case 68498: // Charge (Argent Tournament, Player) - case 64591: // Charge (Argent Tournament, Player) - case 63003: // Charge (Argent Tournament, NPC) - case 63010: // Charge (Argent Tournament, NPC) - case 68321: // Charge (Argent Tournament, NPC) - case 72255: // Mark of the Fallen Champion (Deathbringer Saurfang) - case 72444: // Mark of the Fallen Champion (Deathbringer Saurfang) - case 72445: // Mark of the Fallen Champion (Deathbringer Saurfang) - case 72446: // Mark of the Fallen Champion (Deathbringer Saurfang) - spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; - break; - case 64422: // Sonic Screech (Auriaya) - spellInfo->AttributesCu |= SPELL_ATTR0_CU_SHARE_DAMAGE; - spellInfo->AttributesCu |= SPELL_ATTR0_CU_IGNORE_ARMOR; - break; - case 72293: // Mark of the Fallen Champion (Deathbringer Saurfang) - spellInfo->AttributesCu |= SPELL_ATTR0_CU_NEGATIVE_EFF0; - break; - default: - break; - } - switch (spellInfo->SpellFamilyName) { case SPELLFAMILY_WARRIOR: diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index c7eebb495c0..c0bcd477e5b 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -576,16 +576,28 @@ void SpellScript::PreventHitDefaultEffect(SpellEffIndex effIndex) m_hitPreventDefaultEffectMask |= 1 << effIndex; } -int32 SpellScript::GetEffectValue() +int32 SpellScript::GetEffectValue() const { if (!IsInEffectHook()) { - TC_LOG_ERROR("scripts", "Script: `%s` Spell: `%u`: function SpellScript::PreventHitDefaultEffect was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); + TC_LOG_ERROR("scripts", "Script: `%s` Spell: `%u`: function SpellScript::GetEffectValue was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); return 0; } + return m_spell->damage; } +void SpellScript::SetEffectValue(int32 value) +{ + if (!IsInEffectHook()) + { + TC_LOG_ERROR("scripts", "Script: `%s` Spell: `%u`: function SpellScript::SetEffectValue was called, but function has no effect in current hook!", m_scriptName->c_str(), m_scriptSpellId); + return; + } + + m_spell->damage = value; +} + Item* SpellScript::GetCastItem() { return m_spell->m_CastItem; diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index dfa494e38e6..6378a8bed9b 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -411,7 +411,8 @@ class SpellScript : public _SpellScript void PreventHitDefaultEffect(SpellEffIndex effIndex); // method avalible only in EffectHandler method - int32 GetEffectValue(); + int32 GetEffectValue() const; + void SetEffectValue(int32 value); // returns: cast item if present. Item* GetCastItem(); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 3fde3ad4a11..af2fb90ea1b 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1262,6 +1262,8 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_PACKET_SPOOF_BANDURATION] = sConfigMgr->GetIntDefault("PacketSpoof.BanDuration", 86400); + m_int_configs[CONFIG_BIRTHDAY_TIME] = sConfigMgr->GetIntDefault("BirthdayTime", 1222964635); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index a320933e181..4c43507d038 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -339,6 +339,7 @@ enum WorldIntConfigs CONFIG_BG_REWARD_WINNER_ARENA_LAST, CONFIG_BG_REWARD_LOSER_HONOR_FIRST, CONFIG_BG_REWARD_LOSER_HONOR_LAST, + CONFIG_BIRTHDAY_TIME, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 027a6843c87..1f4713415ac 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -1837,7 +1837,6 @@ public: void IsSummonedBy(Unit*) OVERRIDE { DoCast(me, SPELL_EMERGE_VISUAL); - DoZoneInCombat(me, 100.00f); } void JustDied(Unit* /*killer*/) OVERRIDE diff --git a/src/server/scripts/Outland/zone_nagrand.cpp b/src/server/scripts/Outland/zone_nagrand.cpp index 8d5c81d1c01..9b7a3f8aa2a 100644 --- a/src/server/scripts/Outland/zone_nagrand.cpp +++ b/src/server/scripts/Outland/zone_nagrand.cpp @@ -182,13 +182,11 @@ public: { if (quest->GetQuestId() == QUEST_TOTEM_KARDASH_H) { - if (npc_maghar_captiveAI* pEscortAI = dynamic_cast<npc_maghar_captiveAI*>(creature->AI())) + if (npc_maghar_captiveAI* EscortAI = dynamic_cast<npc_maghar_captiveAI*>(creature->AI())) { creature->SetStandState(UNIT_STAND_STATE_STAND); creature->setFaction(232); - - pEscortAI->Start(true, false, player->GetGUID(), quest); - + EscortAI->Start(true, false, player->GetGUID(), quest); creature->AI()->Talk(SAY_MAG_START); creature->SummonCreature(NPC_MURK_RAIDER, m_afAmbushA[0]+2.5f, m_afAmbushA[1]-2.5f, m_afAmbushA[2], 0.0f, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 25000); @@ -208,15 +206,15 @@ public: { npc_maghar_captiveAI(Creature* creature) : npc_escortAI(creature) { Reset(); } - uint32 m_uiChainLightningTimer; - uint32 m_uiHealTimer; - uint32 m_uiFrostShockTimer; + uint32 ChainLightningTimer; + uint32 HealTimer; + uint32 FrostShockTimer; void Reset() OVERRIDE { - m_uiChainLightningTimer = 1000; - m_uiHealTimer = 0; - m_uiFrostShockTimer = 6000; + ChainLightningTimer = 1000; + HealTimer = 0; + FrostShockTimer = 6000; } void EnterCombat(Unit* /*who*/) OVERRIDE @@ -224,6 +222,18 @@ public: DoCast(me, SPELL_EARTHBIND_TOTEM, false); } + void JustDied(Unit* /*killer*/) OVERRIDE + { + if (!HasEscortState(STATE_ESCORT_ESCORTING)) + return; + + if (Player* player = GetPlayerForEscort()) + { + if (player->GetQuestStatus(QUEST_TOTEM_KARDASH_H) != QUEST_STATUS_COMPLETE) + player->FailQuest(QUEST_TOTEM_KARDASH_H); + } + } + void WaypointReached(uint32 waypointId) OVERRIDE { switch (waypointId) @@ -263,9 +273,9 @@ public: } - void SpellHitTarget(Unit* /*target*/, const SpellInfo* pSpell) OVERRIDE + void SpellHitTarget(Unit* /*target*/, const SpellInfo* spell) OVERRIDE { - if (pSpell->Id == SPELL_CHAIN_LIGHTNING) + if (spell->Id == SPELL_CHAIN_LIGHTNING) { if (rand()%10) return; @@ -274,38 +284,42 @@ public: } } - void UpdateAI(uint32 uiDiff) OVERRIDE + void UpdateAI(uint32 diff) OVERRIDE { - npc_escortAI::UpdateAI(uiDiff); - if (!me->GetVictim()) + npc_escortAI::UpdateAI(diff); + + if (!UpdateVictim()) + return; + + if (me->HasUnitState(UNIT_STATE_CASTING)) return; - if (m_uiChainLightningTimer <= uiDiff) + if (ChainLightningTimer <= diff) { DoCastVictim(SPELL_CHAIN_LIGHTNING); - m_uiChainLightningTimer = urand(7000, 14000); + ChainLightningTimer = urand(7000, 14000); } else - m_uiChainLightningTimer -= uiDiff; + ChainLightningTimer -= diff; if (HealthBelowPct(30)) { - if (m_uiHealTimer <= uiDiff) + if (HealTimer <= diff) { DoCast(me, SPELL_HEALING_WAVE); - m_uiHealTimer = 5000; + HealTimer = 5000; } else - m_uiHealTimer -= uiDiff; + HealTimer -= diff; } - if (m_uiFrostShockTimer <= uiDiff) + if (FrostShockTimer <= diff) { DoCastVictim(SPELL_FROST_SHOCK); - m_uiFrostShockTimer = urand(7500, 15000); + FrostShockTimer = urand(7500, 15000); } else - m_uiFrostShockTimer -= uiDiff; + FrostShockTimer -= diff; DoMeleeAttackIfReady(); } @@ -517,6 +531,7 @@ public: if (npc_kurenai_captiveAI* EscortAI = dynamic_cast<npc_kurenai_captiveAI*>(creature->AI())) { creature->SetStandState(UNIT_STAND_STATE_STAND); + creature->setFaction(231); EscortAI->Start(true, false, player->GetGUID(), quest); creature->AI()->Talk(SAY_KUR_START); @@ -629,6 +644,8 @@ public: void UpdateAI(uint32 diff) OVERRIDE { + npc_escortAI::UpdateAI(diff); + if (!UpdateVictim()) return; diff --git a/src/server/scripts/Spells/spell_dk.cpp b/src/server/scripts/Spells/spell_dk.cpp index e2e4d30541c..e8108f03e7d 100644 --- a/src/server/scripts/Spells/spell_dk.cpp +++ b/src/server/scripts/Spells/spell_dk.cpp @@ -25,6 +25,7 @@ #include "ScriptMgr.h" #include "SpellScript.h" #include "SpellAuraEffects.h" +#include "Containers.h" enum DeathKnightSpells { @@ -49,6 +50,8 @@ enum DeathKnightSpells SPELL_DK_IMPROVED_UNHOLY_PRESENCE_TRIGGERED = 63622, SPELL_DK_ITEM_SIGIL_VENGEFUL_HEART = 64962, SPELL_DK_ITEM_T8_MELEE_4P_BONUS = 64736, + SPELL_DK_MASTER_OF_GHOULS = 52143, + SPELL_DK_RAISE_DEAD_USE_REAGENT = 48289, SPELL_DK_RUNIC_POWER_ENERGIZE = 49088, SPELL_DK_SCENT_OF_BLOOD = 50422, SPELL_DK_SCOURGE_STRIKE_TRIGGERED = 70890, @@ -63,6 +66,11 @@ enum DeathKnightSpellIcons DK_ICON_ID_IMPROVED_DEATH_STRIKE = 2751 }; +enum Misc +{ + NPC_DK_GHOUL = 26125 +}; + // 50462 - Anti-Magic Shell (on raid member) class spell_dk_anti_magic_shell_raid : public SpellScriptLoader { @@ -311,6 +319,28 @@ class spell_dk_blood_gorged : public SpellScriptLoader } }; +class CorpseExplosionCheck +{ +public: + explicit CorpseExplosionCheck(uint64 casterGUID) : _casterGUID(casterGUID) { } + + bool operator()(WorldObject* obj) const + { + if (Unit* target = obj->ToUnit()) + { + if ((target->isDead() || (target->GetEntry() == NPC_DK_GHOUL && target->GetOwnerGUID() == _casterGUID)) + && !(target->GetCreatureTypeMask() & CREATURE_TYPEMASK_MECHANICAL_OR_ELEMENTAL) + && target->GetDisplayId() == target->GetNativeDisplayId()) + return false; + } + + return true; + } + +private: + uint64 _casterGUID; +}; + // 49158 - Corpse Explosion (51325, 51326, 51327, 51328) class spell_dk_corpse_explosion : public SpellScriptLoader { @@ -321,41 +351,87 @@ class spell_dk_corpse_explosion : public SpellScriptLoader { PrepareSpellScript(spell_dk_corpse_explosion_SpellScript); - bool Validate(SpellInfo const* /*spellInfo*/) OVERRIDE + bool Validate(SpellInfo const* spellInfo) OVERRIDE { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED) || !sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_EXPLODE)) - return false; - if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_VISUAL)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED) + || !sSpellMgr->GetSpellInfo(SPELL_DK_GHOUL_EXPLODE) + || !sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_VISUAL) + || !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].CalcValue())) return false; return true; } - void HandleDummy(SpellEffIndex /*effIndex*/) + bool Load() OVERRIDE + { + _target = NULL; + return true; + } + + void CheckTarget(WorldObject*& target) + { + if (CorpseExplosionCheck(GetCaster()->GetGUID())(target)) + target = NULL; + + _target = target; + } + + void CheckTargets(std::list<WorldObject*>& targets) + { + WorldObject* target = _target; + if (!target) + { + targets.remove_if(CorpseExplosionCheck(GetCaster()->GetGUID())); + if (targets.empty()) + { + FinishCast(SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW); + return; + } + target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + else + targets.clear(); + } + + void HandleDamage(SpellEffIndex effIndex, Unit* target) + { + if (effIndex == EFFECT_0) + GetCaster()->CastCustomSpell(GetSpellInfo()->Effects[EFFECT_1].CalcValue(), SPELLVALUE_BASE_POINT0, GetEffectValue(), target, true); + else if (effIndex == EFFECT_1) + GetCaster()->CastCustomSpell(GetEffectValue(), SPELLVALUE_BASE_POINT0, GetSpell()->CalculateDamage(EFFECT_0, NULL), target, true); + } + + void HandleCorpseExplosion(SpellEffIndex effIndex) { if (Unit* unitTarget = GetHitUnit()) { - int32 bp = 0; if (unitTarget->IsAlive()) // Living ghoul as a target { - bp = int32(unitTarget->CountPctFromMaxHealth(25)); - unitTarget->CastCustomSpell(unitTarget, SPELL_DK_GHOUL_EXPLODE, &bp, NULL, NULL, false); + unitTarget->CastSpell(unitTarget, SPELL_DK_GHOUL_EXPLODE, false); + // Corpse Explosion (Suicide) and Set corpse look handled in SpellScript of SPELL_DK_GHOUL_EXPLODE } else // Some corpse { - bp = GetEffectValue(); - GetCaster()->CastCustomSpell(unitTarget, GetSpellInfo()->Effects[EFFECT_1].CalcValue(), &bp, NULL, NULL, true); + HandleDamage(effIndex, unitTarget); // Corpse Explosion (Suicide) unitTarget->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_TRIGGERED, true); + // Set corpse look + GetCaster()->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_VISUAL, true); } - // Set corpse look - GetCaster()->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_VISUAL, true); } } void Register() OVERRIDE { - OnEffectHitTarget += SpellEffectFn(spell_dk_corpse_explosion_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_dk_corpse_explosion_SpellScript::CheckTarget, EFFECT_0, TARGET_UNIT_TARGET_ANY); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dk_corpse_explosion_SpellScript::CheckTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_dk_corpse_explosion_SpellScript::HandleCorpseExplosion, EFFECT_0, SPELL_EFFECT_DUMMY); + OnEffectHitTarget += SpellEffectFn(spell_dk_corpse_explosion_SpellScript::HandleCorpseExplosion, EFFECT_1, SPELL_EFFECT_DUMMY); } + + private: + WorldObject* _target; }; SpellScript* GetSpellScript() const OVERRIDE @@ -616,24 +692,34 @@ class spell_dk_ghoul_explode : public SpellScriptLoader { PrepareSpellScript(spell_dk_ghoul_explode_SpellScript); - bool Validate(SpellInfo const* /*spellInfo*/) OVERRIDE + bool Validate(SpellInfo const* spellInfo) OVERRIDE { - if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED)) + if (!sSpellMgr->GetSpellInfo(SPELL_DK_CORPSE_EXPLOSION_TRIGGERED) + || spellInfo->Effects[EFFECT_2].CalcValue() <= 0) return false; return true; } + void HandleDamage(SpellEffIndex /*effIndex*/) + { + int32 value = int32(GetCaster()->CountPctFromMaxHealth(GetSpellInfo()->Effects[EFFECT_2].CalcValue(GetCaster()))); + SetEffectValue(value); + } + void Suicide(SpellEffIndex /*effIndex*/) { if (Unit* unitTarget = GetHitUnit()) { // Corpse Explosion (Suicide) unitTarget->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_TRIGGERED, true); + // Set corpse look + GetCaster()->CastSpell(unitTarget, SPELL_DK_CORPSE_EXPLOSION_VISUAL, true); } } void Register() OVERRIDE { + OnEffectLaunchTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::HandleDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); OnEffectHitTarget += SpellEffectFn(spell_dk_ghoul_explode_SpellScript::Suicide, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE); } }; @@ -940,6 +1026,162 @@ class spell_dk_presence : public SpellScriptLoader } }; +class RaiseDeadCheck +{ + public: + explicit RaiseDeadCheck(Player const* caster) : _caster(caster) { } + + bool operator()(WorldObject* obj) const + { + if (Unit* target = obj->ToUnit()) + { + if (!target->IsAlive() + && _caster->isHonorOrXPTarget(target) + && target->GetCreatureType() == CREATURE_TYPE_HUMANOID + && target->GetDisplayId() == target->GetNativeDisplayId()) + return false; + } + + return true; + } + + private: + Player const* _caster; +}; + +// 46584 - Raise Dead +class spell_dk_raise_dead : public SpellScriptLoader +{ + public: + spell_dk_raise_dead() : SpellScriptLoader("spell_dk_raise_dead") { } + + class spell_dk_raise_dead_SpellScript : public SpellScript + { + PrepareSpellScript(spell_dk_raise_dead_SpellScript); + + bool Validate(SpellInfo const* spellInfo) OVERRIDE + { + if (!sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_1].CalcValue()) + || !sSpellMgr->GetSpellInfo(spellInfo->Effects[EFFECT_2].CalcValue()) + || !sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_DEAD_USE_REAGENT) + || !sSpellMgr->GetSpellInfo(SPELL_DK_MASTER_OF_GHOULS)) + return false; + return true; + } + + bool Load() OVERRIDE + { + _result = SPELL_CAST_OK; + _corpse = false; + return GetCaster()->GetTypeId() == TYPEID_PLAYER; + } + + SpellCastResult CheckCast() + { + /// process spell target selection before cast starts + /// targets of effect_1 are used to check cast + GetSpell()->SelectSpellTargets(); + /// cleanup spell target map, and fill it again on normal way + GetSpell()->CleanupTargetList(); + /// _result is set in spell target selection + return _result; + } + + SpellCastResult CheckReagents() + { + /// @workaround: there is no access to castresult of other spells, check it manually + SpellInfo const* reagentSpell = sSpellMgr->GetSpellInfo(SPELL_DK_RAISE_DEAD_USE_REAGENT); + Player* player = GetCaster()->ToPlayer(); + if (!player->CanNoReagentCast(reagentSpell)) + { + for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++) + { + if (reagentSpell->Reagent[i] <= 0) + continue; + + if (!player->HasItemCount(reagentSpell->Reagent[i], reagentSpell->ReagentCount[i])) + { + Spell::SendCastResult(player, reagentSpell, 0, SPELL_FAILED_REAGENTS); + return SPELL_FAILED_DONT_REPORT; + } + } + } + return SPELL_CAST_OK; + } + + void CheckTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(RaiseDeadCheck(GetCaster()->ToPlayer())); + + if (targets.empty()) + { + if (GetSpell()->getState() == SPELL_STATE_PREPARING) + _result = CheckReagents(); + + return; + } + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + _corpse = true; + } + + void CheckTarget(WorldObject*& target) + { + // Don't add caster to target map, if we found a corpse to raise dead + if (_corpse) + target = NULL; + } + + void ConsumeReagents() + { + // No corpse found, take reagents + if (!_corpse) + GetCaster()->CastSpell(GetCaster(), SPELL_DK_RAISE_DEAD_USE_REAGENT, TriggerCastFlags(TRIGGERED_FULL_MASK & ~TRIGGERED_IGNORE_POWER_AND_REAGENT_COST)); + } + + uint32 GetGhoulSpellId() + { + // Do we have talent Master of Ghouls? + if (GetCaster()->HasAura(SPELL_DK_MASTER_OF_GHOULS)) + // summon as pet + return GetSpellInfo()->Effects[EFFECT_2].CalcValue(); + + // or guardian + return GetSpellInfo()->Effects[EFFECT_1].CalcValue(); + } + + void HandleRaiseDead(SpellEffIndex /*effIndex*/) + { + SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(GetGhoulSpellId()); + SpellCastTargets targets; + targets.SetDst(*GetHitUnit()); + + GetCaster()->CastSpell(targets, spellInfo, NULL, TRIGGERED_FULL_MASK); + } + + void Register() OVERRIDE + { + OnCheckCast += SpellCheckCastFn(spell_dk_raise_dead_SpellScript::CheckCast); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_dk_raise_dead_SpellScript::CheckTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENTRY); + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_dk_raise_dead_SpellScript::CheckTarget, EFFECT_2, TARGET_UNIT_CASTER); + OnCast += SpellCastFn(spell_dk_raise_dead_SpellScript::ConsumeReagents); + OnEffectHitTarget += SpellEffectFn(spell_dk_raise_dead_SpellScript::HandleRaiseDead, EFFECT_1, SPELL_EFFECT_SCRIPT_EFFECT); + OnEffectHitTarget += SpellEffectFn(spell_dk_raise_dead_SpellScript::HandleRaiseDead, EFFECT_2, SPELL_EFFECT_DUMMY); + } + + private: + SpellCastResult _result; + bool _corpse; + }; + + SpellScript* GetSpellScript() const OVERRIDE + { + return new spell_dk_raise_dead_SpellScript(); + } +}; + // 59754 Rune Tap - Party class spell_dk_rune_tap_party : public SpellScriptLoader { @@ -1224,6 +1466,7 @@ void AddSC_deathknight_spell_scripts() new spell_dk_improved_frost_presence(); new spell_dk_improved_unholy_presence(); new spell_dk_presence(); + new spell_dk_raise_dead(); new spell_dk_rune_tap_party(); new spell_dk_scent_of_blood(); new spell_dk_scourge_strike(); diff --git a/src/server/shared/CompilerDefs.h b/src/server/shared/CompilerDefs.h index 71b20a4d175..8a557328af4 100644 --- a/src/server/shared/CompilerDefs.h +++ b/src/server/shared/CompilerDefs.h @@ -57,6 +57,8 @@ #if defined(__cplusplus) && __cplusplus == 201103L # define COMPILER_HAS_CPP11_SUPPORT 1 +#elif _MSC_VER >= 1700 +# define COMPILER_HAS_CPP11_SUPPORT 1 #else # define COMPILER_HAS_CPP11_SUPPORT 0 #endif diff --git a/src/server/shared/Utilities/ByteConverter.h b/src/server/shared/Utilities/ByteConverter.h index bf1342a10e4..8eebb05bb13 100644 --- a/src/server/shared/Utilities/ByteConverter.h +++ b/src/server/shared/Utilities/ByteConverter.h @@ -47,9 +47,13 @@ namespace ByteConverter #if TRINITY_ENDIAN == TRINITY_BIGENDIAN template<typename T> inline void EndianConvert(T& val) { ByteConverter::apply<T>(&val); } template<typename T> inline void EndianConvertReverse(T&) { } +template<typename T> inline void EndianConvertPtr(void* val) { ByteConverter::apply<T>(val); } +template<typename T> inline void EndianConvertPtrReverse(void*) { } #else template<typename T> inline void EndianConvert(T&) { } template<typename T> inline void EndianConvertReverse(T& val) { ByteConverter::apply<T>(&val); } +template<typename T> inline void EndianConvertPtr(void*) { } +template<typename T> inline void EndianConvertPtrReverse(void* val) { ByteConverter::apply<T>(val); } #endif template<typename T> void EndianConvert(T*); // will generate link error diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 499ad0502b7..ffef61557fc 100644 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -510,6 +510,9 @@ void vutf8printf(FILE* out, const char *str, va_list* ap) wchar_t wtemp_buf[32*1024]; size_t temp_len = vsnprintf(temp_buf, 32*1024, str, *ap); + //vsnprintf returns -1 if the buffer is too small + if (temp_len == size_t(-1)) + temp_len = 32*1024-1; size_t wtemp_len = 32*1024-1; Utf8toWStr(temp_buf, temp_len, wtemp_buf, wtemp_len); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 2a47c8f989e..1762859afae 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1140,6 +1140,15 @@ AccountInstancesPerHour = 5 Account.PasswordChangeSecurity = 0 # +# BirthdayTime +# Description: Set to date of project's birth in UNIX time. By default the date when TrinityCore was started (Thu Oct 2, 2008) +# Default: 1222964635 +# +# + +BirthdayTime = 1222964635 + +# ################################################################################################### ################################################################################################### |
