diff options
Diffstat (limited to 'src')
40 files changed, 1074 insertions, 354 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 99cf1cda4fc..6802c109401 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -71,6 +71,8 @@ void PetAI::_stopAttack() } me->AttackStop(); + me->InterruptNonMeleeSpells(false); + me->SendMeleeAttackStop(); // Should stop pet's attack button from flashing me->GetCharmInfo()->SetIsCommandAttack(false); HandleReturnMovement(); } @@ -89,7 +91,8 @@ void PetAI::UpdateAI(const uint32 diff) m_updateAlliesTimer -= diff; // me->getVictim() can't be used for check in case stop fighting, me->getVictim() clear at Unit death etc. - if (me->getVictim()) + // Must also check if victim is alive + if (me->getVictim() && me->getVictim()->isAlive()) { // is only necessary to stop casting, the pet must not exit combat if (me->getVictim()->HasBreakableByDamageCrowdControlAura(me)) @@ -121,10 +124,16 @@ void PetAI::UpdateAI(const uint32 diff) if (nextTarget) AttackStart(nextTarget); else + { + me->GetCharmInfo()->SetIsCommandAttack(false); HandleReturnMovement(); + } } else + { + me->GetCharmInfo()->SetIsCommandAttack(false); HandleReturnMovement(); + } } else if (owner && !me->HasUnitState(UNIT_STATE_FOLLOW)) // no charm info and no victim HandleReturnMovement(); @@ -301,7 +310,7 @@ void PetAI::KilledUnit(Unit* victim) // Can't use _stopAttack() because that activates movement handlers and ignores // next target selection me->AttackStop(); - me->GetCharmInfo()->SetIsCommandAttack(false); + me->InterruptNonMeleeSpells(false); me->SendMeleeAttackStop(); // Stops the pet's 'Attack' button from flashing Unit* nextTarget = SelectNextTarget(); @@ -309,7 +318,10 @@ void PetAI::KilledUnit(Unit* victim) if (nextTarget) AttackStart(nextTarget); else + { + me->GetCharmInfo()->SetIsCommandAttack(false); HandleReturnMovement(); // Return + } } void PetAI::AttackStart(Unit* target) diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 8e5311fa000..d7f1dca3fbf 100755 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -32,8 +32,6 @@ class PetAI : public CreatureAI explicit PetAI(Creature* c); void EnterEvadeMode(); - void JustDied(Unit* /*who*/) { _stopAttack(); } - void UpdateAI(const uint32); static int Permissible(const Creature*); diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp index 119880bae8d..59dc6761583 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.cpp +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.cpp @@ -188,29 +188,6 @@ bool BattlefieldWG::SetupBattlefield() go->SetUInt32Value(GAMEOBJECT_FACTION, WintergraspFaction[GetDefenderTeam()]); } - // Spawn banners in the keep - for (uint8 i = 0; i < WG_KEEPGAMEOBJECT_MAX; i++) - { - if (GameObject* go = SpawnGameObject(WGKeepGameObject[i].entryHorde, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) - { - go->SetRespawnTime(GetDefenderTeam()? RESPAWN_ONE_DAY : RESPAWN_IMMEDIATELY); - m_KeepGameObject[1].insert(go); - } - if (GameObject* go = SpawnGameObject(WGKeepGameObject[i].entryAlliance, WGKeepGameObject[i].x, WGKeepGameObject[i].y, WGKeepGameObject[i].z, WGKeepGameObject[i].o)) - { - go->SetRespawnTime(GetDefenderTeam()? RESPAWN_IMMEDIATELY : RESPAWN_ONE_DAY); - m_KeepGameObject[0].insert(go); - } - } - - // Show defender banner in keep - for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetDefenderTeam()].begin(); itr != m_KeepGameObject[GetDefenderTeam()].end(); ++itr) - (*itr)->SetRespawnTime(RESPAWN_IMMEDIATELY); - - // Hide attackant banner in keep - for (GameObjectSet::const_iterator itr = m_KeepGameObject[GetAttackerTeam()].begin(); itr != m_KeepGameObject[GetAttackerTeam()].end(); ++itr) - (*itr)->SetRespawnTime(RESPAWN_ONE_DAY); - UpdateCounterVehicle(true); return true; } diff --git a/src/server/game/Battlefield/Zones/BattlefieldWG.h b/src/server/game/Battlefield/Zones/BattlefieldWG.h index 323f7f2b13d..49ea25a5e04 100644 --- a/src/server/game/Battlefield/Zones/BattlefieldWG.h +++ b/src/server/game/Battlefield/Zones/BattlefieldWG.h @@ -440,10 +440,9 @@ uint32 const VehNumWorldState[] = { 3680, 3490 }; uint32 const MaxVehNumWorldState[] = { 3681, 3491 }; uint32 const ClockWorldState[] = { 3781, 4354 }; uint32 const WintergraspFaction[] = { 1732, 1735, 35 }; -float const WintergraspStalkerPos[] = { 0, 0, 0, 0 }; +float const WintergraspStalkerPos[] = { 4948.985f, 2937.789f, 550.5172f, 1.815142f }; uint8 const WG_MAX_OBJ = 32; -uint8 const WG_KEEPGAMEOBJECT_MAX = 44; uint8 const WG_MAX_TURRET = 15; uint8 const WG_MAX_KEEP_NPC = 39; uint8 const WG_MAX_OUTSIDE_NPC = 14; @@ -580,6 +579,19 @@ struct WintergraspBuildingSpawnData uint32 nameId; }; +struct WintergraspRebuildableBuildingData +{ + uint32 entry; + uint64 Guid; + uint32 WorldState; + float x; + float y; + float z; + float o; + uint32 type; + uint32 nameId; +}; + const WintergraspBuildingSpawnData WGGameObjectBuilding[WG_MAX_OBJ] = { // Wall (Not spawned in db) @@ -628,99 +640,6 @@ const WintergraspBuildingSpawnData WGGameObjectBuilding[WG_MAX_OBJ] = { GO_WINTERGRASP_VAULT_GATE, 3773, 5397.11f, 2841.54f, 425.899f, 3.14159f, BATTLEFIELD_WG_OBJECTTYPE_DOOR_LAST, 0 }, }; - -// ********************************************************* -// **********Keep Element(GameObject,Creature)************** -// ********************************************************* - -// Keep gameobject -// 192488 : 10 in sql, 19 in header -// 192501 : 12 in sql, 17 in header -// 192416 : 1 in sql, 33 in header -// 192374 : 1 in sql, 1 in header -// 192375 : 1 in sql, 1 in header -// 192336 : 1 in sql, 1 in header -// 192255 : 1 in sql, 1 in header -// 192269 : 1 in sql, 7 in header -// 192254 : 1 in sql, 1 in header -// 192349 : 1 in sql, 1 in header -// 192366 : 1 in sql, 3 in header -// 192367 : 1 in sql, 1 in header -// 192364 : 1 in sql, 1 in header -// 192370 : 1 in sql, 1 in header -// 192369 : 1 in sql, 1 in header -// 192368 : 1 in sql, 1 in header -// 192362 : 1 in sql, 1 in header -// 192363 : 1 in sql, 1 in header -// 192379 : 1 in sql, 1 in header -// 192378 : 1 in sql, 1 in header -// 192355 : 1 in sql, 1 in header -// 192354 : 1 in sql, 1 in header -// 192358 : 1 in sql, 1 in header -// 192359 : 1 in sql, 1 in header -// 192338 : 1 in sql, 1 in header -// 192339 : 1 in sql, 1 in header -// 192284 : 1 in sql, 1 in header -// 192285 : 1 in sql, 1 in header -// 192371 : 1 in sql, 1 in header -// 192372 : 1 in sql, 1 in header -// 192373 : 1 in sql, 1 in header -// 192360 : 1 in sql, 1 in header -// 192361 : 1 in sql, 1 in header -// 192356 : 1 in sql, 1 in header -// 192352 : 1 in sql, 1 in header -// 192353 : 1 in sql, 1 in header -// 192357 : 1 in sql, 1 in header -// 192350 : 1 in sql, 1 in header -// 192351 : 1 in sql, 1 in header -const WintergraspObjectPositionData WGKeepGameObject[WG_KEEPGAMEOBJECT_MAX] = -{ - { 5262.540039f, 3047.949951f, 432.054993f, 3.106650f, 192488, 192501 }, // Flag on tower - { 5272.939941f, 2976.550049f, 444.492004f, 3.124120f, 192374, 192416 }, // Flag on Wall Intersect - { 5235.189941f, 2941.899902f, 444.278015f, 1.588250f, 192375, 192416 }, // Flag on Wall Intersect - { 5163.129883f, 2952.590088f, 433.502991f, 1.535890f, 192488, 192501 }, // Flag on tower - { 5145.109863f, 2935.000000f, 433.385986f, 3.141590f, 192488, 192501 }, // Flag on tower - { 5158.810059f, 2883.129883f, 431.618011f, 3.141590f, 192488, 192416 }, // Flag on wall - { 5154.490234f, 2862.149902f, 445.011993f, 3.141590f, 192336, 192416 }, // Flag on Wall Intersect - { 5154.520020f, 2853.310059f, 409.183014f, 3.141590f, 192255, 192269 }, // Flag on the floor - { 5154.459961f, 2828.939941f, 409.188995f, 3.141590f, 192254, 192269 }, // Flag on the floor - { 5155.310059f, 2820.739990f, 444.979004f, -3.13286f, 192349, 192416 }, // Flag on wall intersect - { 5160.339844f, 2798.610107f, 430.769012f, 3.141590f, 192488, 192416 }, // Flag on wall - { 5146.040039f, 2747.209961f, 433.584015f, 3.071770f, 192488, 192501 }, // Flag on tower - { 5163.779785f, 2729.679932f, 433.394012f, -1.58825f, 192488, 192501 }, // Flag on tower - { 5236.270020f, 2739.459961f, 444.992004f, -1.59698f, 192366, 192416 }, // Flag on wall intersect - { 5271.799805f, 2704.870117f, 445.183014f, -3.13286f, 192367, 192416 }, // Flag on wall intersect - { 5260.819824f, 2631.800049f, 433.324005f, 3.054330f, 192488, 192501 }, // Flag on tower - { 5278.379883f, 2613.830078f, 433.408997f, -1.58825f, 192488, 192501 }, // Flag on tower - { 5350.879883f, 2622.719971f, 444.686005f, -1.57080f, 192364, 192416 }, // Flag on wall intersect - { 5392.270020f, 2639.739990f, 435.330994f, 1.509710f, 192370, 192416 }, // Flag on wall intersect - { 5350.950195f, 2640.360107f, 435.407990f, 1.570800f, 192369, 192416 }, // Flag on wall intersect - { 5289.459961f, 2704.679932f, 435.875000f, -0.01745f, 192368, 192416 }, // Flag on wall intersect - { 5322.120117f, 2763.610107f, 444.973999f, -1.55334f, 192362, 192416 }, // Flag on wall intersect - { 5363.609863f, 2763.389893f, 445.023987f, -1.54462f, 192363, 192416 }, // Flag on wall intersect - { 5363.419922f, 2781.030029f, 435.763000f, 1.570800f, 192379, 192416 }, // Flag on wall intersect - { 5322.020020f, 2781.129883f, 435.811005f, 1.570800f, 192378, 192416 }, // Flag on wall intersect - { 5288.919922f, 2820.219971f, 435.721008f, 0.017452f, 192355, 192416 }, // Flag on wall intersect - { 5288.410156f, 2861.790039f, 435.721008f, 0.017452f, 192354, 192416 }, // Flag on wall intersect - { 5322.229980f, 2899.429932f, 435.808014f, -1.58825f, 192358, 192416 }, // Flag on wall intersect - { 5364.350098f, 2899.399902f, 435.838989f, -1.57080f, 192359, 192416 }, // Flag on wall intersect - { 5397.759766f, 2873.080078f, 455.460999f, 3.106650f, 192338, 192416 }, // Flag on keep - { 5397.390137f, 2809.330078f, 455.343994f, 3.106650f, 192339, 192416 }, // Flag on keep - { 5372.479980f, 2862.500000f, 409.049011f, 3.141590f, 192284, 192269 }, // Flag on floor - { 5371.490234f, 2820.800049f, 409.177002f, 3.141590f, 192285, 192269 }, // Flag on floor - { 5364.290039f, 2916.939941f, 445.330994f, 1.579520f, 192371, 192416 }, // Flag on wall intersect - { 5322.859863f, 2916.949951f, 445.153992f, 1.562070f, 192372, 192416 }, // Flag on wall intersect - { 5290.350098f, 2976.560059f, 435.221008f, 0.017452f, 192373, 192416 }, // Flag on wall intersect - { 5352.370117f, 3037.090088f, 435.252014f, -1.57080f, 192360, 192416 }, // Flag on wall intersect - { 5392.649902f, 3037.110107f, 433.713013f, -1.52716f, 192361, 192416 }, // Flag on wall intersect - { 5237.069824f, 2757.030029f, 435.795990f, 1.518440f, 192356, 192416 }, // Flag on wall intersect - { 5173.020020f, 2820.929932f, 435.720001f, 0.017452f, 192352, 192416 }, // Flag on wall intersect - { 5172.109863f, 2862.570068f, 435.721008f, 0.017452f, 192353, 192416 }, // Flag on wall intersect - { 5235.339844f, 2924.340088f, 435.040009f, -1.57080f, 192357, 192416 }, // Flag on wall intersect - { 5270.689941f, 2861.780029f, 445.058014f, -3.11539f, 192350, 192416 }, // Flag on wall intersect - { 5271.279785f, 2820.159912f, 445.200989f, -3.13286f, 192351, 192416 } // Flag on wall intersect -}; - const Position WGTurret[WG_MAX_TURRET] = { { 5391.19f, 3060.8f, 419.616f, 1.69557f }, diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 1b303760095..699445f8ccc 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -530,20 +530,23 @@ inline void Battleground::_ProcessJoin(uint32 diff) player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); player->ResetAllPowers(); - // remove auras with duration lower than 30s - Unit::AuraApplicationMap & auraMap = player->GetAppliedAuras(); - for (Unit::AuraApplicationMap::iterator iter = auraMap.begin(); iter != auraMap.end();) + if (!player->isGameMaster()) { - AuraApplication * aurApp = iter->second; - Aura* aura = aurApp->GetBase(); - if (!aura->IsPermanent() - && aura->GetDuration() <= 30*IN_MILLISECONDS - && aurApp->IsPositive() - && (!(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) - && (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY))) - player->RemoveAura(iter); - else - ++iter; + // remove auras with duration lower than 30s + Unit::AuraApplicationMap & auraMap = player->GetAppliedAuras(); + for (Unit::AuraApplicationMap::iterator iter = auraMap.begin(); iter != auraMap.end();) + { + AuraApplication * aurApp = iter->second; + Aura* aura = aurApp->GetBase(); + if (!aura->IsPermanent() + && aura->GetDuration() <= 30*IN_MILLISECONDS + && aurApp->IsPositive() + && (!(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY)) + && (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY))) + player->RemoveAura(iter); + else + ++iter; + } } } diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 917c4cd7f90..406fb7cb753 100755 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -611,7 +611,8 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) const sourceType == CONDITION_SOURCE_TYPE_VEHICLE_SPELL || sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || - sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT); + sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || + sourceType == CONDITION_SOURCE_TYPE_PHASE_DEFINITION); } bool ConditionMgr::CanHaveSourceIdSet(ConditionSourceType sourceType) const @@ -687,6 +688,23 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int32 entryOrGuid, uint32 return cond; } +ConditionList ConditionMgr::GetConditionsForPhaseDefinition(uint32 zone, uint32 entry) +{ + ConditionList cond; + PhaseDefinitionConditionContainer::const_iterator itr = PhaseDefinitionsConditionStore.find(zone); + if (itr != PhaseDefinitionsConditionStore.end()) + { + ConditionTypeContainer::const_iterator i = (*itr).second.find(entry); + if (i != (*itr).second.end()) + { + cond = (*i).second; + sLog->outDebug(LOG_FILTER_CONDITIONSYS, "GetConditionsForPhaseDefinition: found conditions for zone %u entry %u spell %u", zone, entry); + } + } + + return cond; +} + void ConditionMgr::LoadConditions(bool isReload) { uint32 oldMSTime = getMSTime(); @@ -898,6 +916,13 @@ void ConditionMgr::LoadConditions(bool isReload) ++count; continue; } + case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + { + PhaseDefinitionsConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); + valid = true; + ++count; + continue; + } default: break; } @@ -1389,6 +1414,13 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) return false; } break; + case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: + if (!PhaseMgr::IsConditionTypeSupported(cond->ConditionType)) + { + sLog->outError(LOG_FILTER_SQL, "Condition source type `CONDITION_SOURCE_TYPE_PHASE_DEFINITION` does not support condition type %u, ignoring.", cond->ConditionType); + return false; + } + break; case CONDITION_SOURCE_TYPE_GOSSIP_MENU: case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: @@ -1399,6 +1431,7 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) return true; } + bool ConditionMgr::isConditionTypeValid(Condition* cond) { if (cond->ConditionType == CONDITION_NONE || cond->ConditionType >= CONDITION_MAX) @@ -1940,6 +1973,19 @@ void ConditionMgr::Clean() SpellClickEventConditionStore.clear(); + for (PhaseDefinitionConditionContainer::iterator itr = PhaseDefinitionsConditionStore.begin(); itr != PhaseDefinitionsConditionStore.end(); ++itr) + { + for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) + { + for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) + delete *i; + it->second.clear(); + } + itr->second.clear(); + } + + PhaseDefinitionsConditionStore.clear(); + // this is a BIG hack, feel free to fix it if you can figure out the ConditionMgr ;) for (std::list<Condition*>::const_iterator itr = AllocatedMemoryStore.begin(); itr != AllocatedMemoryStore.end(); ++itr) delete *itr; diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index 57af0562dcd..fe7f6a18af8 100755 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -124,7 +124,8 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_QUEST_SHOW_MARK = 20, CONDITION_SOURCE_TYPE_VEHICLE_SPELL = 21, CONDITION_SOURCE_TYPE_SMART_EVENT = 22, - CONDITION_SOURCE_TYPE_MAX = 23 //MAX + CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 23, + CONDITION_SOURCE_TYPE_MAX = 24 //MAX }; enum ComparisionType @@ -211,6 +212,7 @@ typedef std::map<uint32, ConditionList> ConditionTypeContainer; typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer; typedef std::map<uint32, ConditionTypeContainer> CreatureSpellConditionContainer; typedef std::map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer; +typedef std::map<int32 /*zoneId*/, ConditionTypeContainer> PhaseDefinitionConditionContainer; typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references @@ -237,6 +239,7 @@ class ConditionMgr ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType); ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId); + ConditionList GetConditionsForPhaseDefinition(uint32 zone, uint32 entry); private: bool isSourceTypeValid(Condition* cond); @@ -254,6 +257,7 @@ class ConditionMgr CreatureSpellConditionContainer VehicleSpellConditionStore; CreatureSpellConditionContainer SpellClickEventConditionStore; SmartEventConditionContainer SmartEventConditionStore; + PhaseDefinitionConditionContainer PhaseDefinitionsConditionStore; }; template <class T> bool CompareValues(ComparisionType type, T val1, T val2) diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 308b9fa1a60..a1a0931dc5a 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -1408,8 +1408,8 @@ struct LockEntry struct PhaseEntry { uint32 ID; // 0 - char* Name; // 1 - uint32 phaseShift; // 2 + char* Name; // 1 + uint32 flag; // 2 }; struct MailTemplateEntry diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 5a5e4c5c848..d152dc5642f 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -217,6 +217,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa SetDisplayId(goinfo->displayId); + m_model = GameObjectModel::Create(*this); // GAMEOBJECT_BYTES_1, index at 0, 1, 2 and 3 SetGoType(GameobjectTypes(goinfo->type)); SetGoState(go_state); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ddd52ff352f..0582a879d5f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -649,7 +649,7 @@ void KillRewarder::Reward() #ifdef _MSC_VER #pragma warning(disable:4355) #endif -Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this) +Player::Player(WorldSession* session): Unit(true), m_achievementMgr(this), m_reputationMgr(this), phaseMgr(this) { #ifdef _MSC_VER #pragma warning(default:4355) @@ -1564,6 +1564,16 @@ void Player::Update(uint32 p_time) // 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->setUInt32(1, GetSession()->GetAccountId()); + LoginDatabase.Execute(stmt); + } if (!m_timedquests.empty()) { @@ -2928,18 +2938,6 @@ void Player::SetGameMaster(bool on) } else { - // restore phase - uint32 newPhase = 0; - AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - for (AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - newPhase |= (*itr)->GetMiscValue(); - - if (!newPhase) - newPhase = PHASEMASK_NORMAL; - - SetPhaseMask(newPhase, false); - m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON; setFactionForRace(getRace()); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_GM); @@ -2960,6 +2958,9 @@ void Player::SetGameMaster(bool on) getHostileRefManager().setOnlineOfflineState(true); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GM, SEC_PLAYER); + + phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + phaseMgr.Update(); } UpdateObjectVisibility(); @@ -3192,6 +3193,11 @@ void Player::GiveLevel(uint8 level) UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL); + PhaseUpdateData phaseUdateData; + phaseUdateData.AddConditionType(CONDITION_LEVEL); + + phaseMgr.NotifyConditionChanged(phaseUdateData); + // Refer-A-Friend if (GetSession()->GetRecruiterId()) if (level < sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL)) @@ -7618,6 +7624,8 @@ void Player::UpdateArea(uint32 newArea) // so apply them accordingly m_areaUpdateId = newArea; + phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); + AreaTableEntry const* area = GetAreaEntryByAreaID(newArea); pvpInfo.inFFAPvPArea = area && (area->flags & AREA_FLAG_ARENA); UpdatePvPState(true); @@ -7634,10 +7642,14 @@ void Player::UpdateArea(uint32 newArea) } else RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); + + phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); } void Player::UpdateZone(uint32 newZone, uint32 newArea) { + phaseMgr.AddUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); + if (m_zoneUpdateId != newZone) { sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId); @@ -7747,6 +7759,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateLocalChannels(newZone); UpdateZoneDependentAuras(newZone); + + phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_ZONE_UPDATE); } //If players are too far away from the duel flag... they lose the duel @@ -15000,6 +15014,11 @@ void Player::AddQuest(Quest const* quest, Object* questGiver) CastSpell(this, itr->second->spellId, true); } + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr.NotifyConditionChanged(phaseUdateData); + UpdateForQuestWorldObjects(); } @@ -15168,6 +15187,11 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, m_RewardedQuests.insert(quest_id); m_RewardedQuestsSave[quest_id] = true; + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr.NotifyConditionChanged(phaseUdateData); + // StoreNewItem, mail reward, etc. save data directly to the database // to prevent exploitable data desynchronisation we save the quest status to the database too // (to prevent rewarding this quest another time while rewards were already given out) @@ -15757,6 +15781,11 @@ void Player::SetQuestStatus(uint32 quest_id, QuestStatus status) m_QuestStatusSave[quest_id] = true; } + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr.NotifyConditionChanged(phaseUdateData); + UpdateForQuestWorldObjects(); } @@ -15767,6 +15796,11 @@ void Player::RemoveActiveQuest(uint32 quest_id) { m_QuestStatus.erase(itr); m_QuestStatusSave[quest_id] = false; + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr.NotifyConditionChanged(phaseUdateData); return; } } @@ -15778,6 +15812,11 @@ void Player::RemoveRewardedQuest(uint32 quest_id) { m_RewardedQuests.erase(rewItr); m_RewardedQuestsSave[quest_id] = false; + + PhaseUpdateData phaseUdateData; + phaseUdateData.AddQuestUpdate(quest_id); + + phaseMgr.NotifyConditionChanged(phaseUdateData); } } @@ -24410,25 +24449,6 @@ void Player::_LoadSkills(PreparedQueryResult result) } } -uint32 Player::GetPhaseMaskForSpawn() const -{ - uint32 phase = PHASEMASK_NORMAL; - if (!isGameMaster()) - phase = GetPhaseMask(); - else - { - AuraEffectList const& phases = GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - phase = phases.front()->GetMiscValue(); - } - - // some aura phases include 1 normal map in addition to phase itself - if (uint32 n_phase = phase & ~PHASEMASK_NORMAL) - return n_phase; - - return PHASEMASK_NORMAL; -} - InventoryResult Player::CanEquipUniqueItem(Item* pItem, uint8 eslot, uint32 limit_count) const { ItemTemplate const* pProto = pItem->GetTemplate(); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 4d91ac42879..f1f58231bef 100755..100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -37,6 +37,9 @@ #include "Unit.h" #include "Util.h" // for Tokens typedef #include "WorldSession.h" +#include "PhaseMgr.h" + +// for template #include "SpellMgr.h" #include<string> @@ -54,6 +57,7 @@ class PlayerMenu; class PlayerSocial; class SpellCastTargets; class UpdateMask; +class PhaseMgr; typedef std::deque<Mail*> PlayerMails; @@ -1342,7 +1346,8 @@ class Player : public Unit, public GridObject<Player> Pet* GetPet() const; Pet* SummonPet(uint32 entry, float x, float y, float z, float ang, PetType petType, uint32 despwtime); void RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent = false); - uint32 GetPhaseMaskForSpawn() const; // used for proper set phase for DB at GM-mode creature/GO spawn + + PhaseMgr& GetPhaseMgr() { return phaseMgr; } void Say(const std::string& text, const uint32 language); void Yell(const std::string& text, const uint32 language); @@ -3083,6 +3088,8 @@ class Player : public Unit, public GridObject<Player> uint32 _pendingBindTimer; uint32 _activeCheats; + + PhaseMgr phaseMgr; }; void AddItemsSetItem(Player*player, Item* item); diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index f2266f03ae9..eac2b531805 100755 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1101,8 +1101,8 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) //demons benefit from warlocks shadow or fire damage else if (isPet()) { - int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); - int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); + int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); int32 maximum = (fire > shadow) ? fire : shadow; if (maximum < 0) maximum = 0; @@ -1112,7 +1112,7 @@ void Guardian::UpdateAttackPowerAndDamage(bool ranged) //water elementals benefit from mage's frost damage else if (GetEntry() == ENTRY_WATER_ELEMENTAL) { - int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); + int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) + owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); if (frost < 0) frost = 0; SetBonusDamage(int32(frost * 0.4f)); @@ -1145,14 +1145,14 @@ void Guardian::UpdateDamagePhysical(WeaponAttackType attType) //force of nature if (GetEntry() == ENTRY_TREANT) { - int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_NATURE)) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_NATURE); if (spellDmg > 0) bonusDamage = spellDmg * 0.09f; } //greater fire elemental else if (GetEntry() == ENTRY_FIRE_ELEMENTAL) { - int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); + int32 spellDmg = int32(m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) + m_owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); if (spellDmg > 0) bonusDamage = spellDmg * 0.4f; } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 669f89a1b8d..dd2afa44a07 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -7565,7 +7565,7 @@ SpellScriptsBounds ObjectMgr::GetSpellScriptsBounds(uint32 spell_id) } // this allows calculating base reputations to offline players, just by race and class -int32 ObjectMgr::GetBaseReputation(FactionEntry const* factionEntry, uint8 race, uint8 playerClass) +int32 ObjectMgr::GetBaseReputationOff(FactionEntry const* factionEntry, uint8 race, uint8 playerClass) { if (!factionEntry) return 0; @@ -8652,7 +8652,7 @@ void ObjectMgr::LoadFactionChangeTitles() } uint32 count = 0; - + do { Field* fields = result->Fetch(); @@ -8666,7 +8666,7 @@ void ObjectMgr::LoadFactionChangeTitles() sLog->outError(LOG_FILTER_SQL, "Title %u referenced in `player_factionchange_title` does not exist, pair skipped!", horde); else FactionChange_Titles[alliance] = horde; - + ++count; } while (result->NextRow()); @@ -8674,6 +8674,99 @@ void ObjectMgr::LoadFactionChangeTitles() sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadPhaseDefinitions() +{ + _PhaseDefinitionStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 4 5 + QueryResult result = WorldDatabase.Query("SELECT zoneId, entry, phasemask, phaseId, terrainswapmap, flags FROM `phase_definitions` ORDER BY `entry` ASC"); + + if (!result) + { + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty."); + return; + } + + uint32 count = 0; + + do + { + Field *fields = result->Fetch(); + + PhaseDefinition PhaseDefinition; + + PhaseDefinition.zoneId = fields[0].GetUInt32(); + PhaseDefinition.entry = fields[1].GetUInt32(); + PhaseDefinition.phasemask = fields[2].GetUInt32(); + PhaseDefinition.phaseId = fields[3].GetUInt32(); + PhaseDefinition.terrainswapmap = fields[4].GetUInt32(); + PhaseDefinition.flags = fields[5].GetUInt32(); + + // Checks + if ((PhaseDefinition.flags & PHASE_FLAG_OVERWRITE_EXISTING) && (PhaseDefinition.flags & PHASE_FLAG_NEGATE_PHASE)) + { + sLog->outError(LOG_FILTER_SQL, "Flags defined in phase_definitions in zoneId %d and entry %u does contain PHASE_FLAG_OVERWRITE_EXISTING and PHASE_FLAG_NEGATE_PHASE. Setting flags to PHASE_FLAG_OVERWRITE_EXISTING", PhaseDefinition.zoneId, PhaseDefinition.entry); + PhaseDefinition.flags &= ~PHASE_FLAG_NEGATE_PHASE; + } + + _PhaseDefinitionStore[PhaseDefinition.zoneId].push_back(PhaseDefinition); + + ++count; + } + while (result->NextRow()); + + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u phasing definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadSpellPhaseInfo() +{ + _SpellPhaseStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 2 + QueryResult result = WorldDatabase.Query("SELECT id, phasemask, terrainswapmap FROM `spell_phase`"); + + if (!result) + { + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded 0 spell dbc infos. DB table `spell_phase` is empty."); + return; + } + + uint32 count = 0; + do + { + Field *fields = result->Fetch(); + + SpellPhaseInfo spellPhaseInfo; + spellPhaseInfo.spellId = fields[0].GetUInt32(); + + SpellInfo const* spell = sSpellMgr->GetSpellInfo(spellPhaseInfo.spellId); + if (!spell) + { + sLog->outError(LOG_FILTER_SQL, "Spell %u defined in `spell_phase` does not exists, skipped.", spellPhaseInfo.spellId); + continue; + } + + if (!spell->HasAura(SPELL_AURA_PHASE)) + { + sLog->outError(LOG_FILTER_SQL, "Spell %u defined in `spell_phase` does not have aura effect type SPELL_AURA_PHASE, useless value.", spellPhaseInfo.spellId); + continue; + } + + spellPhaseInfo.phasemask = fields[1].GetUInt32(); + spellPhaseInfo.terrainswapmap = fields[2].GetUInt32(); + + _SpellPhaseStore[spellPhaseInfo.spellId] = spellPhaseInfo; + + ++count; + } + while (result->NextRow()); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, ">> Loaded %u spell dbc infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) { GameObjectTemplateContainer::const_iterator itr = _gameObjectTemplateStore.find(entry); diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e727b9724e5..496d5ae224f 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -42,8 +42,10 @@ #include <limits> #include "ConditionMgr.h" #include <functional> +#include "PhaseMgr.h" class Item; +class PhaseMgr; // GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform #if defined(__GNUC__) @@ -743,7 +745,7 @@ class ObjectMgr return NULL; } - int32 GetBaseReputation(FactionEntry const* factionEntry, uint8 race, uint8 playerClass); + int32 GetBaseReputationOff(FactionEntry const* factionEntry, uint8 race, uint8 playerClass); RepSpilloverTemplate const* GetRepSpilloverTemplate(uint32 factionId) const { @@ -906,6 +908,12 @@ class ObjectMgr void LoadTrainerSpell(); void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel); + void LoadPhaseDefinitions(); + void LoadSpellPhaseInfo(); + + PhaseDefinitionStore const* GetPhaseDefinitionStore() { return &_PhaseDefinitionStore; } + SpellPhaseStore const* GetSpellPhaseStore() { return &_SpellPhaseStore; } + std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); uint32 GetXPForLevel(uint8 level) const; @@ -1222,6 +1230,9 @@ class ObjectMgr PageTextContainer _pageTextStore; InstanceTemplateContainer _instanceTemplateStore; + PhaseDefinitionStore _PhaseDefinitionStore; + SpellPhaseStore _SpellPhaseStore; + private: void LoadScripts(ScriptsType type); void CheckScripts(ScriptsType type, std::set<int32>& ids); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index a37362ce7bc..77d1c05abf2 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -2122,10 +2122,10 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData) FactionEntry const* factionEntry = sFactionStore.LookupEntry(oldReputation); // old base reputation - int32 oldBaseRep = sObjectMgr->GetBaseReputation(factionEntry, oldRace, playerClass); + int32 oldBaseRep = sObjectMgr->GetBaseReputationOff(factionEntry, oldRace, playerClass); // new base reputation - int32 newBaseRep = sObjectMgr->GetBaseReputation(sFactionStore.LookupEntry(newReputation), race, playerClass); + int32 newBaseRep = sObjectMgr->GetBaseReputationOff(sFactionStore.LookupEntry(newReputation), race, playerClass); // final reputation shouldnt change int32 FinalRep = oldDBRep + oldBaseRep; diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 2acc8ffcf7b..1947baa43b6 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1753,10 +1753,51 @@ void WorldSession::HandleReadyForAccountDataTimes(WorldPacket& /*recvData*/) SendAccountDataTimes(GLOBAL_CACHE_MASK); } -void WorldSession::SendSetPhaseShift(uint32 PhaseShift) +void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps) { - WorldPacket data(SMSG_SET_PHASE_SHIFT, 4); - data << uint32(PhaseShift); + ObjectGuid guid = _player->GetGUID(); + + WorldPacket data(SMSG_SET_PHASE_SHIFT, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); + data.WriteBit(guid[2]); + data.WriteBit(guid[3]); + data.WriteBit(guid[1]); + data.WriteBit(guid[6]); + data.WriteBit(guid[4]); + data.WriteBit(guid[5]); + data.WriteBit(guid[0]); + data.WriteBit(guid[7]); + + data.WriteByteSeq(guid[7]); + data.WriteByteSeq(guid[4]); + + data << uint32(0); + //for (uint8 i = 0; i < worldMapAreaCount; ++i) + // data << uint16(0); // WorldMapArea.dbc id (controls map display) + + data.WriteByteSeq(guid[1]); + + data << uint32(0); // flags (not phasemask) + + data.WriteByteSeq(guid[2]); + data.WriteByteSeq(guid[6]); + + data << uint32(0); // Inactive terrain swaps + //for (uint8 i = 0; i < inactiveSwapsCount; ++i) + // data << uint16(0); + + data << uint32(phaseIds.size()) * 2; // Phase.dbc ids + for (std::set<uint32>::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) + data << uint16(*itr); + + data.WriteByteSeq(guid[3]); + data.WriteByteSeq(guid[0]); + + data << uint32(terrainswaps.size()) * 2; // Active terrain swaps + for (std::set<uint32>::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) + data << uint16(*itr); + + data.WriteByteSeq(guid[5]); + SendPacket(&data); } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index d967ece9cf2..f14dc3c8b14 100755 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -450,3 +450,14 @@ void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 credi } } } + +void InstanceScript::UpdatePhasing() +{ + PhaseUpdateData phaseUdateData; + phaseUdateData.AddConditionType(CONDITION_INSTANCE_DATA); + + Map::PlayerList const& players = instance->GetPlayers(); + for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) + if (Player* player = itr->getSource()) + player->GetPhaseMgr().NotifyConditionChanged(phaseUdateData); +} diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index ab37c1ab5e9..291ba3be52f 100755 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -217,6 +217,9 @@ class InstanceScript : public ZoneScript virtual void FillInitialWorldStates(WorldPacket& /*data*/) {} + // ReCheck PhaseTemplate related conditions + void UpdatePhasing(); + protected: void SetBossNumber(uint32 number) { bosses.resize(number); } void LoadDoorData(DoorData const* data); diff --git a/src/server/game/Maps/PhaseMgr.cpp b/src/server/game/Maps/PhaseMgr.cpp new file mode 100644 index 00000000000..63bdff2d094 --- /dev/null +++ b/src/server/game/Maps/PhaseMgr.cpp @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "PhaseMgr.h" +#include "Chat.h" + +////////////////////////////////////////////////////////////////// +// Updating + +PhaseMgr::PhaseMgr(Player* _player) : player(_player), phaseData(_player), _UpdateFlags(0) +{ + _PhaseDefinitionStore = sObjectMgr->GetPhaseDefinitionStore(); + _SpellPhaseStore = sObjectMgr->GetSpellPhaseStore(); +} + +void PhaseMgr::Update() +{ + if (IsUpdateInProgress()) + return; + + if (_UpdateFlags & PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED) + phaseData.SendPhaseshiftToPlayer(); + + if (_UpdateFlags & PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED) + phaseData.SendPhaseMaskToPlayer(); + + _UpdateFlags = 0; +} + +void PhaseMgr::RemoveUpdateFlag(PhaseUpdateFlag updateFlag) +{ + _UpdateFlags &= ~updateFlag; + + if (updateFlag == PHASE_UPDATE_FLAG_ZONE_UPDATE) + { + // Update zone changes + if (phaseData.HasActiveDefinitions()) + { + phaseData.ResetDefinitions(); + _UpdateFlags |= (PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED | PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + } + + if (_PhaseDefinitionStore->find(player->GetZoneId()) != _PhaseDefinitionStore->end()) + Recalculate(); + } + + Update(); +} + +///////////////////////////////////////////////////////////////// +// Notifier + +void PhaseMgr::NotifyConditionChanged(PhaseUpdateData const& updateData) +{ + if (NeedsPhaseUpdateWithData(updateData)) + { + Recalculate(); + Update(); + } +} + +////////////////////////////////////////////////////////////////// +// Phasing Definitions + +void PhaseMgr::Recalculate() +{ + if (phaseData.HasActiveDefinitions()) + { + phaseData.ResetDefinitions(); + _UpdateFlags |= (PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED | PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED); + } + + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr != _PhaseDefinitionStore->end()) + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + if (CheckDefinition(&(*phase))) + { + phaseData.AddPhaseDefinition(&(*phase)); + + if (phase->phasemask) + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + if (phase->phaseId || phase->terrainswapmap) + _UpdateFlags |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + if (phase->IsLastDefinition()) + break; + } +} + +inline bool PhaseMgr::CheckDefinition(PhaseDefinition const* phaseDefinition) +{ + return sConditionMgr->IsObjectMeetToConditions(player, sConditionMgr->GetConditionsForPhaseDefinition(phaseDefinition->zoneId, phaseDefinition->entry)); +} + +bool PhaseMgr::NeedsPhaseUpdateWithData(PhaseUpdateData const updateData) const +{ + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr != _PhaseDefinitionStore->end()) + { + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + { + ConditionList conditionList = sConditionMgr->GetConditionsForPhaseDefinition(phase->zoneId, phase->entry); + for (ConditionList::const_iterator condition = conditionList.begin(); condition != conditionList.end(); ++condition) + if (updateData.IsConditionRelated(*condition)) + return true; + } + } + return false; +} + +////////////////////////////////////////////////////////////////// +// Auras + +void PhaseMgr::RegisterPhasingAuraEffect(AuraEffect const* auraEffect) +{ + PhaseInfo phaseInfo; + + if (auraEffect->GetMiscValue()) + { + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + phaseInfo.phasemask = auraEffect->GetMiscValue(); + } + else + { + SpellPhaseStore::const_iterator itr = _SpellPhaseStore->find(auraEffect->GetId()); + if (itr != _SpellPhaseStore->end()) + { + if (itr->second.phasemask) + { + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + phaseInfo.phasemask = itr->second.phasemask; + } + + if (itr->second.terrainswapmap) + phaseInfo.terrainswapmap = itr->second.terrainswapmap; + } + } + + phaseInfo.phaseId = auraEffect->GetMiscValueB(); + + if (phaseInfo.NeedsClientSideUpdate()) + _UpdateFlags |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + phaseData.AddAuraInfo(auraEffect->GetId(), phaseInfo); + + Update(); +} + +void PhaseMgr::UnRegisterPhasingAuraEffect(AuraEffect const* auraEffect) +{ + _UpdateFlags |= phaseData.RemoveAuraInfo(auraEffect->GetId()); + + Update(); +} + +////////////////////////////////////////////////////////////////// +// Commands + +void PhaseMgr::SendDebugReportToPlayer(Player* const debugger) +{ + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_REPORT_STATUS, player->GetName(), player->GetZoneId(), player->getLevel(), player->GetTeamId(), _UpdateFlags); + + PhaseDefinitionStore::const_iterator itr = _PhaseDefinitionStore->find(player->GetZoneId()); + if (itr == _PhaseDefinitionStore->end()) + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_NO_DEFINITIONS, player->GetZoneId()); + else + { + for (PhaseDefinitionContainer::const_iterator phase = itr->second.begin(); phase != itr->second.end(); ++phase) + { + if (CheckDefinition(&(*phase))) + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_SUCCESS, phase->entry, phase->IsNegatingPhasemask() ? "negated Phase" : "Phase", phase->phasemask); + else + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_FAILED, phase->phasemask, phase->entry, phase->zoneId); + + if (phase->IsLastDefinition()) + { + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_LAST_PHASE, phase->phasemask, phase->entry, phase->zoneId); + break; + } + } + } + + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_LIST, phaseData._PhasemaskThroughDefinitions, phaseData._PhasemaskThroughAuras, phaseData._CustomPhasemask); + + ChatHandler(debugger).PSendSysMessage(LANG_PHASING_PHASEMASK, phaseData.GetPhaseMaskForSpawn(), player->GetPhaseMask()); +} + +void PhaseMgr::SetCustomPhase(uint32 const phaseMask) +{ + phaseData._CustomPhasemask = phaseMask; + + _UpdateFlags |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + Update(); +} + +////////////////////////////////////////////////////////////////// +// Phase Data + +uint32 PhaseData::GetCurrentPhasemask() const +{ + if (player->isGameMaster()) + return PHASEMASK_ANYWHERE; + + if (_CustomPhasemask) + return _CustomPhasemask; + + return GetPhaseMaskForSpawn(); +} + +inline uint32 PhaseData::GetPhaseMaskForSpawn() const +{ + uint32 const phase = (_PhasemaskThroughDefinitions | _PhasemaskThroughAuras); + return (phase ? phase : PHASEMASK_NORMAL); +} + +void PhaseData::SendPhaseMaskToPlayer() +{ + // Server side update + uint32 const phasemask = GetCurrentPhasemask(); + if (player->GetPhaseMask() == phasemask) + return; + + player->SetPhaseMask(phasemask, false); + + if (player->IsVisible()) + player->UpdateObjectVisibility(); +} + +void PhaseData::SendPhaseshiftToPlayer() +{ + // Client side update + std::set<uint32> phaseIds; + std::set<uint32> terrainswaps; + + for (PhaseInfoContainer::const_iterator itr = spellPhaseInfo.begin(); itr != spellPhaseInfo.end(); ++itr) + { + if (itr->second.terrainswapmap) + terrainswaps.insert(itr->second.terrainswapmap); + + if (itr->second.phaseId) + phaseIds.insert(itr->second.phaseId); + } + + // Phase Definitions + for (std::list<PhaseDefinition const*>::const_iterator itr = activePhaseDefinitions.begin(); itr != activePhaseDefinitions.end(); ++itr) + { + if ((*itr)->phaseId) + phaseIds.insert((*itr)->phaseId); + + if ((*itr)->terrainswapmap) + terrainswaps.insert((*itr)->terrainswapmap); + } + + player->GetSession()->SendSetPhaseShift(phaseIds, terrainswaps); +} + +void PhaseData::AddPhaseDefinition(PhaseDefinition const* phaseDefinition) +{ + if (phaseDefinition->IsOverwritingExistingPhases()) + { + activePhaseDefinitions.clear(); + _PhasemaskThroughDefinitions = phaseDefinition->phasemask; + } + else + { + if (phaseDefinition->IsNegatingPhasemask()) + _PhasemaskThroughDefinitions &= ~phaseDefinition->phasemask; + else + _PhasemaskThroughDefinitions |= phaseDefinition->phasemask; + } + + activePhaseDefinitions.push_back(phaseDefinition); +} + +void PhaseData::AddAuraInfo(uint32 const spellId, PhaseInfo phaseInfo) +{ + if (phaseInfo.phasemask) + _PhasemaskThroughAuras |= phaseInfo.phasemask; + + spellPhaseInfo[spellId] = phaseInfo; +} + +uint32 PhaseData::RemoveAuraInfo(uint32 const spellId) +{ + PhaseInfoContainer::const_iterator rAura = spellPhaseInfo.find(spellId); + if (rAura != spellPhaseInfo.end()) + { + uint32 updateflag = 0; + + if (rAura->second.NeedsClientSideUpdate()) + updateflag |= PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED; + + if (rAura->second.NeedsServerSideUpdate()) + { + _PhasemaskThroughAuras = 0; + + updateflag |= PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED; + + spellPhaseInfo.erase(rAura); + + for (PhaseInfoContainer::const_iterator itr = spellPhaseInfo.begin(); itr != spellPhaseInfo.end(); ++itr) + _PhasemaskThroughAuras |= itr->second.phasemask; + } + + return updateflag; + } + else + return 0; +} + +////////////////////////////////////////////////////////////////// +// Phase Update Data + +void PhaseUpdateData::AddQuestUpdate(uint32 const questId) +{ + AddConditionType(CONDITION_QUESTREWARDED); + AddConditionType(CONDITION_QUESTTAKEN); + AddConditionType(CONDITION_QUEST_COMPLETE); + AddConditionType(CONDITION_QUEST_NONE); + + _questId = questId; +} + +bool PhaseUpdateData::IsConditionRelated(Condition const* condition) const +{ + switch (condition->ConditionType) + { + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + case CONDITION_QUEST_COMPLETE: + case CONDITION_QUEST_NONE: + return condition->ConditionValue1 == _questId && ((1 << condition->ConditionType) & _conditionTypeFlags); + default: + return (1 << condition->ConditionType) & _conditionTypeFlags; + } +} + +bool PhaseMgr::IsConditionTypeSupported(ConditionTypes const conditionType) +{ + switch (conditionType) + { + case CONDITION_QUESTREWARDED: + case CONDITION_QUESTTAKEN: + case CONDITION_QUEST_COMPLETE: + case CONDITION_QUEST_NONE: + case CONDITION_TEAM: + case CONDITION_CLASS: + case CONDITION_RACE: + case CONDITION_INSTANCE_DATA: + case CONDITION_LEVEL: + return true; + default: + return false; + } +} diff --git a/src/server/game/Maps/PhaseMgr.h b/src/server/game/Maps/PhaseMgr.h new file mode 100644 index 00000000000..accb0cd3ea8 --- /dev/null +++ b/src/server/game/Maps/PhaseMgr.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITY_PHASEMGR_H +#define TRINITY_PHASEMGR_H + +#include "SharedDefines.h" +#include "SpellAuras.h" +#include "SpellAuraEffects.h" + +class ObjectMgr; +class Player; + +// Phasing (visibility) +enum PhasingFlags +{ + PHASE_FLAG_OVERWRITE_EXISTING = 0x01, // don't stack with existing phases, overwrites existing phases + PHASE_FLAG_NO_MORE_PHASES = 0x02, // stop calculating phases after this phase was applied (no more phases will be applied) + PHASE_FLAG_NEGATE_PHASE = 0x04 // negate instead to add the phasemask +}; + +enum PhaseUpdateFlag +{ + PHASE_UPDATE_FLAG_ZONE_UPDATE = 0x01, + PHASE_UPDATE_FLAG_AREA_UPDATE = 0x02, + + // Internal flags + PHASE_UPDATE_FLAG_CLIENTSIDE_CHANGED = 0x08, + PHASE_UPDATE_FLAG_SERVERSIDE_CHANGED = 0x10, +}; + +struct PhaseDefinition +{ + uint32 zoneId; + uint32 entry; + uint32 phasemask; + uint32 phaseId; + uint32 terrainswapmap; + uint8 flags; + + bool IsOverwritingExistingPhases() const { return flags & PHASE_FLAG_OVERWRITE_EXISTING; } + bool IsLastDefinition() const { return flags & PHASE_FLAG_NO_MORE_PHASES; } + bool IsNegatingPhasemask() const { return flags & PHASE_FLAG_NEGATE_PHASE; } +}; + +typedef std::list<PhaseDefinition> PhaseDefinitionContainer; +typedef UNORDERED_MAP<uint32 /*zoneId*/, PhaseDefinitionContainer> PhaseDefinitionStore; + +struct SpellPhaseInfo +{ + uint32 spellId; + uint32 phasemask; + uint32 terrainswapmap; +}; + +typedef UNORDERED_MAP<uint32 /*spellId*/, SpellPhaseInfo> SpellPhaseStore; + +struct PhaseInfo +{ + PhaseInfo() : phasemask(0), terrainswapmap(0), phaseId(0) {} + + uint32 phasemask; + uint32 terrainswapmap; + uint32 phaseId; + + bool NeedsServerSideUpdate() const { return phasemask; } + bool NeedsClientSideUpdate() const { return terrainswapmap || phaseId; } +}; + +typedef UNORDERED_MAP<uint32 /*spellId*/, PhaseInfo> PhaseInfoContainer; + +struct PhaseData +{ + PhaseData(Player* _player) : player(_player), _PhasemaskThroughDefinitions(0), _PhasemaskThroughAuras(0), _CustomPhasemask(0) {} + + uint32 _PhasemaskThroughDefinitions; + uint32 _PhasemaskThroughAuras; + uint32 _CustomPhasemask; + + uint32 GetCurrentPhasemask() const; + inline uint32 GetPhaseMaskForSpawn() const; + + void ResetDefinitions() { _PhasemaskThroughDefinitions = 0; activePhaseDefinitions.clear(); } + void AddPhaseDefinition(PhaseDefinition const* phaseDefinition); + bool HasActiveDefinitions() const { return !activePhaseDefinitions.empty(); } + + void AddAuraInfo(uint32 const spellId, PhaseInfo phaseInfo); + uint32 RemoveAuraInfo(uint32 const spellId); + + void SendPhaseMaskToPlayer(); + void SendPhaseshiftToPlayer(); + +private: + Player* player; + std::list<PhaseDefinition const*> activePhaseDefinitions; + PhaseInfoContainer spellPhaseInfo; +}; + +struct PhaseUpdateData +{ + void AddConditionType(ConditionTypes const conditionType) { _conditionTypeFlags |= (1 << conditionType); } + void AddQuestUpdate(uint32 const questId); + + bool IsConditionRelated(Condition const* condition) const; + +private: + uint32 _conditionTypeFlags; + uint32 _questId; +}; + +class PhaseMgr +{ +public: + PhaseMgr(Player* _player); + ~PhaseMgr() {} + + uint32 GetCurrentPhasemask() { return phaseData.GetCurrentPhasemask(); }; + inline uint32 GetPhaseMaskForSpawn() { return phaseData.GetCurrentPhasemask(); } + + // Phase definitions update handling + void NotifyConditionChanged(PhaseUpdateData const& updateData); + void NotifyStoresReloaded() { Recalculate(); Update(); } + + void Update(); + + // Aura phase effects + void RegisterPhasingAuraEffect(AuraEffect const* auraEffect); + void UnRegisterPhasingAuraEffect(AuraEffect const* auraEffect); + + // Update flags (delayed phasing) + void AddUpdateFlag(PhaseUpdateFlag const updateFlag) { _UpdateFlags |= updateFlag; } + void RemoveUpdateFlag(PhaseUpdateFlag const updateFlag); + + // Needed for modify phase command + void SetCustomPhase(uint32 const phaseMask); + + // Debug + void SendDebugReportToPlayer(Player* const debugger); + + static bool IsConditionTypeSupported(ConditionTypes const conditionType); + +private: + void Recalculate(); + + inline bool CheckDefinition(PhaseDefinition const* phaseDefinition); + + bool NeedsPhaseUpdateWithData(PhaseUpdateData const updateData) const; + + inline bool IsUpdateInProgress() const { return (_UpdateFlags & PHASE_UPDATE_FLAG_ZONE_UPDATE) || (_UpdateFlags & PHASE_UPDATE_FLAG_AREA_UPDATE); } + + PhaseDefinitionStore const* _PhaseDefinitionStore; + SpellPhaseStore const* _SpellPhaseStore; + + Player* player; + PhaseData phaseData; + uint8 _UpdateFlags; +}; + +#endif diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index 5893bbd6564..c55c57481f4 100755 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -174,7 +174,15 @@ enum TrinityStrings LANG_YOU_CHANGE_RUNIC_POWER = 173, LANG_YOURS_RUNIC_POWER_CHANGED = 174, LANG_LIQUID_STATUS = 175, - // Room for more level 1 176-199 not used + + LANG_PHASING_REPORT_STATUS = 176, + LANG_PHASING_NO_DEFINITIONS = 177, // Phasing + LANG_PHASING_SUCCESS = 178, + LANG_PHASING_FAILED = 179, + LANG_PHASING_LAST_PHASE = 180, + LANG_PHASING_LIST = 181, + LANG_PHASING_PHASEMASK = 182, + // Room for more level 1 183-199 not used // level 2 chat LANG_NO_SELECTION = 200, diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 5b6af4b2de8..694b2cf2d7f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1157,7 +1157,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER(SMSG_SET_FLAT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_SET_FORCED_REACTIONS, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - DEFINE_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); + DEFINE_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index e6c13557076..5c61385f537 100755 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -253,7 +253,7 @@ class WorldSession void SendPetNameInvalid(uint32 error, const std::string& name, DeclinedName *declinedName); void SendPartyResult(PartyOperation operation, const std::string& member, PartyResult res, uint32 val = 0); void SendAreaTriggerMessage(const char* Text, ...) ATTR_PRINTF(2, 3); - void SendSetPhaseShift(uint32 phaseShift); + void SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps); void SendQueryTimeResponse(); void SendAuthResponse(uint8 code, bool queued, uint32 queuePos = 0); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 28ddaf05afc..d70c68b9be2 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1808,27 +1808,21 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app Unit* target = aurApp->GetTarget(); - // no-phase is also phase state so same code for apply and remove - uint32 newPhase = 0; - Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE); - if (!phases.empty()) - for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) - newPhase |= (*itr)->GetMiscValue(); - if (Player* player = target->ToPlayer()) { - if (!newPhase) - newPhase = PHASEMASK_NORMAL; - - // GM-mode have mask 0xFFFFFFFF - if (player->isGameMaster()) - newPhase = 0xFFFFFFFF; - - player->SetPhaseMask(newPhase, false); - player->GetSession()->SendSetPhaseShift(newPhase); + if (apply) + player->GetPhaseMgr().RegisterPhasingAuraEffect(this); + else + player->GetPhaseMgr().UnRegisterPhasingAuraEffect(this); } else { + uint32 newPhase = 0; + Unit::AuraEffectList const& phases = target->GetAuraEffectsByType(SPELL_AURA_PHASE); + if (!phases.empty()) + for (Unit::AuraEffectList::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + newPhase |= (*itr)->GetMiscValue(); + if (!newPhase) { newPhase = PHASEMASK_NORMAL; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c092776bc14..04a371ba776 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5655,7 +5655,7 @@ SpellCastResult Spell::CheckCasterAuras() const break; } } - if (foundNotStun) + if (foundNotStun && m_spellInfo->Id != 22812) prevented_reason = SPELL_FAILED_STUNNED; } else diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index ab6c2b1df8b..eb5c26a1c71 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -3514,6 +3514,10 @@ void SpellMgr::LoadDbcDataCorrections() case 71085: // Mana Void (periodic aura) spellInfo->DurationIndex = 9; // 30 seconds (missing) break; + case 72015: // Frostbolt Volley (only heroic) + case 72016: // Frostbolt Volley (only heroic) + spellInfo->EffectRadiusIndex[2] = EFFECT_RADIUS_40_YARDS; + break; case 70936: // Summon Suppressor (needs target selection script) spellInfo->EffectImplicitTargetA[0] = TARGET_UNIT_TARGET_ANY; spellInfo->EffectImplicitTargetB[0] = 0; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 94961b7b930..371668e73d9 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1368,6 +1368,9 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Spell Group Stack Rules..."); sSpellMgr->LoadSpellGroupStackRules(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Spell Phase Dbc Info..."); + sObjectMgr->LoadSpellPhaseInfo(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading NPC Texts..."); sObjectMgr->LoadGossipText(); @@ -1616,6 +1619,9 @@ void World::SetInitialWorldSettings() sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions LoadWorldStates(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Phase definitions..."); + sObjectMgr->LoadPhaseDefinitions(); + sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Loading Conditions..."); sConditionMgr->LoadConditions(); @@ -3022,3 +3028,11 @@ CharacterNameData const* World::GetCharacterNameData(uint32 guid) const else return NULL; } + +void World::UpdatePhaseDefinitions() +{ + SessionMap::const_iterator itr; + for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + if (itr->second && itr->second->GetPlayer() && itr->second->GetPlayer()->IsInWorld()) + itr->second->GetPlayer()->GetPhaseMgr().NotifyStoresReloaded(); +} diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 33ec159ec81..e1465f4897d 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -784,6 +784,8 @@ class World uint32 GetCleaningFlags() const { return m_CleaningFlags; } void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; } void ResetEventSeasonalQuests(uint16 event_id); + + void UpdatePhaseDefinitions(); protected: void _UpdateGameTime(); // callback for UpdateRealmCharacters diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 67b4d780942..363258648f6 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -90,6 +90,7 @@ public: { "areatriggers", SEC_ADMINISTRATOR, false, &HandleDebugAreaTriggersCommand, "", NULL }, { "los", SEC_MODERATOR, false, &HandleDebugLoSCommand, "", NULL }, { "moveflags", SEC_ADMINISTRATOR, false, &HandleDebugMoveflagsCommand, "", NULL }, + { "phase", SEC_MODERATOR, false, &HandleDebugPhaseCommand, "", NULL }, { NULL, SEC_PLAYER, false, NULL, "", NULL } }; static ChatCommand commandTable[] = @@ -948,8 +949,21 @@ public: if (!*args) return false; - uint32 PhaseShift = atoi(args); - handler->GetSession()->SendSetPhaseShift(PhaseShift); + char* t = strtok((char*)args, " "); + char* p = strtok(NULL, " "); + + if (!t) + return false; + + std::set<uint32> terrainswap; + std::set<uint32> phaseId; + + terrainswap.insert((uint32)atoi(t)); + + if (p) + phaseId.insert((uint32)atoi(p)); + + handler->GetSession()->SendSetPhaseShift(phaseId, terrainswap); return true; } @@ -1330,6 +1344,17 @@ public: handler->PSendSysMessage("Waypoint SQL written to SQL Developer log"); return true; } + + static bool HandleDebugPhaseCommand(ChatHandler* handler, char const* args) + { + Unit* unit = handler->getSelectedUnit(); + Player* player = handler->GetSession()->GetPlayer(); + if(unit && unit->GetTypeId() == TYPEID_PLAYER) + player = unit->ToPlayer(); + + player->GetPhaseMgr().SendDebugReportToPlayer(handler->GetSession()->GetPlayer()); + return true; + } }; void AddSC_debug_commandscript() diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 6803354d29b..fd24e618ef0 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -149,7 +149,7 @@ public: GameObject* object = new GameObject; uint32 guidLow = sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT); - if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMgr().GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) { delete object; return false; @@ -162,7 +162,7 @@ public: } // fill the gameobject data and save to the db - object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMaskForSpawn()); + object->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), player->GetPhaseMgr().GetPhaseMaskForSpawn()); // this will generate a new guid if the object is in an instance if (!object->LoadGameObjectFromDB(guidLow, map)) diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index f527d7fb275..9f13dd00fb8 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1003,15 +1003,19 @@ public: if (handler->HasLowerSecurity(target, 0)) return false; - int32 addmoney = atoi((char*)args); + int64 moneyToAdd = 0; + if (strchr(args, 'g') || strchr(args, 's') || strchr(args, 'c')) + moneyToAdd = MoneyStringToMoney(std::string(args)); + else + moneyToAdd = atol(args); - uint64 moneyuser = target->GetMoney(); + uint64 targetMoney = target->GetMoney(); - if (addmoney < 0) + if (moneyToAdd < 0) { - int64 newmoney = int32(moneyuser) + addmoney; + int64 newmoney = int64(targetMoney) + moneyToAdd; - sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_CURRENT_MONEY), moneyuser, addmoney, newmoney); + sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_CURRENT_MONEY), uint32(targetMoney), int32(moneyToAdd), uint32(newmoney)); if (newmoney <= 0) { handler->PSendSysMessage(LANG_YOU_TAKE_ALL_MONEY, handler->GetNameLink(target).c_str()); @@ -1025,25 +1029,26 @@ public: if (newmoney > MAX_MONEY_AMOUNT) newmoney = MAX_MONEY_AMOUNT; - handler->PSendSysMessage(LANG_YOU_TAKE_MONEY, abs(addmoney), handler->GetNameLink(target).c_str()); + handler->PSendSysMessage(LANG_YOU_TAKE_MONEY, uint32(abs(moneyToAdd)), handler->GetNameLink(target).c_str()); if (handler->needReportToTarget(target)) - (ChatHandler(target)).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, handler->GetNameLink().c_str(), abs(addmoney)); + (ChatHandler(target)).PSendSysMessage(LANG_YOURS_MONEY_TAKEN, handler->GetNameLink().c_str(), uint32(abs(moneyToAdd))); target->SetMoney(newmoney); } } else { - handler->PSendSysMessage(LANG_YOU_GIVE_MONEY, uint32(addmoney), handler->GetNameLink(target).c_str()); + handler->PSendSysMessage(LANG_YOU_GIVE_MONEY, uint32(moneyToAdd), handler->GetNameLink(target).c_str()); if (handler->needReportToTarget(target)) - (ChatHandler(target)).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, handler->GetNameLink().c_str(), uint32(addmoney)); + (ChatHandler(target)).PSendSysMessage(LANG_YOURS_MONEY_GIVEN, handler->GetNameLink().c_str(), uint32(moneyToAdd)); - if (addmoney >=MAX_MONEY_AMOUNT) + if (moneyToAdd >= MAX_MONEY_AMOUNT) target->SetMoney(MAX_MONEY_AMOUNT); else - target->ModifyMoney(int64(addmoney)); + target->ModifyMoney(moneyToAdd); } - sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_NEW_MONEY), moneyuser, uint32(addmoney), target->GetMoney()); + sLog->outDebug(LOG_FILTER_GENERAL, handler->GetTrinityString(LANG_NEW_MONEY), uint32(targetMoney), int32(moneyToAdd), uint32(target->GetMoney())); + return true; } @@ -1272,14 +1277,15 @@ public: uint32 phasemask = (uint32)atoi((char*)args); Unit* target = handler->getSelectedUnit(); - if (!target) - target = handler->GetSession()->GetPlayer(); - - // check online security - else if (target->GetTypeId() == TYPEID_PLAYER && handler->HasLowerSecurity(target->ToPlayer(), 0)) - return false; - - target->SetPhaseMask(phasemask, true); + if (target) + { + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->GetPhaseMgr().SetCustomPhase(phasemask); + else + target->SetPhaseMask(phasemask, true); + } + else + handler->GetSession()->GetPlayer()->GetPhaseMgr().SetCustomPhase(phasemask); return true; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index e43760191df..30713728cf6 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -151,13 +151,13 @@ public: } Creature* creature = new Creature(); - if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o)) + if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, (uint32)teamval, x, y, z, o)) { delete creature; return false; } - creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn()); uint32 db_guid = creature->GetDBTableGUIDLow(); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index ce0141290ff..14481884ec8 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -115,6 +115,7 @@ public: { "npc_trainer", SEC_ADMINISTRATOR, true, &HandleReloadNpcTrainerCommand, "", NULL }, { "npc_vendor", SEC_ADMINISTRATOR, true, &HandleReloadNpcVendorCommand, "", NULL }, { "page_text", SEC_ADMINISTRATOR, true, &HandleReloadPageTextsCommand, "", NULL }, + { "phasedefinitions", SEC_ADMINISTRATOR, true, &HandleReloadPhaseDefinitionsCommand, "", NULL }, { "pickpocketing_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesPickpocketingCommand, "", NULL}, { "points_of_interest", SEC_ADMINISTRATOR, true, &HandleReloadPointsOfInterestCommand, "", NULL }, { "prospecting_loot_template", SEC_ADMINISTRATOR, true, &HandleReloadLootTemplatesProspectingCommand, "", NULL }, @@ -1250,6 +1251,15 @@ public: handler->SendGlobalGMSysMessage("Vehicle template accessories reloaded."); return true; } + + static bool HandleReloadPhaseDefinitionsCommand(ChatHandler* handler, const char* /*args*/) + { + sLog->outInfo(LOG_FILTER_GENERAL, "Reloading phase_definitions table..."); + sObjectMgr->LoadPhaseDefinitions(); + sWorld->UpdatePhaseDefinitions(); + handler->SendGlobalGMSysMessage("Phase Definitions reloaded."); + return true; + } }; void AddSC_reload_commandscript() diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index e3cd185e4a3..05226fb55aa 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -688,7 +688,7 @@ public: } // re-create Creature* wpCreature2 = new Creature; - if (!wpCreature2->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) + if (!wpCreature2->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), VISUAL_WAYPOINT, 0, 0, chr->GetPositionX(), chr->GetPositionY(), chr->GetPositionZ(), chr->GetOrientation())) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, VISUAL_WAYPOINT); delete wpCreature2; @@ -696,7 +696,7 @@ public: return false; } - wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); //TODO: Should we first use "Create" then use "LoadFromDB"? if (!wpCreature2->LoadCreatureFromDB(wpCreature2->GetDBTableGUIDLow(), map)) @@ -912,7 +912,7 @@ public: float o = chr->GetOrientation(); Creature* wpCreature = new Creature; - if (!wpCreature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + if (!wpCreature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete wpCreature; @@ -928,7 +928,7 @@ public: WorldDatabase.Execute(stmt); - wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + wpCreature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); if (!wpCreature->LoadCreatureFromDB(wpCreature->GetDBTableGUIDLow(), map)) { @@ -976,14 +976,14 @@ public: Map* map = chr->GetMap(); Creature* creature = new Creature; - if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); delete creature; return false; } - creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) { handler->PSendSysMessage(LANG_WAYPOINT_VP_NOTCREATED, id); @@ -1025,14 +1025,14 @@ public: Map* map = chr->GetMap(); Creature* creature = new Creature; - if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) + if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, chr->GetPhaseMgr().GetPhaseMaskForSpawn(), id, 0, 0, x, y, z, o)) { handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); delete creature; return false; } - creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMaskForSpawn()); + creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMgr().GetPhaseMaskForSpawn()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) { handler->PSendSysMessage(LANG_WAYPOINT_NOTCREATED, id); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 0508d95a60b..ef810b50b6f 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -1844,7 +1844,7 @@ class spell_item_unusual_compass : public SpellScriptLoader { Unit* caster = GetCaster(); caster->SetOrientation(frand(0.0f, 62832.0f) / 10000.0f); - caster->SendMovementFlagUpdate(); + caster->SendMovementFlagUpdate(true); } void Register() diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 23f09a88911..8b1fe6f38ba 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -31,7 +31,7 @@ enum ShamanSpells { SHAMAN_SPELL_GLYPH_OF_MANA_TIDE = 55441, SHAMAN_SPELL_MANA_TIDE_TOTEM = 39609, - SHAMAN_SPELL_FIRE_NOVA_R1 = 1535, + SHAMAN_SPELL_FLAME_SHOCK = 8050, SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1 = 8349, SHAMAN_SPELL_SATED = 57724, SHAMAN_SPELL_EXHAUSTION = 57723, @@ -52,51 +52,8 @@ enum ShamanSpells SHAMAN_LAVA_FLOWS_TRIGGERED_R1 = 64694, }; -// 51474 - Astral shift -class spell_sha_astral_shift : public SpellScriptLoader -{ - public: - spell_sha_astral_shift() : SpellScriptLoader("spell_sha_astral_shift") { } - - class spell_sha_astral_shift_AuraScript : public AuraScript - { - PrepareAuraScript(spell_sha_astral_shift_AuraScript); - - uint32 absorbPct; - - bool Load() - { - absorbPct = GetSpellInfo()->Effects[EFFECT_0].CalcValue(GetCaster()); - return true; - } - - void CalculateAmount(AuraEffect const* /*aurEff*/, int32 & amount, bool & /*canBeRecalculated*/) - { - // Set absorbtion amount to unlimited - amount = -1; - } - - void Absorb(AuraEffect* /*aurEff*/, DamageInfo & dmgInfo, uint32 & absorbAmount) - { - // reduces all damage taken while stun, fear or silence - if (GetTarget()->GetUInt32Value(UNIT_FIELD_FLAGS) & (UNIT_FLAG_FLEEING | UNIT_FLAG_SILENCED) || (GetTarget()->GetUInt32Value(UNIT_FIELD_FLAGS) & (UNIT_FLAG_STUNNED) && GetTarget()->HasAuraWithMechanic(1<<MECHANIC_STUN))) - absorbAmount = CalculatePct(dmgInfo.GetDamage(), absorbPct); - } - - void Register() - { - DoEffectCalcAmount += AuraEffectCalcAmountFn(spell_sha_astral_shift_AuraScript::CalculateAmount, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB); - OnEffectAbsorb += AuraEffectAbsorbFn(spell_sha_astral_shift_AuraScript::Absorb, EFFECT_0); - } - }; - - AuraScript* GetAuraScript() const - { - return new spell_sha_astral_shift_AuraScript(); - } -}; - // 1535 Fire Nova +/// Updated 4.3.4 class spell_sha_fire_nova : public SpellScriptLoader { public: @@ -106,46 +63,21 @@ class spell_sha_fire_nova : public SpellScriptLoader { PrepareSpellScript(spell_sha_fire_nova_SpellScript); - bool Validate(SpellInfo const* spellEntry) - { - if (!sSpellMgr->GetSpellInfo(SHAMAN_SPELL_FIRE_NOVA_R1) || sSpellMgr->GetFirstSpellInChain(SHAMAN_SPELL_FIRE_NOVA_R1) != sSpellMgr->GetFirstSpellInChain(spellEntry->Id)) - return false; - - uint8 rank = sSpellMgr->GetSpellRank(spellEntry->Id); - if (!sSpellMgr->GetSpellWithRank(SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, rank, true)) - return false; - return true; - } - - SpellCastResult CheckFireTotem() - { - // fire totem - if (!GetCaster()->m_SummonSlot[1]) - { - SetCustomCastResultMessage(SPELL_CUSTOM_ERROR_MUST_HAVE_FIRE_TOTEM); - return SPELL_FAILED_CUSTOM_ERROR; - } - - return SPELL_CAST_OK; - } - void HandleDummy(SpellEffIndex /*effIndex*/) { - if (Unit* caster = GetCaster()) + Unit* caster = GetCaster(); + if (Unit* target = GetHitUnit()) { - uint8 rank = sSpellMgr->GetSpellRank(GetSpellInfo()->Id); - if (uint32 spellId = sSpellMgr->GetSpellWithRank(SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, rank)) + if (target->HasAura(SHAMAN_SPELL_FLAME_SHOCK)) { - Creature* totem = caster->GetMap()->GetCreature(caster->m_SummonSlot[1]); - if (totem && totem->isTotem()) - caster->CastSpell(totem, spellId, true); + caster->CastSpell(target, SHAMAN_SPELL_FIRE_NOVA_TRIGGERED_R1, true); + target->RemoveAurasDueToSpell(SHAMAN_SPELL_FLAME_SHOCK); } } } void Register() { - OnCheckCast += SpellCheckCastFn(spell_sha_fire_nova_SpellScript::CheckFireTotem); OnEffectHitTarget += SpellEffectFn(spell_sha_fire_nova_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; @@ -757,7 +689,6 @@ class spell_sha_sentry_totem : public SpellScriptLoader void AddSC_shaman_spell_scripts() { - new spell_sha_astral_shift(); new spell_sha_fire_nova(); new spell_sha_mana_tide_totem(); new spell_sha_earthbind_totem(); diff --git a/src/server/scripts/Spells/spell_warlock.cpp b/src/server/scripts/Spells/spell_warlock.cpp index e7cca8fed36..42296154634 100644 --- a/src/server/scripts/Spells/spell_warlock.cpp +++ b/src/server/scripts/Spells/spell_warlock.cpp @@ -40,11 +40,16 @@ enum WarlockSpells WARLOCK_HAUNT = 48181, WARLOCK_HAUNT_HEAL = 48210, WARLOCK_UNSTABLE_AFFLICTION_DISPEL = 31117, - WARLOCK_CURSE_OF_DOOM_EFFECT = 18662, + WARLOCK_BANE_OF_DOOM_EFFECT = 18662, WARLOCK_IMPROVED_HEALTH_FUNNEL_R1 = 18703, WARLOCK_IMPROVED_HEALTH_FUNNEL_R2 = 18704, WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R1 = 60955, WARLOCK_IMPROVED_HEALTH_FUNNEL_BUFF_R2 = 60956, + WARLOCK_SOULSHATTER = 32835, + WARLOCK_LIFE_TAP_ENERGIZE = 31818, + WARLOCK_LIFE_TAP_ENERGIZE_2 = 32553, + WARLOCK_IMPROVED_LIFE_TAP_ICON_ID = 208, + WARLOCK_MANA_FEED_ICON_ID = 1982, }; /// Updated 4.3.4 @@ -244,6 +249,7 @@ uint32 const spell_warl_create_healthstone::spell_warl_create_healthstone_SpellS }; // 47422 Everlasting Affliction +/// Updated 4.3.4 class spell_warl_everlasting_affliction : public SpellScriptLoader { public: @@ -273,6 +279,8 @@ class spell_warl_everlasting_affliction : public SpellScriptLoader } }; +// 27285 Seed of Corruption +/// Updated 4.3.4 class spell_warl_seed_of_corruption : public SpellScriptLoader { public: @@ -300,11 +308,8 @@ class spell_warl_seed_of_corruption : public SpellScriptLoader } }; -enum Soulshatter -{ - SPELL_SOULSHATTER = 32835, -}; - +// 29858 Soulshatter +/// Updated 4.3.4 class spell_warl_soulshatter : public SpellScriptLoader { public: @@ -316,7 +321,7 @@ class spell_warl_soulshatter : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_SOULSHATTER)) + if (!sSpellMgr->GetSpellInfo(WARLOCK_SOULSHATTER)) return false; return true; } @@ -325,10 +330,8 @@ class spell_warl_soulshatter : public SpellScriptLoader { Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) - { if (target->CanHaveThreatList() && target->getThreatManager().getThreat(caster) > 0.0f) - caster->CastSpell(target, SPELL_SOULSHATTER, true); - } + caster->CastSpell(target, WARLOCK_SOULSHATTER, true); } void Register() @@ -343,14 +346,8 @@ class spell_warl_soulshatter : public SpellScriptLoader } }; -enum LifeTap -{ - SPELL_LIFE_TAP_ENERGIZE = 31818, - SPELL_LIFE_TAP_ENERGIZE_2 = 32553, - ICON_ID_IMPROVED_LIFE_TAP = 208, - ICON_ID_MANA_FEED = 1982, -}; - +// 1454 Life Tap +/// Updated 4.3.4 class spell_warl_life_tap : public SpellScriptLoader { public: @@ -367,7 +364,7 @@ class spell_warl_life_tap : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(SPELL_LIFE_TAP_ENERGIZE) || !sSpellMgr->GetSpellInfo(SPELL_LIFE_TAP_ENERGIZE_2)) + if (!sSpellMgr->GetSpellInfo(WARLOCK_LIFE_TAP_ENERGIZE) || !sSpellMgr->GetSpellInfo(WARLOCK_LIFE_TAP_ENERGIZE_2)) return false; return true; } @@ -377,34 +374,31 @@ class spell_warl_life_tap : public SpellScriptLoader Player* caster = GetCaster()->ToPlayer(); if (Unit* target = GetHitUnit()) { - int32 damage = GetEffectValue(); - int32 mana = int32(damage + (caster->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+SPELL_SCHOOL_SHADOW) * 0.5f)); + int32 damage = caster->CountPctFromMaxHealth(GetSpellInfo()->Effects[EFFECT_2].CalcValue()); + int32 mana = CalculatePct(damage, GetSpellInfo()->Effects[EFFECT_1].CalcValue()); // Shouldn't Appear in Combat Log target->ModifyHealth(-damage); // Improved Life Tap mod - if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, ICON_ID_IMPROVED_LIFE_TAP, 0)) + if (AuraEffect const* aurEff = caster->GetDummyAuraEffect(SPELLFAMILY_WARLOCK, WARLOCK_IMPROVED_LIFE_TAP_ICON_ID, 0)) AddPct(mana, aurEff->GetAmount()); - caster->CastCustomSpell(target, SPELL_LIFE_TAP_ENERGIZE, &mana, NULL, NULL, false); + caster->CastCustomSpell(target, WARLOCK_LIFE_TAP_ENERGIZE, &mana, NULL, NULL, false); // Mana Feed - int32 manaFeedVal = 0; - if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, ICON_ID_MANA_FEED, 0)) - manaFeedVal = aurEff->GetAmount(); - - if (manaFeedVal > 0) + if (AuraEffect const* aurEff = caster->GetAuraEffect(SPELL_AURA_ADD_FLAT_MODIFIER, SPELLFAMILY_WARLOCK, WARLOCK_MANA_FEED_ICON_ID, 0)) { + int32 manaFeedVal = aurEff->GetAmount(); ApplyPct(manaFeedVal, mana); - caster->CastCustomSpell(caster, SPELL_LIFE_TAP_ENERGIZE_2, &manaFeedVal, NULL, NULL, true, NULL); + caster->CastCustomSpell(caster, WARLOCK_LIFE_TAP_ENERGIZE_2, &manaFeedVal, NULL, NULL, true, NULL); } } } SpellCastResult CheckCast() { - if ((int32(GetCaster()->GetHealth()) > int32(GetSpellInfo()->Effects[EFFECT_0].CalcValue() + (6.3875 * GetSpellInfo()->BaseLevel)))) + if (int32(GetCaster()->GetHealth()) > int32(GetCaster()->CountPctFromMaxHealth(GetSpellInfo()->Effects[EFFECT_2].CalcValue()))) return SPELL_CAST_OK; return SPELL_FAILED_FIZZLE; } @@ -422,6 +416,8 @@ class spell_warl_life_tap : public SpellScriptLoader } }; +// 48018 Demonic Circle: Summon +/// Updated 4.3.4 class spell_warl_demonic_circle_summon : public SpellScriptLoader { public: @@ -473,6 +469,8 @@ class spell_warl_demonic_circle_summon : public SpellScriptLoader } }; +// 48020 Demonic Circle: Teleport +/// Updated 4.3.4 class spell_warl_demonic_circle_teleport : public SpellScriptLoader { public: @@ -506,6 +504,8 @@ class spell_warl_demonic_circle_teleport : public SpellScriptLoader } }; +// 48181 Haunt +/// Updated 4.3.4 class spell_warl_haunt : public SpellScriptLoader { public: @@ -565,6 +565,7 @@ class spell_warl_haunt : public SpellScriptLoader } }; +/// Updated 4.3.4 class spell_warl_unstable_affliction : public SpellScriptLoader { public: @@ -604,10 +605,12 @@ class spell_warl_unstable_affliction : public SpellScriptLoader } }; -class spell_warl_curse_of_doom : public SpellScriptLoader +// 603 Bane of Doom +/// Updated 4.3.4 +class spell_warl_bane_of_doom : public SpellScriptLoader { public: - spell_warl_curse_of_doom() : SpellScriptLoader("spell_warl_curse_of_doom") { } + spell_warl_bane_of_doom() : SpellScriptLoader("spell_warl_bane_of_doom") { } class spell_warl_curse_of_doom_AuraScript : public AuraScript { @@ -615,7 +618,7 @@ class spell_warl_curse_of_doom : public SpellScriptLoader bool Validate(SpellInfo const* /*spell*/) { - if (!sSpellMgr->GetSpellInfo(WARLOCK_CURSE_OF_DOOM_EFFECT)) + if (!sSpellMgr->GetSpellInfo(WARLOCK_BANE_OF_DOOM_EFFECT)) return false; return true; } @@ -635,7 +638,7 @@ class spell_warl_curse_of_doom : public SpellScriptLoader return; if (GetCaster()->ToPlayer()->isHonorOrXPTarget(GetTarget())) - GetCaster()->CastSpell(GetTarget(), WARLOCK_CURSE_OF_DOOM_EFFECT, true, NULL, aurEff); + GetCaster()->CastSpell(GetTarget(), WARLOCK_BANE_OF_DOOM_EFFECT, true, NULL, aurEff); } void Register() @@ -650,6 +653,8 @@ class spell_warl_curse_of_doom : public SpellScriptLoader } }; +// 755 Health Funnel +/// Updated 4.3.4 class spell_warl_health_funnel : public SpellScriptLoader { public: @@ -705,6 +710,6 @@ void AddSC_warlock_spell_scripts() new spell_warl_demonic_circle_teleport(); new spell_warl_haunt(); new spell_warl_unstable_affliction(); - new spell_warl_curse_of_doom(); + new spell_warl_bane_of_doom(); new spell_warl_health_funnel(); } diff --git a/src/server/scripts/World/npcs_special.cpp b/src/server/scripts/World/npcs_special.cpp index 3e3e18b1c80..f689d2f29ac 100644 --- a/src/server/scripts/World/npcs_special.cpp +++ b/src/server/scripts/World/npcs_special.cpp @@ -2121,8 +2121,6 @@ class npc_shadowfiend : public CreatureScript if (Unit* owner = me->ToTempSummon()->GetSummoner()) if (owner->HasAura(GLYPH_OF_SHADOWFIEND)) owner->CastSpell(owner, GLYPH_OF_SHADOWFIEND_MANA, true); - - PetAI::JustDied(killer); } }; diff --git a/src/server/shared/Utilities/Util.cpp b/src/server/shared/Utilities/Util.cpp index 0897c8814ab..b3176beb50b 100755 --- a/src/server/shared/Utilities/Util.cpp +++ b/src/server/shared/Utilities/Util.cpp @@ -150,6 +150,37 @@ std::string secsToTimeString(uint64 timeInSecs, bool shortText, bool hoursOnly) return ss.str(); } +int64 MoneyStringToMoney(const std::string& moneyString) +{ + int64 money = 0; + + if (!(std::count(moneyString.begin(), moneyString.end(), 'g') == 1 || + std::count(moneyString.begin(), moneyString.end(), 's') == 1 || + std::count(moneyString.begin(), moneyString.end(), 'c') == 1)) + return 0; // Bad format + + Tokenizer tokens(moneyString, ' '); + for (Tokenizer::const_iterator itr = tokens.begin(); itr != tokens.end(); ++itr) + { + std::string tokenString(*itr); + uint32 gCount = std::count(tokenString.begin(), tokenString.end(), 'g'); + uint32 sCount = std::count(tokenString.begin(), tokenString.end(), 's'); + uint32 cCount = std::count(tokenString.begin(), tokenString.end(), 'c'); + if (gCount + sCount + cCount != 1) + return 0; + + uint64 amount = atol(*itr); + if (gCount == 1) + money += amount * 100 * 100; + else if (sCount == 1) + money += amount * 100; + else if (cCount == 1) + money += amount; + } + + return money; +} + uint32 TimeStringToSecs(const std::string& timestring) { uint32 secs = 0; diff --git a/src/server/shared/Utilities/Util.h b/src/server/shared/Utilities/Util.h index f84e5155bb1..949fa67008f 100755 --- a/src/server/shared/Utilities/Util.h +++ b/src/server/shared/Utilities/Util.h @@ -66,6 +66,8 @@ private: void stripLineInvisibleChars(std::string &src); +int64 MoneyStringToMoney(const std::string& moneyString); + std::string secsToTimeString(uint64 timeInSecs, bool shortText = false, bool hoursOnly = false); uint32 TimeStringToSecs(const std::string& timestring); std::string TimeToTimestampStr(time_t t); |