jhoancito

Members
  • Content Count

    14
  • Joined

  • Last visited

Community Reputation

1 Neutral

About jhoancito

  • Rank
    Member
  • Birthday 11/04/1995

Personal Information

  • Specialty
    None

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. hello friend help me please I have an error I have a patch to remove fatigue from the server I have an error is in the Player.cpp I will put a picture of the error help me please thank you I use the rev 61 of trinitycore fatiga.patch From 3da0ab4bd11ccae9d86b86a0089ec7b9d49c73d3 Mon Sep 17 00:00:00 2001 From: LordPsyan <uppp@juno.com> Date: Sat, 12 Nov 2011 13:41:43 -0600 Subject: [PATCH] 2011-11-12_Fatigue --- src/server/game/Entities/Player/Player.cpp | 11 +++++++++-- src/server/worldserver/worldserver.conf.dist | 7 +++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 9b1b2c3..193ac0d 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -74,6 +74,7 @@ #include "InstanceScript.h" #include <cmath> #include "AccountMgr.h" +#include "Config.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -1304,9 +1305,12 @@ int32 Player::getMaxTimer(MirrorTimerType timer) { switch (timer) { + if(ConfigMgr::GetBoolDefault("fatigue.enabled", true)) // If "fatigue.enabled" is enabled + { case FATIGUE_TIMER: return MINUTE * IN_MILLISECONDS; - case BREATH_TIMER: + } + case BREATH_TIMER: { if (!isAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING))) return DISABLED_MIRROR_TIMER; @@ -1376,6 +1380,9 @@ void Player::HandleDrowning(uint32 time_diff) } // In dark water +if(ConfigMgr::GetBoolDefault("fatigue.enabled", true)) // If "fatigue.enabled" is enabled +{ + if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER) { // Fatigue timer not activated - activate it @@ -1412,7 +1419,7 @@ void Player::HandleDrowning(uint32 time_diff) else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER) SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10); } - +} if (m_MirrorTimerFlags & (UNDERWATER_INLAVA|UNDERWATER_INSLIME)) { // Breath timer not activated - activate it diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index a8c0d91..b28f440 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1144,6 +1144,13 @@ InstantLogout = 1 DisableWaterBreath = 4 # +# Enable or Disable "Fatigue" timer +# default = 1 (enabled) +# = 0 (disabled) + +fatigue.enabled = 1 + +# # AllFlightPaths # Description: Character knows all flight paths (of both factions) after creation. # Default: 0 - (Disabled) -- 1.7.2.3 /* * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> * * 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/>. */ #include "Player.h" #include "AccountMgr.h" #include "Config.h" #include "AchievementMgr.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "Battlefield.h" #include "BattlefieldMgr.h" #include "BattlefieldWG.h" #include "Battleground.h" #include "BattlegroundMgr.h" #include "BattlegroundScore.h" #include "CellImpl.h" #include "Channel.h" #include "ChannelMgr.h" #include "CharacterDatabaseCleaner.h" #include "Chat.h" #include "Common.h" #include "ConditionMgr.h" #include "CreatureAI.h" #include "DatabaseEnv.h" #include "DisableMgr.h" #include "Formulas.h" #include "GameEventMgr.h" #include "GossipDef.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" #include "Group.h" #include "GroupMgr.h" #include "Guild.h" #include "GuildMgr.h" #include "InstanceSaveMgr.h" #include "InstanceScript.h" #include "KillRewarder.h" #include "LFGMgr.h" #include "Language.h" #include "Log.h" #include "MapManager.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" #include "OutdoorPvP.h" #include "OutdoorPvPMgr.h" #include "Pet.h" #include "QuestDef.h" #include "ReputationMgr.h" #include "GitRevision.h" #include "SkillDiscovery.h" #include "SocialMgr.h" #include "Spell.h" #include "SpellAuraEffects.h" #include "SpellAuras.h" #include "SpellMgr.h" #include "SpellHistory.h" #include "Transport.h" #include "TicketMgr.h" #include "UpdateData.h" #include "UpdateFieldFlags.h" #include "UpdateMask.h" #include "Util.h" #include "Weather.h" #include "WeatherMgr.h" #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" #include "GameObjectAI.h" #ifdef ELUNA #include "LuaEngine.h" #endif #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) #define PLAYER_SKILL_INDEX(x) (PLAYER_SKILL_INFO_1_1 + ((x)*3)) #define PLAYER_SKILL_VALUE_INDEX(x) (PLAYER_SKILL_INDEX(x)+1) #define PLAYER_SKILL_BONUS_INDEX(x) (PLAYER_SKILL_INDEX(x)+2) #define SKILL_VALUE(x) PAIR32_LOPART(x) #define SKILL_MAX(x) PAIR32_HIPART(x) #define MAKE_SKILL_VALUE(v, m) MAKE_PAIR32(v, m) #define SKILL_TEMP_BONUS(x) int16(PAIR32_LOPART(x)) #define SKILL_PERM_BONUS(x) int16(PAIR32_HIPART(x)) #define MAKE_SKILL_BONUS(t, p) MAKE_PAIR32(t, p) enum CharacterFlags { CHARACTER_FLAG_NONE = 0x00000000, CHARACTER_FLAG_UNK1 = 0x00000001, CHARACTER_FLAG_UNK2 = 0x00000002, CHARACTER_LOCKED_FOR_TRANSFER = 0x00000004, CHARACTER_FLAG_UNK4 = 0x00000008, CHARACTER_FLAG_UNK5 = 0x00000010, CHARACTER_FLAG_UNK6 = 0x00000020, CHARACTER_FLAG_UNK7 = 0x00000040, CHARACTER_FLAG_UNK8 = 0x00000080, CHARACTER_FLAG_UNK9 = 0x00000100, CHARACTER_FLAG_UNK10 = 0x00000200, CHARACTER_FLAG_HIDE_HELM = 0x00000400, CHARACTER_FLAG_HIDE_CLOAK = 0x00000800, CHARACTER_FLAG_UNK13 = 0x00001000, CHARACTER_FLAG_GHOST = 0x00002000, CHARACTER_FLAG_RENAME = 0x00004000, CHARACTER_FLAG_UNK16 = 0x00008000, CHARACTER_FLAG_UNK17 = 0x00010000, CHARACTER_FLAG_UNK18 = 0x00020000, CHARACTER_FLAG_UNK19 = 0x00040000, CHARACTER_FLAG_UNK20 = 0x00080000, CHARACTER_FLAG_UNK21 = 0x00100000, CHARACTER_FLAG_UNK22 = 0x00200000, CHARACTER_FLAG_UNK23 = 0x00400000, CHARACTER_FLAG_UNK24 = 0x00800000, CHARACTER_FLAG_LOCKED_BY_BILLING = 0x01000000, CHARACTER_FLAG_DECLINED = 0x02000000, CHARACTER_FLAG_UNK27 = 0x04000000, CHARACTER_FLAG_UNK28 = 0x08000000, CHARACTER_FLAG_UNK29 = 0x10000000, CHARACTER_FLAG_UNK30 = 0x20000000, CHARACTER_FLAG_UNK31 = 0x40000000, CHARACTER_FLAG_UNK32 = 0x80000000 }; enum CharacterCustomizeFlags { CHAR_CUSTOMIZE_FLAG_NONE = 0x00000000, CHAR_CUSTOMIZE_FLAG_CUSTOMIZE = 0x00000001, // name, gender, etc... CHAR_CUSTOMIZE_FLAG_FACTION = 0x00010000, // name, gender, faction, etc... CHAR_CUSTOMIZE_FLAG_RACE = 0x00100000 // name, gender, race, etc... }; // corpse reclaim times #define DEATH_EXPIRE_STEP (5*MINUTE) #define MAX_DEATH_COUNT 3 static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 }; uint32 const MAX_MONEY_AMOUNT = static_cast<uint32>(std::numeric_limits<int32>::max()); // == PlayerTaxi ================================================ PlayerTaxi::PlayerTaxi() { memset(m_taximask, 0, sizeof(m_taximask)); } void PlayerTaxi::InitTaxiNodesForLevel(uint32 race, uint32 chrClass, uint8 level) { // class specific initial known nodes switch (chrClass) { case CLASS_DEATH_KNIGHT: { for (uint8 i = 0; i < TaxiMaskSize; ++i) m_taximask[i] |= sOldContinentsNodesMask[i]; break; } } // race specific initial known nodes: capital and taxi hub masks switch (race) { case RACE_HUMAN: SetTaximaskNode(2); break; // Human case RACE_ORC: SetTaximaskNode(23); break; // Orc case RACE_DWARF: SetTaximaskNode(6); break; // Dwarf case RACE_NIGHTELF: SetTaximaskNode(26); SetTaximaskNode(27); break; // Night Elf case RACE_UNDEAD_PLAYER: SetTaximaskNode(11); break;// Undead case RACE_TAUREN: SetTaximaskNode(22); break; // Tauren case RACE_GNOME: SetTaximaskNode(6); break; // Gnome case RACE_TROLL: SetTaximaskNode(23); break; // Troll case RACE_BLOODELF: SetTaximaskNode(82); break; // Blood Elf case RACE_DRAENEI: SetTaximaskNode(94); break; // Draenei } // new continent starting masks (It will be accessible only at new map) switch (Player::TeamForRace(race)) { case ALLIANCE: SetTaximaskNode(100); break; case HORDE: SetTaximaskNode(99); break; } // level dependent taxi hubs if (level >= 68) SetTaximaskNode(213); //Shattered Sun Staging Area } void PlayerTaxi::LoadTaxiMask(std::string const &data) { Tokenizer tokens(data, ' '); uint8 index = 0; for (Tokenizer::const_iterator iter = tokens.begin(); index < TaxiMaskSize && iter != tokens.end(); ++iter, ++index) { // load and set bits only for existing taxi nodes m_taximask[index] = sTaxiNodesMask[index] & atoul(*iter); } } void PlayerTaxi::AppendTaximaskTo(ByteBuffer& data, bool all) { if (all) { for (uint8 i = 0; i < TaxiMaskSize; ++i) data << uint32(sTaxiNodesMask[i]); // all existing nodes } else { for (uint8 i = 0; i < TaxiMaskSize; ++i) data << uint32(m_taximask[i]); // known nodes } } bool PlayerTaxi::LoadTaxiDestinationsFromString(const std::string& values, uint32 team) { ClearTaxiDestinations(); Tokenizer Tokenizer(values, ' '); for (Tokenizer::const_iterator iter = Tokenizer.begin(); iter != Tokenizer.end(); ++iter) { uint32 node = atoul(*iter); AddTaxiDestination(node); } if (m_TaxiDestinations.empty()) return true; // Check integrity if (m_TaxiDestinations.size() < 2) return false; for (size_t i = 1; i < m_TaxiDestinations.size(); ++i) { uint32 cost; uint32 path; sObjectMgr->GetTaxiPath(m_TaxiDestinations[i-1], m_TaxiDestinations[i], path, cost); if (!path) return false; } // can't load taxi path without mount set (quest taxi path?) if (!sObjectMgr->GetTaxiMountDisplayId(GetTaxiSource(), team, true)) return false; return true; } std::string PlayerTaxi::SaveTaxiDestinationsToString() { if (m_TaxiDestinations.empty()) return ""; std::ostringstream ss; for (size_t i=0; i < m_TaxiDestinations.size(); ++i) ss << m_TaxiDestinations[i] << ' '; return ss.str(); } uint32 PlayerTaxi::GetCurrentTaxiPath() const { if (m_TaxiDestinations.size() < 2) return 0; uint32 path; uint32 cost; sObjectMgr->GetTaxiPath(m_TaxiDestinations[0], m_TaxiDestinations[1], path, cost); return path; } std::ostringstream& operator<< (std::ostringstream& ss, PlayerTaxi const& taxi) { for (uint8 i = 0; i < TaxiMaskSize; ++i) ss << taxi.m_taximask[i] << ' '; return ss; } Player::Player(WorldSession* session): Unit(true) { m_speakTime = 0; m_speakCount = 0; m_objectType |= TYPEMASK_PLAYER; m_objectTypeId = TYPEID_PLAYER; m_valuesCount = PLAYER_END; m_session = session; m_ingametime = 0; m_ExtraFlags = 0; m_spellModTakingSpell = nullptr; //m_pad = 0; // players always accept if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) SetAcceptWhispers(true); m_comboPoints = 0; m_usedTalentCount = 0; m_questRewardTalentCount = 0; m_regenTimer = 0; m_regenTimerCount = 0; m_weaponChangeTimer = 0; m_zoneUpdateId = uint32(-1); m_zoneUpdateTimer = 0; m_areaUpdateId = 0; m_team = 0; m_needsZoneUpdate = false; m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE); memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT); m_social = nullptr; // group is initialized in the reference constructor SetGroupInvite(nullptr); m_groupUpdateMask = 0; m_auraRaidUpdateMask = 0; m_bPassOnGroupLoot = false; duel = nullptr; m_GuildIdInvited = 0; m_ArenaTeamIdInvited = 0; m_atLoginFlags = AT_LOGIN_NONE; mSemaphoreTeleport_Near = false; mSemaphoreTeleport_Far = false; m_DelayedOperations = 0; m_bCanDelayTeleport = false; m_bHasDelayedTeleport = false; m_teleport_options = 0; m_trade = nullptr; m_cinematic = 0; PlayerTalkClass = new PlayerMenu(GetSession()); m_currentBuybackSlot = BUYBACK_SLOT_START; m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; // Init rune flags for (uint8 i = 0; i < MAX_RUNES; ++i) { SetRuneTimer(i, 0xFFFFFFFF); SetLastRuneGraceTimer(i, 0); } for (uint8 i=0; i < MAX_TIMERS; i++) m_MirrorTimer[i] = DISABLED_MIRROR_TIMER; m_MirrorTimerFlags = UNDERWATER_NONE; m_MirrorTimerFlagsLast = UNDERWATER_NONE; m_isInWater = false; m_drunkTimer = 0; m_deathTimer = 0; m_deathExpireTime = 0; m_swingErrorMsg = 0; for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j) { m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; m_bgBattlegroundQueueID[j].invitedToInstance = 0; } m_logintime = time(nullptr); m_Last_tick = m_logintime; m_Played_time[PLAYED_TIME_TOTAL] = 0; m_Played_time[PLAYED_TIME_LEVEL] = 0; m_WeaponProficiency = 0; m_ArmorProficiency = 0; m_canParry = false; m_canBlock = false; m_canTitanGrip = false; m_ammoDPS = 0.0f; m_temporaryUnsummonedPetNumber = 0; //cache for UNIT_CREATED_BY_SPELL to allow //returning reagents for temporarily removed pets //when dying/logging out m_oldpetspell = 0; m_lastpetnumber = 0; ////////////////////Rest System///////////////////// _restTime = 0; inn_triggerId = 0; m_rest_bonus = 0; _restFlagMask = 0; ////////////////////Rest System///////////////////// m_mailsLoaded = false; m_mailsUpdated = false; unReadMails = 0; m_nextMailDelivereTime = 0; m_resetTalentsCost = 0; m_resetTalentsTime = 0; m_itemUpdateQueueBlocked = false; for (uint8 i = 0; i < MAX_MOVE_TYPE; ++i) m_forced_speed_changes[i] = 0; m_stableSlots = 0; /////////////////// Instance System ///////////////////// m_HomebindTimer = 0; m_InstanceValid = true; m_dungeonDifficulty = DUNGEON_DIFFICULTY_NORMAL; m_raidDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; m_raidMapDifficulty = RAID_DIFFICULTY_10MAN_NORMAL; m_lastPotionId = 0; m_activeSpec = 0; m_specsCount = 1; for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) { for (uint8 g = 0; g < MAX_GLYPH_SLOT_INDEX; ++g) m_Glyphs[i][g] = 0; m_talents[i] = new PlayerTalentMap(); } for (uint8 i = 0; i < BASEMOD_END; ++i) { m_auraBaseMod[i][FLAT_MOD] = 0.0f; m_auraBaseMod[i][PCT_MOD] = 1.0f; } for (uint8 i = 0; i < MAX_COMBAT_RATING; i++) m_baseRatingValue[i] = 0; m_baseSpellPower = 0; m_baseFeralAP = 0; m_baseManaRegen = 0; m_baseHealthRegen = 0; m_spellPenetrationItemMod = 0; // Honor System m_lastHonorUpdateTime = time(nullptr); m_IsBGRandomWinner = false; // Player summoning m_summon_expire = 0; m_mover = this; m_movedPlayer = this; m_seer = this; m_homebindMapId = 0; m_homebindAreaId = 0; m_homebindX = 0; m_homebindY = 0; m_homebindZ = 0; m_contestedPvPTimer = 0; m_declinedname = nullptr; m_isActive = true; m_runes = nullptr; m_lastFallTime = 0; m_lastFallZ = 0; m_grantableLevels = 0; m_ControlledByPlayer = true; sWorld->IncreasePlayerCount(); m_ChampioningFaction = 0; m_timeSyncCounter = 0; m_timeSyncTimer = 0; m_timeSyncClient = 0; m_timeSyncServer = 0; for (uint8 i = 0; i < MAX_POWERS; ++i) m_powerFraction[i] = 0; isDebugAreaTriggers = false; m_WeeklyQuestChanged = false; m_MonthlyQuestChanged = false; m_SeasonalQuestChanged = false; SetPendingBind(0, 0); _activeCheats = CHEAT_NONE; healthBeforeDuel = 0; manaBeforeDuel = 0; _cinematicMgr = new CinematicMgr(this); m_achievementMgr = new AchievementMgr(this); m_reputationMgr = new ReputationMgr(this); } Player::~Player() { // it must be unloaded already in PlayerLogout and accessed only for logged in player //m_social = NULL; // Note: buy back item already deleted from DB when player was saved for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i) delete m_items[i]; for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr) delete itr->second; for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i) { for (PlayerTalentMap::const_iterator itr = m_talents[i]->begin(); itr != m_talents[i]->end(); ++itr) delete itr->second; delete m_talents[i]; } //all mailed items should be deleted, also all mail should be deallocated for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr) delete *itr; for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated delete PlayerTalkClass; for (size_t x = 0; x < ItemSetEff.size(); x++) delete ItemSetEff[x]; delete m_declinedname; delete m_runes; delete m_achievementMgr; delete m_reputationMgr; delete _cinematicMgr; sWorld->DecreasePlayerCount(); } void Player::CleanupsBeforeDelete(bool finalCleanup) { TradeCancel(false); DuelComplete(DUEL_INTERRUPTED); Unit::CleanupsBeforeDelete(finalCleanup); // clean up player-instance binds, may unload some instance saves for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) for (BoundInstancesMap::iterator itr = m_boundInstances[i].begin(); itr != m_boundInstances[i].end(); ++itr) itr->second.save->RemovePlayer(this); } bool Player::Create(ObjectGuid::LowType guidlow, CharacterCreateInfo* createInfo) { //FIXME: outfitId not used in player creating /// @todo need more checks against packet modifications Object::_Create(guidlow, 0, HighGuid::Player); m_name = createInfo->Name; PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class); if (!info) { TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid race/class pair (%u/%u) - refusing to do so.", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Race, createInfo->Class); return false; } for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++) m_items[i] = nullptr; Relocate(info->positionX, info->positionY, info->positionZ, info->orientation); ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class); if (!cEntry) { TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid character class (%u) - refusing to do so (wrong DBC-files?)", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Class); return false; } SetMap(sMapMgr->CreateMap(info->mapId, this)); uint8 powertype = cEntry->powerType; SetObjectScale(1.0f); setFactionForRace(createInfo->Race); if (!IsValidGender(createInfo->Gender)) { TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with an invalid gender (%u) - refusing to do so", GetSession()->GetAccountId(), m_name.c_str(), createInfo->Gender); return false; } if (!ValidateAppearance(createInfo->Race, createInfo->Class, createInfo->Gender, createInfo->HairStyle, createInfo->HairColor, createInfo->Face, createInfo->FacialHair, createInfo->Skin, true)) { TC_LOG_ERROR("entities.player", "Player::Create: Possible hacking attempt: Account %u tried to create a character named '%s' with invalid appearance attributes - refusing to do so", GetSession()->GetAccountId(), m_name.c_str()); return false; } SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_RACE, createInfo->Race); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_CLASS, createInfo->Class); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_GENDER, createInfo->Gender); SetByteValue(UNIT_FIELD_BYTES_0, UNIT_BYTES_0_OFFSET_POWER_TYPE, powertype); InitDisplayIds(); if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP) { SetByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_PVP); SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PVP_ATTACKABLE); } SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_REGENERATE_POWER); SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f); // fix cast time showed in spell tooltip on client SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f); // default for players in 3.0.3 SetInt32Value(PLAYER_FIELD_WATCHED_FACTION_INDEX, uint32(-1)); // -1 is default value SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_SKIN_ID, createInfo->Skin); SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_FACE_ID, createInfo->Face); SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_STYLE_ID, createInfo->HairStyle); SetByteValue(PLAYER_BYTES, PLAYER_BYTES_OFFSET_HAIR_COLOR_ID, createInfo->HairColor); SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_FACIAL_STYLE, createInfo->FacialHair); SetByteValue(PLAYER_BYTES_2, PLAYER_BYTES_2_OFFSET_REST_STATE, (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NOT_RAF_LINKED); SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_GENDER, createInfo->Gender); SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_ARENA_FACTION, 0); SetUInt32Value(PLAYER_GUILDID, 0); SetUInt32Value(PLAYER_GUILDRANK, 0); SetUInt32Value(PLAYER_GUILD_TIMESTAMP, 0); for (int i = 0; i < KNOWN_TITLES_SIZE; ++i) SetUInt64Value(PLAYER__FIELD_KNOWN_TITLES + i, 0); // 0=disabled SetUInt32Value(PLAYER_CHOSEN_TITLE, 0); SetUInt32Value(PLAYER_FIELD_KILLS, 0); SetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS, 0); SetUInt32Value(PLAYER_FIELD_TODAY_CONTRIBUTION, 0); SetUInt32Value(PLAYER_FIELD_YESTERDAY_CONTRIBUTION, 0); // set starting level uint32 start_level = getClass() != CLASS_DEATH_KNIGHT ? sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL) : sWorld->getIntConfig(CONFIG_START_HEROIC_PLAYER_LEVEL); if (m_session->HasPermission(rbac::RBAC_PERM_USE_START_GM_LEVEL)) { uint32 gm_level = sWorld->getIntConfig(CONFIG_START_GM_LEVEL); if (gm_level > start_level) start_level = gm_level; } SetUInt32Value(UNIT_FIELD_LEVEL, start_level); InitRunes(); SetUInt32Value(PLAYER_FIELD_COINAGE, sWorld->getIntConfig(CONFIG_START_PLAYER_MONEY)); SetHonorPoints(sWorld->getIntConfig(CONFIG_START_HONOR_POINTS)); SetArenaPoints(sWorld->getIntConfig(CONFIG_START_ARENA_POINTS)); // start with every map explored if (sWorld->getBoolConfig(CONFIG_START_ALL_EXPLORED)) { for (uint8 i=0; i<PLAYER_EXPLORED_ZONES_SIZE; i++) SetFlag(PLAYER_EXPLORED_ZONES_1+i, 0xFFFFFFFF); } //Reputations if "StartAllReputation" is enabled, -- @todo Fix this in a better way if (sWorld->getBoolConfig(CONFIG_START_ALL_REP)) { GetReputationMgr().SetReputation(sFactionStore.LookupEntry(942), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(935), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(936), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1011), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(970), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(967), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(989), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(932), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(934), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1038), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(1077), 42999); // Factions depending on team, like cities and some more stuff switch (GetTeam()) { case ALLIANCE: GetReputationMgr().SetReputation(sFactionStore.LookupEntry(72), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(47), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(69), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(930), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(730), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(978), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(54), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(946), 42999); break; case HORDE: GetReputationMgr().SetReputation(sFactionStore.LookupEntry(76), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(68), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(81), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(911), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(729), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(941), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(530), 42999); GetReputationMgr().SetReputation(sFactionStore.LookupEntry(947), 42999); break; default: break; } } // Played time m_Last_tick = time(nullptr); m_Played_time[PLAYED_TIME_TOTAL] = 0; m_Played_time[PLAYED_TIME_LEVEL] = 0; // base stats and related field values InitStatsForLevel(); InitTaxiNodesForLevel(); InitGlyphsForLevel(); InitTalentForLevel(); InitPrimaryProfessions(); // to max set before any spell added // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods() UpdateMaxHealth(); // Update max Health (for add bonus from stamina) SetFullHealth(); if (getPowerType() == POWER_MANA) { UpdateMaxPower(POWER_MANA); // Update max Mana (for add bonus from intellect) SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); } if (getPowerType() == POWER_RUNIC_POWER) { SetPower(POWER_RUNE, 8); SetMaxPower(POWER_RUNE, 8); SetPower(POWER_RUNIC_POWER, 0); SetMaxPower(POWER_RUNIC_POWER, 1000); } // original spells LearnDefaultSkills(); LearnCustomSpells(); // original action bar for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr) addActionButton(action_itr->button, action_itr->action, action_itr->type); // original items if (CharStartOutfitEntry const* oEntry = GetCharStartOutfitEntry(createInfo->Race, createInfo->Class, createInfo->Gender)) { for (int j = 0; j < MAX_OUTFIT_ITEMS; ++j) { if (oEntry->ItemId[j] <= 0) continue; uint32 itemId = oEntry->ItemId[j]; // just skip, reported in ObjectMgr::LoadItemTemplates ItemTemplate const* iProto = sObjectMgr->GetItemTemplate(itemId); if (!iProto) continue; // BuyCount by default uint32 count = iProto->BuyCount; // special amount for food/drink if (iProto->Class == ITEM_CLASS_CONSUMABLE && iProto->SubClass == ITEM_SUBCLASS_FOOD) { switch (iProto->Spells[0].SpellCategory) { case SPELL_CATEGORY_FOOD: // food count = getClass() == CLASS_DEATH_KNIGHT ? 10 : 4; break; case SPELL_CATEGORY_DRINK: // drink count = 2; break; } if (iProto->GetMaxStackSize() < count) count = iProto->GetMaxStackSize(); } StoreNewItemInBestSlots(itemId, count); } } for (PlayerCreateInfoItems::const_iterator item_id_itr = info->item.begin(); item_id_itr != info->item.end(); ++item_id_itr) StoreNewItemInBestSlots(item_id_itr->item_id, item_id_itr->item_amount); // bags and main-hand weapon must equipped at this moment // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon) // or ammo not equipped in special bag for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++) { if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i)) { uint16 eDest; // equip offhand weapon/shield if it attempt equipped before main-hand weapon InventoryResult msg = CanEquipItem(NULL_SLOT, eDest, pItem, false); if (msg == EQUIP_ERR_OK) { RemoveItem(INVENTORY_SLOT_BAG_0, i, true); EquipItem(eDest, pItem, true); } // move other items to more appropriate slots (ammo not equipped in special bag) else { ItemPosCountVec sDest; msg = CanStoreItem(NULL_BAG, NULL_SLOT, sDest, pItem, false); if (msg == EQUIP_ERR_OK) { RemoveItem(INVENTORY_SLOT_BAG_0, i, true); StoreItem(sDest, pItem, true); } // if this is ammo then use it msg = CanUseAmmo(pItem->GetEntry()); if (msg == EQUIP_ERR_OK) SetAmmo(pItem->GetEntry()); } } } // all item positions resolved return true; } bool Player::StoreNewItemInBestSlots(uint32 titem_id, uint32 titem_amount) { TC_LOG_DEBUG("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) creates initial item (ItemID: %u, Count: %u)", GetName().c_str(), GetGUID().ToString().c_str(), titem_id, titem_amount); // attempt equip by one while (titem_amount > 0) { uint16 eDest; InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, titem_id, false); if (msg != EQUIP_ERR_OK) break; EquipNewItem(eDest, titem_id, true); AutoUnequipOffhandIfNeed(); --titem_amount; } if (titem_amount == 0) return true; // equipped // attempt store ItemPosCountVec sDest; // store in main bag to simplify second pass (special bags can be not equipped yet at this moment) InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, titem_id, titem_amount); if (msg == EQUIP_ERR_OK) { StoreNewItem(sDest, titem_id, true, Item::GenerateItemRandomPropertyId(titem_id)); return true; // stored } // item can't be added TC_LOG_ERROR("entities.player.items", "Player::StoreNewItemInBestSlots: Player '%s' (%s) can't equip or store initial item (ItemID: %u, Race: %u, Class: %u, InventoryResult: %u)", GetName().c_str(), GetGUID().ToString().c_str(), titem_id, getRace(), getClass(), msg); return false; } void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen) { if (int(MaxValue) == DISABLED_MIRROR_TIMER) { if (int(CurrentValue) != DISABLED_MIRROR_TIMER) StopMirrorTimer(Type); return; } WorldPacket data(SMSG_START_MIRROR_TIMER, (21)); data << (uint32)Type; data << CurrentValue; data << MaxValue; data << Regen; data << (uint8)0; data << (uint32)0; // spell id GetSession()->SendPacket(&data); } void Player::StopMirrorTimer(MirrorTimerType Type) { m_MirrorTimer[Type] = DISABLED_MIRROR_TIMER; WorldPacket data(SMSG_STOP_MIRROR_TIMER, 4); data << (uint32)Type; GetSession()->SendPacket(&data); } bool Player::IsImmuneToEnvironmentalDamage() const { // check for GM and death state included in isAttackableByAOE return !isTargetableForAttack(false); } uint32 Player::EnvironmentalDamage(EnviromentalDamage type, uint32 damage) { if (IsImmuneToEnvironmentalDamage()) return 0; // Absorb, resist some environmental damage type uint32 absorb = 0; uint32 resist = 0; if (type == DAMAGE_LAVA) CalcAbsorbResist(this, SPELL_SCHOOL_MASK_FIRE, DIRECT_DAMAGE, damage, &absorb, &resist); else if (type == DAMAGE_SLIME) CalcAbsorbResist(this, SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, damage, &absorb, &resist); damage -= absorb + resist; DealDamageMods(this, damage, &absorb); WorldPacket data(SMSG_ENVIRONMENTALDAMAGELOG, (21)); data << uint64(GetGUID()); data << uint8(type != DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL); data << uint32(damage); data << uint32(absorb); data << uint32(resist); SendMessageToSet(&data, true); uint32 final_damage = DealDamage(this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false); if (!IsAlive()) { if (type == DAMAGE_FALL) // DealDamage does not apply item durability loss from self-induced damage. { TC_LOG_DEBUG("entities.player", "Player::EnvironmentalDamage: Player '%s' (%s) fall to death, losing 10%% durability", GetName().c_str(), GetGUID().ToString().c_str()); DurabilityLossAll(0.10f, false); // durability lost message WorldPacket data2(SMSG_DURABILITY_DAMAGE_DEATH, 0); GetSession()->SendPacket(&data2); } UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM, 1, type); } return final_damage; } int32 Player::getMaxTimer(MirrorTimerType timer) const { switch (timer) { if(ConfigMgr::GetBoolDefault("fatigue.enabled", true)) // If "fatigue.enabled" is enabled { case FATIGUE_TIMER: return MINUTE * IN_MILLISECONDS; } case BREATH_TIMER: { if (!IsAlive() || HasAuraType(SPELL_AURA_WATER_BREATHING) || GetSession()->GetSecurity() >= AccountTypes(sWorld->getIntConfig(CONFIG_DISABLE_BREATHING))) return DISABLED_MIRROR_TIMER; int32 UnderWaterTime = 3 * MINUTE * IN_MILLISECONDS; AuraEffectList const& mModWaterBreathing = GetAuraEffectsByType(SPELL_AURA_MOD_WATER_BREATHING); for (AuraEffectList::const_iterator i = mModWaterBreathing.begin(); i != mModWaterBreathing.end(); ++i) AddPct(UnderWaterTime, (*i)->GetAmount()); return UnderWaterTime; } case FIRE_TIMER: { if (!IsAlive()) return DISABLED_MIRROR_TIMER; return 1 * IN_MILLISECONDS; } default: return 0; } } void Player::UpdateMirrorTimers() { // Desync flags for update on next HandleDrowning if (m_MirrorTimerFlags) m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags; } void Player::StopMirrorTimers() { StopMirrorTimer(FATIGUE_TIMER); StopMirrorTimer(BREATH_TIMER); StopMirrorTimer(FIRE_TIMER); } bool Player::IsMirrorTimerActive(MirrorTimerType type) const { return m_MirrorTimer[type] == getMaxTimer(type); } void Player::HandleDrowning(uint32 time_diff) { if (!m_MirrorTimerFlags) return; // In water if (m_MirrorTimerFlags & UNDERWATER_INWATER) { // Breath timer not activated - activate it if (m_MirrorTimer[BREATH_TIMER] == DISABLED_MIRROR_TIMER) { m_MirrorTimer[BREATH_TIMER] = getMaxTimer(BREATH_TIMER); SendMirrorTimer(BREATH_TIMER, m_MirrorTimer[BREATH_TIMER], m_MirrorTimer[BREATH_TIMER], -1); } else // If activated - do tick { m_MirrorTimer[BREATH_TIMER]-=time_diff; // Timer limit - need deal damage if (m_MirrorTimer[BREATH_TIMER] < 0) { m_MirrorTimer[BREATH_TIMER]+= 1*IN_MILLISECONDS; // Calculate and deal damage /// @todo Check this formula uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); EnvironmentalDamage(DAMAGE_DROWNING, damage); } else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need SendMirrorTimer(BREATH_TIMER, getMaxTimer(BREATH_TIMER), m_MirrorTimer[BREATH_TIMER], -1); } } else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer { int32 UnderWaterTime = getMaxTimer(BREATH_TIMER); // Need breath regen m_MirrorTimer[BREATH_TIMER]+=10*time_diff; if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !IsAlive()) StopMirrorTimer(BREATH_TIMER); else if (m_MirrorTimerFlagsLast & UNDERWATER_INWATER) SendMirrorTimer(BREATH_TIMER, UnderWaterTime, m_MirrorTimer[BREATH_TIMER], 10); } // In dark water if(ConfigMgr::GetBoolDefault("fatigue.enabled", true)) // If "fatigue.enabled" is enabled { if (m_MirrorTimerFlags & UNDERWARER_INDARKWATER) { // Fatigue timer not activated - activate it if (m_MirrorTimer[FATIGUE_TIMER] == DISABLED_MIRROR_TIMER) { m_MirrorTimer[FATIGUE_TIMER] = getMaxTimer(FATIGUE_TIMER); SendMirrorTimer(FATIGUE_TIMER, m_MirrorTimer[FATIGUE_TIMER], m_MirrorTimer[FATIGUE_TIMER], -1); } else { m_MirrorTimer[FATIGUE_TIMER]-=time_diff; // Timer limit - need deal damage or teleport ghost to graveyard if (m_MirrorTimer[FATIGUE_TIMER] < 0) { m_MirrorTimer[FATIGUE_TIMER]+= 1*IN_MILLISECONDS; if (IsAlive()) // Calculate and deal damage { uint32 damage = GetMaxHealth() / 5 + urand(0, getLevel()-1); EnvironmentalDamage(DAMAGE_EXHAUSTED, damage); } else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard RepopAtGraveyard(); } else if (!(m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER)) SendMirrorTimer(FATIGUE_TIMER, getMaxTimer(FATIGUE_TIMER), m_MirrorTimer[FATIGUE_TIMER], -1); } } else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer { int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER); m_MirrorTimer[FATIGUE_TIMER]+=10*time_diff; if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !IsAlive()) StopMirrorTimer(FATIGUE_TIMER); else if (m_MirrorTimerFlagsLast & UNDERWARER_INDARKWATER) SendMirrorTimer(FATIGUE_TIMER, DarkWaterTime, m_MirrorTimer[FATIGUE_TIMER], 10); } } if (m_MirrorTimerFlags & (UNDERWATER_INLAVA /*| UNDERWATER_INSLIME*/) && !(_lastLiquid && _lastLiquid->SpellId)) { // Breath timer not activated - activate it if (m_MirrorTimer[FIRE_TIMER] == DISABLED_MIRROR_TIMER) m_MirrorTimer[FIRE_TIMER] = getMaxTimer(FIRE_TIMER); else { m_MirrorTimer[FIRE_TIMER] -= time_diff; if (m_MirrorTimer[FIRE_TIMER] < 0) { m_MirrorTimer[FIRE_TIMER]+= 1*IN_MILLISECONDS; // Calculate and deal damage /// @todo Check this formula uint32 damage = urand(600, 700); if (m_MirrorTimerFlags & UNDERWATER_INLAVA) EnvironmentalDamage(DAMAGE_LAVA, damage); // need to skip Slime damage in Undercity, // maybe someone can find better way to handle environmental damage //else if (m_zoneUpdateId != 1497) // EnvironmentalDamage(DAMAGE_SLIME, damage); } } } else m_MirrorTimer[FIRE_TIMER] = DISABLED_MIRROR_TIMER; // Recheck timers flag m_MirrorTimerFlags&=~UNDERWATER_EXIST_TIMERS; for (uint8 i = 0; i< MAX_TIMERS; ++i) if (m_MirrorTimer[i] != DISABLED_MIRROR_TIMER) { m_MirrorTimerFlags|=UNDERWATER_EXIST_TIMERS; break; } m_MirrorTimerFlagsLast = m_MirrorTimerFlags; } ///The player sobers by 1% every 9 seconds void Player::HandleSobering() { m_drunkTimer = 0; uint8 currentDrunkValue = GetDrunkValue(); uint8 drunk = currentDrunkValue ? --currentDrunkValue : 0; SetDrunkValue(drunk); } DrunkenState Player::GetDrunkenstateByValue(uint8 value) { if (value >= 90) return DRUNKEN_SMASHED; if (value >= 50) return DRUNKEN_DRUNK; if (value) return DRUNKEN_TIPSY; return DRUNKEN_SOBER; } void Player::SetDrunkValue(uint8 newDrunkValue, uint32 itemId /*= 0*/) { bool isSobering = newDrunkValue < GetDrunkValue(); uint32 oldDrunkenState = Player::GetDrunkenstateByValue(GetDrunkValue()); if (newDrunkValue > 100) newDrunkValue = 100; // select drunk percent or total SPELL_AURA_MOD_FAKE_INEBRIATE amount, whichever is higher for visibility updates int32 drunkPercent = std::max<int32>(newDrunkValue, GetTotalAuraModifier(SPELL_AURA_MOD_FAKE_INEBRIATE)); if (drunkPercent) { m_invisibilityDetect.AddFlag(INVISIBILITY_DRUNK); m_invisibilityDetect.SetValue(INVISIBILITY_DRUNK, drunkPercent); } else if (!HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE) && !newDrunkValue) m_invisibilityDetect.DelFlag(INVISIBILITY_DRUNK); uint32 newDrunkenState = Player::GetDrunkenstateByValue(newDrunkValue); SetByteValue(PLAYER_BYTES_3, PLAYER_BYTES_3_OFFSET_INEBRIATION, newDrunkValue); UpdateObjectVisibility(); if (!isSobering) m_drunkTimer = 0; // reset sobering timer if (newDrunkenState == oldDrunkenState) return; WorldPacket data(SMSG_CROSSED_INEBRIATION_THRESHOLD, (8+4+4)); data << uint64(GetGUID()); data << uint32(newDrunkenState); data << uint32(itemId); SendMessageToSet(&data, true); } void Player::Update(uint32 p_time) { if (!IsInWorld()) return; // undelivered mail if (m_nextMailDelivereTime && m_nextMailDelivereTime <= time(nullptr)) { SendNewMail(); ++unReadMails; // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated) m_nextMailDelivereTime = 0; } // If this is set during update SetSpellModTakingSpell call is missing somewhere in the code // Having this would prevent more aura charges to be dropped, so let's crash //ASSERT (!m_spellModTakingSpell); if (m_spellModTakingSpell) { //TC_LOG_FATAL("entities.player", "Player has m_pad %u during update!", m_pad); //if (m_spellModTakingSpell) TC_LOG_FATAL("spells", "Player::Update: Player '%s' (%s) has m_spellModTakingSpell (SpellID: %u) during update!", GetName().c_str(), GetGUID().ToString().c_str(), m_spellModTakingSpell->m_spellInfo->Id); m_spellModTakingSpell = nullptr; } // Update cinematic location, if 500ms have passed and we're doing a cinematic now. _cinematicMgr->m_cinematicDiff += p_time; if (_cinematicMgr->m_cinematicCamera && _cinematicMgr->m_activeCinematicCameraId && GetMSTimeDiffToNow(_cinematicMgr->m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF) { _cinematicMgr->m_lastCinematicCheck = getMSTime(); _cinematicMgr->UpdateCinematicLocation(p_time); } //used to implement delayed far teleports SetCanDelayTeleport(true); Unit::Update(p_time); SetCanDelayTeleport(false); time_t now = time(nullptr); UpdatePvPFlag(now); UpdateContestedPvP(p_time); UpdateDuelFlag(now); CheckDuelDistance(now); UpdateAfkReport(now); if (IsAIEnabled && GetAI()) GetAI()->UpdateAI(p_time); else if (NeedChangeAI) { UpdateCharmAI(); NeedChangeAI = false; IsAIEnabled = (GetAI() != nullptr); } // Update items that have just a limited lifetime if (now > m_Last_tick) UpdateItemDuration(uint32(now - m_Last_tick)); // check every second if (now > m_Last_tick + 1) UpdateSoulboundTradeItems(); // If mute expired, remove it from the DB if (GetSession()->m_muteTime && GetSession()->m_muteTime < now) { GetSession()->m_muteTime = 0; PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_MUTE_TIME); stmt->setInt64(0, 0); // Set the mute time to 0 stmt->setString(1, ""); stmt->setString(2, ""); stmt->setUInt32(3, GetSession()->GetAccountId()); LoginDatabase.Execute(stmt); } if (!m_timedquests.empty()) { QuestSet::iterator iter = m_timedquests.begin(); while (iter != m_timedquests.end()) { QuestStatusData& q_status = m_QuestStatus[*iter]; if (q_status.Timer <= p_time) { uint32 quest_id = *iter; ++iter; // current iter will be removed in FailQuest FailQuest(quest_id); } else { q_status.Timer -= p_time; m_QuestStatusSave[*iter] = QUEST_DEFAULT_SAVE_TYPE; ++iter; } } } m_achievementMgr->UpdateTimedAchievements(p_time); if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING)) { if (Unit* victim = GetVictim()) { // default combat reach 10 /// @todo add weapon, skill check if (isAttackReady(BASE_ATTACK)) { if (!IsWithinMeleeRange(victim)) { setAttackTimer(BASE_ATTACK, 100); if (m_swingErrorMsg != 1) // send single time (client auto repeat) { SendAttackSwingNotInRange(); m_swingErrorMsg = 1; } } //120 degrees of radiant range else if (!HasInArc(2 * float(M_PI) / 3, victim)) { setAttackTimer(BASE_ATTACK, 100); if (m_swingErrorMsg != 2) // send single time (client auto repeat) { SendAttackSwingBadFacingAttack(); m_swingErrorMsg = 2; } } else { m_swingErrorMsg = 0; // reset swing error state // prevent base and off attack in same time, delay attack at 0.2 sec if (haveOffhandWeapon()) if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); // do attack AttackerStateUpdate(victim, BASE_ATTACK); resetAttackTimer(BASE_ATTACK); } } if (haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) { if (!IsWithinMeleeRange(victim)) setAttackTimer(OFF_ATTACK, 100); else if (!HasInArc(2 * float(M_PI) / 3, victim)) setAttackTimer(OFF_ATTACK, 100); else { // prevent base and off attack in same time, delay attack at 0.2 sec if (getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY) setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); // do attack AttackerStateUpdate(victim, OFF_ATTACK); resetAttackTimer(OFF_ATTACK); } } /*Unit* owner = victim->GetOwner(); Unit* u = owner ? owner : victim; if (u->IsPvP() && (!duel || duel->opponent != u)) { UpdatePvP(true); RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_ENTER_PVP_COMBAT); }*/ } } if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING)) { if (roll_chance_i(3) && _restTime > 0) // freeze update { time_t currTime = time(nullptr); time_t timeDiff = currTime - _restTime; if (timeDiff >= 10) // freeze update { _restTime = currTime; float bubble = 0.125f * sWorld->getRate(RATE_REST_INGAME); float extraPerSec = ((float)GetUInt32Value(PLAYER_NEXT_LEVEL_XP) / 72000.0f) * bubble; // speed collect rest bonus (section/in hour) float currRestBonus = GetRestBonus(); SetRestBonus(currRestBonus + timeDiff * extraPerSec); } } } if (m_weaponChangeTimer > 0) { if (p_time >= m_weaponChangeTimer) m_weaponChangeTimer = 0; else m_weaponChangeTimer -= p_time; } if (m_zoneUpdateTimer > 0) { if (p_time >= m_zoneUpdateTimer) { // On zone update tick check if we are still in an inn if we are supposed to be in one if (HasRestFlag(REST_FLAG_IN_TAVERN)) { AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(GetInnTriggerId()); if (!atEntry || !IsInAreaTriggerRadius(atEntry)) RemoveRestFlag(REST_FLAG_IN_TAVERN); } uint32 newzone, newarea; GetZoneAndAreaId(newzone, newarea); if (m_zoneUpdateId != newzone) UpdateZone(newzone, newarea); // also update area else { // use area updates as well // needed for free far all arenas for example if (m_areaUpdateId != newarea) UpdateArea(newarea); m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; } } else m_zoneUpdateTimer -= p_time; } if (m_timeSyncTimer > 0) { if (p_time >= m_timeSyncTimer) SendTimeSync(); else m_timeSyncTimer -= p_time; } if (IsAlive()) { m_regenTimer += p_time; RegenerateAll(); } if (m_deathState == JUST_DIED) KillPlayer(); if (m_nextSave > 0) { if (p_time >= m_nextSave) { // m_nextSave reset in SaveToDB call SaveToDB(); TC_LOG_DEBUG("entities.player", "Player::Update: Player '%s' (%s) saved", GetName().c_str(), GetGUID().ToString().c_str()); } else m_nextSave -= p_time; } //Handle Water/drowning HandleDrowning(p_time); // Played time if (now > m_Last_tick) { uint32 elapsed = uint32(now - m_Last_tick); m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time m_Last_tick = now; } if (GetDrunkValue()) { m_drunkTimer += p_time; if (m_drunkTimer > 9 * IN_MILLISECONDS) HandleSobering(); } if (HasPendingBind()) { if (_pendingBindTimer <= p_time) { // Player left the instance if (_pendingBindId == GetInstanceId()) BindToInstance(); SetPendingBind(0, 0); } else _pendingBindTimer -= p_time; } // not auto-free ghost from body in instances or if its affected by risen ally if (m_deathTimer > 0 && !GetBaseMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION) && !IsGhouled()) { if (p_time >= m_deathTimer) { m_deathTimer = 0; BuildPlayerRepop(); RepopAtGraveyard(); } else m_deathTimer -= p_time; } UpdateEnchantTime(p_time); UpdateHomebindTime(p_time); if (!_instanceResetTimes.empty()) { for (InstanceTimeMap::iterator itr = _instanceResetTimes.begin(); itr != _instanceResetTimes.end();) { if (itr->second < now) _instanceResetTimes.erase(itr++); else ++itr; } } if (getClass() == CLASS_DEATH_KNIGHT) { // Update rune timers for (uint8 i = 0; i < MAX_RUNES; ++i) { uint32 timer = GetRuneTimer(i); // Don't update timer if rune is disabled if (GetRuneCooldown(i)) continue; // Timer has began if (timer < 0xFFFFFFFF) { timer += p_time; SetRuneTimer(i, std::min(uint32(2500), timer)); } } } // group update SendUpdateToOutOfRangeGroupMembers(); Pet* pet = GetPet(); if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed()) //if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID()))) RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true); //we should execute delayed teleports only for alive(!) players //because we don't want player's ghost teleported from graveyard if (IsHasDelayedTeleport() && IsAlive()) TeleportTo(m_teleport_dest, m_teleport_options); } void Player::setDeathState(DeathState s) { uint32 ressSpellId = 0; bool cur = IsAlive(); if (s == JUST_DIED) { if (!cur) { TC_LOG_ERROR("entities.player", "Player::setDeathState: Attempt to kill a dead player '%s' (%s)", GetName().c_str(), GetGUID().ToString().c_str()); return; } // drunken state is cleared on death SetDrunkValue(0); // lost combo points at any target (targeted combo points clear in Unit::setDeathState) ClearComboPoints(); ClearResurrectRequestData(); //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequestOpcode and define pet unsummon here with (s == DEAD) RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true); // save value before aura remove in Unit::setDeathState ressSpellId = GetUInt32Value(PLAYER_SELF_RES_SPELL); // passive spell if (!ressSpellId) ressSpellId = GetResurrectionSpellId(); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP, 1); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH, 1); UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON, 1); ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, ACHIEVEMENT_CRITERIA_CONDITION_NO_DEATH); } Unit::setDeathState(s); // restore resurrection spell id for player after aura remove if (s == JUST_DIED && cur && ressSpellId) SetUInt32Value(PLAYER_SELF_RES_SPELL, ressSpellId); if (IsAlive() && !cur) //clear aura case after resurrection by another way (spells will be applied before next death) SetUInt32Value(PLAYER_SELF_RES_SPELL, 0); } bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) { // 0 1 2 3 4 5 6 7 // SELECT characters.guid, characters.name, characters.race, characters.class, characters.gender, characters.skin, characters.face, characters.hairStyle, // 8 9 10 11 12 13 14 15 // characters.hairColor, characters.facialStyle, characters.level, characters.zone, characters.map, characters.position_x, characters.position_y, characters.position_z, // 16 17 18 19 20 21 22 // guild_member.guildid, characters.playerFlags, characters.at_login, character_pet.entry, character_pet.modelid, character_pet.level, characters.equipmentCache, // 23 24 // character_banned.guid, character_declinedname.genitive Field* fields = result->Fetch(); ObjectGuid::LowType guid = fields[0].GetUInt32(); uint8 plrRace = fields[2].GetUInt8(); uint8 plrClass = fields[3].GetUInt8(); uint8 gender = fields[4].GetUInt8(); PlayerInfo const* info = sObjectMgr->GetPlayerInfo(plrRace, plrClass); if (!info) { TC_LOG_ERROR("entities.player.loading", "Player %u has incorrect race/class pair. Don't build enum.", guid); return false; } else if (!IsValidGender(gender)) { TC_LOG_ERROR("entities.player.loading", "Player (%u) has incorrect gender (%u), don't build enum.", guid, gender); return false; } *data << ObjectGuid(HighGuid::Player, guid); *data << fields[1].GetString(); // name *data << uint8(plrRace); // race *data << uint8(plrClass); // class *data << uint8(gender); // gender uint8 skin = fields[5].GetUInt8(); uint8 face = fields[6].GetUInt8(); uint8 hairStyle = fields[7].GetUInt8(); uint8 hairColor = fields[8].GetUInt8(); uint8 facialStyle = fields[9].GetUInt8(); uint16 atLoginFlags = fields[18].GetUInt16(); if (!ValidateAppearance(uint8(plrRace), uint8(plrClass), gender, hairStyle, hairColor, face, facialStyle, skin)) { TC_LOG_ERROR("entities.player.loading", "Player %u has wrong Appearance values (Hair/Skin/Color), forcing recustomize", guid); if (!(atLoginFlags & AT_LOGIN_CUSTOMIZE)) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG); stmt->setUInt16(0, uint16(AT_LOGIN_CUSTOMIZE)); stmt->setUInt32(1, guid); CharacterDatabase.Execute(stmt); atLoginFlags |= AT_LOGIN_CUSTOMIZE; } } *data << uint8(skin); *data << uint8(face); *data << uint8(hairStyle); *data << uint8(hairColor); *data << uint8(facialStyle); *data << uint8(fields[10].GetUInt8()); // level *data << uint32(fields[11].GetUInt16()); // zone *data << uint32(fields[12].GetUInt16()); // map *data << fields[13].GetFloat(); // x *data << fields[14].GetFloat(); // y *data << fields[15].GetFloat(); // z *data << uint32(fields[16].GetUInt32()); // guild id uint32 charFlags = 0; uint32 playerFlags = fields[17].GetUInt32(); if (atLoginFlags & AT_LOGIN_RESURRECT) playerFlags &= ~PLAYER_FLAGS_GHOST; if (playerFlags & PLAYER_FLAGS_HIDE_HELM) charFlags |= CHARACTER_FLAG_HIDE_HELM; if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK) charFlags |= CHARACTER_FLAG_HIDE_CLOAK; if (playerFlags & PLAYER_FLAGS_GHOST) charFlags |= CHARACTER_FLAG_GHOST; if (atLoginFlags & AT_LOGIN_RENAME) charFlags |= CHARACTER_FLAG_RENAME; if (fields[23].GetUInt32()) charFlags |= CHARACTER_FLAG_LOCKED_BY_BILLING; if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED)) { if (!fields[24].GetString().empty()) charFlags |= CHARACTER_FLAG_DECLINED; } else charFlags |= CHARACTER_FLAG_DECLINED; *data << uint32(charFlags); // character flags // character customize flags if (atLoginFlags & AT_LOGIN_CUSTOMIZE) *data << uint32(CHAR_CUSTOMIZE_FLAG_CUSTOMIZE); else if (atLoginFlags & AT_LOGIN_CHANGE_FACTION) *data << uint32(CHAR_CUSTOMIZE_FLAG_FACTION); else if (atLoginFlags & AT_LOGIN_CHANGE_RACE) *data << uint32(CHAR_CUSTOMIZE_FLAG_RACE); else *data << uint32(CHAR_CUSTOMIZE_FLAG_NONE); // First login *data << uint8(atLoginFlags & AT_LOGIN_FIRST ? 1 : 0); // Pets info uint32 petDisplayId = 0; uint32 petLevel = 0; CreatureFamily petFamily = CREATURE_FAMILY_NONE; // show pet at selection character in character list only for non-ghost character if (result && !(playerFlags & PLAYER_FLAGS_GHOST) && (plrClass == CLASS_WARLOCK || plrClass == CLASS_HUNTER || plrClass == CLASS_DEATH_KNIGHT)) { uint32 entry = fields[19].GetUInt32(); CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(entry); if (creatureInfo) { petDisplayId = fields[20].GetUInt32(); petLevel = fields[21].GetUInt16(); petFamily = creatureInfo->family; } } *data << uint32(petDisplayId); *data << uint32(petLevel); *data << uint32(petFamily); Tokenizer equipment(fields[22].GetString(), ' '); for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) { uint32 visualBase = slot * 2; uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase); ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); if (!proto) { *data << uint32(0); *data << uint8(0); *data << uint32(0); continue; } SpellItemEnchantmentEntry const* enchant = NULL; uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1); for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) { // values stored in 2 uint16 uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot * 16); if (!enchantId) continue; enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId); if (enchant) break; } *data << uint32(proto->DisplayInfoID); *data << uint8(proto->InventoryType); *data << uint32(enchant ? enchant->aura_id : 0); } return true; } void Player::ToggleAFK() { ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); // afk player not allowed in battleground if (isAFK() && InBattleground() && !InArena()) LeaveBattleground(); } void Player::ToggleDND() { ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_DND); } uint8 Player::GetChatTag() const { uint8 tag = CHAT_TAG_NONE; if (isGMChat()) tag |= CHAT_TAG_GM; if (isDND()) tag |= CHAT_TAG_DND; if (isAFK()) tag |= CHAT_TAG_AFK; if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_DEVELOPER)) tag |= CHAT_TAG_DEV; return tag; } void Player::SendTeleportAckPacket() { WorldPacket data(MSG_MOVE_TELEPORT_ACK, 41); data << GetPackGUID(); data << uint32(0); // this value increments every time BuildMovementPacket(&data); GetSession()->SendPacket(&data); } bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options) { if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation)) { TC_LOG_ERROR("maps", "Player::TeleportTo: Invalid map (%d) or invalid coordinates (X: %f, Y: %f, Z: %f, O: %f) given when teleporting player '%s' (%s, MapID: %d, X: %f, Y: %f, Z: %f, O: %f).", mapid, x, y, z, orientation, GetGUID().ToString().c_str(), GetName().c_str(), GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation()); return false; } if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_DISABLE_MAP) && DisableMgr::IsDisabledFor(DISABLE_TYPE_MAP, mapid, this)) { TC_LOG_ERROR("maps", "Player::TeleportTo: Player '%s' (%s) tried to enter a forbidden map (MapID: %u)", GetGUID().ToString().c_str(), GetName().c_str(), mapid); SendTransferAborted(mapid, TRANSFER_ABORT_MAP_NOT_ALLOWED); return false; } // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later) Pet* pet = GetPet(); MapEntry const* mEntry = sMapStore.LookupEntry(mapid); // don't let enter battlegrounds without assigned battleground id (for example through areatrigger)... // don't let gm level > 1 either if (!InBattleground() && mEntry->IsBattlegroundOrArena()) return false; // client without expansion support if (GetSession()->Expansion() < mEntry->Expansion()) { TC_LOG_DEBUG("maps", "Player '%s' (%s) using client without required expansion tried teleport to non accessible map (MapID: %u)", GetName().c_str(), GetGUID().ToString().c_str(), mapid); if (Transport* transport = GetTransport()) { transport->RemovePassenger(this); RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } SendTransferAborted(mapid, TRANSFER_ABORT_INSUF_EXPAN_LVL, mEntry->Expansion()); return false; // normal client can't teleport to this map... } else TC_LOG_DEBUG("maps", "Player %s (%s) is being teleported to map (MapID: %u)", GetName().c_str(), GetGUID().ToString().c_str(), mapid); if (m_vehicle) ExitVehicle(); // reset movement flags at teleport, because player will continue move with these flags after teleport SetUnitMovementFlags(GetUnitMovementFlags() & MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE); DisableSpline(); if (Transport* transport = GetTransport()) { if (options & TELE_TO_NOT_LEAVE_TRANSPORT) AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT); else transport->RemovePassenger(this); } // The player was ported to another map and loses the duel immediately. // We have to perform this check before the teleport, otherwise the // ObjectAccessor won't find the flag. if (duel && GetMapId() != mapid && GetMap()->GetGameObject(GetGuidValue(PLAYER_DUEL_ARBITER))) DuelComplete(DUEL_FLED); if (GetMapId() == mapid) { //lets reset far teleport flag if it wasn't reset during chained teleport SetSemaphoreTeleportFar(false); //setup delayed teleport flag SetDelayedTeleportFlag(IsCanDelayTeleport()); //if teleport spell is cast in Unit::Update() func //then we need to delay it until update process will be finished if (IsHasDelayedTeleport()) { SetSemaphoreTeleportNear(true); //lets save teleport destination for player m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); m_teleport_options = options; return true; } if (!(options & TELE_TO_NOT_UNSUMMON_PET)) { //same map, only remove pet if out of range for new position if (pet && !pet->IsWithinDist3d(x, y, z, GetMap()->GetVisibilityRange())) UnsummonPetTemporaryIfAny(); } if (!(options & TELE_TO_NOT_LEAVE_COMBAT)) CombatStop(); // this will be used instead of the current location in SaveToDB m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); SetFallInformation(0, z); // code for finish transfer called in WorldSession::HandleMovementOpcodes() // at client packet MSG_MOVE_TELEPORT_ACK SetSemaphoreTeleportNear(true); // near teleport, triggering send MSG_MOVE_TELEPORT_ACK from client at landing if (!GetSession()->PlayerLogout()) { Position oldPos = GetPosition(); if (HasUnitMovementFlag(MOVEMENTFLAG_HOVER)) z += GetFloatValue(UNIT_FIELD_HOVERHEIGHT); Relocate(x, y, z, orientation); SendTeleportAckPacket(); SendTeleportPacket(oldPos); // this automatically relocates to oldPos in order to broadcast the packet in the right place } } else { if (getClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977)) return false; // far teleport to another map Map* oldmap = IsInWorld() ? GetMap() : NULL; // check if we can enter before stopping combat / removing pet / totems / interrupting spells // Check enter rights before map getting to avoid creating instance copy for player // this check not dependent from map instance copy and same for all instance copies of selected map if (sMapMgr->PlayerCannotEnter(mapid, this, false)) return false; //I think this always returns true. Correct me if I am wrong. // If the map is not created, assume it is possible to enter it. // It will be created in the WorldPortAck. //Map* map = sMapMgr->FindBaseNonInstanceMap(mapid); //if (!map || map->CanEnter(this)) { //lets reset near teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportNear(false); //setup delayed teleport flag SetDelayedTeleportFlag(IsCanDelayTeleport()); //if teleport spell is cast in Unit::Update() func //then we need to delay it until update process will be finished if (IsHasDelayedTeleport()) { SetSemaphoreTeleportFar(true); //lets save teleport destination for player m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); m_teleport_options = options; return true; } SetSelection(ObjectGuid::Empty); CombatStop(); ResetContestedPvP(); // remove player from battleground on far teleport (when changing maps) if (Battleground const* bg = GetBattleground()) { // Note: at battleground join battleground id set before teleport // and we already will found "current" battleground // just need check that this is targeted map or leave if (bg->GetMapId() != mapid) LeaveBattleground(false); // don't teleport to entry point } // remove arena spell coldowns/buffs now to also remove pet's cooldowns before it's temporarily unsummoned if (mEntry->IsBattleArena()) { RemoveArenaSpellCooldowns(true); RemoveArenaAuras(); if (pet) pet->RemoveArenaAuras(); } // remove pet on map change if (pet) UnsummonPetTemporaryIfAny(); // remove all dyn objects RemoveAllDynObjects(); // stop spellcasting // not attempt interrupt teleportation spell at caster teleport if (!(options & TELE_TO_SPELL)) if (IsNonMeleeSpellCast(true)) InterruptNonMeleeSpells(true); //remove auras before removing from map... RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP | AURA_INTERRUPT_FLAG_MOVE | AURA_INTERRUPT_FLAG_TURNING); if (!GetSession()->PlayerLogout()) { // send transfer packets WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); data << uint32(mapid); if (Transport* transport = GetTransport()) data << transport->GetEntry() << GetMapId(); GetSession()->SendPacket(&data); } // remove from old map now if (oldmap) oldmap->RemovePlayerFromMap(this, false); m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); SetFallInformation(0, z); // if the player is saved before worldportack (at logout for example) // this will be used instead of the current location in SaveToDB if (!GetSession()->PlayerLogout()) { WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4); data << uint32(mapid); if (GetTransport()) data << m_movementInfo.transport.pos.PositionXYZOStream(); else data << m_teleport_dest.PositionXYZOStream(); GetSession()->SendPacket(&data); SendSavedInstances(); } // move packet sent by client always after far teleport // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet SetSemaphoreTeleportFar(true); } //else // return false; } return true; } bool Player::TeleportTo(WorldLocation const &loc, uint32 options /*= 0*/) { return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options); } bool Player::TeleportToBGEntryPoint() { if (m_bgData.joinPos.m_mapId == MAPID_INVALID) return false; ScheduleDelayedOperation(DELAYED_BG_MOUNT_RESTORE); ScheduleDelayedOperation(DELAYED_BG_TAXI_RESTORE); ScheduleDelayedOperation(DELAYED_BG_GROUP_RESTORE); return TeleportTo(m_bgData.joinPos); } void Player::ProcessDelayedOperations() { if (m_DelayedOperations == 0) return; if (m_DelayedOperations & DELAYED_RESURRECT_PLAYER) ResurrectUsingRequestDataImpl(); if (m_DelayedOperations & DELAYED_SAVE_PLAYER) SaveToDB(); if (m_DelayedOperations & DELAYED_SPELL_CAST_DESERTER) CastSpell(this, 26013, true); // Deserter if (m_DelayedOperations & DELAYED_BG_MOUNT_RESTORE) { if (m_bgData.mountSpell) { CastSpell(this, m_bgData.mountSpell, true); m_bgData.mountSpell = 0; } } if (m_DelayedOperations & DELAYED_BG_TAXI_RESTORE) { if (m_bgData.HasTaxiPath()) { m_taxi.AddTaxiDestination(m_bgData.taxiPath[0]); m_taxi.AddTaxiDestination(m_bgData.taxiPath[1]); m_bgData.ClearTaxiPath(); ContinueTaxiFlight(); } } if (m_DelayedOperations & DELAYED_BG_GROUP_RESTORE) { if (Group* g = GetGroup()) g->SendUpdateToPlayer(GetGUID()); } //we have executed ALL delayed ops, so clear the flag m_DelayedOperations = 0; } void Player::AddToWorld() { ///- Do not add/remove the player from the object storage ///- It will crash when updating the ObjectAccessor ///- The player should only be added when logging in Unit::AddToWorld(); for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) if (m_items[i]) m_items[i]->AddToWorld(); } void Player::RemoveFromWorld() { // cleanup if (IsInWorld()) { ///- Release charmed creatures, unsummon totems and remove pets/guardians StopCastingCharm(); StopCastingBindSight(); UnsummonPetTemporaryIfAny(); sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); } // Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i) { if (m_items[i]) m_items[i]->RemoveFromWorld(); } ///- Do not add/remove the player from the object storage ///- It will crash when updating the ObjectAccessor ///- The player should only be removed when logging out Unit::RemoveFromWorld(); for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter) iter->second->RemoveFromWorld(); if (m_uint32Values) { if (WorldObject* viewpoint = GetViewpoint()) { TC_LOG_ERROR("entities.player", "Player::RemoveFromWorld: Player '%s' (%s) has viewpoint (Entry:%u, Type: %u) when removed from world", GetName().c_str(), GetGUID().ToString().c_str(), viewpoint->GetEntry(), viewpoint->GetTypeId()); SetViewpoint(viewpoint, false); } } } bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const { // players are immune to taunt (the aura and the spell effect) if (spellInfo->Effects[index].IsAura(SPELL_AURA_MOD_TAUNT)) return true; if (spellInfo->Effects[index].IsEffect(SPELL_EFFECT_ATTACK_ME)) return true; return Unit::IsImmunedToSpellEffect(spellInfo, index); } void Player::RegenerateAll() { //if (m_regenTimer <= 500) // return; m_regenTimerCount += m_regenTimer; Regenerate(POWER_ENERGY); Regenerate(POWER_MANA); // Runes act as cooldowns, and they don't need to send any data if (getClass() == CLASS_DEATH_KNIGHT) for (uint8 i = 0; i < MAX_RUNES; ++i) if (uint32 cd = GetRuneCooldown(i)) SetRuneCooldown(i, (cd > m_regenTimer) ? cd - m_regenTimer : 0); if (m_regenTimerCount >= 2000) { // Not in combat or they have regeneration if (!IsInCombat() || IsPolymorphed() || m_baseHealthRegen || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT) || HasAuraType(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT)) { RegenerateHealth(); } Regenerate(POWER_RAGE); if (getClass() == CLASS_DEATH_KNIGHT) Regenerate(POWER_RUNIC_POWER); m_regenTimerCount -= 2000; } m_regenTimer = 0; } void Player::Regenerate(Powers power) { uint32 maxValue = GetMaxPower(power); if (!maxValue) return; uint32 curValue = GetPower(power); /// @todo possible use of miscvalueb instead of amount if (HasAuraTypeWithValue(SPELL_AURA_PREVENT_REGENERATE_POWER, power)) return; float addvalue = 0.0f; switch (power) { case POWER_MANA: { bool recentCast = IsUnderLastManaUseEffect(); float ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA); if (getLevel() < 15) ManaIncreaseRate = sWorld->getRate(RATE_POWER_MANA) * (2.066f - (getLevel() * 0.066f)); if (recentCast) // Trinity Updates Mana in intervals of 2s, which is correct addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer; else addvalue += GetFloatValue(UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER) * ManaIncreaseRate * 0.001f * m_regenTimer; } break; case POWER_RAGE: // Regenerate rage { if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN)) { float RageDecreaseRate = sWorld->getRate(RATE_POWER_RAGE_LOSS); addvalue += -20 * RageDecreaseRate; // 2 rage by tick (= 2 seconds => 1 rage/sec) } } break; case POWER_ENERGY: // Regenerate energy (rogue) addvalue += 0.01f * m_regenTimer * sWorld->getRate(RATE_POWER_ENERGY); break; case POWER_RUNIC_POWER: { if (!IsInCombat() && !HasAuraType(SPELL_AURA_INTERRUPT_REGEN)) { float RunicPowerDecreaseRate = sWorld->getRate(RATE_POWER_RUNICPOWER_LOSS); addvalue += -30 * RunicPowerDecreaseRate; // 3 RunicPower by tick } } break; case POWER_RUNE: case POWER_FOCUS: case POWER_HAPPINESS: break; case POWER_HEALTH: return; default: break; } // Mana regen calculated in Player::UpdateManaRegen() if (power != POWER_MANA) { AuraEffectList const& ModPowerRegenPCTAuras = GetAuraEffectsByType(SPELL_AURA_MOD_POWER_REGEN_PERCENT); for (AuraEffectList::const_iterator i = ModPowerRegenPCTAuras.begin(); i != ModPowerRegenPCTAuras.end(); ++i) if (Powers((*i)->GetMiscValue()) == power) AddPct(addvalue, (*i)->GetAmount()); // Butchery requires combat for this effect if (power != POWER_RUNIC_POWER || IsInCombat()) addvalue += GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, power) * ((power != POWER_ENERGY) ? m_regenTimerCount : m_regenTimer) / (5 * IN_MILLISECONDS); } if (addvalue < 0.0f) { if (curValue == 0) return; } else if (addvalue > 0.0f) { if (curValue == maxValue) return; } else return; addvalue += m_powerFraction[power]; uint32 integerValue = uint32(std::fabs(addvalue)); if (addvalue < 0.0f) { if (curValue > integerValue) { curValue -= integerValue; m_powerFraction[power] = addvalue + integerValue; } else { curValue = 0; m_powerFraction[power] = 0; } } else { curValue += integerValue; if (curValue > maxValue) { curValue = maxValue; m_powerFraction[power] = 0; } else m_powerFraction[power] = addvalue - integerValue; } if (m_regenTimerCount >= 2000) SetPower(power, curValue); else UpdateUInt32Value(UNIT_FIELD_POWER1 + power, curValue); } void Player::RegenerateHealth() { uint32 curValue = GetHealth(); uint32 maxValue = GetMaxHealth(); if (curValue >= maxValue) return; float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH); if (getLevel() < 15) HealthIncreaseRate = sWorld->getRate(RATE_HEALTH) * (2.066f - (getLevel() * 0.066f)); float addValue = 0.0f; // polymorphed case if (IsPolymorphed()) addValue = float(GetMaxHealth()) / 3.0f; // normal regen case (maybe partly in combat case) else if (!IsInCombat() || HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) { addValue = OCTRegenHPPerSpirit() * HealthIncreaseRate; if (!IsInCombat()) { AuraEffectList const& mModHealthRegenPct = GetAuraEffectsByType(SPELL_AURA_MOD_HEALTH_REGEN_PERCENT); for (AuraEffectList::const_iterator i = mModHealthRegenPct.begin(); i != mModHealthRegenPct.end(); ++i) AddPct(addValue, (*i)->GetAmount()); addValue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * 0.4f; } else if (HasAuraType(SPELL_AURA_MOD_REGEN_DURING_COMBAT)) ApplyPct(addValue, GetTotalAuraModifier(SPELL_AURA_MOD_REGEN_DURING_COMBAT)); if (!IsStandState()) addValue *= 1.5f; } // always regeneration bonus (including combat) addValue += GetTotalAuraModifier(SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT); addValue += m_baseHealthRegen / 2.5f; if (addValue < 0.0f) addValue = 0.0f; ModifyHealth(int32(addValue)); } void Player::ResetAllPowers() { SetHealth(GetMaxHealth()); switch (getPowerType()) { case POWER_MANA: SetPower(POWER_MANA, GetMaxPower(POWER_MANA)); break; case POWER_RAGE: SetPower(POWER_RAGE, 0); break; case POWER_ENERGY: SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY)); break; case POWER_RUNIC_POWER: SetPower(POWER_RUNIC_POWER, 0); break; default: break; } } bool Player::CanInteractWithQuestGiver(Object* questGiver) const { switch (questGiver->GetTypeId()) { case TYPEID_UNIT: return GetNPCIfCanInteractWith(questGiver->GetGUID(), UNIT_NPC_FLAG_QUESTGIVER) != nullptr; case TYPEID_GAMEOBJECT: return GetGameObjectIfCanInteractWith(questGiver->GetGUID(), GAMEOBJECT_TYPE_QUESTGIVER) != nullptr; case TYPEID_PLAYER: return IsAlive() && questGiver->ToPlayer()->IsAlive(); case TYPEID_ITEM: return IsAlive(); default: break; } return false; } Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, uint32 npcflagmask) const { // unit checks if (!guid) return nullptr; if (!IsInWorld()) return nullptr; if (IsInFlight()) return nullptr; // exist (we need look pets also for some interaction (quest/etc) Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid); if (!creature) return nullptr; // Deathstate checks if (!IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_GHOST_VISIBLE)) return nullptr; // alive or spirit healer if (!creature->IsAlive() && !(creature->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_CAN_INTERACT_WHILE_DEAD)) return nullptr; // appropriate npc type if (npcflagmask && !creature->HasFlag(UNIT_NPC_FLAGS, npcflagmask)) return nullptr; // not allow interaction under control, but allow with own pets if (creature->GetCharmerGUID()) return nullptr; // not unfriendly/hostile if (creature->GetReactionTo(this) <= REP_UNFRIENDLY) return nullptr; // not too far if (!creature->IsWithinDistInMap(this, INTERACTION_DISTANCE)) return nullptr; return creature; } GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const { if (GameObject* go = GetMap()->GetGameObject(guid)) { if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) return go; TC_LOG_DEBUG("maps", "GetGameObjectIfCanInteractWith: GameObject '%s' [GUID: %u] is too far away from player %s [GUID: %u] to be used by him (distance=%f, maximal %f is allowed)", go->GetGOInfo()->name.c_str(), go->GetGUID().GetCounter(), GetName().c_str(), GetGUID().GetCounter(), go->GetDistance(this), go->GetInteractionDistance()); } return nullptr; } GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid, GameobjectTypes type) const { if (GameObject* go = GetMap()->GetGameObject(guid)) { if (go->GetGoType() == type) { if (go->IsWithinDistInMap(this, go->GetInteractionDistance())) return go; TC_LOG_DEBUG("maps", "Player::GetGameObjectIfCanInteractWith: GameObject '%s' (%s) is too far away from player '%s' (%s) to be used by him (Distance: %f, maximal 10 is allowed)", go->GetGOInfo()->name.c_str(), go->GetGUID().ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str(), go->GetDistance(this)); } } return nullptr; } bool Player::IsUnderWater() const { return IsInWater() && GetPositionZ() < (GetBaseMap()->GetWaterLevel(GetPositionX(), GetPositionY())-2); } void Player::SetInWater(bool apply) { if (m_isInWater == apply) return; //define player in water by opcodes //move player's guid into HateOfflineList of those mobs //which can't swim and move guid back into ThreatList when //on surface. /// @todo exist also swimming mobs, and function must be symmetric to enter/leave water m_isInWater = apply; // remove auras that need water/land RemoveAurasWithInterruptFlags(apply ? AURA_INTERRUPT_FLAG_NOT_ABOVEWATER : AURA_INTERRUPT_FLAG_NOT_UNDERWATER); getHostileRefManager().updateThreatTables(); } bool Player::IsInAreaTriggerRadius(const AreaTriggerEntry* trigger) const { if (!trigger || GetMapId() != trigger->mapid) return false; if (trigger->radius > 0.f) { // if we have radius check it float dist = GetDistance(trigger->x, trigger->y, trigger->z); if (dist > trigger->radius) return false; } else { Position center(trigger->x, trigger->y, trigger->z, trigger->box_orientation); if (!IsWithinBox(center, trigger->box_x / 2.f, trigger->box_y / 2.f, trigger->box_z / 2.f)) return false; } return true; } void Player::SetGameMaster(bool on) { if (on) { m_ExtraFlags |= PLAYER_EXTRA_GM_ON; setFaction(35); SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); SetFlag(UNIT_FIELD_FLAGS_2, UNIT_FLAG2_ALLOW_CHEAT_SPELLS); if (Pet* pet = GetPet()) { pet->setFaction(35); pet->getHostileRefManager().setOnlineOfflineState(false); } RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_FFA_PVP); ResetContestedPvP(); getHostileRefManager().setOnlineOfflineState(false); CombatStopWithPets(); SetPhaseMask(uint32(PHASEMASK_ANYWHERE), false); // see and visible in all phases m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, GetSession()->GetSecurity()); } else {
  2. hello this my order is please if you give me some help I want to add wings to my server 3.3.5a I don't know where to wait for the dbc which are what to add and since another server has it as a tabard there is some guide please I would really appreciate it
  3. In my frame I get real as you see the picture as I can anchor that some guide please thank you
  4. ya lo areclaste el forma de oso de la luz verde muy fuerte
  5. some solution to this problem will be useful to me
  6. hello community I have a problem with the client alpha link ===) 1: my mistake is that I put all Patch in my Spanish client that is "esEs" 2: insert the sql well without any problem 3: now I give the command ".learn ID does not appear to me how to learn mount and I put Command .npc add so it appears but in npc not in mount how can I solve this problem please I have a photo and when I put the command .learn ID twice I get I've already learned that spell, I don't really have it 4: use Trinitycore Rev 61 upload image
  7. I have an error download it all right insert well sql but the frames do not come out I put command ".learn mount ID does not come out to learn only em comes out as npc not as mount that I can be friends some solution to this problem
  8. could you pass the sql to add to the world friend please thank you your theme is good
  9. and downloaded that pacht is for druid form everything is fine only the bear form comes out very strong the color verder on the neck as it is anchored that if you can anchor me please thank you link descargar artivo del error https://model-changing.net/files/file/194-new-druid-forms-night-elf-tauren-wow-335a/?tab=comments picture hosting
    esta bueno gracias por tu aporte espero que aporte otras cosas mas increhible como este tema
  10. tengo un error elfo de noche forma Oso sale luz verde muy fuerte
  11. como lo puedo agregar ami servidor alguna guia porfavor