diff options
Diffstat (limited to 'src')
62 files changed, 2647 insertions, 1191 deletions
diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 9931595e860..8276183fb10 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -83,8 +83,8 @@ typedef struct AUTH_LOGON_PROOF_S uint8 cmd; uint8 error; uint8 M2[20]; - uint32 unk1; - uint32 unk2; + uint32 AccountFlags; + uint32 SurveyId; uint16 unk3; } sAuthLogonProof_S; @@ -540,9 +540,9 @@ bool AuthSession::HandleLogonProof() memcpy(proof.M2, sha.GetDigest(), 20); proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; - proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) - proof.unk2 = 0x00; // SurveyId - proof.unk3 = 0x00; + proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) + proof.SurveyId = 0; + proof.unk3 = 0; packet.resize(sizeof(proof)); std::memcpy(packet.contents(), &proof, sizeof(proof)); @@ -831,7 +831,7 @@ bool AuthSession::HandleRealmList() pkt << AmountOfCharacters; pkt << realm.timezone; // realm category if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients - pkt << uint8(0x2C); // unk, may be realm number/id? + pkt << uint8(realm.m_ID); else pkt << uint8(0x0); // 1.12.1 and 1.12.2 clients diff --git a/src/server/game/AI/CreatureAISelector.cpp b/src/server/game/AI/CreatureAISelector.cpp index afbd306c184..3643bccdb6f 100644 --- a/src/server/game/AI/CreatureAISelector.cpp +++ b/src/server/game/AI/CreatureAISelector.cpp @@ -68,7 +68,7 @@ namespace FactorySelector else ai_factory = ai_registry.GetRegistryItem("NullCreatureAI"); } - else if (creature->GetCreatureType() == CREATURE_TYPE_CRITTER && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) + else if (creature->IsCritter() && !creature->HasUnitTypeMask(UNIT_MASK_GUARDIAN)) ai_factory = ai_registry.GetRegistryItem("CritterAI"); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index b06ee8613e9..c19ed4ff54b 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -477,7 +477,8 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (IsPlayer(*itr)) { - (*itr)->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest); + (*itr)->ToPlayer()->GroupEventHappens(e.action.quest.quest, me); + TC_LOG_DEBUG("scripts.ai", "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player guidLow %u credited quest %u", (*itr)->GetGUIDLow(), e.action.quest.quest); } @@ -3213,7 +3214,7 @@ void SmartScript::InitTimer(SmartScriptHolder& e) void SmartScript::RecalcTimer(SmartScriptHolder& e, uint32 min, uint32 max) { // min/max was checked at loading! - e.timer = urand(uint32(min), uint32(max)); + e.timer = urand(min, max); e.active = e.timer ? false : true; } diff --git a/src/server/game/Accounts/RBAC.h b/src/server/game/Accounts/RBAC.h index f2637a5febc..855ffd51bb8 100644 --- a/src/server/game/Accounts/RBAC.h +++ b/src/server/game/Accounts/RBAC.h @@ -427,8 +427,8 @@ enum RBACPermissions RBAC_PERM_COMMAND_REPAIRITEMS = 521, RBAC_PERM_COMMAND_RESPAWN = 522, RBAC_PERM_COMMAND_REVIVE = 523, - RBAC_PERM_COMMAND_SAVE = 524, - RBAC_PERM_COMMAND_SAVEALL = 525, + RBAC_PERM_COMMAND_SAVEALL = 524, + RBAC_PERM_COMMAND_SAVE = 525, RBAC_PERM_COMMAND_SETSKILL = 526, RBAC_PERM_COMMAND_SHOWAREA = 527, RBAC_PERM_COMMAND_SUMMON = 528, @@ -549,10 +549,10 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_EVENT_SCRIPTS = 643, RBAC_PERM_COMMAND_RELOAD_FISHING_LOOT_TEMPLATE = 644, RBAC_PERM_COMMAND_RELOAD_GAME_GRAVEYARD_ZONE = 645, - RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER = 646, - RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE = 647, - RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER = 648, - RBAC_PERM_COMMAND_RELOAD_GAME_TELE = 649, + RBAC_PERM_COMMAND_RELOAD_GAME_TELE = 646, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTENDER = 647, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUEST_LOOT_TEMPLATE = 648, + RBAC_PERM_COMMAND_RELOAD_GAMEOBJECT_QUESTSTARTER = 649, RBAC_PERM_COMMAND_RELOAD_GM_TICKETS = 650, RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU = 651, RBAC_PERM_COMMAND_RELOAD_GOSSIP_MENU_OPTION = 652, @@ -585,34 +585,34 @@ enum RBACPermissions RBAC_PERM_COMMAND_RELOAD_QUEST_TEMPLATE = 679, RBAC_PERM_COMMAND_RELOAD_RBAC = 680, RBAC_PERM_COMMAND_RELOAD_REFERENCE_LOOT_TEMPLATE = 681, - RBAC_PERM_COMMAND_RELOAD_REPUTATION_REWARD_RATE = 682, - RBAC_PERM_COMMAND_RELOAD_RESERVED_NAME = 683, - RBAC_PERM_COMMAND_RELOAD_SKILL_DISCOVERY_TEMPLATE = 684, - RBAC_PERM_COMMAND_RELOAD_SKILL_EXTRA_ITEM_TEMPLATE = 685, - RBAC_PERM_COMMAND_RELOAD_SKILL_FISHING_BASE_LEVEL = 686, - RBAC_PERM_COMMAND_RELOAD_SKINNING_LOOT_TEMPLATE = 687, - RBAC_PERM_COMMAND_RELOAD_SMART_SCRIPTS = 688, - RBAC_PERM_COMMAND_RELOAD_SPELL_AREA = 689, - RBAC_PERM_COMMAND_RELOAD_SPELL_BONUS_DATA = 690, - RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP = 691, - RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES = 692, - RBAC_PERM_COMMAND_RELOAD_SPELL_LEARN_SPELL = 693, - RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 694, + RBAC_PERM_COMMAND_RELOAD_RESERVED_NAME = 682, + RBAC_PERM_COMMAND_RELOAD_REPUTATION_REWARD_RATE = 683, + RBAC_PERM_COMMAND_RELOAD_SPILLOVER_TEMPLATE = 684, + RBAC_PERM_COMMAND_RELOAD_SKILL_DISCOVERY_TEMPLATE = 685, + RBAC_PERM_COMMAND_RELOAD_SKILL_EXTRA_ITEM_TEMPLATE = 686, + RBAC_PERM_COMMAND_RELOAD_SKILL_FISHING_BASE_LEVEL = 687, + RBAC_PERM_COMMAND_RELOAD_SKINNING_LOOT_TEMPLATE = 688, + RBAC_PERM_COMMAND_RELOAD_SMART_SCRIPTS = 689, + RBAC_PERM_COMMAND_RELOAD_SPELL_REQUIRED = 690, + RBAC_PERM_COMMAND_RELOAD_SPELL_AREA = 691, + RBAC_PERM_COMMAND_RELOAD_SPELL_BONUS_DATA = 692, + RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP = 693, + RBAC_PERM_COMMAND_RELOAD_SPELL_LEARN_SPELL = 694, RBAC_PERM_COMMAND_RELOAD_SPELL_LOOT_TEMPLATE = 695, - RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 696, - RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 697, + RBAC_PERM_COMMAND_RELOAD_SPELL_LINKED_SPELL = 696, + RBAC_PERM_COMMAND_RELOAD_SPELL_PET_AURAS = 697, RBAC_PERM_COMMAND_RELOAD_SPELL_PROC_EVENT = 698, - RBAC_PERM_COMMAND_RELOAD_SPELL_REQUIRED = 699, + RBAC_PERM_COMMAND_RELOAD_SPELL_PROC = 699, RBAC_PERM_COMMAND_RELOAD_SPELL_SCRIPTS = 700, RBAC_PERM_COMMAND_RELOAD_SPELL_TARGET_POSITION = 701, RBAC_PERM_COMMAND_RELOAD_SPELL_THREATS = 702, - RBAC_PERM_COMMAND_RELOAD_SPILLOVER_TEMPLATE = 703, + RBAC_PERM_COMMAND_RELOAD_SPELL_GROUP_STACK_RULES = 703, RBAC_PERM_COMMAND_RELOAD_TRINITY_STRING = 704, - RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESORY = 705, - RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY = 706, - RBAC_PERM_COMMAND_RELOAD_WARDEN_ACTION = 707, - RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA = 708, - RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS = 709, + RBAC_PERM_COMMAND_RELOAD_WARDEN_ACTION = 705, + RBAC_PERM_COMMAND_RELOAD_WAYPOINT_SCRIPTS = 706, + RBAC_PERM_COMMAND_RELOAD_WAYPOINT_DATA = 707, + RBAC_PERM_COMMAND_RELOAD_VEHICLE_ACCESORY = 708, + RBAC_PERM_COMMAND_RELOAD_VEHICLE_TEMPLATE_ACCESSORY = 709, RBAC_PERM_COMMAND_RESET = 710, RBAC_PERM_COMMAND_RESET_ACHIEVEMENTS = 711, RBAC_PERM_COMMAND_RESET_HONOR = 712, diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index aa3bd99a988..547cd9a8502 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -2584,7 +2584,7 @@ void AchievementGlobalMgr::LoadRewardLocales() AchievementRewardLocale& data = m_achievementRewardLocales[entry]; - for (int i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; ObjectMgr::AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.subject); @@ -2593,7 +2593,7 @@ void AchievementGlobalMgr::LoadRewardLocales() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu achievement reward locale strings in %u ms", (unsigned long)m_achievementRewardLocales.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u achievement reward locale strings in %u ms", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime)); } AchievementEntry const* AchievementGlobalMgr::GetAchievement(uint32 achievementId) const diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index f4699f0519e..6d8e695f02a 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -544,8 +544,16 @@ void AuctionHouseObject::BuildListAuctionItems(WorldPacket& data, Player* player if (levelmin != 0x00 && (proto->RequiredLevel < levelmin || (levelmax != 0x00 && proto->RequiredLevel > levelmax))) continue; - if (usable != 0x00 && player->CanUseItem(item) != EQUIP_ERR_OK) - continue; + if (usable != 0x00) + { + if (player->CanUseItem(item) != EQUIP_ERR_OK) + continue; + + if (proto->Class == ITEM_CLASS_RECIPE) + if (SpellEntry const* spell = sSpellStore.LookupEntry(proto->Spells[0].SpellId)) + if (player->HasSpell(spell->EffectTriggerSpell[EFFECT_INDEX_0])) + continue; + } // Allow search by suffix (ie: of the Monkey) or partial name (ie: Monkey) // No need to do any of this if no search term was entered diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 86236cd0f2b..3a59ffa8cf9 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -844,12 +844,14 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac Player* player = ObjectAccessor::FindPlayer(guid); - // should remove spirit of redemption if (player) { + // should remove spirit of redemption if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION)) player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT); + player->RemoveAurasByType(SPELL_AURA_MOUNTED); + if (!player->IsAlive()) // resurrect on exit { player->ResurrectPlayer(1.0f); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index c9a2015dbb8..c04f2845110 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -384,9 +384,9 @@ bool Creature::UpdateEntry(uint32 entry, CreatureData const* data /*= nullptr*/) RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); - SetAttackTime(BASE_ATTACK, cInfo->baseattacktime); - SetAttackTime(OFF_ATTACK, cInfo->baseattacktime); - SetAttackTime(RANGED_ATTACK, cInfo->rangeattacktime); + SetAttackTime(BASE_ATTACK, cInfo->BaseAttackTime); + SetAttackTime(OFF_ATTACK, cInfo->BaseAttackTime); + SetAttackTime(RANGED_ATTACK, cInfo->RangeAttackTime); SelectLevel(); @@ -815,7 +815,7 @@ bool Creature::Create(uint32 guidlow, Map* map, uint32 phaseMask, uint32 entry, void Creature::InitializeReactState() { - if (IsTotem() || IsTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || IsSpiritService()) + if (IsTotem() || IsTrigger() || IsCritter() || IsSpiritService()) SetReactState(REACT_PASSIVE); /* else if (IsCivilian()) @@ -2277,7 +2277,7 @@ void Creature::AllLootRemovedFromCorpse() if (loot.loot_type == LOOT_SKINNING) m_corpseRemoveTime = now; else - m_corpseRemoveTime = now + m_corpseDelay * decayRate; + m_corpseRemoveTime = now + uint32(m_corpseDelay * decayRate); m_respawnTime = m_corpseRemoveTime + m_respawnDelay; } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index ea4da5d5611..9b332bb5de4 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -64,12 +64,12 @@ enum CreatureFlagsExtra CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \ CREATURE_FLAG_EXTRA_GUARD) -#define MAX_KILL_CREDIT 2 #define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS +#define MAX_KILL_CREDIT 2 +#define MAX_CREATURE_MODELS 4 #define MAX_CREATURE_QUEST_ITEMS 6 - -#define MAX_EQUIPMENT_ITEMS 3 +#define CREATURE_MAX_SPELLS 8 // from `creature_template` table struct CreatureTemplate @@ -94,13 +94,11 @@ struct CreatureTemplate float speed_run; float scale; uint32 rank; - float mindmg; - float maxdmg; uint32 dmgschool; - uint32 attackpower; - float dmg_multiplier; - uint32 baseattacktime; - uint32 rangeattacktime; + uint32 BaseAttackTime; + uint32 RangeAttackTime; + float BaseVariance; + float RangeVariance; uint32 unit_class; // enum Classes. Note only 4 classes are known for creatures. uint32 unit_flags; // enum UnitFlags mask values uint32 unit_flags2; // enum UnitFlags2 mask values @@ -110,9 +108,6 @@ struct CreatureTemplate uint32 trainer_spell; uint32 trainer_class; uint32 trainer_race; - float minrangedmg; - float maxrangedmg; - uint32 rangedattackpower; uint32 type; // enum CreatureType values uint32 type_flags; // enum CreatureTypeFlags mask values uint32 lootid; @@ -131,6 +126,8 @@ struct CreatureTemplate float ModHealth; float ModMana; float ModArmor; + float ModDamage; + float ModExperience; bool RacialLeader; uint32 questItems[MAX_CREATURE_QUEST_ITEMS]; uint32 movementId; @@ -237,6 +234,8 @@ struct PointOfInterestLocale StringVector IconName; }; +#define MAX_EQUIPMENT_ITEMS 3 + struct EquipmentInfo { uint32 ItemEntry[MAX_EQUIPMENT_ITEMS]; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index ee39ed48ad6..c8c0eaefb27 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -143,7 +143,12 @@ void GameObject::AddToWorld() // The state can be changed after GameObject::Create but before GameObject::AddToWorld bool toggledState = GetGoType() == GAMEOBJECT_TYPE_CHEST ? getLootState() == GO_READY : (GetGoState() == GO_STATE_READY || IsTransport()); if (m_model) - GetMap()->InsertGameObjectModel(*m_model); + { + if (Transport* trans = ToTransport()) + trans->SetDelayedAddModelToMap(); + else + GetMap()->InsertGameObjectModel(*m_model); + } EnableCollision(toggledState); WorldObject::AddToWorld(); diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 09911fc8f57..6894dd86493 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -1265,6 +1265,14 @@ void Item::ItemContainerSaveLootToDB() // but we don't want to resave it. if (!_li->canSave) continue; + // Conditions are not checked when loot is generated, it is checked when loot is sent to a player. + // For items that are lootable, loot is saved to the DB immediately, that means that loot can be + // saved to the DB that the player never should have gotten. This check prevents that, so that only + // items that the player should get in loot are in the DB. + // IE: Horde items are not saved to the DB for Ally players. + Player* const guid = GetOwner(); + if (!_li->AllowedForPlayer(guid)) + continue; stmt_items = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEMCONTAINER_ITEMS); diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index dc6007cbfe0..13f4dd13a83 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -805,14 +805,16 @@ namespace Trinity class ObjectDistanceOrderPred { public: - ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending = true) : m_refObj(pRefObj), m_ascending(ascending) { } - bool operator()(WorldObject const* pLeft, WorldObject const* pRight) const + ObjectDistanceOrderPred(WorldObject const* refObj, bool ascending = true) : _refObj(refObj), _ascending(ascending) { } + + bool operator()(WorldObject const* left, WorldObject const* right) const { - return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight); + return _refObj->GetDistanceOrder(left, right) == _ascending; } + private: - WorldObject const* m_refObj; - const bool m_ascending; + WorldObject const* _refObj; + bool _ascending; }; } diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index 876f35a58ce..37087663328 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -182,8 +182,7 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c setFaction(owner->getFaction()); SetUInt32Value(UNIT_CREATED_BY_SPELL, summonSpellId); - CreatureTemplate const* cinfo = GetCreatureTemplate(); - if (cinfo->type == CREATURE_TYPE_CRITTER) + if (IsCritter()) { float px, py, pz; owner->GetClosePoint(px, py, pz, GetObjectSize(), PET_FOLLOW_DIST, GetFollowAngle()); @@ -1019,7 +1018,7 @@ bool Guardian::InitStatsForLevel(uint8 petlevel) SetCreateHealth(30*petlevel); // wolf attack speed is 1.5s - SetAttackTime(BASE_ATTACK, cinfo->baseattacktime); + SetAttackTime(BASE_ATTACK, cinfo->BaseAttackTime); SetBaseWeaponDamage(BASE_ATTACK, MINDAMAGE, float((petlevel * 4 - petlevel))); SetBaseWeaponDamage(BASE_ATTACK, MAXDAMAGE, float((petlevel * 4 + petlevel))); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index fa009d94fe2..c9ac4e73374 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -13176,13 +13176,6 @@ void Player::SwapItem(uint16 src, uint16 dst) // SRC checks - if (pSrcItem->m_lootGenerated) // prevent swap looting item - { - //best error message found for attempting to swap while looting - SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pSrcItem, NULL); - return; - } - // check unequip potability for equipped items and bank bags if (IsEquipmentPos(src) || IsBagPos(src)) { @@ -13213,13 +13206,6 @@ void Player::SwapItem(uint16 src, uint16 dst) if (pDstItem) { - if (pDstItem->m_lootGenerated) // prevent swap looting item - { - //best error message found for attempting to swap while looting - SendEquipError(EQUIP_ERR_CANT_DO_RIGHT_NOW, pDstItem, NULL); - return; - } - // check unequip potability for equipped items and bank bags if (IsEquipmentPos(dst) || IsBagPos(dst)) { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index d907274f8d1..367ccd34cdb 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -35,7 +35,8 @@ Transport::Transport() : GameObject(), _transportInfo(NULL), _isMoving(true), _pendingStop(false), - _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengerTeleportItr(_passengers.begin()) + _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), + _passengerTeleportItr(_passengers.begin()), _delayedAddModel(false) { m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION; } @@ -186,6 +187,14 @@ void Transport::Update(uint32 diff) return; // Update more in new map thread } + // Add model to map after we are fully done with moving maps + if (_delayedAddModel) + { + _delayedAddModel = false; + if (m_model) + GetMap()->InsertGameObjectModel(*m_model); + } + // Set position _positionChangeTimer.Update(diff); if (_positionChangeTimer.Passed()) @@ -625,7 +634,6 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl } Relocate(x, y, z, o); - UpdateModelPosition(); GetMap()->AddToMap<Transport>(this); return true; } diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index e644417f1ac..2c924eb33ed 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -95,6 +95,8 @@ class Transport : public GameObject, public TransportBase void EnableMovement(bool enabled); + void SetDelayedAddModelToMap() { _delayedAddModel = true; } + TransportTemplate const* GetTransportTemplate() const { return _transportInfo; } private: @@ -123,6 +125,8 @@ class Transport : public GameObject, public TransportBase PassengerSet _passengers; PassengerSet::iterator _passengerTeleportItr; PassengerSet _staticPassengers; + + bool _delayedAddModel; }; #endif diff --git a/src/server/game/Entities/Unit/StatSystem.cpp b/src/server/game/Entities/Unit/StatSystem.cpp index 04136221d0d..bac2a8ef856 100644 --- a/src/server/game/Entities/Unit/StatSystem.cpp +++ b/src/server/game/Entities/Unit/StatSystem.cpp @@ -1037,17 +1037,21 @@ void Creature::UpdateAttackPowerAndDamage(bool ranged) void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, bool addTotalPct, float& minDamage, float& maxDamage) { + float variance = 1.0f; UnitMods unitMod; switch (attType) { case BASE_ATTACK: default: + variance = GetCreatureTemplate()->BaseVariance; unitMod = UNIT_MOD_DAMAGE_MAINHAND; break; case OFF_ATTACK: + variance = GetCreatureTemplate()->BaseVariance; unitMod = UNIT_MOD_DAMAGE_OFFHAND; break; case RANGED_ATTACK: + variance = GetCreatureTemplate()->RangeVariance; unitMod = UNIT_MOD_DAMAGE_RANGED; break; } @@ -1070,11 +1074,11 @@ void Creature::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float attackPower = GetTotalAttackPowerValue(attType); float attackSpeedMulti = GetAPMultiplier(attType, normalized); - float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f); + float baseValue = GetModifierValue(unitMod, BASE_VALUE) + (attackPower / 14.0f) * variance; float basePct = GetModifierValue(unitMod, BASE_PCT) * attackSpeedMulti; float totalValue = GetModifierValue(unitMod, TOTAL_VALUE); float totalPct = addTotalPct ? GetModifierValue(unitMod, TOTAL_PCT) : 1.0f; - float dmgMultiplier = GetCreatureTemplate()->dmg_multiplier; // = dmg_multiplier * _GetDamageMod(rank); + float dmgMultiplier = GetCreatureTemplate()->ModDamage; // = ModDamage * _GetDamageMod(rank); minDamage = ((weaponMinDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct; maxDamage = ((weaponMaxDamage + baseValue) * dmgMultiplier * basePct + totalValue) * totalPct; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index e1876c9e839..a42836682bb 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13998,7 +13998,7 @@ void Unit::ProcDamageAndSpellFor(bool isVictim, Unit* target, uint32 procFlag, u // On melee based hit/miss/resist need update skill (for victim and attacker) if (procExtra & (PROC_EX_NORMAL_HIT|PROC_EX_MISS|PROC_EX_RESIST)) { - if (target->GetTypeId() != TYPEID_PLAYER && target->GetCreatureType() != CREATURE_TYPE_CRITTER) + if (target->GetTypeId() != TYPEID_PLAYER && !target->IsCritter()) ToPlayer()->UpdateCombatSkills(target, attType, isVictim); } // Update defence if player is victim and parry/dodge/block @@ -14662,7 +14662,7 @@ Unit* Unit::SelectNearbyTarget(Unit* exclude, float dist) const // remove not LoS targets for (std::list<Unit*>::iterator tIter = targets.begin(); tIter != targets.end();) { - if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->GetCreatureType() == CREATURE_TYPE_CRITTER) + if (!IsWithinLOSInMap(*tIter) || (*tIter)->IsTotem() || (*tIter)->IsSpiritService() || (*tIter)->IsCritter()) targets.erase(tIter++); else ++tIter; @@ -15283,7 +15283,7 @@ void Unit::Kill(Unit* victim, bool durabilityLoss) if (Unit* owner = GetOwner()) owner->ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_NONE, PROC_EX_NONE, 0); - if (victim->GetCreatureType() != CREATURE_TYPE_CRITTER) + if (!victim->IsCritter()) ProcDamageAndSpell(victim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); // Proc auras on death - must be before aura/combat remove diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index b65081ba89e..2e8d93ec995 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -265,7 +265,6 @@ enum UnitRename UNIT_CAN_BE_ABANDONED = 0x02 }; -#define CREATURE_MAX_SPELLS 8 #define MAX_SPELL_CHARM 4 #define MAX_SPELL_VEHICLE 6 #define MAX_SPELL_POSSESS 8 @@ -1528,6 +1527,7 @@ class Unit : public WorldObject bool IsArmorer() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_REPAIR); } bool IsServiceProvider() const; bool IsSpiritService() const { return HasFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPIRITHEALER | UNIT_NPC_FLAG_SPIRITGUIDE); } + bool IsCritter() const { return GetCreatureType() == CREATURE_TYPE_CRITTER; } bool IsInFlight() const { return HasUnitState(UNIT_STATE_IN_FLIGHT); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index b7f2cd3dae4..944ad4d4a19 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -315,7 +315,7 @@ void ObjectMgr::LoadCreatureLocales() CreatureLocale& data = _creatureLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Name); @@ -323,7 +323,7 @@ void ObjectMgr::LoadCreatureLocales() } } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu creature locale strings in %u ms", (unsigned long)_creatureLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u creature locale strings in %u ms", uint32(_creatureLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadGossipMenuItemsLocales() @@ -351,7 +351,7 @@ void ObjectMgr::LoadGossipMenuItemsLocales() GossipMenuItemsLocale& data = _gossipMenuItemsLocaleStore[MAKE_PAIR32(menuId, id)]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; AddLocaleString(fields[2 + 2 * (i - 1)].GetString(), locale, data.OptionText); @@ -360,7 +360,7 @@ void ObjectMgr::LoadGossipMenuItemsLocales() } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu gossip_menu_option locale strings in %u ms", (unsigned long)_gossipMenuItemsLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u gossip_menu_option locale strings in %u ms", uint32(_gossipMenuItemsLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadPointOfInterestLocales() @@ -382,33 +382,33 @@ void ObjectMgr::LoadPointOfInterestLocales() PointOfInterestLocale& data = _pointOfInterestLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.IconName); } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu points_of_interest locale strings in %u ms", (unsigned long)_pointOfInterestLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u points_of_interest locale strings in %u ms", uint32(_pointOfInterestLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadCreatureTemplates() { uint32 oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 7 8 + // 0 1 2 3 4 5 6 7 8 QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, " - // 9 10 11 12 13 14 15 16 17 18 19 20 21 + // 9 10 11 12 13 14 15 16 17 18 19 20 "modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, " - // 22 23 24 25 26 27 28 29 30 31 32 33 - "scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, " - // 34 35 36 37 38 39 40 41 42 43 - "dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, " - // 44 45 46 47 48 49 50 51 52 53 54 + // 21 22 23 24 25 26 27 28 29 30 + "scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, " + // 31 32 33 34 35 36 37 + "dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, " + // 38 39 40 41 42 43 44 45 46 47 48 "type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, " - // 55 56 57 58 59 60 61 62 63 64 65 66 67 + // 49 50 51 52 53 54 55 56 57 58 59 60 61 "spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, " - // 68 69 70 71 72 73 74 75 76 77 78 - "InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, " - // 79 80 81 82 83 84 - " questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName " + // 62 63 64 65 66 67 68 69 + "InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, " + // 70 71 72 73 74 75 76 77 78 79 80 + "questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName " "FROM creature_template;"); if (!result) @@ -422,90 +422,7 @@ void ObjectMgr::LoadCreatureTemplates() do { Field* fields = result->Fetch(); - - uint32 entry = fields[0].GetUInt32(); - - - CreatureTemplate& creatureTemplate = _creatureTemplateStore[entry]; - - creatureTemplate.Entry = entry; - - for (uint8 i = 0; i < MAX_DIFFICULTY - 1; ++i) - creatureTemplate.DifficultyEntry[i] = fields[1 + i].GetUInt32(); - - for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i) - creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32(); - - creatureTemplate.Modelid1 = fields[6].GetUInt32(); - creatureTemplate.Modelid2 = fields[7].GetUInt32(); - creatureTemplate.Modelid3 = fields[8].GetUInt32(); - creatureTemplate.Modelid4 = fields[9].GetUInt32(); - creatureTemplate.Name = fields[10].GetString(); - creatureTemplate.SubName = fields[11].GetString(); - creatureTemplate.IconName = fields[12].GetString(); - creatureTemplate.GossipMenuId = fields[13].GetUInt32(); - creatureTemplate.minlevel = fields[14].GetUInt8(); - creatureTemplate.maxlevel = fields[15].GetUInt8(); - creatureTemplate.expansion = uint32(fields[16].GetInt16()); - creatureTemplate.faction = uint32(fields[17].GetUInt16()); - creatureTemplate.npcflag = fields[18].GetUInt32(); - creatureTemplate.speed_walk = fields[19].GetFloat(); - creatureTemplate.speed_run = fields[20].GetFloat(); - creatureTemplate.scale = fields[21].GetFloat(); - creatureTemplate.rank = uint32(fields[22].GetUInt8()); - creatureTemplate.mindmg = fields[23].GetFloat(); - creatureTemplate.maxdmg = fields[24].GetFloat(); - creatureTemplate.dmgschool = uint32(fields[25].GetInt8()); - creatureTemplate.attackpower = fields[26].GetUInt32(); - creatureTemplate.dmg_multiplier = fields[27].GetFloat(); - creatureTemplate.baseattacktime = fields[28].GetUInt32(); - creatureTemplate.rangeattacktime = fields[29].GetUInt32(); - creatureTemplate.unit_class = uint32(fields[30].GetUInt8()); - creatureTemplate.unit_flags = fields[31].GetUInt32(); - creatureTemplate.unit_flags2 = fields[32].GetUInt32(); - creatureTemplate.dynamicflags = fields[33].GetUInt32(); - creatureTemplate.family = uint32(fields[34].GetUInt8()); - creatureTemplate.trainer_type = uint32(fields[35].GetUInt8()); - creatureTemplate.trainer_spell = fields[36].GetUInt32(); - creatureTemplate.trainer_class = uint32(fields[37].GetUInt8()); - creatureTemplate.trainer_race = uint32(fields[38].GetUInt8()); - creatureTemplate.minrangedmg = fields[39].GetFloat(); - creatureTemplate.maxrangedmg = fields[40].GetFloat(); - creatureTemplate.rangedattackpower = uint32(fields[41].GetUInt16()); - creatureTemplate.type = uint32(fields[42].GetUInt8()); - creatureTemplate.type_flags = fields[43].GetUInt32(); - creatureTemplate.lootid = fields[44].GetUInt32(); - creatureTemplate.pickpocketLootId = fields[45].GetUInt32(); - creatureTemplate.SkinLootId = fields[46].GetUInt32(); - - for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - creatureTemplate.resistance[i] = fields[47 + i -1].GetInt16(); - - for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) - creatureTemplate.spells[i] = fields[53 + i].GetUInt32(); - - creatureTemplate.PetSpellDataId = fields[61].GetUInt32(); - creatureTemplate.VehicleId = fields[62].GetUInt32(); - creatureTemplate.mingold = fields[63].GetUInt32(); - creatureTemplate.maxgold = fields[64].GetUInt32(); - creatureTemplate.AIName = fields[65].GetString(); - creatureTemplate.MovementType = uint32(fields[66].GetUInt8()); - creatureTemplate.InhabitType = uint32(fields[67].GetUInt8()); - creatureTemplate.HoverHeight = fields[68].GetFloat(); - creatureTemplate.ModHealth = fields[69].GetFloat(); - creatureTemplate.ModMana = fields[70].GetFloat(); - creatureTemplate.ModArmor = fields[71].GetFloat(); - creatureTemplate.RacialLeader = fields[72].GetBool(); - - for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) - creatureTemplate.questItems[i] = fields[73 + i].GetUInt32(); - - creatureTemplate.movementId = fields[79].GetUInt32(); - creatureTemplate.RegenHealth = fields[80].GetBool(); - creatureTemplate.MechanicImmuneMask = fields[81].GetUInt32(); - creatureTemplate.flags_extra = fields[82].GetUInt32(); - creatureTemplate.ScriptID = GetScriptId(fields[83].GetCString()); - + LoadCreatureTemplate(fields); ++count; } while (result->NextRow()); @@ -517,6 +434,88 @@ void ObjectMgr::LoadCreatureTemplates() TC_LOG_INFO("server.loading", ">> Loaded %u creature definitions in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } +void ObjectMgr::LoadCreatureTemplate(Field* fields) +{ + uint32 entry = fields[0].GetUInt32(); + + CreatureTemplate& creatureTemplate = _creatureTemplateStore[entry]; + + creatureTemplate.Entry = entry; + + for (uint8 i = 0; i < MAX_DIFFICULTY - 1; ++i) + creatureTemplate.DifficultyEntry[i] = fields[1 + i].GetUInt32(); + + for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i) + creatureTemplate.KillCredit[i] = fields[4 + i].GetUInt32(); + + creatureTemplate.Modelid1 = fields[6].GetUInt32(); + creatureTemplate.Modelid2 = fields[7].GetUInt32(); + creatureTemplate.Modelid3 = fields[8].GetUInt32(); + creatureTemplate.Modelid4 = fields[9].GetUInt32(); + creatureTemplate.Name = fields[10].GetString(); + creatureTemplate.SubName = fields[11].GetString(); + creatureTemplate.IconName = fields[12].GetString(); + creatureTemplate.GossipMenuId = fields[13].GetUInt32(); + creatureTemplate.minlevel = fields[14].GetUInt8(); + creatureTemplate.maxlevel = fields[15].GetUInt8(); + creatureTemplate.expansion = uint32(fields[16].GetInt16()); + creatureTemplate.faction = fields[17].GetUInt16(); + creatureTemplate.npcflag = fields[18].GetUInt32(); + creatureTemplate.speed_walk = fields[19].GetFloat(); + creatureTemplate.speed_run = fields[20].GetFloat(); + creatureTemplate.scale = fields[21].GetFloat(); + creatureTemplate.rank = fields[22].GetUInt8(); + creatureTemplate.dmgschool = uint32(fields[23].GetInt8()); + creatureTemplate.BaseAttackTime = fields[24].GetUInt32(); + creatureTemplate.RangeAttackTime = fields[25].GetUInt32(); + creatureTemplate.BaseVariance = fields[26].GetFloat(); + creatureTemplate.RangeVariance = fields[27].GetFloat(); + creatureTemplate.unit_class = fields[28].GetUInt8(); + creatureTemplate.unit_flags = fields[29].GetUInt32(); + creatureTemplate.unit_flags2 = fields[30].GetUInt32(); + creatureTemplate.dynamicflags = fields[31].GetUInt32(); + creatureTemplate.family = fields[32].GetUInt8(); + creatureTemplate.trainer_type = fields[33].GetUInt8(); + creatureTemplate.trainer_spell = fields[34].GetUInt32(); + creatureTemplate.trainer_class = fields[35].GetUInt8(); + creatureTemplate.trainer_race = fields[36].GetUInt8(); + creatureTemplate.type = fields[37].GetUInt8(); + creatureTemplate.type_flags = fields[38].GetUInt32(); + creatureTemplate.lootid = fields[39].GetUInt32(); + creatureTemplate.pickpocketLootId = fields[40].GetUInt32(); + creatureTemplate.SkinLootId = fields[41].GetUInt32(); + + for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) + creatureTemplate.resistance[i] = fields[42 + i - 1].GetInt16(); + + for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) + creatureTemplate.spells[i] = fields[48 + i].GetUInt32(); + + creatureTemplate.PetSpellDataId = fields[56].GetUInt32(); + creatureTemplate.VehicleId = fields[57].GetUInt32(); + creatureTemplate.mingold = fields[58].GetUInt32(); + creatureTemplate.maxgold = fields[59].GetUInt32(); + creatureTemplate.AIName = fields[60].GetString(); + creatureTemplate.MovementType = fields[61].GetUInt8(); + creatureTemplate.InhabitType = fields[62].GetUInt8(); + creatureTemplate.HoverHeight = fields[63].GetFloat(); + creatureTemplate.ModHealth = fields[64].GetFloat(); + creatureTemplate.ModMana = fields[65].GetFloat(); + creatureTemplate.ModArmor = fields[66].GetFloat(); + creatureTemplate.ModDamage = fields[67].GetFloat(); + creatureTemplate.ModExperience = fields[68].GetFloat(); + creatureTemplate.RacialLeader = fields[69].GetBool(); + + for (uint8 i = 0; i < MAX_CREATURE_QUEST_ITEMS; ++i) + creatureTemplate.questItems[i] = fields[70 + i].GetUInt32(); + + creatureTemplate.movementId = fields[76].GetUInt32(); + creatureTemplate.RegenHealth = fields[77].GetBool(); + creatureTemplate.MechanicImmuneMask = fields[78].GetUInt32(); + creatureTemplate.flags_extra = fields[79].GetUInt32(); + creatureTemplate.ScriptID = GetScriptId(fields[80].GetCString()); +} + void ObjectMgr::LoadCreatureTemplateAddons() { uint32 oldMSTime = getMSTime(); @@ -856,11 +855,11 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->dmgschool = SPELL_SCHOOL_NORMAL; } - if (cInfo->baseattacktime == 0) - const_cast<CreatureTemplate*>(cInfo)->baseattacktime = BASE_ATTACK_TIME; + if (cInfo->BaseAttackTime == 0) + const_cast<CreatureTemplate*>(cInfo)->BaseAttackTime = BASE_ATTACK_TIME; - if (cInfo->rangeattacktime == 0) - const_cast<CreatureTemplate*>(cInfo)->rangeattacktime = BASE_ATTACK_TIME; + if (cInfo->RangeAttackTime == 0) + const_cast<CreatureTemplate*>(cInfo)->RangeAttackTime = BASE_ATTACK_TIME; if ((cInfo->npcflag & UNIT_NPC_FLAG_TRAINER) && cInfo->trainer_type >= MAX_TRAINER_TYPE) TC_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong trainer type %u.", cInfo->Entry, cInfo->trainer_type); @@ -955,7 +954,7 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo) const_cast<CreatureTemplate*>(cInfo)->flags_extra &= CREATURE_FLAG_EXTRA_DB_ALLOWED; } - const_cast<CreatureTemplate*>(cInfo)->dmg_multiplier *= Creature::_GetDamageMod(cInfo->rank); + const_cast<CreatureTemplate*>(cInfo)->ModDamage *= Creature::_GetDamageMod(cInfo->rank); } void ObjectMgr::LoadCreatureAddons() @@ -2199,7 +2198,7 @@ void ObjectMgr::LoadItemLocales() ItemLocale& data = _itemLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; AddLocaleString(fields[1 + 2 * (i - 1)].GetString(), locale, data.Name); @@ -2207,7 +2206,7 @@ void ObjectMgr::LoadItemLocales() } } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu Item locale strings in %u ms", (unsigned long)_itemLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u Item locale strings in %u ms", uint32(_itemLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadItemTemplates() @@ -2841,7 +2840,7 @@ void ObjectMgr::LoadItemSetNameLocales() ItemSetNameLocale& data = _itemSetNameLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Name); } while (result->NextRow()); @@ -4523,7 +4522,7 @@ void ObjectMgr::LoadQuestLocales() QuestLocale& data = _questLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; @@ -4540,7 +4539,7 @@ void ObjectMgr::LoadQuestLocales() } } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu Quest locale strings in %u ms", (unsigned long)_questLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u Quest locale strings in %u ms", uint32(_questLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadScripts(ScriptsType type) @@ -5152,11 +5151,11 @@ void ObjectMgr::LoadPageTextLocales() PageTextLocale& data = _pageTextLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Text); } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu PageText locale strings in %u ms", (unsigned long)_pageTextLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u PageText locale strings in %u ms", uint32(_pageTextLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadInstanceTemplate() @@ -5400,10 +5399,10 @@ void ObjectMgr::LoadNpcTextLocales() NpcTextLocale& data = _npcTextLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = (LocaleConstant) i; - for (uint8 j = 0; j < MAX_LOCALES; ++j) + for (uint8 j = 0; j < MAX_GOSSIP_TEXT_OPTIONS; ++j) { AddLocaleString(fields[1 + 8 * 2 * (i - 1) + 2 * j].GetString(), locale, data.Text_0[j]); AddLocaleString(fields[1 + 8 * 2 * (i - 1) + 2 * j + 1].GetString(), locale, data.Text_1[j]); @@ -5411,7 +5410,7 @@ void ObjectMgr::LoadNpcTextLocales() } } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu NpcText locale strings in %u ms", (unsigned long)_npcTextLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u NpcText locale strings in %u ms", uint32(_npcTextLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } //not very fast function but it is called only once a day, or on starting-up @@ -6435,14 +6434,14 @@ void ObjectMgr::LoadGameObjectLocales() GameObjectLocale& data = _gameObjectLocaleStore[entry]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) + { AddLocaleString(fields[i].GetString(), LocaleConstant(i), data.Name); - - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) AddLocaleString(fields[i + (TOTAL_LOCALES - 1)].GetString(), LocaleConstant(i), data.CastBarCaption); + } } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %lu gameobject locale strings in %u ms", (unsigned long)_gameObjectLocaleStore.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u gameobject locale strings in %u ms", uint32(_gameObjectLocaleStore.size()), GetMSTimeDiffToNow(oldMSTime)); } inline void CheckGOLockId(GameObjectTemplate const* goInfo, uint32 dataN, uint32 N) @@ -7758,7 +7757,7 @@ bool ObjectMgr::LoadTrinityStrings(const char* table, int32 min_value, int32 max data.Content.resize(1); ++count; - for (uint8 i = 0; i < TOTAL_LOCALES; ++i) + for (int8 i = TOTAL_LOCALES - 1; i >= 0; --i) AddLocaleString(fields[i + 1].GetString(), LocaleConstant(i), data.Content); } while (result->NextRow()); @@ -8780,11 +8779,11 @@ void ObjectMgr::LoadBroadcastTextLocales() continue; } - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = LocaleConstant(i); - ObjectMgr::AddLocaleString(fields[1 + (i - 1)].GetString(), locale, bct->second.MaleText); - ObjectMgr::AddLocaleString(fields[9 + (i - 1)].GetString(), locale, bct->second.FemaleText); + AddLocaleString(fields[1 + (i - 1)].GetString(), locale, bct->second.MaleText); + AddLocaleString(fields[9 + (i - 1)].GetString(), locale, bct->second.FemaleText); } ++count; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 738b99778f8..56ae4a4c6d1 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -961,6 +961,7 @@ class ObjectMgr void LoadCreatureLocales(); void LoadCreatureTemplates(); void LoadCreatureTemplateAddons(); + void LoadCreatureTemplate(Field* fields); void CheckCreatureTemplate(CreatureTemplate const* cInfo); void LoadTempSummons(); void LoadCreatures(); diff --git a/src/server/game/Handlers/ArenaTeamHandler.cpp b/src/server/game/Handlers/ArenaTeamHandler.cpp index 3bb3edac500..20d89d9efb5 100644 --- a/src/server/game/Handlers/ArenaTeamHandler.cpp +++ b/src/server/game/Handlers/ArenaTeamHandler.cpp @@ -311,6 +311,10 @@ void WorldSession::HandleArenaTeamRemoveOpcode(WorldPacket& recvData) SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, "", "", ERR_ARENA_TEAM_LEADER_LEAVE_S); return; } + + // Player cannot be removed during fights + if (arenaTeam->IsFighting()) + return; arenaTeam->DelMember(member->Guid, true); diff --git a/src/server/game/Handlers/NPCHandler.h b/src/server/game/Handlers/NPCHandler.h index 7210d9a53b5..855536c7d9e 100644 --- a/src/server/game/Handlers/NPCHandler.h +++ b/src/server/game/Handlers/NPCHandler.h @@ -51,10 +51,10 @@ struct PageTextLocale struct NpcTextLocale { - NpcTextLocale() { Text_0.resize(8); Text_1.resize(8); } + NpcTextLocale() { } - std::vector<StringVector> Text_0; - std::vector<StringVector> Text_1; + StringVector Text_0[MAX_GOSSIP_TEXT_OPTIONS]; + StringVector Text_1[MAX_GOSSIP_TEXT_OPTIONS]; }; #endif diff --git a/src/server/game/Miscellaneous/Formulas.h b/src/server/game/Miscellaneous/Formulas.h index 8d0e97dc765..e6ff1a0b40f 100644 --- a/src/server/game/Miscellaneous/Formulas.h +++ b/src/server/game/Miscellaneous/Formulas.h @@ -160,27 +160,32 @@ namespace Trinity inline uint32 Gain(Player* player, Unit* u) { - uint32 gain; + Creature* creature = u->ToCreature(); + uint32 gain = 0; - if (u->GetTypeId() == TYPEID_UNIT && - (((Creature*)u)->IsTotem() || ((Creature*)u)->IsPet() || - (((Creature*)u)->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL) || - ((Creature*)u)->GetCreatureTemplate()->type == CREATURE_TYPE_CRITTER)) - gain = 0; - else + if (!creature || (!creature->IsTotem() && !creature->IsPet() && !creature->IsCritter() && + !(creature->GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_NO_XP_AT_KILL))) { + float xpMod = 1.0f; + gain = BaseGain(player->getLevel(), u->getLevel(), GetContentLevelsForMapAndZone(u->GetMapId(), u->GetZoneId())); - if (gain != 0 && u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->isElite()) + if (gain && creature) { - // Elites in instances have a 2.75x XP bonus instead of the regular 2x world bonus. - if (u->GetMap() && u->GetMap()->IsDungeon()) - gain = uint32(gain * 2.75); - else - gain *= 2; + if (creature->isElite()) + { + // Elites in instances have a 2.75x XP bonus instead of the regular 2x world bonus. + if (u->GetMap() && u->GetMap()->IsDungeon()) + xpMod *= 2.75f; + else + xpMod *= 2.0f; + } + + xpMod *= creature->GetCreatureTemplate()->ModExperience; } - gain = uint32(gain * sWorld->getRate(RATE_XP_KILL)); + xpMod *= sWorld->getRate(RATE_XP_KILL); + gain = uint32(gain * xpMod); } sScriptMgr->OnGainCalculation(gain, player, u); diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index a26b14af4b7..eb9b1ad45b9 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -197,18 +197,22 @@ uint32 Quest::XPValue(Player* player) const int32 Quest::GetRewOrReqMoney() const { + // RequiredMoney: the amount is the negative copper sum. if (RewardOrRequiredMoney <= 0) return RewardOrRequiredMoney; - return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_DROP_MONEY)); + // RewardMoney: the positive amount + return int32(RewardOrRequiredMoney * sWorld->getRate(RATE_MONEY_QUEST)); } uint32 Quest::GetRewMoneyMaxLevel() const { + // If Quest has flag to not give money on max level, it's 0 if (HasFlag(QUEST_FLAGS_NO_MONEY_FROM_XP)) return 0; - return RewardMoneyMaxLevel; + // Else, return the rewarded copper sum modified by the rate + return uint32(RewardMoneyMaxLevel * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); } bool Quest::IsAutoAccept() const diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index a0185bf7709..d036d438926 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -266,7 +266,6 @@ void AddSC_blasted_lands(); void AddSC_burning_steppes(); void AddSC_duskwood(); void AddSC_eastern_plaguelands(); -void AddSC_eversong_woods(); void AddSC_ghostlands(); void AddSC_hinterlands(); void AddSC_isle_of_queldanas(); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index d2602e83944..ca8e2cd5a34 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -16,13 +16,14 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <memory> #include "WorldSocket.h" #include "BigNumber.h" #include "Opcodes.h" +#include "Player.h" #include "ScriptMgr.h" #include "SHA1.h" #include "PacketLog.h" +#include <memory> using boost::asio::ip::tcp; @@ -63,6 +64,22 @@ void WorldSocket::ReadHeaderHandler() EndianConvertReverse(header->size); EndianConvert(header->cmd); + if (!header->IsValid()) + { + if (_worldSession) + { + Player* player = _worldSession->GetPlayer(); + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client (account: %u, char [GUID: %u, name: %s]) sent malformed packet (size: %hu, cmd: %u)", + _worldSession->GetAccountId(), player ? player->GetGUIDLow() : 0, player ? player->GetName().c_str() : "<none>", header->size, header->cmd); + } + else + TC_LOG_ERROR("network", "WorldSocket::ReadHeaderHandler(): client %s sent malformed packet (size: %hu, cmd: %u)", + GetRemoteIpAddress().to_string().c_str(), header->size, header->cmd); + + CloseSocket(); + return; + } + AsyncReadData(header->size - sizeof(header->cmd)); } @@ -70,8 +87,6 @@ void WorldSocket::ReadDataHandler() { ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetHeaderBuffer()); - header->size -= sizeof(header->cmd); - uint16 opcode = uint16(header->cmd); std::string opcodeName = GetOpcodeNameForLogging(opcode); @@ -106,7 +121,8 @@ void WorldSocket::ReadDataHandler() if (!_worldSession) { TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); - break; + CloseSocket(); + return; } // Our Idle timer will reset on any non PING opcodes. @@ -155,35 +171,30 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) std::string account; SHA1Hash sha; uint32 clientBuild; - uint32 unk2, unk3, unk5, unk6, unk7; + uint32 serverId, loginServerType, region, battlegroup, realmIndex; uint64 unk4; WorldPacket packet, SendAddonPacked; BigNumber k; bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); - if (sWorld->IsClosed()) - { - SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); - return; - } - // Read the content of the packet recvPacket >> clientBuild; - recvPacket >> unk2; + recvPacket >> serverId; // Used for GRUNT only recvPacket >> account; - recvPacket >> unk3; + recvPacket >> loginServerType; // 0 GRUNT, 1 Battle.net recvPacket >> clientSeed; - recvPacket >> unk5 >> unk6 >> unk7; + recvPacket >> region >> battlegroup; // Used for Battle.net only + recvPacket >> realmIndex; // realmId from auth_database.realmlist table recvPacket >> unk4; recvPacket.read(digest, 20); - TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: client %u, unk2 %u, account %s, unk3 %u, clientseed %u", + TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: client %u, serverId %u, account %s, loginServerType %u, clientseed %u, realmIndex %u", clientBuild, - unk2, + serverId, account.c_str(), - unk3, - clientSeed); + loginServerType, + clientSeed, + realmIndex); // Get the account information from the auth database // 0 1 2 3 4 5 6 7 8 @@ -200,6 +211,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // We can not log here, as we do not know the account. Thus, no accountId. SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (unknown account)."); + DelayedCloseSocket(); return; } @@ -225,6 +237,57 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) // id has to be fetched at this point, so that first actual account response that fails can be logged id = fields[0].GetUInt32(); + k.SetHexStr(fields[1].GetCString()); + + // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it + _authCrypt.Init(&k); + + // First reject the connection if packet contains invalid data or realm state doesn't allow logging in + if (sWorld->IsClosed()) + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + if (realmIndex != realmID) + { + SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (bad realm)."); + DelayedCloseSocket(); + return; + } + + std::string os = fields[8].GetString(); + + // Must be done before WorldSession is created + if (wardenActive && os != "Win" && os != "OSX") + { + SendAuthResponseError(AUTH_REJECT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); + DelayedCloseSocket(); + return; + } + + // Check that Key and account name are the same on client and server + uint32 t = 0; + + sha.UpdateData(account); + sha.UpdateData((uint8*)&t, 4); + sha.UpdateData((uint8*)&clientSeed, 4); + sha.UpdateData((uint8*)&_authSeed, 4); + sha.UpdateBigNumbers(&k, NULL); + sha.Finalize(); + + if (memcmp(sha.GetDigest(), digest, 20)) + { + SendAuthResponseError(AUTH_FAILED); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); + DelayedCloseSocket(); + return; + } + ///- Re-check ip locking (same check as in auth). if (fields[3].GetUInt8() == 1) // if ip is locked { @@ -234,12 +297,11 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) TC_LOG_DEBUG("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account IP differs. Original IP: %s, new IP: %s).", fields[2].GetCString(), address.c_str()); // We could log on hook only instead of an additional db log, however action logger is config based. Better keep DB logging as well sScriptMgr->OnFailedAccountLogin(id); + DelayedCloseSocket(); return; } } - k.SetHexStr(fields[1].GetCString()); - int64 mutetime = fields[5].GetInt64(); //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. if (mutetime < 0) @@ -259,16 +321,6 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) locale = LOCALE_enUS; uint32 recruiter = fields[7].GetUInt32(); - std::string os = fields[8].GetString(); - - // Must be done before WorldSession is created - if (wardenActive && os != "Win" && os != "OSX") - { - SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client %s attempted to log in using invalid client OS (%s).", address.c_str(), os.c_str()); - return; - } - // Checks gmlevel per Realm stmt = LoginDatabase.GetPreparedStatement(LOGIN_GET_GMLEVEL_BY_REALMID); @@ -298,6 +350,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_BANNED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Sent Auth Response (Account banned)."); sScriptMgr->OnFailedAccountLogin(id); + DelayedCloseSocket(); return; } @@ -309,23 +362,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) SendAuthResponseError(AUTH_UNAVAILABLE); TC_LOG_INFO("network", "WorldSocket::HandleAuthSession: User tries to login but his security level is not enough"); sScriptMgr->OnFailedAccountLogin(id); - return; - } - - // Check that Key and account name are the same on client and server - uint32 t = 0; - - sha.UpdateData(account); - sha.UpdateData((uint8*)&t, 4); - sha.UpdateData((uint8*)&clientSeed, 4); - sha.UpdateData((uint8*)&_authSeed, 4); - sha.UpdateBigNumbers(&k, NULL); - sha.Finalize(); - - if (memcmp(sha.GetDigest(), digest, 20)) - { - SendAuthResponseError(AUTH_FAILED); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", id, account.c_str(), address.c_str()); + DelayedCloseSocket(); return; } @@ -352,19 +389,15 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) LoginDatabase.Execute(stmt); - // NOTE ATM the socket is single-threaded, have this in mind ... - _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); - - _authCrypt.Init(&k); + // At this point, we can safely hook a successful login + sScriptMgr->OnAccountLogin(id); + _worldSession = new WorldSession(id, shared_from_this(), AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter); _worldSession->LoadGlobalAccountData(); _worldSession->LoadTutorialsData(); _worldSession->ReadAddonsInfo(recvPacket); _worldSession->LoadPermissions(); - // At this point, we can safely hook a successful login - sScriptMgr->OnAccountLogin(id); - // Initialize Warden system only if it is enabled by config if (wardenActive) _worldSession->InitWarden(&k, os); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index faa57b58f93..0667c1b090a 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -48,6 +48,8 @@ struct ClientPktHeader { uint16 size; uint32 cmd; + + bool IsValid() const { return size >= 4 && size < 10240 && cmd < NUM_MSG_TYPES; } }; #pragma pack(pop) diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 9a315d48d29..cb555bf2954 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -5089,7 +5089,7 @@ SpellCastResult Spell::CheckCast(bool strict) return SPELL_FAILED_TARGET_UNSKINNABLE; Creature* creature = m_targets.GetUnitTarget()->ToCreature(); - if (creature->GetCreatureType() != CREATURE_TYPE_CRITTER && !creature->loot.isLooted()) + if (!creature->IsCritter() && !creature->loot.isLooted()) return SPELL_FAILED_TARGET_NOT_LOOTED; uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill(); diff --git a/src/server/game/Texts/CreatureTextMgr.cpp b/src/server/game/Texts/CreatureTextMgr.cpp index 8bd7a5a5e71..0412128754c 100644 --- a/src/server/game/Texts/CreatureTextMgr.cpp +++ b/src/server/game/Texts/CreatureTextMgr.cpp @@ -180,7 +180,7 @@ void CreatureTextMgr::LoadCreatureTextLocales() { Field* fields = result->Fetch(); CreatureTextLocale& loc = mLocaleTextMap[CreatureTextId(fields[0].GetUInt32(), uint32(fields[1].GetUInt8()), uint32(fields[2].GetUInt8()))]; - for (uint8 i = 1; i < TOTAL_LOCALES; ++i) + for (uint8 i = TOTAL_LOCALES - 1; i > 0; --i) { LocaleConstant locale = LocaleConstant(i); ObjectMgr::AddLocaleString(fields[3 + i - 1].GetString(), locale, loc.Text); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 3f94cfbf56f..4de9cb34df6 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -557,6 +557,18 @@ void World::LoadConfigSettings(bool reload) TC_LOG_ERROR("server.loading", "DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.", rate_values[RATE_DURABILITY_LOSS_BLOCK]); rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f; } + rate_values[RATE_MONEY_QUEST] = sConfigMgr->GetFloatDefault("Rate.Quest.Money.Reward", 1.0f); + if (rate_values[RATE_MONEY_QUEST] < 0.0f) + { + TC_LOG_ERROR("server.loading", "Rate.Quest.Money.Reward (%f) must be >=0. Using 0 instead.", rate_values[RATE_MONEY_QUEST]); + rate_values[RATE_MONEY_QUEST] = 0.0f; + } + rate_values[RATE_MONEY_MAX_LEVEL_QUEST] = sConfigMgr->GetFloatDefault("Rate.Quest.Money.Max.Level.Reward", 1.0f); + if (rate_values[RATE_MONEY_MAX_LEVEL_QUEST] < 0.0f) + { + TC_LOG_ERROR("server.loading", "Rate.Quest.Money.Max.Level.Reward (%f) must be >=0. Using 0 instead.", rate_values[RATE_MONEY_MAX_LEVEL_QUEST]); + rate_values[RATE_MONEY_MAX_LEVEL_QUEST] = 0.0f; + } ///- Read other configuration items from the config file m_bool_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfigMgr->GetBoolDefault("DurabilityLoss.InPvP", false); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 0711ead6187..cb87e1739c2 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -399,6 +399,8 @@ enum Rates RATE_DURABILITY_LOSS_ABSORB, RATE_DURABILITY_LOSS_BLOCK, RATE_MOVESPEED, + RATE_MONEY_QUEST, + RATE_MONEY_MAX_LEVEL_QUEST, MAX_RATES }; diff --git a/src/server/scripts/Commands/cs_ban.cpp b/src/server/scripts/Commands/cs_ban.cpp index cc5c8e49c69..a90bbd69e24 100644 --- a/src/server/scripts/Commands/cs_ban.cpp +++ b/src/server/scripts/Commands/cs_ban.cpp @@ -109,21 +109,23 @@ public: return false; } - switch (sWorld->BanCharacter(name, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "")) + std::string author = handler->GetSession() ? handler->GetSession()->GetPlayerName() : "Server"; + + switch (sWorld->BanCharacter(name, durationStr, reasonStr, author)) { case BAN_SUCCESS: { if (atoi(durationStr) > 0) { if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) - sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUBANNEDMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), name.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); + sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUBANNEDMESSAGE_WORLD, author.c_str(), name.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); else handler->PSendSysMessage(LANG_BAN_YOUBANNED, name.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); } else { if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) - sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUPERMBANNEDMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), name.c_str(), reasonStr); + sWorld->SendWorldText(LANG_BAN_CHARACTER_YOUPERMBANNEDMESSAGE_WORLD, author.c_str(), name.c_str(), reasonStr); else handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, name.c_str(), reasonStr); } @@ -195,20 +197,22 @@ public: break; } - switch (sWorld->BanAccount(mode, nameOrIP, durationStr, reasonStr, handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "")) + std::string author = handler->GetSession() ? handler->GetSession()->GetPlayerName() : "Server"; + + switch (sWorld->BanAccount(mode, nameOrIP, durationStr, reasonStr, author)) { case BAN_SUCCESS: if (atoi(durationStr) > 0) { if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) - sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), nameOrIP.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD, author.c_str(), nameOrIP.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); else handler->PSendSysMessage(LANG_BAN_YOUBANNED, nameOrIP.c_str(), secsToTimeString(TimeStringToSecs(durationStr), true).c_str(), reasonStr); } else { if (sWorld->getBoolConfig(CONFIG_SHOW_BAN_IN_WORLD)) - sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), nameOrIP.c_str(), reasonStr); + sWorld->SendWorldText(LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD, author.c_str(), nameOrIP.c_str(), reasonStr); else handler->PSendSysMessage(LANG_BAN_YOUPERMBANNED, nameOrIP.c_str(), reasonStr); } diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index 47128dd9911..a3848c00877 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -1609,16 +1609,7 @@ public: banReason = fields[3].GetString(); } - // Can be used to query data from World database - stmt2 = WorldDatabase.GetPreparedStatement(WORLD_SEL_REQ_XP); - stmt2->setUInt8(0, level); - PreparedQueryResult result3 = WorldDatabase.Query(stmt2); - if (result3) - { - Field* fields = result3->Fetch(); - xptotal = fields[0].GetUInt32(); - } // Can be used to query data from Characters database stmt2 = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PINFO_XP); @@ -1630,6 +1621,7 @@ public: Field* fields = result4->Fetch(); xp = fields[0].GetUInt32(); // Used for "current xp" output and "%u XP Left" calculation uint32 gguid = fields[1].GetUInt32(); // We check if have a guild for the person, so we might not require to query it at all + xptotal = sObjectMgr->GetXPForLevel(level); if (gguid != 0) { @@ -1766,10 +1758,10 @@ public: Player* player = handler->GetSession()->GetPlayer(); // accept only explicitly selected target (not implicitly self targeting case) - Unit* target = handler->getSelectedUnit(); - if (player->GetTarget() && target) + Creature* target = player->GetTarget() ? handler->getSelectedCreature() : nullptr; + if (target) { - if (target->GetTypeId() != TYPEID_UNIT || target->IsPet()) + if (target->IsPet()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); @@ -1777,19 +1769,13 @@ public: } if (target->isDead()) - target->ToCreature()->Respawn(); + target->Respawn(); return true; } - CellCoord p(Trinity::ComputeCellCoord(player->GetPositionX(), player->GetPositionY())); - Cell cell(p); - cell.SetNoCreate(); - Trinity::RespawnDo u_do; Trinity::WorldObjectWorker<Trinity::RespawnDo> worker(player, u_do); - - TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::RespawnDo>, GridTypeMapContainer > obj_worker(worker); - cell.Visit(p, obj_worker, *player->GetMap(), *player, player->GetGridActivationRange()); + player->VisitNearbyGridObject(player->GetGridActivationRange(), worker); return true; } @@ -1843,14 +1829,9 @@ public: std::string nameLink = handler->playerLink(targetName); if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD)) - { - sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, (handler->GetSession() ? handler->GetSession()->GetPlayerName().c_str() : "Server"), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); - ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str()); - } - else - { - ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str()); - } + sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + + ChatHandler(target->GetSession()).PSendSysMessage(LANG_YOUR_CHAT_DISABLED, notSpeakTime, muteBy.c_str(), muteReasonStr.c_str()); } else { @@ -1865,10 +1846,11 @@ public: LoginDatabase.Execute(stmt); std::string nameLink = handler->playerLink(targetName); - if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD) && !target) - sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, handler->GetSession()->GetPlayerName().c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); - else - handler->PSendSysMessage(target ? LANG_YOU_DISABLE_CHAT : LANG_COMMAND_DISABLE_CHAT_DELAYED, nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + if (sWorld->getBoolConfig(CONFIG_SHOW_MUTE_IN_WORLD) && !target) + sWorld->SendWorldText(LANG_COMMAND_MUTEMESSAGE_WORLD, muteBy.c_str(), nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + else + handler->PSendSysMessage(target ? LANG_YOU_DISABLE_CHAT : LANG_COMMAND_DISABLE_CHAT_DELAYED, nameLink.c_str(), notSpeakTime, muteReasonStr.c_str()); + return true; } diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index cc4bf3dd22f..70aacbfc227 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -440,7 +440,7 @@ public: continue; } - CreatureTemplate* cInfo = const_cast<CreatureTemplate*>(sObjectMgr->GetCreatureTemplate(entry)); + CreatureTemplate const* cInfo = sObjectMgr->GetCreatureTemplate(entry); if (!cInfo) { handler->PSendSysMessage(LANG_COMMAND_CREATURESTORAGE_NOTFOUND, entry); @@ -450,89 +450,7 @@ public: TC_LOG_INFO("misc", "Reloading creature template entry %u", entry); Field* fields = result->Fetch(); - - cInfo->DifficultyEntry[0] = fields[0].GetUInt32(); - cInfo->DifficultyEntry[1] = fields[1].GetUInt32(); - cInfo->DifficultyEntry[2] = fields[2].GetUInt32(); - cInfo->KillCredit[0] = fields[3].GetUInt32(); - cInfo->KillCredit[1] = fields[4].GetUInt32(); - cInfo->Modelid1 = fields[5].GetUInt32(); - cInfo->Modelid2 = fields[6].GetUInt32(); - cInfo->Modelid3 = fields[7].GetUInt32(); - cInfo->Modelid4 = fields[8].GetUInt32(); - cInfo->Name = fields[9].GetString(); - cInfo->SubName = fields[10].GetString(); - cInfo->IconName = fields[11].GetString(); - cInfo->GossipMenuId = fields[12].GetUInt32(); - cInfo->minlevel = fields[13].GetUInt8(); - cInfo->maxlevel = fields[14].GetUInt8(); - cInfo->expansion = fields[15].GetUInt16(); - cInfo->faction = fields[16].GetUInt16(); - cInfo->npcflag = fields[17].GetUInt32(); - cInfo->speed_walk = fields[18].GetFloat(); - cInfo->speed_run = fields[19].GetFloat(); - cInfo->scale = fields[20].GetFloat(); - cInfo->rank = fields[21].GetUInt8(); - cInfo->mindmg = fields[22].GetFloat(); - cInfo->maxdmg = fields[23].GetFloat(); - cInfo->dmgschool = fields[24].GetUInt8(); - cInfo->attackpower = fields[25].GetUInt32(); - cInfo->dmg_multiplier = fields[26].GetFloat(); - cInfo->baseattacktime = fields[27].GetUInt32(); - cInfo->rangeattacktime = fields[28].GetUInt32(); - cInfo->unit_class = fields[29].GetUInt8(); - cInfo->unit_flags = fields[30].GetUInt32(); - cInfo->unit_flags2 = fields[31].GetUInt32(); - cInfo->dynamicflags = fields[32].GetUInt32(); - cInfo->family = fields[33].GetUInt8(); - cInfo->trainer_type = fields[34].GetUInt8(); - cInfo->trainer_spell = fields[35].GetUInt32(); - cInfo->trainer_class = fields[36].GetUInt8(); - cInfo->trainer_race = fields[37].GetUInt8(); - cInfo->minrangedmg = fields[38].GetFloat(); - cInfo->maxrangedmg = fields[39].GetFloat(); - cInfo->rangedattackpower = fields[40].GetUInt16(); - cInfo->type = fields[41].GetUInt8(); - cInfo->type_flags = fields[42].GetUInt32(); - cInfo->lootid = fields[43].GetUInt32(); - cInfo->pickpocketLootId = fields[44].GetUInt32(); - cInfo->SkinLootId = fields[45].GetUInt32(); - - for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) - cInfo->resistance[i] = fields[46 + i -1].GetUInt16(); - - cInfo->spells[0] = fields[52].GetUInt32(); - cInfo->spells[1] = fields[53].GetUInt32(); - cInfo->spells[2] = fields[54].GetUInt32(); - cInfo->spells[3] = fields[55].GetUInt32(); - cInfo->spells[4] = fields[56].GetUInt32(); - cInfo->spells[5] = fields[57].GetUInt32(); - cInfo->spells[6] = fields[58].GetUInt32(); - cInfo->spells[7] = fields[59].GetUInt32(); - cInfo->PetSpellDataId = fields[60].GetUInt32(); - cInfo->VehicleId = fields[61].GetUInt32(); - cInfo->mingold = fields[62].GetUInt32(); - cInfo->maxgold = fields[63].GetUInt32(); - cInfo->AIName = fields[64].GetString(); - cInfo->MovementType = fields[65].GetUInt8(); - cInfo->InhabitType = fields[66].GetUInt8(); - cInfo->HoverHeight = fields[67].GetFloat(); - cInfo->ModHealth = fields[68].GetFloat(); - cInfo->ModMana = fields[69].GetFloat(); - cInfo->ModArmor = fields[70].GetFloat(); - cInfo->RacialLeader = fields[71].GetBool(); - cInfo->questItems[0] = fields[72].GetUInt32(); - cInfo->questItems[1] = fields[73].GetUInt32(); - cInfo->questItems[2] = fields[74].GetUInt32(); - cInfo->questItems[3] = fields[75].GetUInt32(); - cInfo->questItems[4] = fields[76].GetUInt32(); - cInfo->questItems[5] = fields[77].GetUInt32(); - cInfo->movementId = fields[78].GetUInt32(); - cInfo->RegenHealth = fields[79].GetBool(); - cInfo->MechanicImmuneMask = fields[80].GetUInt32(); - cInfo->flags_extra = fields[81].GetUInt32(); - cInfo->ScriptID = sObjectMgr->GetScriptId(fields[82].GetCString()); - + sObjectMgr->LoadCreatureTemplate(fields); sObjectMgr->CheckCreatureTemplate(cInfo); } diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp index f18c0aac8bb..26937a83e63 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_arcanist_doan.cpp @@ -70,6 +70,11 @@ class boss_arcanist_doan : public CreatureScript events.ScheduleEvent(EVENT_POLYMORPH, 30 * IN_MILLISECONDS); } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + } + void UpdateAI(uint32 diff) override { if (!UpdateVictim()) @@ -119,7 +124,7 @@ class boss_arcanist_doan : public CreatureScript CreatureAI* GetAI(Creature* creature) const override { - return new boss_arcanist_doanAI(creature); + return GetInstanceAI<boss_arcanist_doanAI>(creature); } }; diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp index dd173c75232..72874bba510 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_azshir_the_sleepless.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -25,79 +24,104 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "scarlet_monastery.h" enum Spells { - SPELL_CALLOFTHEGRAVE = 17831, + SPELL_CALL_OF_THE_GRAVE = 17831, SPELL_TERRIFY = 7399, - SPELL_SOULSIPHON = 7290 + SPELL_SOUL_SIPHON = 7290 }; -class boss_azshir_the_sleepless : public CreatureScript +enum Events { -public: - boss_azshir_the_sleepless() : CreatureScript("boss_azshir_the_sleepless") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_azshir_the_sleeplessAI(creature); - } - - struct boss_azshir_the_sleeplessAI : public ScriptedAI - { - boss_azshir_the_sleeplessAI(Creature* creature) : ScriptedAI(creature) { } + EVENT_CALL_OF_GRAVE = 1, + EVENT_TERRIFY, + EVENT_SOUL_SIPHON +}; - uint32 SoulSiphon_Timer; - uint32 CallOftheGrave_Timer; - uint32 Terrify_Timer; +class boss_azshir_the_sleepless : public CreatureScript +{ + public: + boss_azshir_the_sleepless() : CreatureScript("boss_azshir_the_sleepless") { } - void Reset() override + struct boss_azshir_the_sleeplessAI : public BossAI { - SoulSiphon_Timer = 1; - CallOftheGrave_Timer = 30000; - Terrify_Timer = 20000; - } - - void EnterCombat(Unit* /*who*/) override { } + boss_azshir_the_sleeplessAI(Creature* creature) : BossAI(creature, DATA_AZSHIR) + { + _siphon = false; + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void Reset() override + { + _Reset(); + _siphon = false; + } - //If we are <50% hp cast Soul Siphon rank 1 - if (!HealthAbovePct(50) && !me->IsNonMeleeSpellCast(false)) + void EnterCombat(Unit* /*who*/) override { - //SoulSiphon_Timer - if (SoulSiphon_Timer <= diff) - { - DoCastVictim(SPELL_SOULSIPHON); - return; + _EnterCombat(); + events.ScheduleEvent(EVENT_CALL_OF_GRAVE, 30000); + events.ScheduleEvent(EVENT_TERRIFY, 20000); + } - //SoulSiphon_Timer = 20000; - } - else SoulSiphon_Timer -= diff; + void JustDied(Unit* /*killer*/) override + { + _JustDied(); } - //CallOfTheGrave_Timer - if (CallOftheGrave_Timer <= diff) + void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override { - DoCastVictim(SPELL_CALLOFTHEGRAVE); - CallOftheGrave_Timer = 30000; + if (HealthBelowPct(50) && !_siphon) + { + DoCastVictim(SPELL_SOUL_SIPHON); + events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000); + _siphon = true; + } } - else CallOftheGrave_Timer -= diff; - //Terrify_Timer - if (Terrify_Timer <= diff) + void UpdateAI(uint32 diff) override { - DoCastVictim(SPELL_TERRIFY); - Terrify_Timer = 20000; + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CALL_OF_GRAVE: + DoCastVictim(SPELL_CALL_OF_THE_GRAVE); + events.ScheduleEvent(EVENT_CALL_OF_GRAVE, 30000); + break; + case EVENT_TERRIFY: + DoCastVictim(SPELL_TERRIFY); + events.ScheduleEvent(EVENT_TERRIFY, 20000); + break; + case EVENT_SOUL_SIPHON: + DoCastVictim(SPELL_SOUL_SIPHON); + events.ScheduleEvent(EVENT_SOUL_SIPHON, 20000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); } - else Terrify_Timer -= diff; - DoMeleeAttackIfReady(); + private: + bool _siphon; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_azshir_the_sleeplessAI>(creature); } - }; }; void AddSC_boss_azshir_the_sleepless() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp index 207c12f608a..43a9ef32be6 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_bloodmage_thalnos.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,15 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Bloodmage_Thalnos -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "scarlet_monastery.h" enum Yells { @@ -38,95 +31,102 @@ enum Spells SPELL_FLAMESHOCK = 8053, SPELL_SHADOWBOLT = 1106, SPELL_FLAMESPIKE = 8814, - SPELL_FIRENOVA = 16079, + SPELL_FIRENOVA = 16079 }; -class boss_bloodmage_thalnos : public CreatureScript +enum Events { -public: - boss_bloodmage_thalnos() : CreatureScript("boss_bloodmage_thalnos") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_bloodmage_thalnosAI(creature); - } - - struct boss_bloodmage_thalnosAI : public ScriptedAI - { - boss_bloodmage_thalnosAI(Creature* creature) : ScriptedAI(creature) { } - - bool HpYell; - uint32 FlameShock_Timer; - uint32 ShadowBolt_Timer; - uint32 FlameSpike_Timer; - uint32 FireNova_Timer; + EVENT_FLAME_SHOCK = 1, + EVENT_SHADOW_BOLT, + EVENT_FLAME_SPIKE, + EVENT_FIRE_NOVA +}; - void Reset() override - { - HpYell = false; - FlameShock_Timer = 10000; - ShadowBolt_Timer = 2000; - FlameSpike_Timer = 8000; - FireNova_Timer = 40000; - } +class boss_bloodmage_thalnos : public CreatureScript +{ + public: + boss_bloodmage_thalnos() : CreatureScript("boss_bloodmage_thalnos") { } - void EnterCombat(Unit* /*who*/) override + struct boss_bloodmage_thalnosAI : public BossAI { - Talk(SAY_AGGRO); - } + boss_bloodmage_thalnosAI(Creature* creature) : BossAI(creature, DATA_BLOODMAGE_THALNOS) + { + _hpYell = false; + } - void KilledUnit(Unit* /*Victim*/) override - { - Talk(SAY_KILL); - } + void Reset() override + { + _hpYell = false; + _Reset(); + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); + events.ScheduleEvent(EVENT_FLAME_SHOCK, 10000); + events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000); + events.ScheduleEvent(EVENT_FLAME_SPIKE, 8000); + events.ScheduleEvent(EVENT_FIRE_NOVA, 40000); + } - //If we are <35% hp - if (!HpYell && !HealthAbovePct(35)) + void JustDied(Unit* /*killer*/) override { - Talk(SAY_HEALTH); - HpYell = true; + _JustDied(); } - //FlameShock_Timer - if (FlameShock_Timer <= diff) + void KilledUnit(Unit* /*victim*/) override { - DoCastVictim(SPELL_FLAMESHOCK); - FlameShock_Timer = urand(10000, 15000); + Talk(SAY_KILL); } - else FlameShock_Timer -= diff; - //FlameSpike_Timer - if (FlameSpike_Timer <= diff) + void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override { - DoCastVictim(SPELL_FLAMESPIKE); - FlameSpike_Timer = 30000; + if (HealthBelowPct(35) && !_hpYell) + { + Talk(SAY_HEALTH); + _hpYell = true; + } } - else FlameSpike_Timer -= diff; - //FireNova_Timer - if (FireNova_Timer <= diff) + void ExecuteEvent(uint32 eventId) override { - DoCastVictim(SPELL_FIRENOVA); - FireNova_Timer = 40000; + switch (eventId) + { + case EVENT_FLAME_SHOCK: + DoCastVictim(SPELL_FLAMESHOCK); + events.ScheduleEvent(EVENT_FLAME_SHOCK, urand(10000, 15000)); + break; + case EVENT_SHADOW_BOLT: + DoCastVictim(SPELL_SHADOWBOLT); + events.ScheduleEvent(EVENT_SHADOW_BOLT, 2000); + break; + case EVENT_FLAME_SPIKE: + DoCastVictim(SPELL_FLAMESPIKE); + events.ScheduleEvent(EVENT_FLAME_SPIKE, 30000); + break; + case EVENT_FIRE_NOVA: + DoCastVictim(SPELL_FIRENOVA); + events.ScheduleEvent(EVENT_FIRE_NOVA, 40000); + break; + default: + break; + } } - else FireNova_Timer -= diff; - //ShadowBolt_Timer - if (ShadowBolt_Timer <= diff) + void UpdateAI(uint32 diff) override { - DoCastVictim(SPELL_SHADOWBOLT); - ShadowBolt_Timer = 2000; + BossAI::UpdateAI(diff); } - else ShadowBolt_Timer -= diff; - DoMeleeAttackIfReady(); + private: + bool _hpYell; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_bloodmage_thalnosAI>(creature); } - }; }; void AddSC_boss_bloodmage_thalnos() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp index 5939d4a41db..cad46b84748 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_headless_horseman.cpp @@ -155,13 +155,13 @@ public: { npc_wisp_invisAI(Creature* creature) : ScriptedAI(creature) { - Creaturetype = delay = spell = spell2 = 0; + Creaturetype = delay = _spell = _spell2 = 0; } uint32 Creaturetype; uint32 delay; - uint32 spell; - uint32 spell2; + uint32 _spell; + uint32 _spell2; void Reset() override { } void EnterCombat(Unit* /*who*/) override { } void SetType(uint32 _type) @@ -169,24 +169,24 @@ public: switch (Creaturetype = _type) { case 1: - spell = SPELL_PUMPKIN_AURA_GREEN; + _spell = SPELL_PUMPKIN_AURA_GREEN; break; case 2: delay = 15000; - spell = SPELL_BODY_FLAME; - spell2 = SPELL_DEATH; + _spell = SPELL_BODY_FLAME; + _spell2 = SPELL_DEATH; break; case 3: delay = 15000; - spell = SPELL_SMOKE; + _spell = SPELL_SMOKE; break; case 4: delay = 7000; - spell2 = SPELL_WISP_BLUE; + _spell2 = SPELL_WISP_BLUE; break; } - if (spell) - DoCast(me, spell); + if (_spell) + DoCast(me, _spell); } void SpellHit(Unit* /*caster*/, const SpellInfo* spell) override @@ -196,7 +196,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!who || Creaturetype != 1 || !who->isTargetableForAttack()) return; @@ -212,8 +211,8 @@ public: if (delay <= diff) { me->RemoveAurasDueToSpell(SPELL_SMOKE); - if (spell2) - DoCast(me, spell2); + if (_spell2) + DoCast(me, _spell2); delay = 0; } else delay -= diff; } @@ -435,7 +434,7 @@ public: } me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); - //instance->SetData(DATA_HORSEMAN_EVENT, NOT_STARTED); + //instance->SetBossState(DATA_HORSEMAN_EVENT, NOT_STARTED); } void FlyMode() @@ -471,7 +470,7 @@ public: break; } case 6: - instance->SetData(GAMEOBJECT_PUMPKIN_SHRINE, 0); //hide gameobject + instance->SetData(DATA_PUMPKIN_SHRINE, 0); //hide gameobject break; case 19: me->SetDisableGravity(false); @@ -493,7 +492,7 @@ public: void EnterCombat(Unit* /*who*/) override { - instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_HORSEMAN_EVENT, IN_PROGRESS); DoZoneInCombat(); } @@ -503,7 +502,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (withhead && Phase != 0) ScriptedAI::MoveInLineOfSight(who); @@ -567,7 +565,7 @@ public: flame->CastSpell(flame, SPELL_BODY_FLAME, false); if (Creature* wisp = DoSpawnCreature(WISP_INVIS, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN, 60000)) ENSURE_AI(npc_wisp_invis::npc_wisp_invisAI, wisp->AI())->SetType(4); - instance->SetData(DATA_HORSEMAN_EVENT, DONE); + instance->SetBossState(DATA_HORSEMAN_EVENT, DONE); Map::PlayerList const& players = me->GetMap()->GetPlayers(); if (!players.isEmpty()) @@ -852,7 +850,6 @@ public: } void MoveInLineOfSight(Unit* who) override - { if (!who || !me->IsValidAttackTarget(who) || me->GetVictim()) return; @@ -880,9 +877,9 @@ public: InstanceScript* instance = player->GetInstanceScript(); if (instance) { - if (instance->GetData(DATA_HORSEMAN_EVENT) != NOT_STARTED) + if (instance->GetBossState(DATA_HORSEMAN_EVENT) != NOT_STARTED) return true; - instance->SetData(DATA_HORSEMAN_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_HORSEMAN_EVENT, IN_PROGRESS); } /* if (soil->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER && player->getLevel() > 64) { diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp index 480b354fe29..0b7ad73fefd 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_herod.cpp @@ -26,6 +26,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "ScriptedEscortAI.h" +#include "scarlet_monastery.h" enum Says { @@ -44,89 +45,103 @@ enum Spells SPELL_FRENZY = 8269 }; -enum Entry +enum Npcs { - ENTRY_SCARLET_TRAINEE = 6575, - ENTRY_SCARLET_MYRMIDON = 4295 + NPC_SCARLET_TRAINEE = 6575, + NPC_SCARLET_MYRMIDON = 4295 }; -class boss_herod : public CreatureScript +enum Events { -public: - boss_herod() : CreatureScript("boss_herod") { } + EVENT_CLEAVE = 1, + EVENT_WHIRLWIND +}; - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_herodAI(creature); - } +Position const ScarletTraineePos = { 1939.18f, -431.58f, 17.09f, 6.22f }; - struct boss_herodAI : public ScriptedAI - { - boss_herodAI(Creature* creature) : ScriptedAI(creature) { } +class boss_herod : public CreatureScript +{ + public: + boss_herod() : CreatureScript("boss_herod") { } - bool Enrage; + struct boss_herodAI : public BossAI + { + boss_herodAI(Creature* creature) : BossAI(creature, DATA_HEROD) + { + _enrage = false; + } - uint32 Cleave_Timer; - uint32 Whirlwind_Timer; + void Reset() override + { + _enrage = false; + _Reset(); + } - void Reset() override - { - Enrage = false; - Cleave_Timer = 12000; - Whirlwind_Timer = 60000; - } + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + DoCast(me, SPELL_RUSHINGCHARGE); + _EnterCombat(); - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - DoCast(me, SPELL_RUSHINGCHARGE); - } + events.ScheduleEvent(EVENT_CLEAVE, 12000); + events.ScheduleEvent(EVENT_WHIRLWIND, 60000); + } - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_KILL); - } + void KilledUnit(Unit* /*victim*/) override + { + Talk(SAY_KILL); + } - void JustDied(Unit* /*killer*/) override - { - for (uint8 i = 0; i < 20; ++i) - me->SummonCreature(ENTRY_SCARLET_TRAINEE, 1939.18f, -431.58f, 17.09f, 6.22f, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + for (uint8 i = 0; i < 20; ++i) + me->SummonCreature(NPC_SCARLET_TRAINEE, ScarletTraineePos, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, 600000); + } - //If we are <30% hp goes Enraged - if (!Enrage && !HealthAbovePct(30) && !me->IsNonMeleeSpellCast(false)) + void DamageTaken(Unit* /*done_by*/, uint32& /*damage*/) override { - Talk(EMOTE_ENRAGE); - Talk(SAY_ENRAGE); - DoCast(me, SPELL_FRENZY); - Enrage = true; + if (HealthBelowPct(30) && !_enrage) + { + Talk(EMOTE_ENRAGE); + Talk(SAY_ENRAGE); + DoCast(me, SPELL_FRENZY); + _enrage = true; + } } - //Cleave_Timer - if (Cleave_Timer <= diff) + void ExecuteEvent(uint32 eventId) override { - DoCastVictim(SPELL_CLEAVE); - Cleave_Timer = 12000; + switch (eventId) + { + case EVENT_CLEAVE: + DoCastVictim(SPELL_CLEAVE); + events.ScheduleEvent(EVENT_CLEAVE, 12000); + break; + case EVENT_WHIRLWIND: + Talk(SAY_WHIRLWIND); + DoCastVictim(SPELL_WHIRLWIND); + events.ScheduleEvent(EVENT_WHIRLWIND, 30000); + break; + default: + break; + } } - else Cleave_Timer -= diff; - // Whirlwind_Timer - if (Whirlwind_Timer <= diff) + void UpdateAI(uint32 diff) override { - Talk(SAY_WHIRLWIND); - DoCastVictim(SPELL_WHIRLWIND); - Whirlwind_Timer = 30000; + BossAI::UpdateAI(diff); } - else Whirlwind_Timer -= diff; + + private: + bool _enrage; + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_herodAI>(creature); } - }; }; class npc_scarlet_trainee : public CreatureScript diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp index f58ab1519e4..a4a3660b360 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_high_inquisitor_fairbanks.cpp @@ -25,6 +25,7 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "scarlet_monastery.h" enum Spells { @@ -43,12 +44,15 @@ public: CreatureAI* GetAI(Creature* creature) const override { - return new boss_high_inquisitor_fairbanksAI(creature); + return GetInstanceAI<boss_high_inquisitor_fairbanksAI>(creature); } struct boss_high_inquisitor_fairbanksAI : public ScriptedAI { - boss_high_inquisitor_fairbanksAI(Creature* creature) : ScriptedAI(creature) { } + boss_high_inquisitor_fairbanksAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + } uint32 CurseOfBlood_Timer; uint32 DispelMagic_Timer; @@ -57,6 +61,7 @@ public: uint32 Sleep_Timer; uint32 Dispel_Timer; bool PowerWordShield; + InstanceScript* instance; void Reset() override { @@ -69,12 +74,19 @@ public: PowerWordShield = false; me->SetStandState(UNIT_STAND_STATE_DEAD); me->SetUInt32Value(UNIT_FIELD_BYTES_1, 7); + instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, NOT_STARTED); } void EnterCombat(Unit* /*who*/) override { me->SetStandState(UNIT_STAND_STATE_STAND); me->SetUInt32Value(UNIT_FIELD_BYTES_1, 0); + instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, IN_PROGRESS); + } + + void JustDied(Unit* /*killer*/) override + { + instance->SetBossState(DATA_HIGH_INQUISITOR_FAIRBANKS, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp index 5aa9729a7e8..40c7667843b 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_houndmaster_loksey.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,15 +15,9 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Boss_Houndmaster_Loksey -SD%Complete: 100 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "scarlet_monastery.h" enum Yells { @@ -37,47 +30,60 @@ enum Spells SPELL_BLOODLUST = 6742 }; -class boss_houndmaster_loksey : public CreatureScript +enum Events { -public: - boss_houndmaster_loksey() : CreatureScript("boss_houndmaster_loksey") { } + EVENT_BLOODLUST = 1 +}; - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_houndmaster_lokseyAI(creature); - } +class boss_houndmaster_loksey : public CreatureScript +{ + public: + boss_houndmaster_loksey() : CreatureScript("boss_houndmaster_loksey") { } - struct boss_houndmaster_lokseyAI : public ScriptedAI - { - boss_houndmaster_lokseyAI(Creature* creature) : ScriptedAI(creature) { } + struct boss_houndmaster_lokseyAI : public BossAI + { + boss_houndmaster_lokseyAI(Creature* creature) : BossAI(creature, DATA_HOUNDMASTER_LOKSEY) { } - uint32 BloodLust_Timer; + void Reset() override + { + _Reset(); + } - void Reset() override - { - BloodLust_Timer = 20000; - } + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); + events.ScheduleEvent(EVENT_BLOODLUST, 20000); + } - void EnterCombat(Unit* /*who*/) override - { - Talk(SAY_AGGRO); - } + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void ExecuteEvent(uint32 eventId) override + { + switch (eventId) + { + case EVENT_BLOODLUST: + DoCast(me, SPELL_BLOODLUST); + events.ScheduleEvent(EVENT_BLOODLUST, 20000); + break; + default: + break; + } + } - if (BloodLust_Timer <= diff) + void UpdateAI(uint32 diff) override { - DoCast(me, SPELL_BLOODLUST); - BloodLust_Timer = 20000; + BossAI::UpdateAI(diff); } - else BloodLust_Timer -= diff; + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_houndmaster_lokseyAI>(creature); } - }; }; void AddSC_boss_houndmaster_loksey() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp index a7c795a81f6..a73cf946a7c 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_interrogator_vishas.cpp @@ -69,11 +69,13 @@ public: ShadowWordPain_Timer = 5000; Yell60 = false; Yell30 = false; + instance->SetBossState(DATA_INTERROGATOR_VISHAS, NOT_STARTED); } void EnterCombat(Unit* /*who*/) override { Talk(SAY_AGGRO); + instance->SetBossState(DATA_INTERROGATOR_VISHAS, IN_PROGRESS); } void KilledUnit(Unit* /*Victim*/) override @@ -86,6 +88,7 @@ public: //Any other Actions to do with vorrel? setStandState? if (Creature* vorrel = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_VORREL))) vorrel->AI()->Talk(SAY_TRIGGER_VORREL); + instance->SetBossState(DATA_INTERROGATOR_VISHAS, DONE); } void UpdateAI(uint32 diff) override diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 25bb08620a1..a9988584edd 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -95,7 +95,7 @@ public: me->SetStandState(UNIT_STAND_STATE_STAND); if (me->IsAlive()) - instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); + instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); _bHasDied = false; _bHeal = false; @@ -104,8 +104,8 @@ public: void JustReachedHome() override { - if (instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED) - instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, FAIL); + if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) != NOT_STARTED) + instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, FAIL); } void EnterCombat(Unit* /*who*/) override @@ -129,7 +129,7 @@ public: //On first death, fake death and open door, as well as initiate whitemane if exist if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_WHITEMANE))) { - instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); + instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, IN_PROGRESS); Whitemane->GetMotionMaster()->MovePoint(1, 1163.113370f, 1398.856812f, 32.527786f); @@ -163,7 +163,7 @@ public: Talk(SAY_MO_RESURRECTED); _bFakeDeath = false; - instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL); + instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, SPECIAL); } } @@ -172,7 +172,7 @@ public: if (!UpdateVictim()) return; - if (_bHasDied && !_bHeal && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) + if (_bHasDied && !_bHeal && instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) { //On resurrection, stop fake death and heal whitemane and resume fight if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_WHITEMANE))) @@ -254,12 +254,12 @@ public: _bCanResurrect = false; if (me->IsAlive()) - instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); + instance->SetBossState(DATA_MOGRAINE_AND_WHITE_EVENT, NOT_STARTED); } void AttackStart(Unit* who) override { - if (instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) + if (instance->GetBossState(DATA_MOGRAINE_AND_WHITE_EVENT) == NOT_STARTED) return; ScriptedAI::AttackStart(who); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp index 3ed32b71cbb..24efd7017ec 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_scorn.cpp @@ -25,84 +25,87 @@ EndScriptData */ #include "ScriptMgr.h" #include "ScriptedCreature.h" +#include "scarlet_monastery.h" enum Spells { SPELL_LICHSLAP = 28873, - SPELL_FROSTBOLTVOLLEY = 8398, + SPELL_FROSTBOLT_VOLLEY = 8398, SPELL_MINDFLAY = 17313, SPELL_FROSTNOVA = 15531 }; -class boss_scorn : public CreatureScript +enum Events { -public: - boss_scorn() : CreatureScript("boss_scorn") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return new boss_scornAI(creature); - } - - struct boss_scornAI : public ScriptedAI - { - boss_scornAI(Creature* creature) : ScriptedAI(creature) { } + EVENT_LICH_SLAP = 1, + EVENT_FROSTBOLT_VOLLEY, + EVENT_MIND_FLAY, + EVENT_FROST_NOVA +}; - uint32 LichSlap_Timer; - uint32 FrostboltVolley_Timer; - uint32 MindFlay_Timer; - uint32 FrostNova_Timer; +class boss_scorn : public CreatureScript +{ + public: + boss_scorn() : CreatureScript("boss_scorn") { } - void Reset() override + struct boss_scornAI : public BossAI { - LichSlap_Timer = 45000; - FrostboltVolley_Timer = 30000; - MindFlay_Timer = 30000; - FrostNova_Timer = 30000; - } - - void EnterCombat(Unit* /*who*/) override { } + boss_scornAI(Creature* creature) : BossAI(creature, DATA_SCORN) { } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void Reset() override + { + _Reset(); + } - //LichSlap_Timer - if (LichSlap_Timer <= diff) + void EnterCombat(Unit* /*who*/) override { - DoCastVictim(SPELL_LICHSLAP); - LichSlap_Timer = 45000; + _EnterCombat(); + events.ScheduleEvent(EVENT_LICH_SLAP, 45000); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 30000); + events.ScheduleEvent(EVENT_MIND_FLAY, 30000); + events.ScheduleEvent(EVENT_FROST_NOVA, 30000); } - else LichSlap_Timer -= diff; - //FrostboltVolley_Timer - if (FrostboltVolley_Timer <= diff) + void JustDied(Unit* /*killer*/) override { - DoCastVictim(SPELL_FROSTBOLTVOLLEY); - FrostboltVolley_Timer = 20000; + _JustDied(); } - else FrostboltVolley_Timer -= diff; - //MindFlay_Timer - if (MindFlay_Timer <= diff) + void ExecuteEvent(uint32 eventId) override { - DoCastVictim(SPELL_MINDFLAY); - MindFlay_Timer = 20000; + switch (eventId) + { + case EVENT_LICH_SLAP: + DoCastVictim(SPELL_LICHSLAP); + events.ScheduleEvent(EVENT_LICH_SLAP, 45000); + break; + case EVENT_FROSTBOLT_VOLLEY: + DoCastVictim(SPELL_FROSTBOLT_VOLLEY); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 20000); + break; + case EVENT_MIND_FLAY: + DoCastVictim(SPELL_MINDFLAY); + events.ScheduleEvent(EVENT_MIND_FLAY, 20000); + break; + case EVENT_FROST_NOVA: + DoCastVictim(SPELL_FROSTNOVA); + events.ScheduleEvent(EVENT_FROST_NOVA, 15000); + break; + default: + break; + } } - else MindFlay_Timer -= diff; - //FrostNova_Timer - if (FrostNova_Timer <= diff) + void UpdateAI(uint32 diff) override { - DoCastVictim(SPELL_FROSTNOVA); - FrostNova_Timer = 15000; + BossAI::UpdateAI(diff); } - else FrostNova_Timer -= diff; + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_scornAI>(creature); } - }; }; void AddSC_boss_scorn() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp index dc564e43af5..78837912688 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/instance_scarlet_monastery.cpp @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -16,146 +15,205 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -/* ScriptData -SDName: Instance_Scarlet_Monastery -SD%Complete: 50 -SDComment: -SDCategory: Scarlet Monastery -EndScriptData */ - #include "ScriptMgr.h" -#include "ScriptedCreature.h" +#include "InstanceScript.h" #include "scarlet_monastery.h" -enum Entry +DoorData const doorData[] = { - ENTRY_PUMPKIN_SHRINE = 186267, - ENTRY_HORSEMAN = 23682, - ENTRY_HEAD = 23775, - ENTRY_PUMPKIN = 23694 + { GO_HIGH_INQUISITORS_DOOR, DATA_MOGRAINE_AND_WHITE_EVENT, DOOR_TYPE_ROOM, BOUNDARY_NONE }, + { 0, 0, DOOR_TYPE_ROOM, BOUNDARY_NONE } // END }; -#define MAX_ENCOUNTER 2 - class instance_scarlet_monastery : public InstanceMapScript { -public: - instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { } + public: + instance_scarlet_monastery() : InstanceMapScript("instance_scarlet_monastery", 189) { } - InstanceScript* GetInstanceScript(InstanceMap* map) const override - { - return new instance_scarlet_monastery_InstanceMapScript(map); - } + struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript + { + instance_scarlet_monastery_InstanceMapScript(Map* map) : InstanceScript(map) + { + SetBossNumber(EncounterCount); + LoadDoorData(doorData); - struct instance_scarlet_monastery_InstanceMapScript : public InstanceScript - { - instance_scarlet_monastery_InstanceMapScript(Map* map) : InstanceScript(map) { } + PumpkinShrineGUID = 0; + HorsemanGUID = 0; + HeadGUID = 0; + MograineGUID = 0; + WhitemaneGUID = 0; + VorrelGUID = 0; - uint64 PumpkinShrineGUID; - uint64 HorsemanGUID; - uint64 HeadGUID; - std::set<uint64> HorsemanAdds; + HorsemanAdds.clear(); + } - uint64 MograineGUID; - uint64 WhitemaneGUID; - uint64 VorrelGUID; - uint64 DoorHighInquisitorGUID; + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_PUMPKIN_SHRINE: + PumpkinShrineGUID = go->GetGUID(); + break; + case GO_HIGH_INQUISITORS_DOOR: + AddDoor(go, true); + break; + default: + break; + } + } - uint32 encounter[MAX_ENCOUNTER]; + void OnGameObjectRemove(GameObject* go) override + { + switch (go->GetEntry()) + { + case GO_HIGH_INQUISITORS_DOOR: + AddDoor(go, false); + break; + default: + break; + } + } - void Initialize() override - { - memset(&encounter, 0, sizeof(encounter)); + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_HORSEMAN: + HorsemanGUID = creature->GetGUID(); + break; + case NPC_HEAD: + HeadGUID = creature->GetGUID(); + break; + case NPC_PUMPKIN: + HorsemanAdds.insert(creature->GetGUID()); + break; + case NPC_MOGRAINE: + MograineGUID = creature->GetGUID(); + break; + case NPC_WHITEMANE: + WhitemaneGUID = creature->GetGUID(); + break; + case NPC_VORREL: + VorrelGUID = creature->GetGUID(); + break; + default: + break; + } + } - PumpkinShrineGUID = 0; - HorsemanGUID = 0; - HeadGUID = 0; - HorsemanAdds.clear(); + void SetData(uint32 type, uint32 /*data*/) override + { + switch (type) + { + case DATA_PUMPKIN_SHRINE: + HandleGameObject(PumpkinShrineGUID, false); + break; + default: + break; + } + } - MograineGUID = 0; - WhitemaneGUID = 0; - VorrelGUID = 0; - DoorHighInquisitorGUID = 0; - } + bool SetBossState(uint32 type, EncounterState state) override + { + if (!InstanceScript::SetBossState(type, state)) + return false; - void OnGameObjectCreate(GameObject* go) override - { - switch (go->GetEntry()) + switch (type) + { + case DATA_HORSEMAN_EVENT: + if (state == DONE) + { + for (uint64 guid : HorsemanAdds) + { + Creature* add = instance->GetCreature(guid); + if (add && add->IsAlive()) + add->Kill(add); + } + HorsemanAdds.clear(); + HandleGameObject(PumpkinShrineGUID, false); + } + break; + default: + break; + } + return true; + } + + uint64 GetData64(uint32 type) const override { - case ENTRY_PUMPKIN_SHRINE: PumpkinShrineGUID = go->GetGUID();break; - case 104600: DoorHighInquisitorGUID = go->GetGUID(); break; + switch (type) + { + case DATA_MOGRAINE: + return MograineGUID; + case DATA_WHITEMANE: + return WhitemaneGUID; + case DATA_VORREL: + return VorrelGUID; + default: + break; + } + return 0; } - } - void OnCreatureCreate(Creature* creature) override - { - switch (creature->GetEntry()) + std::string GetSaveData() override { - case ENTRY_HORSEMAN: HorsemanGUID = creature->GetGUID(); break; - case ENTRY_HEAD: HeadGUID = creature->GetGUID(); break; - case ENTRY_PUMPKIN: HorsemanAdds.insert(creature->GetGUID());break; - case 3976: MograineGUID = creature->GetGUID(); break; - case 3977: WhitemaneGUID = creature->GetGUID(); break; - case 3981: VorrelGUID = creature->GetGUID(); break; + OUT_SAVE_INST_DATA; + + std::ostringstream saveStream; + saveStream << "S M " << GetBossSaveData(); + + OUT_SAVE_INST_DATA_COMPLETE; + return saveStream.str(); } - } - void SetData(uint32 type, uint32 data) override - { - switch (type) + void Load(const char* str) override { - case TYPE_MOGRAINE_AND_WHITE_EVENT: - if (data == IN_PROGRESS) - DoUseDoorOrButton(DoorHighInquisitorGUID); - if (data == FAIL) - DoUseDoorOrButton(DoorHighInquisitorGUID); - - encounter[0] = data; - break; - case GAMEOBJECT_PUMPKIN_SHRINE: - HandleGameObject(PumpkinShrineGUID, false); - break; - case DATA_HORSEMAN_EVENT: - encounter[1] = data; - if (data == DONE) + if (!str) { - for (std::set<uint64>::const_iterator itr = HorsemanAdds.begin(); itr != HorsemanAdds.end(); ++itr) + OUT_LOAD_INST_DATA_FAIL; + return; + } + + OUT_LOAD_INST_DATA(str); + + char dataHead1, dataHead2; + + std::istringstream loadStream(str); + loadStream >> dataHead1 >> dataHead2; + + if (dataHead1 == 'S' && dataHead2 == 'M') + { + for (uint8 i = 0; i < EncounterCount; ++i) { - Creature* add = instance->GetCreature(*itr); - if (add && add->IsAlive()) - add->Kill(add); + uint32 tmpState; + loadStream >> tmpState; + if (tmpState == IN_PROGRESS || tmpState > SPECIAL) + tmpState = NOT_STARTED; + + SetBossState(i, EncounterState(tmpState)); } - HorsemanAdds.clear(); - HandleGameObject(PumpkinShrineGUID, false); } - break; - } - } + else + OUT_LOAD_INST_DATA_FAIL; - uint64 GetData64(uint32 type) const override - { - switch (type) - { - //case GAMEOBJECT_PUMPKIN_SHRINE: return PumpkinShrineGUID; - //case DATA_HORSEMAN: return HorsemanGUID; - //case DATA_HEAD: return HeadGUID; - case DATA_MOGRAINE: return MograineGUID; - case DATA_WHITEMANE: return WhitemaneGUID; - case DATA_VORREL: return VorrelGUID; - case DATA_DOOR_WHITEMANE: return DoorHighInquisitorGUID; + OUT_LOAD_INST_DATA_COMPLETE; } - return 0; - } - uint32 GetData(uint32 type) const override + protected: + uint64 PumpkinShrineGUID; + uint64 HorsemanGUID; + uint64 HeadGUID; + uint64 MograineGUID; + uint64 WhitemaneGUID; + uint64 VorrelGUID; + + std::set<uint64> HorsemanAdds; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override { - if (type == TYPE_MOGRAINE_AND_WHITE_EVENT) - return encounter[0]; - if (type == DATA_HORSEMAN_EVENT) - return encounter[1]; - return 0; + return new instance_scarlet_monastery_InstanceMapScript(map); } - }; }; void AddSC_instance_scarlet_monastery() diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h index bdac6b089fd..40089cd9817 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/scarlet_monastery.h @@ -1,6 +1,5 @@ /* * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> * * 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 @@ -19,19 +18,43 @@ #ifndef SCARLET_M_ #define SCARLET_M_ +uint32 const EncounterCount = 10; + enum DataTypes { - TYPE_MOGRAINE_AND_WHITE_EVENT = 1, - + DATA_MOGRAINE_AND_WHITE_EVENT = 1, DATA_MOGRAINE = 2, DATA_WHITEMANE = 3, - DATA_DOOR_WHITEMANE = 4, - DATA_HORSEMAN_EVENT = 5, - GAMEOBJECT_PUMPKIN_SHRINE = 6, + DATA_HORSEMAN_EVENT = 4, + DATA_PUMPKIN_SHRINE = 5, + + DATA_VORREL = 6, + DATA_ARCANIST_DOAN = 7, + DATA_AZSHIR = 8, + DATA_BLOODMAGE_THALNOS = 9, + DATA_HEROD = 10, + DATA_HIGH_INQUISITOR_FAIRBANKS = 11, + DATA_HOUNDMASTER_LOKSEY = 12, + DATA_INTERROGATOR_VISHAS = 13, + DATA_SCORN = 14 +}; + +enum CreatureIds +{ + NPC_MOGRAINE = 3976, + NPC_WHITEMANE = 3977, + NPC_VORREL = 3981, + + NPC_HORSEMAN = 23682, + NPC_HEAD = 23775, + NPC_PUMPKIN = 23694 +}; - DATA_VORREL = 7, - DATA_ARCANIST_DOAN = 8 +enum GameObjectIds +{ + GO_HIGH_INQUISITORS_DOOR = 104600, + GO_PUMPKIN_SHRINE = 186267 }; #endif // SCARLET_M_ diff --git a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp index f996bcc6f70..e3021ff7a95 100644 --- a/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp +++ b/src/server/scripts/Kalimdor/RazorfenKraul/razorfen_kraul.cpp @@ -47,27 +47,20 @@ class npc_willix : public CreatureScript public: npc_willix() : CreatureScript("npc_willix") { } - bool OnQuestAccept(Player* player, Creature* creature, Quest const* quest) override - { - if (quest->GetQuestId() == QUEST_WILLIX_THE_IMPORTER) - { - ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID()); - creature->AI()->Talk(SAY_READY, player); - creature->setFaction(113); - } - - return true; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_willixAI(creature); - } - struct npc_willixAI : public npc_escortAI { npc_willixAI(Creature* creature) : npc_escortAI(creature) { } + void sQuestAccept(Player* player, Quest const* quest) override + { + if (quest->GetQuestId() == QUEST_WILLIX_THE_IMPORTER) + { + Start(true, false, player->GetGUID()); + Talk(SAY_READY, player); + me->setFaction(113); + } + } + void WaypointReached(uint32 waypointId) override { Player* player = GetPlayerForEscort(); @@ -137,6 +130,10 @@ public: } }; + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_willixAI(creature); + } }; enum SnufflenoseGopher @@ -147,18 +144,6 @@ enum SnufflenoseGopher POINT_TUBBER = 0 }; -struct DistanceOrder : public std::binary_function<GameObject, GameObject, bool> -{ - DistanceOrder(Creature* me) : me(me) { } - - bool operator() (GameObject* first, GameObject* second) - { - return me->GetDistanceOrder(first, second); - } - - Creature* me; -}; - struct npc_snufflenose_gopher : public CreatureScript { public: @@ -208,18 +193,14 @@ public: if (tubbersInRange.empty()) return; - tubbersInRange.sort(DistanceOrder(me)); - GameObject* nearestTubber = NULL; - - for (std::list<GameObject*>::const_iterator itr = tubbersInRange.begin(); itr != tubbersInRange.end(); ++itr) + tubbersInRange.remove_if([](GameObject* go) { - if (!(*itr)->isSpawned() && (*itr)->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND)) - { - nearestTubber = *itr; - break; - } - } + return go->isSpawned() || !go->HasFlag(GAMEOBJECT_FLAGS, GO_FLAG_INTERACT_COND); + }); + tubbersInRange.sort(Trinity::ObjectDistanceOrderPred(me)); + + GameObject* nearestTubber = tubbersInRange.front(); if (!nearestTubber) return; @@ -259,21 +240,16 @@ class spell_snufflenose_command : public SpellScriptLoader { PrepareSpellScript(spell_snufflenose_commandSpellScript); - bool Load() override - { - return GetCaster()->GetTypeId() == TYPEID_PLAYER; - } - - void HandleAfterCast() + void HandleEffect(SpellEffIndex /*effIndex*/) { - if (Unit* target = GetCaster()->ToPlayer()->GetSelectedUnit()) + if (Creature* target = GetHitCreature()) if (target->GetEntry() == NPC_SNUFFLENOSE_GOPHER) - target->ToCreature()->AI()->DoAction(ACTION_FIND_NEW_TUBBER); + target->AI()->DoAction(ACTION_FIND_NEW_TUBBER); } void Register() override { - AfterCast += SpellCastFn(spell_snufflenose_commandSpellScript::HandleAfterCast); + OnEffectHitTarget += SpellEffectFn(spell_snufflenose_commandSpellScript::HandleEffect, EFFECT_0, SPELL_EFFECT_DUMMY); } }; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp index f284aacf996..b769c7e141e 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_mimiron.cpp @@ -15,10 +15,16 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "Cell.h" +#include "CellImpl.h" +#include "GridNotifiers.h" +#include "GridNotifiersImpl.h" #include "ScriptMgr.h" #include "ScriptedCreature.h" #include "SpellScript.h" +#include "SpellAuraEffects.h" #include "ulduar.h" +#include "Vehicle.h" enum Yells { @@ -39,78 +45,1413 @@ enum Yells SAY_BERSERK = 14 }; +enum ComputerYells +{ + SAY_SELF_DESTRUCT_INITIATED = 0, + SAY_SELF_DESTRUCT_TERMINATED = 1, + SAY_SELF_DESTRUCT_10 = 2, + SAY_SELF_DESTRUCT_9 = 3, + SAY_SELF_DESTRUCT_8 = 4, + SAY_SELF_DESTRUCT_7 = 5, + SAY_SELF_DESTRUCT_6 = 6, + SAY_SELF_DESTRUCT_5 = 7, + SAY_SELF_DESTRUCT_4 = 8, + SAY_SELF_DESTRUCT_3 = 9, + SAY_SELF_DESTRUCT_2 = 10, + SAY_SELF_DESTRUCT_1 = 11, + SAY_SELF_DESTRUCT_FINALIZED = 12 +}; + enum Spells { + // Mimiron + SPELL_WELD = 63339, // Idle aura. + SPELL_SEAT_1 = 52391, // Cast on all vehicles, Cycled on MKII + SPELL_SEAT_2 = 63313, // Cast on MKII and VX-001, Cycled on MKII + SPELL_SEAT_3 = 63314, // Cast on MKII, Cycled on MKII + SPELL_SEAT_5 = 63316, // Cast on MKII and VX-001, Cycled on MKII + SPELL_SEAT_6 = 63344, // Cast on MKII + SPELL_SEAT_7 = 63345, // Cast on MKII SPELL_JETPACK = 63341, - SPELL_EMERGENCY_MODE = 64582, - SPELL_SELF_REPAIR = 64383, - SPELL_MAGNETIC_CORE = 64444, + SPELL_DESPAWN_ASSAULT_BOTS = 64463, // only despawns assault bots... no equivalent spell for the other adds... + SPELL_TELEPORT_VISUAL = 41232, + SPELL_SLEEP_VISUAL_1 = 64393, + SPELL_SLEEP_VISUAL_2 = 64394, + // Leviathan MK II SPELL_FLAME_SUPPRESSANT_MK = 64570, SPELL_NAPALM_SHELL = 63666, - SPELL_PLASMA_BLAST = 62977, - SPELL_PROXIMITY_MINES = 63027, + SPELL_FORCE_CAST_NAPALM_SHELL = 64539, + SPELL_PLASMA_BLAST = 62997, + SPELL_SCRIPT_EFFECT_PLASMA_BLAST = 64542, SPELL_SHOCK_BLAST = 63631, - // VX 001 + SPELL_SHOCK_BLAST_AURA = 63632, // Deprecated? It is never cast. + + // VX-001 SPELL_FLAME_SUPPRESSANT_VX = 65192, - SPELL_FROSTBOMB = 64623, - SPELL_HAND_PULSE = 64348, SPELL_SPINNING_UP = 63414, - SPELL_RAPID_BURST = 63387, - SPELL_P3WX2_LASER_BARRAGE = 63293, - SPELL_ROCKET_STRIKE = 63041, - SPELL_HEAT_WAVE = 63677, + SPELL_HEAT_WAVE_AURA = 63679, + SPELL_HAND_PULSE_LEFT = 64348, + SPELL_HAND_PULSE_RIGHT = 64352, + SPELL_MOUNT_MKII = 64387, + SPELL_TORSO_DISABLED = 64120, + // Aerial Command Unit - SPELL_PLASMA_BALL = 63689, - // Additonal spells - SPELL_MAGNETIC_FIELD = 64668, - SPELL_DEAFENING_SIREN = 64616, + SPELL_PLASMA_BALL_P1 = 63689, + SPELL_PLASMA_BALL_P2 = 65647, + SPELL_MOUNT_VX_001 = 64388, + + // Proximity Mines + SPELL_PROXIMITY_MINES = 63027, // Cast by Leviathan MK II + SPELL_PROXIMITY_MINE_EXPLOSION = 66351, + SPELL_PROXIMITY_MINE_TRIGGER = 65346, + SPELL_PROXIMITY_MINE_PERIODIC_TRIGGER = 65345, + SPELL_PERIODIC_PROXIMITY_AURA = 65345, + SPELL_SUMMON_PROXIMITY_MINE = 65347, + + // Rapid Burst + SPELL_RAPID_BURST_LEFT = 63387, + SPELL_RAPID_BURST_RIGHT = 64019, + SPELL_RAPID_BURST = 63382, // Cast by VX-001 + SPELL_RAPID_BURST_TARGET_ME = 64841, // Cast by Burst Target + SPELL_SUMMON_BURST_TARGET = 64840, // Cast by VX-001 + + // Rocket Strike + SPELL_SUMMON_ROCKET_STRIKE = 63036, + SPELL_SCRIPT_EFFECT_ROCKET_STRIKE = 63681, // Cast by Rocket (Mimiron Visual) + SPELL_ROCKET_STRIKE = 64064, // Added in creature_template_addon + SPELL_ROCKET_STRIKE_LEFT = 64402, // Cast by VX-001 + SPELL_ROCKET_STRIKE_BOTH = 65034, // Cast by VX-001 + + // Flames + SPELL_FLAMES_PERIODIC_TRIGGER = 64561, // Added in creature_template_addon + SPELL_SUMMON_FLAMES_SPREAD_TRIGGER = 64562, + SPELL_SUMMON_FLAMES_INITIAL = 64563, + SPELL_SUMMON_FLAMES_SPREAD = 64564, + SPELL_FLAMES = 64566, + SPELL_SCRIPT_EFFECT_SUMMON_FLAMES_INITIAL = 64567, + + // Frost Bomb + SPELL_SCRIPT_EFFECT_FROST_BOMB = 64623, // Cast by VX-001 + SPELL_FROST_BOMB_LINKED = 64624, // Added in creature_template_addon + SPELL_FROST_BOMB_DUMMY = 64625, + SPELL_SUMMON_FROST_BOMB = 64627, // Cast by VX-001 + SPELL_FROST_BOMB_EXPLOSION = 64626, + SPELL_CLEAR_FIRES = 65354, + + // Bots + SPELL_SUMMON_FIRE_BOT = 64622, + SPELL_SUMMON_FIRE_BOT_DUMMY = 64621, + SPELL_SUMMON_FIRE_BOT_TRIGGER = 64620, // Cast by Areal Command Unit + SPELL_DEAFENING_SIREN = 64616, // Added in creature_template_addon + SPELL_FIRE_SEARCH_AURA = 64617, // Added in creature_template_addon + SPELL_FIRE_SEARCH = 64618, SPELL_WATER_SPRAY = 64619, - SPELL_FROST_BOMB_HARD_MODE = 64627, - SPELL_EXPLOSION = 66351, - SPELL_DISARM = 1842, - SPELL_RIDE_VEHICLE = 46598, - SPELL_TRIGGER_MISSILE = 65347, + + SPELL_SUMMON_JUNK_BOT = 63819, + SPELL_SUMMON_JUNK_BOT_TRIGGER = 63820, // Cast by Areal Command Unit + SPELL_SUMMON_JUNK_BOT_DUMMY = 64398, + + SPELL_SUMMON_ASSAULT_BOT_TRIGGER = 64425, // Cast by Areal Command Unit + SPELL_SUMMON_ASSAULT_BOT_DUMMY = 64426, + SPELL_SUMMON_ASSAULT_BOT = 64427, + SPELL_MAGNETIC_FIELD = 64668, + + SPELL_SUMMON_BOMB_BOT = 63811, // Cast by Areal Command Unit + SPELL_BOMB_BOT_AURA = 63767, // Added in creature_template_addon + + // Miscellaneous + SPELL_SELF_DESTRUCTION_AURA = 64610, + SPELL_SELF_DESTRUCTION_VISUAL = 64613, + SPELL_NOT_SO_FRIENDLY_FIRE = 65040, + SPELL_ELEVATOR_KNOCKBACK = 65096, // Cast by worldtrigger. + SPELL_VEHICLE_DAMAGED = 63415, + SPELL_EMERGENCY_MODE = 64582, // mkii, vx001, aerial, assault, junk + SPELL_EMERGENCY_MODE_TURRET = 65101, // Cast by Leviathan MK II, only hits Leviathan MK II turret + SPELL_SELF_REPAIR = 64383, + SPELL_MAGNETIC_CORE = 64436, + SPELL_MAGNETIC_CORE_VISUAL = 64438, + SPELL_HALF_HEAL = 64188, + SPELL_CLEAR_ALL_DEBUFFS = 34098, // TODO: make use of this spell... + SPELL_FREEZE_ANIM_STUN = 63354, // used to prevent mkii from doing stuff?.. + SPELL_FREEZE_ANIM = 16245 // Idle aura. Freezes animation. }; -enum Npc +enum Data { - NPC_ASSAULT_BOT = 34057, - NPC_BOMB_BOT = 33836, - NPC_JUNK_BOT = 33855, - NPC_EMERGENCE_FIRE_BOT = 34147, - NPC_FROST_BOMB = 34149, + DATA_SETUP_MINE, + DATA_SETUP_BOMB, + DATA_SETUP_ROCKET, + DATA_NOT_SO_FRIENDLY_FIRE, + DATA_FIREFIGHTER, + DATA_WATERSPRAY, + DATA_MOVE_NEW }; -class spell_ulduar_proximity_mines : public SpellScriptLoader +enum Events +{ + // Leviathan MK II + EVENT_PROXIMITY_MINE = 1, + EVENT_NAPALM_SHELL, + EVENT_PLASMA_BLAST, + EVENT_SHOCK_BLAST, + EVENT_FLAME_SUPPRESSANT_MK, + EVENT_MOVE_POINT_2, + EVENT_MOVE_POINT_3, + EVENT_MOVE_POINT_5, + + // VX-001 + EVENT_RAPID_BURST, + EVENT_SPINNING_UP, + EVENT_ROCKET_STRIKE, + EVENT_HAND_PULSE, + EVENT_FROST_BOMB, + EVENT_FLAME_SUPPRESSANT_VX, + EVENT_RELOAD, + + // Aerial Command Unit + EVENT_SUMMON_FIRE_BOTS, + EVENT_SUMMON_JUNK_BOT, + EVENT_SUMMON_ASSAULT_BOT, + EVENT_SUMMON_BOMB_BOT, + + // Mimiron + EVENT_SUMMON_FLAMES, + EVENT_INTRO_1, + EVENT_INTRO_2, + EVENT_INTRO_3, + + EVENT_VX001_ACTIVATION_1, + EVENT_VX001_ACTIVATION_2, + EVENT_VX001_ACTIVATION_3, + EVENT_VX001_ACTIVATION_4, + EVENT_VX001_ACTIVATION_5, + EVENT_VX001_ACTIVATION_6, + EVENT_VX001_ACTIVATION_7, + EVENT_VX001_ACTIVATION_8, + EVENT_VX001_ACTIVATION_9, + + EVENT_AERIAL_ACTIVATION_1, + EVENT_AERIAL_ACTIVATION_2, + EVENT_AERIAL_ACTIVATION_3, + EVENT_AERIAL_ACTIVATION_4, + EVENT_AERIAL_ACTIVATION_5, + EVENT_AERIAL_ACTIVATION_6, + + EVENT_VOL7RON_ACTIVATION_1, + EVENT_VOL7RON_ACTIVATION_2, + EVENT_VOL7RON_ACTIVATION_3, + EVENT_VOL7RON_ACTIVATION_4, + EVENT_VOL7RON_ACTIVATION_5, + EVENT_VOL7RON_ACTIVATION_6, + EVENT_VOL7RON_ACTIVATION_7, + + EVENT_OUTTRO_1, + EVENT_OUTTRO_2, + EVENT_OUTTRO_3, + + // Computer + EVENT_SELF_DESTRUCT_10, + EVENT_SELF_DESTRUCT_9, + EVENT_SELF_DESTRUCT_8, + EVENT_SELF_DESTRUCT_7, + EVENT_SELF_DESTRUCT_6, + EVENT_SELF_DESTRUCT_5, + EVENT_SELF_DESTRUCT_4, + EVENT_SELF_DESTRUCT_3, + EVENT_SELF_DESTRUCT_2, + EVENT_SELF_DESTRUCT_1, + EVENT_SELF_DESTRUCT_FINALIZED, + + // Misc + EVENT_MAGNETIC_FIELD, + EVENT_SPREAD_FLAMES, + EVENT_FROST_BOMB_EXPLOSION, + EVENT_FROST_BOMB_CLEAR_FIRES, + EVENT_PROXIMITY_MINE_ARM, + EVENT_PROXIMITY_MINE_DETONATION, + EVENT_SEARCH_FLAMES, + EVENT_WATER_SPRAY +}; + +enum Actions +{ + DO_START_MKII, + DO_HARDMODE_MKII, + + DO_ACTIVATE_VX001, + DO_START_VX001, + DO_HARDMODE_VX001, + + DO_ACTIVATE_AERIAL, + DO_START_AERIAL, + DO_HARDMODE_AERIAL, + DO_DISABLE_AERIAL, + DO_ENABLE_AERIAL, + + DO_ACTIVATE_V0L7R0N_1, + DO_ACTIVATE_V0L7R0N_2, + DO_ASSEMBLED_COMBAT, // All 3 parts use this action, its done on purpose. + + DO_ACTIVATE_HARD_MODE, + DO_ACTIVATE_COMPUTER, + DO_DEACTIVATE_COMPUTER, + DO_ACTIVATE_SELF_DESTRUCT, + + DO_ENCOUNTER_DONE +}; + +enum Phases +{ + // Leviathan MK II + PHASE_LEVIATHAN_SOLO = 1, + PHASE_LEVIATHAN_ASSEMBLED, + + // VX-001 + PHASE_VX001_SOLO, + PHASE_VX001_ASSEMBLED, + + // Aerial Command Unit + PHASE_AERIAL_SOLO, + PHASE_AERIAL_ASSEMBLED +}; + +uint32 const RepairSpells[4] = +{ + SPELL_SEAT_1, + SPELL_SEAT_2, + SPELL_SEAT_3, + SPELL_SEAT_5 +}; + +// 63801 Bomb Bot +class spell_mimiron_bomb_bot : public SpellScriptLoader +{ + public: + spell_mimiron_bomb_bot() : SpellScriptLoader("spell_mimiron_bomb_bot") { } + + class spell_mimiron_bomb_bot_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_bomb_bot_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitPlayer()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* mkii = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkii->AI()->SetData(DATA_SETUP_BOMB, 0); + } + + void HandleDespawn(SpellEffIndex /*effIndex*/) + { + if (Creature* target = GetHitCreature()) + { + target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_PACIFIED); + target->DespawnOrUnsummon(1000); + } + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_bomb_bot_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_bomb_bot_SpellScript::HandleDespawn, EFFECT_1, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_bomb_bot_SpellScript(); + } +}; + +// 65192 - Flame Suppressant, 65224 - Clear Fires, 65354 - Clear Fires, 64619 - Water Spray +class spell_mimiron_clear_fires : public SpellScriptLoader { public: - spell_ulduar_proximity_mines() : SpellScriptLoader("spell_ulduar_proximity_mines") { } + spell_mimiron_clear_fires() : SpellScriptLoader("spell_mimiron_clear_fires") { } - class spell_ulduar_proximity_minesSpellScript : public SpellScript + class spell_mimiron_clear_fires_SpellScript : public SpellScript { - PrepareSpellScript(spell_ulduar_proximity_minesSpellScript); + PrepareSpellScript(spell_mimiron_clear_fires_SpellScript); + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + if (GetHitCreature()) + GetHitCreature()->DespawnOrUnsummon(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_clear_fires_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_clear_fires_SpellScript(); + } +}; + +// 64463 - Despawn Assault Bots +class spell_mimiron_despawn_assault_bots : public SpellScriptLoader +{ + public: + spell_mimiron_despawn_assault_bots() : SpellScriptLoader("spell_mimiron_despawn_assault_bots") { } + + class spell_mimiron_despawn_assault_bots_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_despawn_assault_bots_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitCreature()) + GetHitCreature()->DespawnOrUnsummon(); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_despawn_assault_bots_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_despawn_assault_bots_SpellScript(); + } +}; + +// 64618 - Fire Search +class spell_mimiron_fire_search : public SpellScriptLoader +{ + public: + spell_mimiron_fire_search() : SpellScriptLoader("spell_mimiron_fire_search") { } + + class spell_mimiron_fire_search_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_fire_search_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_WATER_SPRAY)) + return false; + return true; + } + + bool Load() override + { + _noTarget = false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + _noTarget = targets.empty(); + if (_noTarget) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + targets.clear(); + targets.push_back(target); + } + + void HandleAftercast() + { + if (_noTarget) + GetCaster()->GetMotionMaster()->MoveRandom(15.0f); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + + if (UnitAI* ai = caster->GetAI()) + { + if (caster->GetDistance2d(GetHitUnit()) <= 15.0f && ai->GetData(DATA_WATERSPRAY)) + { + caster->CastSpell(GetHitUnit(), SPELL_WATER_SPRAY, true); + ai->SetData(DATA_WATERSPRAY, 0); + ai->SetData(DATA_MOVE_NEW, 1); + } + else if (caster->GetAI()->GetData(DATA_MOVE_NEW)) + { + caster->GetMotionMaster()->MoveChase(GetHitUnit()); + ai->SetData(DATA_MOVE_NEW, 0); + } + } + } + + void Register() override + { + AfterCast += SpellCastFn(spell_mimiron_fire_search_SpellScript::HandleAftercast); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_fire_search_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_fire_search_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + + private: + bool _noTarget; + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_fire_search_SpellScript(); + } +}; + +// 64436 - Magnetic Core +class spell_mimiron_magnetic_core : public SpellScriptLoader +{ + public: + spell_mimiron_magnetic_core() : SpellScriptLoader("spell_mimiron_magnetic_core") { } + + class spell_mimiron_magnetic_core_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_magnetic_core_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if([](WorldObject* obj) { return obj->ToUnit() && (obj->ToUnit()->GetVehicleBase() || obj->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE)); }); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_magnetic_core_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_SRC_AREA_ENTRY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_magnetic_core_SpellScript(); + } + + class spell_mimiron_magnetic_core_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_magnetic_core_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_MAGNETIC_CORE_VISUAL)) + return false; + return true; + } + + void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + target->GetAI()->DoAction(DO_DISABLE_AERIAL); + target->CastSpell(target, SPELL_MAGNETIC_CORE_VISUAL, true); + } + } + + void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (Creature* target = GetTarget()->ToCreature()) + { + target->GetAI()->DoAction(DO_ENABLE_AERIAL); + target->RemoveAurasDueToSpell(SPELL_MAGNETIC_CORE_VISUAL); + } + } - void HandleScript(SpellEffIndex effIndex) + void OnRemoveSelf(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (TempSummon* summ = GetTarget()->ToTempSummon()) + summ->DespawnOrUnsummon(); + } + + void Register() override + { + AfterEffectApply += AuraEffectApplyFn(spell_mimiron_magnetic_core_AuraScript::OnApply, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_mimiron_magnetic_core_AuraScript::OnRemove, EFFECT_1, SPELL_AURA_MOD_DAMAGE_PERCENT_TAKEN, AURA_EFFECT_HANDLE_REAL); + AfterEffectRemove += AuraEffectRemoveFn(spell_mimiron_magnetic_core_AuraScript::OnRemoveSelf, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_magnetic_core_AuraScript(); + } +}; + +// 63667 - Napalm Shell +class spell_mimiron_napalm_shell : public SpellScriptLoader +{ + public: + spell_mimiron_napalm_shell() : SpellScriptLoader("spell_mimiron_napalm_shell") { } + + class spell_mimiron_napalm_shell_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_napalm_shell_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_NAPALM_SHELL)) + return false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + + targets.remove_if(Trinity::AllWorldObjectsInRange(GetCaster(), 15.0f)); + + if (!targets.empty()) + target = Trinity::Containers::SelectRandomContainerElement(targets); + + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_NAPALM_SHELL); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_napalm_shell_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_napalm_shell_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_napalm_shell_SpellScript(); + } +}; + +// 63274 - P3Wx2 Laser Barrage -- HACK! Core will currently not set UNIT_FIELD_CHANNEL_OBJECT automatially if the spell targets more than a single target. +class spell_mimiron_p3wx2_laser_barrage : public SpellScriptLoader +{ + public: + spell_mimiron_p3wx2_laser_barrage() : SpellScriptLoader("spell_mimiron_p3wx2_laser_barrage") { } + + class spell_mimiron_p3wx2_laser_barrage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_p3wx2_laser_barrage_SpellScript); + + void OnHit(SpellEffIndex /*effIndex*/) + { + GetCaster()->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, GetHitUnit()->GetGUID()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_p3wx2_laser_barrage_SpellScript::OnHit, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_p3wx2_laser_barrage_SpellScript(); + } +}; + +// 64542 - Plasma Blast +class spell_mimiron_plasma_blast : public SpellScriptLoader +{ + public: + spell_mimiron_plasma_blast() : SpellScriptLoader("spell_mimiron_plasma_blast") { } + + class spell_mimiron_plasma_blast_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_plasma_blast_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_PLASMA_BLAST)) + return false; + return true; + } + + bool Load() override + { + return GetCaster()->GetVehicleKit() != nullptr; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Unit* caster = GetCaster()->GetVehicleKit()->GetPassenger(3)) + caster->CastSpell(GetHitUnit(), SPELL_PLASMA_BLAST); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_plasma_blast_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_plasma_blast_SpellScript(); + } +}; + +// 66351 - Explosion +class spell_mimiron_proximity_explosion : public SpellScriptLoader +{ + public: + spell_mimiron_proximity_explosion() : SpellScriptLoader("spell_mimiron_proximity_explosion") { } + + class spell_mimiron_proximity_explosion_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_proximity_explosion_SpellScript); + + void OnHit(SpellEffIndex /*effIndex*/) + { + if (GetHitPlayer()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* mkII = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkII->AI()->SetData(DATA_SETUP_MINE, 0); + } + + void HandleAura(SpellEffIndex /*effIndex*/) + { + GetCaster()->RemoveAurasDueToSpell(SPELL_PROXIMITY_MINE_PERIODIC_TRIGGER); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_proximity_explosion_SpellScript::OnHit, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_proximity_explosion_SpellScript::HandleAura, EFFECT_1, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_proximity_explosion_SpellScript(); + } +}; + +// 63027 - Proximity Mines +class spell_mimiron_proximity_mines : public SpellScriptLoader +{ + public: + spell_mimiron_proximity_mines() : SpellScriptLoader("spell_mimiron_proximity_mines") { } + + class spell_mimiron_proximity_mines_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_proximity_mines_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_PROXIMITY_MINE)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) { - PreventHitDefaultEffect(effIndex); for (uint8 i = 0; i < 10; ++i) - GetCaster()->CastSpell(GetCaster(), SPELL_TRIGGER_MISSILE, true); + GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_PROXIMITY_MINE, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_proximity_mines_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_proximity_mines_SpellScript(); + } +}; + +// 65346 - Proximity Mine +class spell_mimiron_proximity_trigger : public SpellScriptLoader +{ + public: + spell_mimiron_proximity_trigger() : SpellScriptLoader("spell_mimiron_proximity_trigger") { } + + class spell_mimiron_proximity_trigger_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_proximity_trigger_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_PROXIMITY_MINE_EXPLOSION)) + return false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove(GetExplTargetWorldObject()); + + if (targets.empty()) + FinishCast(SPELL_FAILED_NO_VALID_TARGETS); + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell((Unit*)NULL, SPELL_PROXIMITY_MINE_EXPLOSION, true); } void Register() override { - OnEffectHitTarget += SpellEffectFn(spell_ulduar_proximity_minesSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_proximity_trigger_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHit += SpellEffectFn(spell_mimiron_proximity_trigger_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); } }; SpellScript* GetSpellScript() const override { - return new spell_ulduar_proximity_minesSpellScript(); + return new spell_mimiron_proximity_trigger_SpellScript(); + } +}; + +// 63382 - Rapid Burst +class spell_mimiron_rapid_burst : public SpellScriptLoader +{ + public: + spell_mimiron_rapid_burst() : SpellScriptLoader("spell_mimiron_rapid_burst") { } + + class spell_mimiron_rapid_burst_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_rapid_burst_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_RAPID_BURST_LEFT) || !sSpellMgr->GetSpellInfo(SPELL_RAPID_BURST_RIGHT)) + return false; + return true; + } + + void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) + { + if (TempSummon* summ = GetTarget()->ToTempSummon()) + summ->DespawnOrUnsummon(); + } + + void HandleDummyTick(AuraEffect const* aurEff) + { + if (GetCaster()) + GetCaster()->CastSpell(GetTarget(), aurEff->GetTickNumber() % 2 == 0 ? SPELL_RAPID_BURST_RIGHT : SPELL_RAPID_BURST_LEFT, true, NULL, aurEff); + } + + void Register() override + { + AfterEffectRemove += AuraEffectApplyFn(spell_mimiron_rapid_burst_AuraScript::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_rapid_burst_AuraScript::HandleDummyTick, EFFECT_1, SPELL_AURA_PERIODIC_DUMMY); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_rapid_burst_AuraScript(); + } +}; + +// 64402 - Rocket Strike, 65034 - Rocket Strike +class spell_mimiron_rocket_strike : public SpellScriptLoader +{ + public: + spell_mimiron_rocket_strike() : SpellScriptLoader("spell_mimiron_rocket_strike") { } + + class spell_mimiron_rocket_strike_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_rocket_strike_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SCRIPT_EFFECT_ROCKET_STRIKE)) + return false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + if (m_scriptSpellId == SPELL_ROCKET_STRIKE_LEFT && GetCaster()->IsVehicle()) + if (WorldObject* target = GetCaster()->GetVehicleKit()->GetPassenger(6)) + { + targets.clear(); + targets.push_back(target); + } + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell((Unit*)NULL, SPELL_SCRIPT_EFFECT_ROCKET_STRIKE, true, NULL, NULL, GetCaster()->GetGUID()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_rocket_strike_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_rocket_strike_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_rocket_strike_SpellScript(); + } +}; + +// 63041 - Rocket Strike +class spell_mimiron_rocket_strike_damage : public SpellScriptLoader +{ + public: + spell_mimiron_rocket_strike_damage() : SpellScriptLoader("spell_mimiron_rocket_strike_damage") { } + + class spell_mimiron_rocket_strike_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_rocket_strike_damage_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_NOT_SO_FRIENDLY_FIRE)) + return false; + return true; + } + + void HandleAfterCast() + { + if (TempSummon* summ = GetCaster()->ToTempSummon()) + summ->DespawnOrUnsummon(); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (GetHitPlayer()) + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + if (Creature* mkii = ObjectAccessor::GetCreature(*GetCaster(), instance->GetData64(DATA_LEVIATHAN_MK_II))) + mkii->AI()->SetData(DATA_SETUP_ROCKET, 0); + } + + void HandleFriendlyFire(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell((Unit*)NULL, SPELL_NOT_SO_FRIENDLY_FIRE, true); + } + + void Register() override + { + AfterCast += SpellCastFn(spell_mimiron_rocket_strike_damage_SpellScript::HandleAfterCast); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_rocket_strike_damage_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_rocket_strike_damage_SpellScript::HandleFriendlyFire, EFFECT_1, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_rocket_strike_damage_SpellScript(); + } +}; + +// 63681 - Rocket Strike +class spell_mimiron_rocket_strike_target_select : public SpellScriptLoader +{ + public: + spell_mimiron_rocket_strike_target_select() : SpellScriptLoader("spell_mimiron_rocket_strike_target_select") { } + + class spell_mimiron_rocket_strike_target_select_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_rocket_strike_target_select_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ROCKET_STRIKE)) + return false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + + targets.remove_if(Trinity::AllWorldObjectsInRange(GetCaster(), 15.0f)); + + if (!targets.empty()) + target = Trinity::Containers::SelectRandomContainerElement(targets); + + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_ROCKET_STRIKE, true, NULL, NULL, instance->GetData64(DATA_VX_001)); + GetCaster()->SetDisplayId(11686); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_rocket_strike_target_select_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_rocket_strike_target_select_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_rocket_strike_target_select_SpellScript(); + } +}; + +// 64383 - Self Repair +class spell_mimiron_self_repair : public SpellScriptLoader +{ + public: + spell_mimiron_self_repair() : SpellScriptLoader("spell_mimiron_self_repair") { } + + class spell_mimiron_self_repair_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_self_repair_SpellScript); + + void HandleScript() + { + if (GetCaster()->GetAI()) + GetCaster()->GetAI()->DoAction(DO_ASSEMBLED_COMBAT); + } + + void Register() override + { + AfterHit += SpellHitFn(spell_mimiron_self_repair_SpellScript::HandleScript); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_self_repair_SpellScript(); + } +}; + +// 63414 - Spinning Up -- HACK! Core will currently not set UNIT_FIELD_CHANNEL_OBJECT automatially if the spell targets more than a single target. +// eff0 will hit both caster and target due to hack in spellmgr.cpp, it is necessary because caster will interrupt itself if aura is not active on caster. +class spell_mimiron_spinning_up : public SpellScriptLoader +{ + public: + spell_mimiron_spinning_up() : SpellScriptLoader("spell_mimiron_spinning_up") { } + + class spell_mimiron_spinning_up_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_spinning_up_SpellScript); + + void OnHit(SpellEffIndex /*effIndex*/) + { + if (GetHitUnit() != GetCaster()) + GetCaster()->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, GetHitUnit()->GetGUID()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_spinning_up_SpellScript::OnHit, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_spinning_up_SpellScript(); + } +}; + +// 64426 - Summon Scrap Bot +class spell_mimiron_summon_assault_bot : public SpellScriptLoader +{ + public: + spell_mimiron_summon_assault_bot() : SpellScriptLoader("spell_mimiron_summon_assault_bot") { } + + class spell_mimiron_summon_assault_bot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_summon_assault_bot_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ASSAULT_BOT)) + return false; + return true; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (instance->GetBossState(BOSS_MIMIRON) == IN_PROGRESS) + caster->CastSpell(caster, SPELL_SUMMON_ASSAULT_BOT, false, NULL, aurEff, instance->GetData64(DATA_AERIAL_COMMAND_UNIT)); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_mimiron_summon_assault_bot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_summon_assault_bot_AuraScript(); + } +}; + +// 64425 - Summon Scrap Bot Trigger +class spell_mimiron_summon_assault_bot_target : public SpellScriptLoader +{ + public: + spell_mimiron_summon_assault_bot_target() : SpellScriptLoader("spell_mimiron_summon_assault_bot_target") { } + + class spell_mimiron_summon_assault_bot_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_summon_assault_bot_target_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ASSAULT_BOT_DUMMY)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_ASSAULT_BOT_DUMMY, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_summon_assault_bot_target_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_summon_assault_bot_target_SpellScript(); + } +}; + +// 64621 - Summon Fire Bot +class spell_mimiron_summon_fire_bot : public SpellScriptLoader +{ + public: + spell_mimiron_summon_fire_bot() : SpellScriptLoader("spell_mimiron_summon_fire_bot") { } + + class spell_mimiron_summon_fire_bot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_summon_fire_bot_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_FIRE_BOT)) + return false; + + return true; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (instance->GetBossState(BOSS_MIMIRON) == IN_PROGRESS) + caster->CastSpell(caster, SPELL_SUMMON_FIRE_BOT, false, NULL, aurEff, instance->GetData64(DATA_AERIAL_COMMAND_UNIT)); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_mimiron_summon_fire_bot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_summon_fire_bot_AuraScript(); + } +}; + +// 64620 - Summon Fire Bot Trigger +class spell_mimiron_summon_fire_bot_target : public SpellScriptLoader +{ + public: + spell_mimiron_summon_fire_bot_target() : SpellScriptLoader("spell_mimiron_summon_fire_bot_target") { } + + class spell_mimiron_summon_fire_bot_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_summon_fire_bot_target_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_FIRE_BOT_DUMMY)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_FIRE_BOT_DUMMY, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_summon_fire_bot_target_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_summon_fire_bot_target_SpellScript(); + } +}; + +// 64562 - Summon Flames Spread Trigger +class spell_mimiron_summon_flames_spread : public SpellScriptLoader +{ + public: + spell_mimiron_summon_flames_spread() : SpellScriptLoader("spell_mimiron_summon_flames_spread") { } + + class spell_mimiron_summon_flames_spread_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_summon_flames_spread_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + // Flames must chase the closest player + WorldObject* target = targets.front(); + + for (std::list<WorldObject*>::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) + if (GetCaster()->GetDistance2d(*iter) < GetCaster()->GetDistance2d(target)) + target = *iter; + + targets.clear(); + targets.push_back(target); + } + + void OnHit(SpellEffIndex /*effIndex*/) + { + GetCaster()->SetInFront(GetHitUnit()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_summon_flames_spread_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_summon_flames_spread_SpellScript::OnHit, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_summon_flames_spread_SpellScript(); + } + + class spell_mimiron_summon_flames_spread_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_summon_flames_spread_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_FLAMES_SPREAD)) + return false; + return true; + } + + void HandleTick(AuraEffect const* /*aurEff*/) + { + PreventDefaultAction(); + if (Unit* caster = GetCaster()) + if (caster->HasAura(SPELL_FLAMES_PERIODIC_TRIGGER)) + caster->CastSpell(GetTarget(), SPELL_SUMMON_FLAMES_SPREAD, true); + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_summon_flames_spread_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_summon_flames_spread_AuraScript(); + } +}; + +// 64623 - Frost Bomb +class spell_mimiron_summon_frost_bomb_target : public SpellScriptLoader +{ + public: + spell_mimiron_summon_frost_bomb_target() : SpellScriptLoader("spell_mimiron_summon_frost_bomb_target") { } + + class spell_mimiron_summon_frost_bomb_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_summon_frost_bomb_target_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_FROST_BOMB)) + return false; + return true; + } + + void FilterTargets(std::list<WorldObject*>& targets) + { + if (targets.empty()) + return; + + targets.remove_if(Trinity::AllWorldObjectsInRange(GetCaster(), 15.0f)); + + if (targets.empty()) + return; + + WorldObject* target = Trinity::Containers::SelectRandomContainerElement(targets); + + targets.clear(); + targets.push_back(target); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_SUMMON_FROST_BOMB, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_mimiron_summon_frost_bomb_target_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_mimiron_summon_frost_bomb_target_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_summon_frost_bomb_target_SpellScript(); + } +}; + +// 64398 - Summon Scrap Bot +class spell_mimiron_summon_junk_bot : public SpellScriptLoader +{ + public: + spell_mimiron_summon_junk_bot() : SpellScriptLoader("spell_mimiron_summon_junk_bot") { } + + class spell_mimiron_summon_junk_bot_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_summon_junk_bot_AuraScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_JUNK_BOT)) + return false; + return true; + } + + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) + { + if (Unit* caster = GetCaster()) + if (InstanceScript* instance = caster->GetInstanceScript()) + if (instance->GetBossState(BOSS_MIMIRON) == IN_PROGRESS) + caster->CastSpell(caster, SPELL_SUMMON_JUNK_BOT, false, NULL, aurEff, instance->GetData64(DATA_AERIAL_COMMAND_UNIT)); + } + + void Register() override + { + OnEffectRemove += AuraEffectRemoveFn(spell_mimiron_summon_junk_bot_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_summon_junk_bot_AuraScript(); + } +}; + +// 63820 - Summon Scrap Bot Trigger +class spell_mimiron_summon_junk_bot_target : public SpellScriptLoader +{ + public: + spell_mimiron_summon_junk_bot_target() : SpellScriptLoader("spell_mimiron_summon_junk_bot_target") { } + + class spell_mimiron_summon_junk_bot_target_SpellScript : public SpellScript + { + PrepareSpellScript(spell_mimiron_summon_junk_bot_target_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_JUNK_BOT_DUMMY)) + return false; + return true; + } + + void HandleDummy(SpellEffIndex /*effIndex*/) + { + GetHitUnit()->CastSpell(GetHitUnit(), SPELL_SUMMON_JUNK_BOT_DUMMY, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_mimiron_summon_junk_bot_target_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_mimiron_summon_junk_bot_target_SpellScript(); + } +}; + +// 63339 - Weld +class spell_mimiron_weld : public SpellScriptLoader +{ + public: + spell_mimiron_weld() : SpellScriptLoader("spell_mimiron_weld") { } + + class spell_mimiron_weld_AuraScript : public AuraScript + { + PrepareAuraScript(spell_mimiron_weld_AuraScript); + + void HandleTick(AuraEffect const* aurEff) + { + Unit* caster = GetTarget(); + if (Unit* vehicle = caster->GetVehicleBase()) + { + if (aurEff->GetTickNumber() % 5 == 0) + caster->CastSpell(vehicle, RepairSpells[urand(0, 3)]); + caster->SetFacingToObject(vehicle); + } + } + + void Register() override + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_mimiron_weld_AuraScript::HandleTick, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const override + { + return new spell_mimiron_weld_AuraScript(); } }; void AddSC_boss_mimiron() { - new spell_ulduar_proximity_mines(); + new spell_mimiron_bomb_bot(); + new spell_mimiron_clear_fires(); + new spell_mimiron_despawn_assault_bots(); + new spell_mimiron_fire_search(); + new spell_mimiron_magnetic_core(); + new spell_mimiron_napalm_shell(); + new spell_mimiron_p3wx2_laser_barrage(); + new spell_mimiron_plasma_blast(); + new spell_mimiron_proximity_explosion(); + new spell_mimiron_proximity_mines(); + new spell_mimiron_proximity_trigger(); + new spell_mimiron_rapid_burst(); + new spell_mimiron_rocket_strike(); + new spell_mimiron_rocket_strike_damage(); + new spell_mimiron_rocket_strike_target_select(); + new spell_mimiron_self_repair(); + new spell_mimiron_spinning_up(); + new spell_mimiron_summon_assault_bot(); + new spell_mimiron_summon_assault_bot_target(); + new spell_mimiron_summon_fire_bot(); + new spell_mimiron_summon_fire_bot_target(); + new spell_mimiron_summon_flames_spread(); + new spell_mimiron_summon_frost_bomb_target(); + new spell_mimiron_summon_junk_bot(); + new spell_mimiron_summon_junk_bot_target(); + new spell_mimiron_weld(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 6aa753eac98..79f9283eb40 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -15,13 +15,12 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "ScriptMgr.h" -#include "ScriptedCreature.h" -#include "InstanceScript.h" +#include "ulduar.h" #include "Player.h" -#include "WorldPacket.h" +#include "ScriptedCreature.h" +#include "ScriptMgr.h" #include "SpellScript.h" -#include "ulduar.h" +#include "WorldPacket.h" static DoorData const doorData[] = { @@ -32,6 +31,9 @@ static DoorData const doorData[] = { GO_HODIR_ENTRANCE, BOSS_HODIR, DOOR_TYPE_ROOM, BOUNDARY_E }, { GO_HODIR_DOOR, BOSS_HODIR, DOOR_TYPE_PASSAGE, BOUNDARY_NONE }, { GO_HODIR_ICE_DOOR, BOSS_HODIR, DOOR_TYPE_PASSAGE, BOUNDARY_W }, + { GO_MIMIRON_DOOR_1, BOSS_MIMIRON, DOOR_TYPE_ROOM, BOUNDARY_W }, + { GO_MIMIRON_DOOR_2, BOSS_MIMIRON, DOOR_TYPE_ROOM, BOUNDARY_E }, + { GO_MIMIRON_DOOR_3, BOSS_MIMIRON, DOOR_TYPE_ROOM, BOUNDARY_S }, { GO_VEZAX_DOOR, BOSS_VEZAX, DOOR_TYPE_PASSAGE, BOUNDARY_E }, { GO_YOGG_SARON_DOOR, BOSS_YOGG_SARON, DOOR_TYPE_ROOM, BOUNDARY_S }, { GO_DOODAD_UL_SIGILDOOR_03, BOSS_ALGALON, DOOR_TYPE_ROOM, BOUNDARY_W }, @@ -70,11 +72,14 @@ class instance_ulduar : public InstanceMapScript uint64 AssemblyGUIDs[3]; uint64 KologarnGUID; uint64 AuriayaGUID; - uint64 MimironGUID; uint64 HodirGUID; uint64 ThorimGUID; uint64 FreyaGUID; uint64 ElderGUIDs[3]; + uint64 MimironGUID; + uint64 MimironVehicleGUIDs[3]; + uint64 MimironComputerGUID; + uint64 MimironWorldTriggerGUID; uint64 VezaxGUID; uint64 YoggSaronGUID; uint64 VoiceOfYoggSaronGUID; @@ -92,6 +97,9 @@ class instance_ulduar : public InstanceMapScript uint64 ThorimChestGUID; uint64 HodirRareCacheGUID; uint64 HodirChestGUID; + uint64 MimironTramGUID; + uint64 MimironElevatorGUID; + uint64 MimironButtonGUID; uint64 BrainRoomDoorGUIDs[3]; uint64 AlgalonSigilDoorGUID[3]; uint64 AlgalonFloorGUID[2]; @@ -126,6 +134,8 @@ class instance_ulduar : public InstanceMapScript KologarnGUID = 0; AuriayaGUID = 0; MimironGUID = 0; + MimironComputerGUID = 0; + MimironWorldTriggerGUID = 0; HodirGUID = 0; ThorimGUID = 0; FreyaGUID = 0; @@ -140,6 +150,9 @@ class instance_ulduar : public InstanceMapScript ThorimChestGUID = 0; HodirRareCacheGUID = 0; HodirChestGUID = 0; + MimironTramGUID = 0; + MimironElevatorGUID = 0; + MimironButtonGUID = 0; LeviathanGateGUID = 0; AlgalonUniverseGUID = 0; AlgalonTrapdoorGUID = 0; @@ -166,6 +179,7 @@ class instance_ulduar : public InstanceMapScript memset(AssemblyGUIDs, 0, sizeof(AssemblyGUIDs)); memset(RazorHarpoonGUIDs, 0, sizeof(RazorHarpoonGUIDs)); memset(ElderGUIDs, 0, sizeof(ElderGUIDs)); + memset(MimironVehicleGUIDs, 0, sizeof(MimironVehicleGUIDs)); memset(BrainRoomDoorGUIDs, 0, sizeof(BrainRoomDoorGUIDs)); memset(KeeperGUIDs, 0, sizeof(KeeperGUIDs)); memset(_summonObservationRingKeeper, false, sizeof(_summonObservationRingKeeper)); @@ -289,9 +303,6 @@ class instance_ulduar : public InstanceMapScript case NPC_AURIAYA: AuriayaGUID = creature->GetGUID(); break; - case NPC_MIMIRON: - MimironGUID = creature->GetGUID(); - break; // Hodir case NPC_HODIR: @@ -354,6 +365,26 @@ class instance_ulduar : public InstanceMapScript creature->DespawnOrUnsummon(); break; + // Mimiron + case NPC_MIMIRON: + MimironGUID = creature->GetGUID(); + break; + case NPC_LEVIATHAN_MKII: + MimironVehicleGUIDs[0] = creature->GetGUID(); + break; + case NPC_VX_001: + MimironVehicleGUIDs[1] = creature->GetGUID(); + break; + case NPC_AERIAL_COMMAND_UNIT: + MimironVehicleGUIDs[2] = creature->GetGUID(); + break; + case NPC_COMPUTER: + MimironComputerGUID = creature->GetGUID(); + break; + case NPC_WORLD_TRIGGER_MIMIRON: + MimironWorldTriggerGUID = creature->GetGUID(); + break; + case NPC_VEZAX: VezaxGUID = creature->GetGUID(); break; @@ -470,6 +501,15 @@ class instance_ulduar : public InstanceMapScript case GO_HODIR_CHEST: HodirChestGUID = gameObject->GetGUID(); break; + case GO_MIMIRON_TRAM: + MimironTramGUID = gameObject->GetGUID(); + break; + case GO_MIMIRON_ELEVATOR: + MimironElevatorGUID = gameObject->GetGUID(); + break; + case GO_MIMIRON_BUTTON: + MimironButtonGUID = gameObject->GetGUID(); + break; case GO_LEVIATHAN_GATE: LeviathanGateGUID = gameObject->GetGUID(); if (GetBossState(BOSS_LEVIATHAN) == DONE) @@ -482,6 +522,9 @@ class instance_ulduar : public InstanceMapScript case GO_HODIR_ENTRANCE: case GO_HODIR_DOOR: case GO_HODIR_ICE_DOOR: + case GO_MIMIRON_DOOR_1: + case GO_MIMIRON_DOOR_2: + case GO_MIMIRON_DOOR_3: case GO_VEZAX_DOOR: case GO_YOGG_SARON_DOOR: AddDoor(gameObject, true); @@ -566,6 +609,9 @@ class instance_ulduar : public InstanceMapScript case GO_HODIR_ENTRANCE: case GO_HODIR_DOOR: case GO_HODIR_ICE_DOOR: + case GO_MIMIRON_DOOR_1: + case GO_MIMIRON_DOOR_2: + case GO_MIMIRON_DOOR_3: case GO_VEZAX_DOOR: case GO_YOGG_SARON_DOOR: case GO_DOODAD_UL_SIGILDOOR_03: @@ -774,6 +820,10 @@ class instance_ulduar : public InstanceMapScript break; case DATA_UNBROKEN: Unbroken = data != 0; + break; + case DATA_MIMIRON_ELEVATOR: + if (GameObject* gameObject = instance->GetGameObject(MimironElevatorGUID)) + gameObject->SetGoState((GOState)data); break; case DATA_ILLUSION: illusion = data; @@ -846,8 +896,6 @@ class instance_ulduar : public InstanceMapScript return KologarnGUID; case BOSS_AURIAYA: return AuriayaGUID; - case BOSS_MIMIRON: - return MimironGUID; case BOSS_HODIR: return HodirGUID; case BOSS_THORIM: @@ -863,6 +911,22 @@ class instance_ulduar : public InstanceMapScript case BOSS_STONEBARK: return ElderGUIDs[2]; + // Mimiron + case BOSS_MIMIRON: + return MimironGUID; + case DATA_LEVIATHAN_MK_II: + return MimironVehicleGUIDs[0]; + case DATA_VX_001: + return MimironVehicleGUIDs[1]; + case DATA_AERIAL_COMMAND_UNIT: + return MimironVehicleGUIDs[2]; + case DATA_COMPUTER: + return MimironComputerGUID; + case DATA_MIMIRON_WORLD_TRIGGER: + return MimironWorldTriggerGUID; + case DATA_MIMIRON_BUTTON: + return MimironButtonGUID; + case BOSS_VEZAX: return VezaxGUID; diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 3544ff3c079..81cb469318f 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -18,6 +18,7 @@ #ifndef DEF_ULDUAR_H #define DEF_ULDUAR_H +#include "InstanceScript.h" #include "ObjectMgr.h" #define UlduarScriptName "instance_ulduar" @@ -83,6 +84,18 @@ enum UlduarNPCs NPC_LEVIATHAN_MKII = 33432, NPC_VX_001 = 33651, NPC_AERIAL_COMMAND_UNIT = 33670, + NPC_ASSAULT_BOT = 34057, + NPC_BOMB_BOT = 33836, + NPC_JUNK_BOT = 33855, + NPC_EMERGENCY_FIRE_BOT = 34147, + NPC_FROST_BOMB = 34149, + NPC_BURST_TARGET = 34211, + NPC_FLAME = 34363, + NPC_FLAME_SPREAD = 34121, + NPC_DB_TARGET = 33576, + NPC_ROCKET_MIMIRON_VISUAL = 34050, + NPC_WORLD_TRIGGER_MIMIRON = 21252, + NPC_COMPUTER = 34143, // Freya's Keepers NPC_IRONBRANCH = 32913, @@ -204,6 +217,18 @@ enum UlduarGameObjects GO_THORIM_CHEST_HERO = 194315, GO_THORIM_CHEST = 194314, + // Mimiron + GO_MIMIRON_TRAM = 194675, + GO_MIMIRON_ELEVATOR = 194749, + GO_MIMIRON_BUTTON = 194739, + GO_MIMIRON_DOOR_1 = 194774, + GO_MIMIRON_DOOR_2 = 194775, + GO_MIMIRON_DOOR_3 = 194776, + GO_CACHE_OF_INNOVATION = 194789, + GO_CACHE_OF_INNOVATION_FIREFIGHTER = 194957, + GO_CACHE_OF_INNOVATION_HERO = 194956, + GO_CACHE_OF_INNOVATION_FIREFIGHTER_HERO = 194958, + // Vezax GO_VEZAX_DOOR = 194750, @@ -292,6 +317,16 @@ enum UlduarData // Hodir DATA_HODIR_RARE_CACHE, + // Mimiron + DATA_LEVIATHAN_MK_II, + DATA_VX_001, + DATA_AERIAL_COMMAND_UNIT, + DATA_COMPUTER, + DATA_MIMIRON_WORLD_TRIGGER, + DATA_MIMIRON_ELEVATOR, + DATA_MIMIRON_TRAM, + DATA_MIMIRON_BUTTON, + // Yogg-Saron DATA_VOICE_OF_YOGG_SARON, DATA_SARA, diff --git a/src/server/scripts/Northrend/zone_sholazar_basin.cpp b/src/server/scripts/Northrend/zone_sholazar_basin.cpp index f9fb3801955..c56739c783f 100644 --- a/src/server/scripts/Northrend/zone_sholazar_basin.cpp +++ b/src/server/scripts/Northrend/zone_sholazar_basin.cpp @@ -18,12 +18,11 @@ /* ScriptData SDName: Sholazar_Basin SD%Complete: 100 -SDComment: Quest support: 12570, 12573, 12621, 12726 +SDComment: Quest support: 12573, 12621, 12726 SDCategory: Sholazar_Basin EndScriptData */ /* ContentData -npc_injured_rainspeaker_oracle npc_vekjik avatar_of_freya npc_haiphoon (Quest: "Song of Wind and Water") @@ -40,141 +39,6 @@ EndContentData */ #include "Player.h" /*###### -## npc_injured_rainspeaker_oracle -######*/ - -#define GOSSIP_ITEM1 "I am ready to travel to your village now." - -enum Rainspeaker -{ - SAY_START_IRO = 0, - SAY_QUEST_ACCEPT_IRO = 1, - SAY_END_IRO = 2, - - QUEST_FORTUNATE_MISUNDERSTANDINGS = 12570, - FACTION_ESCORTEE_A = 774, - FACTION_ESCORTEE_H = 775 -}; - -class npc_injured_rainspeaker_oracle : public CreatureScript -{ -public: - npc_injured_rainspeaker_oracle() : CreatureScript("npc_injured_rainspeaker_oracle") { } - - struct npc_injured_rainspeaker_oracleAI : public npc_escortAI - { - npc_injured_rainspeaker_oracleAI(Creature* creature) : npc_escortAI(creature) { c_guid = creature->GetGUID(); } - - uint64 c_guid; - - void Reset() override - { - me->RestoreFaction(); - // if we will have other way to assign this to only one npc remove this part - if (GUID_LOPART(me->GetGUID()) != 101030) - { - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_QUESTGIVER); - me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_GOSSIP); - } - } - - void WaypointReached(uint32 waypointId) override - { - Player* player = GetPlayerForEscort(); - if (!player) - return; - - switch (waypointId) - { - case 1: - SetRun(); - break; - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - me->RemoveUnitMovementFlag(MOVEMENTFLAG_FALLING); - me->SetSpeed(MOVE_SWIM, 0.85f, true); - me->SetSwim(true); - me->SetDisableGravity(true); - break; - case 19: - me->GetMotionMaster()->MoveFall(); - break; - case 28: - player->GroupEventHappens(QUEST_FORTUNATE_MISUNDERSTANDINGS, me); - // me->RestoreFaction(); - Talk(SAY_END_IRO); - SetRun(false); - break; - } - } - - void JustDied(Unit* /*killer*/) override - { - if (!HasEscortState(STATE_ESCORT_ESCORTING)) - return; - - if (Player* player = GetPlayerForEscort()) - { - if (player->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) != QUEST_STATUS_COMPLETE) - player->FailQuest(QUEST_FORTUNATE_MISUNDERSTANDINGS); - } - } - }; - - bool OnGossipHello(Player* player, Creature* creature) override - { - if (creature->IsQuestGiver()) - player->PrepareQuestMenu(creature->GetGUID()); - - if (player->GetQuestStatus(QUEST_FORTUNATE_MISUNDERSTANDINGS) == QUEST_STATUS_INCOMPLETE) - player->ADD_GOSSIP_ITEM(GOSSIP_ICON_CHAT, GOSSIP_ITEM1, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF+1); - - player->SEND_GOSSIP_MENU(player->GetGossipTextId(creature), creature->GetGUID()); - - return true; - } - - bool OnGossipSelect(Player* player, Creature* creature, uint32 /*sender*/, uint32 action) override - { - player->PlayerTalkClass->ClearMenus(); - if (action == GOSSIP_ACTION_INFO_DEF+1) - { - ENSURE_AI(npc_escortAI, (creature->AI()))->Start(true, false, player->GetGUID()); - ENSURE_AI(npc_escortAI, (creature->AI()))->SetMaxPlayerDistance(35.0f); - creature->AI()->Talk(SAY_START_IRO); - - switch (player->GetTeam()){ - case ALLIANCE: - creature->setFaction(FACTION_ESCORTEE_A); - break; - case HORDE: - creature->setFaction(FACTION_ESCORTEE_H); - break; - } - } - return true; - } - - bool OnQuestAccept(Player* /*player*/, Creature* creature, Quest const* /*_Quest*/) override - { - creature->AI()->Talk(SAY_QUEST_ACCEPT_IRO); - return false; - } - - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_injured_rainspeaker_oracleAI(creature); - } -}; - -/*###### ## npc_vekjik ######*/ @@ -1143,7 +1007,6 @@ public: void AddSC_sholazar_basin() { - new npc_injured_rainspeaker_oracle(); new npc_vekjik(); new npc_avatar_of_freya(); new npc_bushwhacker(); diff --git a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp index dc0a6643624..d4fdb262c8e 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SteamVault/boss_hydromancer_thespia.cpp @@ -19,156 +19,169 @@ #include "ScriptedCreature.h" #include "steam_vault.h" -enum HydromancerThespia +enum Yells { SAY_SUMMON = 0, SAY_AGGRO = 1, SAY_SLAY = 2, SAY_DEAD = 3, +}; +enum Spells +{ SPELL_LIGHTNING_CLOUD = 25033, SPELL_LUNG_BURST = 31481, - SPELL_ENVELOPING_WINDS = 31718, + SPELL_ENVELOPING_WINDS = 31718 +}; - SPELL_WATER_BOLT_VOLLEY = 34449, - H_SPELL_WATER_BOLT_VOLLEY = 37924 +enum Events +{ + EVENT_LIGHTNING_CLOUD = 1, + EVENT_LUNG_BURST, + EVENT_ENVELOPING_WINDS }; class boss_hydromancer_thespia : public CreatureScript { -public: - boss_hydromancer_thespia() : CreatureScript("boss_hydromancer_thespia") { } - - CreatureAI* GetAI(Creature* creature) const override - { - return GetInstanceAI<boss_thespiaAI>(creature); - } - - struct boss_thespiaAI : public ScriptedAI - { - boss_thespiaAI(Creature* creature) : ScriptedAI(creature) - { - instance = creature->GetInstanceScript(); - } - - InstanceScript* instance; - - uint32 LightningCloud_Timer; - uint32 LungBurst_Timer; - uint32 EnvelopingWinds_Timer; - - void Reset() override - { - LightningCloud_Timer = 15000; - LungBurst_Timer = 7000; - EnvelopingWinds_Timer = 9000; - - instance->SetBossState(DATA_HYDROMANCER_THESPIA, NOT_STARTED); - } - - void JustDied(Unit* /*killer*/) override - { - Talk(SAY_DEAD); - - instance->SetBossState(DATA_HYDROMANCER_THESPIA, DONE); - } - - void KilledUnit(Unit* /*victim*/) override - { - Talk(SAY_SLAY); - } + public: + boss_hydromancer_thespia() : CreatureScript("boss_hydromancer_thespia") { } - void EnterCombat(Unit* /*who*/) override + struct boss_thespiaAI : public BossAI { - Talk(SAY_AGGRO); + boss_thespiaAI(Creature* creature) : BossAI(creature, DATA_HYDROMANCER_THESPIA) { } - instance->SetBossState(DATA_HYDROMANCER_THESPIA, IN_PROGRESS); - } + void Reset() override + { + _Reset(); + } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void JustDied(Unit* /*killer*/) override + { + Talk(SAY_DEAD); + _JustDied(); + } - //LightningCloud_Timer - if (LightningCloud_Timer <= diff) + void KilledUnit(Unit* who) override { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_LIGHTNING_CLOUD); + if (who->GetTypeId() == TYPEID_PLAYER) + Talk(SAY_SLAY); + } - //cast twice in Heroic mode - if (IsHeroic()) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_LIGHTNING_CLOUD); + void EnterCombat(Unit* /*who*/) override + { + Talk(SAY_AGGRO); + _EnterCombat(); - LightningCloud_Timer = 15000 + rand32() % 10000; - } else LightningCloud_Timer -=diff; + events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, 15000); + events.ScheduleEvent(EVENT_LUNG_BURST, 7000); + events.ScheduleEvent(EVENT_ENVELOPING_WINDS, 9000); + } - //LungBurst_Timer - if (LungBurst_Timer <= diff) + void ExecuteEvent(uint32 eventId) override { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_LUNG_BURST); - LungBurst_Timer = 7000 + rand32() % 5000; - } else LungBurst_Timer -=diff; - - //EnvelopingWinds_Timer - if (EnvelopingWinds_Timer <= diff) + switch (eventId) + { + case EVENT_LIGHTNING_CLOUD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_LIGHTNING_CLOUD); + // cast twice in Heroic mode + if (IsHeroic()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, true)) + DoCast(target, SPELL_LIGHTNING_CLOUD); + + events.ScheduleEvent(EVENT_LIGHTNING_CLOUD, urand(15000, 25000)); + break; + case EVENT_LUNG_BURST: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true)) + DoCast(target, SPELL_LUNG_BURST); + events.ScheduleEvent(EVENT_LUNG_BURST, urand(7000, 12000)); + break; + case EVENT_ENVELOPING_WINDS: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true)) + DoCast(target, SPELL_ENVELOPING_WINDS); + // cast twice in Heroic mode + if (IsHeroic()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 35.0f, true)) + DoCast(target, SPELL_ENVELOPING_WINDS); + + events.ScheduleEvent(EVENT_ENVELOPING_WINDS, urand(10000, 15000)); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override { - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_ENVELOPING_WINDS); - - //cast twice in Heroic mode - if (IsHeroic()) - if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) - DoCast(target, SPELL_ENVELOPING_WINDS); - EnvelopingWinds_Timer = 10000 + rand32() % 5000; - } else EnvelopingWinds_Timer -=diff; + BossAI::UpdateAI(diff); + } + }; - DoMeleeAttackIfReady(); + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_thespiaAI>(creature); } - }; +}; +enum CoilfangWaterElemental +{ + EVENT_WATER_BOLT_VOLLEY = 1, + SPELL_WATER_BOLT_VOLLEY = 34449 }; class npc_coilfang_waterelemental : public CreatureScript { -public: - npc_coilfang_waterelemental() : CreatureScript("npc_coilfang_waterelemental") { } + public: + npc_coilfang_waterelemental() : CreatureScript("npc_coilfang_waterelemental") { } - CreatureAI* GetAI(Creature* creature) const override - { - return new npc_coilfang_waterelementalAI(creature); - } - - struct npc_coilfang_waterelementalAI : public ScriptedAI - { - npc_coilfang_waterelementalAI(Creature* creature) : ScriptedAI(creature) { } - - uint32 WaterBoltVolley_Timer; - - void Reset() override + struct npc_coilfang_waterelementalAI : public ScriptedAI { - WaterBoltVolley_Timer = 3000 + rand32() % 3000; - } - - void EnterCombat(Unit* /*who*/) override { } + npc_coilfang_waterelementalAI(Creature* creature) : ScriptedAI(creature) { } - void UpdateAI(uint32 diff) override - { - if (!UpdateVictim()) - return; + void Reset() override + { + _events.Reset(); + } - if (WaterBoltVolley_Timer <= diff) + void EnterCombat(Unit* /*who*/) override { - DoCast(me, SPELL_WATER_BOLT_VOLLEY); - WaterBoltVolley_Timer = 7000 + rand32() % 5000; - } else WaterBoltVolley_Timer -= diff; + _events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(3000, 6000)); + } - DoMeleeAttackIfReady(); + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + _events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = _events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_WATER_BOLT_VOLLEY: + DoCast(me, SPELL_WATER_BOLT_VOLLEY); + _events.ScheduleEvent(EVENT_WATER_BOLT_VOLLEY, urand(7000, 12000)); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap _events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return new npc_coilfang_waterelementalAI(creature); } - }; - }; void AddSC_boss_hydromancer_thespia() diff --git a/src/server/scripts/Pet/pet_hunter.cpp b/src/server/scripts/Pet/pet_hunter.cpp index 7dbdc7af63f..8fd6cb54b0e 100644 --- a/src/server/scripts/Pet/pet_hunter.cpp +++ b/src/server/scripts/Pet/pet_hunter.cpp @@ -57,7 +57,7 @@ class npc_pet_hunter_snake_trap : public CreatureScript me->SetMaxHealth(uint32(107 * (me->getLevel() - 40) * 0.025f)); // Add delta to make them not all hit the same time uint32 delta = (rand32() % 7) * 100; - me->SetAttackTime(BASE_ATTACK, Info->baseattacktime + delta); + me->SetAttackTime(BASE_ATTACK, Info->BaseAttackTime + delta); //me->SetStatFloatValue(UNIT_FIELD_RANGED_ATTACK_POWER, float(Info->attackpower)); // Start attacking attacker of owner on first ai update after spawn - move in line of sight may choose better target diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 87c323aa22f..c43b781936c 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -991,7 +991,7 @@ class spell_item_unsated_craving : public SpellScriptLoader return false; Unit* target = procInfo.GetActionTarget(); - if (!target || target->GetTypeId() != TYPEID_UNIT || target->GetCreatureType() == CREATURE_TYPE_CRITTER || (target->GetEntry() != NPC_SINDRAGOSA && target->IsSummon())) + if (!target || target->GetTypeId() != TYPEID_UNIT || target->IsCritter() || (target->GetEntry() != NPC_SINDRAGOSA && target->IsSummon())) return false; return true; diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index aa2ca4b7e2e..f5d9913bc5b 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -76,7 +76,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, permission, help FROM command", CONNECTION_SYNCH); - PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, rank, mindmg, maxdmg, dmgschool, attackpower, dmg_multiplier, baseattacktime, rangeattacktime, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, minrangedmg, maxrangedmg, rangedattackpower, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, Health_mod, Mana_mod, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); + PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, rank, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, lootid, pickpocketloot, skinloot, resistance1, resistance2, resistance3, resistance4, resistance5, resistance6, spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); @@ -89,6 +89,4 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_DEL_DISABLES, "DELETE FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_ASYNC); - // 0: uint8 - PrepareStatement(WORLD_SEL_REQ_XP, "SELECT xp_for_next_level FROM player_xp_for_level WHERE lvl = ?", CONNECTION_SYNCH); } diff --git a/src/server/shared/Database/Implementation/WorldDatabase.h b/src/server/shared/Database/Implementation/WorldDatabase.h index 625dfc68ce6..8a5bd206021 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.h +++ b/src/server/shared/Database/Implementation/WorldDatabase.h @@ -110,7 +110,6 @@ enum WorldDatabaseStatements WORLD_SEL_DISABLES, WORLD_INS_DISABLES, WORLD_DEL_DISABLES, - WORLD_SEL_REQ_XP, MAX_WORLDDATABASE_STATEMENTS }; diff --git a/src/server/shared/Database/QueryHolder.cpp b/src/server/shared/Database/QueryHolder.cpp index bd938561b50..f0dc3c96e4e 100644 --- a/src/server/shared/Database/QueryHolder.cpp +++ b/src/server/shared/Database/QueryHolder.cpp @@ -166,8 +166,16 @@ void SQLQueryHolder::SetSize(size_t size) m_queries.resize(size); } +SQLQueryHolderTask::~SQLQueryHolderTask() +{ + if (!m_executed) + delete m_holder; +} + bool SQLQueryHolderTask::Execute() { + m_executed = true; + if (!m_holder) return false; diff --git a/src/server/shared/Database/QueryHolder.h b/src/server/shared/Database/QueryHolder.h index 273980c3ac5..39e51b591c5 100644 --- a/src/server/shared/Database/QueryHolder.h +++ b/src/server/shared/Database/QueryHolder.h @@ -47,14 +47,16 @@ class SQLQueryHolderTask : public SQLOperation private: SQLQueryHolder* m_holder; QueryResultHolderPromise m_result; + bool m_executed; public: SQLQueryHolderTask(SQLQueryHolder* holder) - : m_holder(holder) { }; + : m_holder(holder), m_executed(false) { } + + ~SQLQueryHolderTask(); bool Execute() override; QueryResultHolderFuture GetFuture() { return m_result.get_future(); } - }; -#endif
\ No newline at end of file +#endif diff --git a/src/server/shared/Networking/MessageBuffer.h b/src/server/shared/Networking/MessageBuffer.h index fff94b86c1e..c7f8ba31a71 100644 --- a/src/server/shared/Networking/MessageBuffer.h +++ b/src/server/shared/Networking/MessageBuffer.h @@ -40,6 +40,10 @@ public: bool IsMessageReady() const { return _wpos == _storage.size(); } + size_type GetSize() const { return _storage.size(); } + + size_type GetReadyDataSize() const { return _wpos; } + size_type GetMissingSize() const { return _storage.size() - _wpos; } uint8* Data() { return _storage.data(); } @@ -55,8 +59,6 @@ public: void ResetWritePointer() { _wpos = 0; } - size_type GetSize() { return _storage.size(); } - std::vector<uint8>&& Move() { _wpos = 0; diff --git a/src/server/shared/Networking/Socket.h b/src/server/shared/Networking/Socket.h index c8bd5a1dd81..3bd30bd731b 100644 --- a/src/server/shared/Networking/Socket.h +++ b/src/server/shared/Networking/Socket.h @@ -42,7 +42,7 @@ class Socket : public std::enable_shared_from_this<T> public: Socket(tcp::socket&& socket, std::size_t headerSize) : _socket(std::move(socket)), _remoteAddress(_socket.remote_endpoint().address()), - _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false) + _remotePort(_socket.remote_endpoint().port()), _readHeaderBuffer(), _readDataBuffer(), _closed(false), _closing(false) { _readHeaderBuffer.Grow(headerSize); } @@ -126,7 +126,7 @@ public: std::placeholders::_1, std::placeholders::_2)); } - bool IsOpen() const { return !_closed; } + bool IsOpen() const { return !_closed && !_closing; } virtual void CloseSocket() { @@ -140,12 +140,18 @@ public: shutdownError.value(), shutdownError.message().c_str()); } + /// Marks the socket for closing after write buffer becomes empty + void DelayedCloseSocket() { _closing = true; } + virtual bool IsHeaderReady() const { return _readHeaderBuffer.IsMessageReady(); } virtual bool IsDataReady() const { return _readDataBuffer.IsMessageReady(); } uint8* GetHeaderBuffer() { return _readHeaderBuffer.Data(); } uint8* GetDataBuffer() { return _readDataBuffer.Data(); } + size_t GetHeaderSize() const { return _readHeaderBuffer.GetReadyDataSize(); } + size_t GetDataSize() const { return _readDataBuffer.GetReadyDataSize(); } + MessageBuffer&& MoveHeader() { return std::move(_readHeaderBuffer); } MessageBuffer&& MoveData() { return std::move(_readDataBuffer); } @@ -218,6 +224,8 @@ private: if (!_writeQueue.empty()) AsyncWrite(_writeQueue.front()); + else if (_closing) + CloseSocket(); } else CloseSocket(); @@ -238,6 +246,7 @@ private: MessageBuffer _readDataBuffer; std::atomic<bool> _closed; + std::atomic<bool> _closing; }; #endif // __SOCKET_H__ diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index dd8f213b6df..d98a061b9f3 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -1741,6 +1741,15 @@ Rate.XP.Quest = 1 Rate.XP.Explore = 1 # +# Rate.Quest.Money.Reward +# Rate.Quest.Money.Max.Level.Reward +# Description: Multiplier for money quest rewards. Can not be below 0. +# Default: 1 + +Rate.Quest.Money.Reward = 1 +Rate.Quest.Money.Max.Level.Reward = 1 + +# # Rate.RepairCost # Description: Repair cost rate. # Default: 1 |
