diff options
Diffstat (limited to 'src')
29 files changed, 382 insertions, 349 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 86d86739bc9..e37b9e777d8 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -1893,12 +1893,19 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_JUMP_TO_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->GetMotionMaster()->Clear(); - me->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (Creature* creature = (*itr)->ToCreature()) + { + creature->GetMotionMaster()->Clear(); + creature->GetMotionMaster()->MoveJump(e.target.x, e.target.y, e.target.z, (float)e.action.jump.speedxy, (float)e.action.jump.speedz); + } // TODO: Resume path when reached jump location + + delete targets; break; } case SMART_ACTION_GO_SET_LOOT_STATE: @@ -1977,23 +1984,48 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u } case SMART_ACTION_SET_HOME_POS: { - if (!me) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - if (e.GetTargetType() == SMART_TARGET_SELF) - me->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); - else if (e.GetTargetType() == SMART_TARGET_POSITION) - me->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); - else - sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + { + if (e.GetTargetType() == SMART_TARGET_SELF) + (*itr)->ToCreature()->SetHomePosition(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + else if (e.GetTargetType() == SMART_TARGET_POSITION) + (*itr)->ToCreature()->SetHomePosition(e.target.x, e.target.y, e.target.z, e.target.o); + else + sLog->outError(LOG_FILTER_SQL, "SmartScript: Action target for SMART_ACTION_SET_HOME_POS is not using SMART_TARGET_SELF or SMART_TARGET_POSITION, skipping"); + } - break; + delete targets; + break; } case SMART_ACTION_SET_HEALTH_REGEN: { - if (!me || me->GetTypeId() != TYPEID_UNIT) + ObjectList* targets = GetTargets(e, unit); + if (!targets) break; - me->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->setRegeneratingHealth(e.action.setHealthRegen.regenHealth ? true : false); + + delete targets; + break; + } + case SMART_ACTION_SET_ROOT: + { + ObjectList* targets = GetTargets(e, unit); + if (!targets) + break; + + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); ++itr) + if (IsCreature(*itr)) + (*itr)->ToCreature()->SetControlled(e.action.setRoot.root ? true : false, UNIT_STATE_ROOT); + + delete targets; break; } default: diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp index 76fcb7bad00..69902954fde 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.cpp @@ -906,6 +906,7 @@ bool SmartAIMgr::IsEventValid(SmartScriptHolder& e) case SMART_ACTION_SEND_TARGET_TO_TARGET: case SMART_ACTION_SET_HOME_POS: case SMART_ACTION_SET_HEALTH_REGEN: + case SMART_ACTION_SET_ROOT: break; default: sLog->outError(LOG_FILTER_SQL, "SmartAIMgr: Not handled action_type(%u), event_type(%u), Entry %d SourceType %u Event %u, skipped.", e.GetActionType(), e.GetEventType(), e.entryOrGuid, e.GetScriptType(), e.event_id); diff --git a/src/server/game/AI/SmartScripts/SmartScriptMgr.h b/src/server/game/AI/SmartScripts/SmartScriptMgr.h index a909cb56098..a3420071f5e 100644 --- a/src/server/game/AI/SmartScripts/SmartScriptMgr.h +++ b/src/server/game/AI/SmartScripts/SmartScriptMgr.h @@ -487,8 +487,9 @@ enum SMART_ACTION SMART_ACTION_SEND_TARGET_TO_TARGET = 100, // id SMART_ACTION_SET_HOME_POS = 101, // none SMART_ACTION_SET_HEALTH_REGEN = 102, // 0/1 + SMART_ACTION_SET_ROOT = 103, // off/on - SMART_ACTION_END = 103 + SMART_ACTION_END = 104 }; struct SmartAction @@ -920,6 +921,11 @@ struct SmartAction uint32 regenHealth; } setHealthRegen; + struct + { + uint32 root; + } setRoot; + //! Note for any new future actions //! All parameters must have type uint32 diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 2db63040e83..f7bc6a99fb1 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -14547,15 +14547,32 @@ void Unit::SetControlled(bool apply, UnitState state) { switch (state) { - case UNIT_STATE_STUNNED: if (HasAuraType(SPELL_AURA_MOD_STUN)) return; - else SetStunned(false); break; - case UNIT_STATE_ROOT: if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) return; - else SetRooted(false); break; - case UNIT_STATE_CONFUSED:if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) return; - else SetConfused(false); break; - case UNIT_STATE_FLEEING: if (HasAuraType(SPELL_AURA_MOD_FEAR)) return; - else SetFeared(false); break; - default: return; + case UNIT_STATE_STUNNED: + if (HasAuraType(SPELL_AURA_MOD_STUN)) + return; + + SetStunned(false); + break; + case UNIT_STATE_ROOT: + if (HasAuraType(SPELL_AURA_MOD_ROOT) || GetVehicle()) + return; + + SetRooted(false); + break; + case UNIT_STATE_CONFUSED: + if (HasAuraType(SPELL_AURA_MOD_CONFUSE)) + return; + + SetConfused(false); + break; + case UNIT_STATE_FLEEING: + if (HasAuraType(SPELL_AURA_MOD_FEAR)) + return; + + SetFeared(false); + break; + default: + return; } ClearUnitState(state); diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 3828005b041..5bdda34a428 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -26,6 +26,7 @@ #include "SpellInfo.h" #include "Group.h" #include "Player.h" +#include "Containers.h" static Rates const qualityToRate[MAX_ITEM_QUALITY] = { @@ -51,10 +52,26 @@ LootStore LootTemplates_Reference("reference_loot_template", "reference LootStore LootTemplates_Skinning("skinning_loot_template", "creature skinning id", true); LootStore LootTemplates_Spell("spell_loot_template", "spell id (random item creating)", false); +struct NotMatchingLootMode : public std::unary_function<LootStoreItem*, bool> +{ + explicit NotMatchingLootMode(uint16 lootMode) : _lootMode(lootMode) { } + + bool operator()(LootStoreItem* item) const + { + return !(item->lootmode & _lootMode); + } + +private: + uint16 _lootMode; +}; + class LootTemplate::LootGroup // A set of loot definitions for items (refs are not allowed) { public: - void AddEntry(LootStoreItem& item); // Adds an entry to the group (at loading stage) + LootGroup() { } + ~LootGroup(); + + void AddEntry(LootStoreItem* item); // Adds an entry to the group (at loading stage) bool HasQuestDrop() const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const* player) const; // The same for active quests of the player @@ -72,7 +89,11 @@ class LootTemplate::LootGroup // A set of loot def LootStoreItemList ExplicitlyChanced; // Entries with chances defined in DB LootStoreItemList EqualChanced; // Zero chances - every entry takes the same chance - LootStoreItem const* Roll() const; // Rolls an item from the group, returns NULL if all miss their chances + LootStoreItem const* Roll(uint16 lootMode) const; // Rolls an item from the group, returns NULL if all miss their chances + + // This class must never be copied - storing pointers + LootGroup(LootGroup const&); + LootGroup& operator=(LootGroup const&); }; //Remove all data and free all memory @@ -126,10 +147,13 @@ uint32 LootStore::LoadLootTable() continue; // error already printed to log/console. } - LootStoreItem storeitem = LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); + LootStoreItem* storeitem = new LootStoreItem(item, chanceOrQuestChance, lootmode, group, mincountOrRef, maxcount); - if (!storeitem.IsValid(*this, entry)) // Validity checks + if (!storeitem->IsValid(*this, entry)) // Validity checks + { + delete storeitem; continue; + } // Looking for the template of the entry // often entries are put together @@ -139,7 +163,7 @@ uint32 LootStore::LoadLootTable() tab = m_LootTemplates.find(entry); if (tab == m_LootTemplates.end()) { - std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate)); + std::pair< LootTemplateMap::iterator, bool > pr = m_LootTemplates.insert(LootTemplateMap::value_type(entry, new LootTemplate())); tab = pr.first; } } @@ -182,7 +206,7 @@ void LootStore::ResetConditions() for (LootTemplateMap::iterator itr = m_LootTemplates.begin(); itr != m_LootTemplates.end(); ++itr) { ConditionList empty; - (*itr).second->CopyConditions(empty); + itr->second->CopyConditions(empty); } } @@ -1028,34 +1052,56 @@ ByteBuffer& operator<<(ByteBuffer& b, LootView const& lv) // --------- LootTemplate::LootGroup --------- // +LootTemplate::LootGroup::~LootGroup() +{ + while (!ExplicitlyChanced.empty()) + { + delete ExplicitlyChanced.back(); + ExplicitlyChanced.pop_back(); + } + + while (!EqualChanced.empty()) + { + delete EqualChanced.back(); + EqualChanced.pop_back(); + } +} + // Adds an entry to the group (at loading stage) -void LootTemplate::LootGroup::AddEntry(LootStoreItem& item) +void LootTemplate::LootGroup::AddEntry(LootStoreItem* item) { - if (item.chance != 0) + if (item->chance != 0) ExplicitlyChanced.push_back(item); else EqualChanced.push_back(item); } // Rolls an item from the group, returns NULL if all miss their chances -LootStoreItem const* LootTemplate::LootGroup::Roll() const +LootStoreItem const* LootTemplate::LootGroup::Roll(uint16 lootMode) const { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + LootStoreItemList possibleLoot = ExplicitlyChanced; + possibleLoot.remove_if(NotMatchingLootMode(lootMode)); + + if (!possibleLoot.empty()) // First explicitly chanced entries are checked { - float Roll = (float)rand_chance(); + float roll = (float)rand_chance(); - for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality. + for (LootStoreItemList::const_iterator itr = possibleLoot.begin(); itr != possibleLoot.end(); ++itr) // check each explicitly chanced entry in the template and modify its chance based on quality. { - if (ExplicitlyChanced[i].chance >= 100.0f) - return &ExplicitlyChanced[i]; + LootStoreItem* item = *itr; + if (item->chance >= 100.0f) + return item; - Roll -= ExplicitlyChanced[i].chance; - if (Roll < 0) - return &ExplicitlyChanced[i]; + roll -= item->chance; + if (roll < 0) + return item; } } - if (!EqualChanced.empty()) // If nothing selected yet - an item is taken from equal-chanced part - return &EqualChanced[irand(0, EqualChanced.size()-1)]; + + possibleLoot = EqualChanced; + possibleLoot.remove_if(NotMatchingLootMode(lootMode)); + if (!possibleLoot.empty()) // If nothing selected yet - an item is taken from equal-chanced part + return Trinity::Containers::SelectRandomContainerElement(possibleLoot); return NULL; // Empty drop from the group } @@ -1063,12 +1109,14 @@ LootStoreItem const* LootTemplate::LootGroup::Roll() const // True if group includes at least 1 quest drop entry bool LootTemplate::LootGroup::HasQuestDrop() const { - for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (i->needs_quest) + for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) + if ((*i)->needs_quest) return true; - for (LootStoreItemList::const_iterator i=EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (i->needs_quest) + + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) + if ((*i)->needs_quest) return true; + return false; } @@ -1076,111 +1124,30 @@ bool LootTemplate::LootGroup::HasQuestDrop() const bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const* player) const { for (LootStoreItemList::const_iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + for (LootStoreItemList::const_iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - if (player->HasQuestForItem(i->itemid)) + if (player->HasQuestForItem((*i)->itemid)) return true; + return false; } void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/) { for (LootStoreItemList::iterator i = ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); + for (LootStoreItemList::iterator i = EqualChanced.begin(); i != EqualChanced.end(); ++i) - { - i->conditions.clear(); - } + (*i)->conditions.clear(); } // Rolls an item from the group (if any takes its chance) and adds the item to the loot void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const { - // build up list of possible drops - LootStoreItemList EqualPossibleDrops = EqualChanced; - LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced; - - uint8 uiAttemptCount = 0; - const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size(); - - while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty()) - { - if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort - return; - - LootStoreItem* item = NULL; - - // begin rolling (normally called via Roll()) - LootStoreItemList::iterator itr; - uint8 itemSource = 0; - if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked - { - itemSource = 1; - float Roll = (float)rand_chance(); - // check each explicitly chanced entry in the template and modify its chance based on quality - for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); itr = ExplicitPossibleDrops.erase(itr)) - { - if (itr->chance >= 100.0f) - { - item = &*itr; - break; - } - - Roll -= itr->chance; - if (Roll < 0) - { - item = &*itr; - break; - } - } - } - if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part - { - itemSource = 2; - itr = EqualPossibleDrops.begin(); - std::advance(itr, irand(0, EqualPossibleDrops.size()-1)); - item = &*itr; - } - // finish rolling - - ++uiAttemptCount; - - if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches - { - bool duplicate = false; - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(item->itemid)) - { - uint8 _item_counter = 0; - for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item) - if (_item->itemid == item->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - duplicate = true; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - duplicate = true; - } - } - if (duplicate) // if item->itemid is a duplicate, remove it - switch (itemSource) - { - case 1: // item came from ExplicitPossibleDrops - ExplicitPossibleDrops.erase(itr); - break; - case 2: // item came from EqualPossibleDrops - EqualPossibleDrops.erase(itr); - break; - } - else // otherwise, add the item and exit the function - { - loot.AddItem(*item); - return; - } - } - } + if (LootStoreItem const* item = Roll(lootMode)) + loot.AddItem(*item); } // Overall chance for the group without equal chanced items @@ -1189,8 +1156,8 @@ float LootTemplate::LootGroup::RawTotalChance() const float result = 0; for (LootStoreItemList::const_iterator i=ExplicitlyChanced.begin(); i != ExplicitlyChanced.end(); ++i) - if (!i->needs_quest) - result += i->chance; + if (!(*i)->needs_quest) + result += (*i)->chance; return result; } @@ -1218,25 +1185,27 @@ void LootTemplate::LootGroup::Verify(LootStore const& lootstore, uint32 id, uint void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, LootIdSet* ref_set) const { - for (LootStoreItemList::const_iterator ieItr=ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = ExplicitlyChanced.begin(); ieItr != ExplicitlyChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } - for (LootStoreItemList::const_iterator ieItr=EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) + for (LootStoreItemList::const_iterator ieItr = EqualChanced.begin(); ieItr != EqualChanced.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } } @@ -1245,14 +1214,30 @@ void LootTemplate::LootGroup::CheckLootRefs(LootTemplateMap const& /*store*/, Lo // --------- LootTemplate --------- // +LootTemplate::~LootTemplate() +{ + while (!Entries.empty()) + { + delete Entries.back(); + Entries.pop_back(); + } + + for (size_t i = 0; i < Groups.size(); ++i) + delete Groups[i]; + Groups.clear(); +} + // Adds an entry to the group (at loading stage) -void LootTemplate::AddEntry(LootStoreItem& item) +void LootTemplate::AddEntry(LootStoreItem* item) { - if (item.group > 0 && item.mincountOrRef > 0) // Group + if (item->group > 0 && item->mincountOrRef > 0) // Group { - if (item.group >= Groups.size()) - Groups.resize(item.group); // Adds new group the the loot template if needed - Groups[item.group-1].AddEntry(item); // Adds new entry to the group + if (item->group >= Groups.size()) + Groups.resize(item->group, NULL); // Adds new group the the loot template if needed + if (!Groups[item->group - 1]) + Groups[item->group - 1] = new LootGroup(); + + Groups[item->group-1]->AddEntry(item); // Adds new entry to the group } else // Non-grouped entries and references are stored together Entries.push_back(item); @@ -1261,10 +1246,11 @@ void LootTemplate::AddEntry(LootStoreItem& item) void LootTemplate::CopyConditions(ConditionList conditions) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) - i->conditions.clear(); + (*i)->conditions.clear(); for (LootGroups::iterator i = Groups.begin(); i != Groups.end(); ++i) - i->CopyConditions(conditions); + if (LootGroup* group = *i) + group->CopyConditions(conditions); } void LootTemplate::CopyConditions(LootItem* li) const @@ -1272,10 +1258,11 @@ void LootTemplate::CopyConditions(LootItem* li) const // Copies the conditions list from a template item to a LootItem for (LootStoreItemList::const_iterator _iter = Entries.begin(); _iter != Entries.end(); ++_iter) { - if (_iter->itemid != li->itemid) + LootStoreItem* item = *_iter; + if (item->itemid != li->itemid) continue; - li->conditions = _iter->conditions; + li->conditions = item->conditions; break; } } @@ -1288,54 +1275,42 @@ void LootTemplate::Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId if (groupId > Groups.size()) return; // Error message already printed at loading stage - Groups[groupId-1].Process(loot, lootMode); + if (!Groups[groupId - 1]) + return; + + Groups[groupId-1]->Process(loot, lootMode); return; } // Rolling non-grouped items for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->lootmode &~ lootMode) // Do not add if mode mismatch + LootStoreItem* item = *i; + if (item->lootmode &~ lootMode) // Do not add if mode mismatch continue; - if (!i->Roll(rate)) - continue; // Bad luck for the entry + if (!item->Roll(rate)) + continue; // Bad luck for the entry - if (ItemTemplate const* _proto = sObjectMgr->GetItemTemplate(i->itemid)) + if (item->mincountOrRef < 0) // References processing { - uint8 _item_counter = 0; - LootItemList::const_iterator _item = loot.items.begin(); - for (; _item != loot.items.end(); ++_item) - if (_item->itemid == i->itemid) // search through the items that have already dropped - { - ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops - continue; - else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop - continue; - } - if (_item != loot.items.end()) - continue; - } - - if (i->mincountOrRef < 0) // References processing - { - LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-i->mincountOrRef); + LootTemplate const* Referenced = LootTemplates_Reference.GetLootFor(-item->mincountOrRef); if (!Referenced) - continue; // Error message already printed at loading stage + continue; // Error message already printed at loading stage - uint32 maxcount = uint32(float(i->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); - for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, rate, lootMode, i->group); + uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); + for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator + Referenced->Process(loot, rate, lootMode, item->group); } - else // Plain entries (not a reference, not grouped) - loot.AddItem(*i); // Chance is already checked, just add + else // Plain entries (not a reference, not grouped) + loot.AddItem(*item); // Chance is already checked, just add } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - i->Process(loot, lootMode); + if (LootGroup* group = *i) + group->Process(loot, lootMode); } // True if template includes at least 1 quest drop entry @@ -1345,27 +1320,33 @@ bool LootTemplate::HasQuestDrop(LootTemplateMap const& store, uint8 groupId) con { if (groupId > Groups.size()) return false; // Error message [should be] already printed at loading stage - return Groups[groupId-1].HasQuestDrop(); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDrop(); } for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message [should be] already printed at loading stage - if (Referenced->second->HasQuestDrop(store, i->group)) + if (Referenced->second->HasQuestDrop(store, item->group)) return true; } - else if (i->needs_quest) + else if (item->needs_quest) return true; // quest drop found } // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDrop()) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDrop()) + return true; return false; } @@ -1377,28 +1358,34 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co { if (groupId > Groups.size()) return false; // Error message already printed at loading stage - return Groups[groupId-1].HasQuestDropForPlayer(player); + + if (!Groups[groupId - 1]) + return false; + + return Groups[groupId-1]->HasQuestDropForPlayer(player); } // Checking non-grouped entries for (LootStoreItemList::const_iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->mincountOrRef < 0) // References processing + LootStoreItem* item = *i; + if (item->mincountOrRef < 0) // References processing { - LootTemplateMap::const_iterator Referenced = store.find(-i->mincountOrRef); + LootTemplateMap::const_iterator Referenced = store.find(-item->mincountOrRef); if (Referenced == store.end()) continue; // Error message already printed at loading stage - if (Referenced->second->HasQuestDropForPlayer(store, player, i->group)) + if (Referenced->second->HasQuestDropForPlayer(store, player, item->group)) return true; } - else if (player->HasQuestForItem(i->itemid)) + else if (player->HasQuestForItem(item->itemid)) return true; // active quest drop found } // Now checking groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) - if (i->HasQuestDropForPlayer(player)) - return true; + if (LootGroup* group = *i) + if (group->HasQuestDropForPlayer(player)) + return true; return false; } @@ -1407,8 +1394,9 @@ bool LootTemplate::HasQuestDropForPlayer(LootTemplateMap const& store, Player co void LootTemplate::Verify(LootStore const& lootstore, uint32 id) const { // Checking group chances - for (uint32 i=0; i < Groups.size(); ++i) - Groups[i].Verify(lootstore, id, i+1); + for (uint32 i = 0; i < Groups.size(); ++i) + if (Groups[i]) + Groups[i]->Verify(lootstore, id, i + 1); // TODO: References validity checks } @@ -1417,18 +1405,21 @@ void LootTemplate::CheckLootRefs(LootTemplateMap const& store, LootIdSet* ref_se { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) { - if (ieItr->mincountOrRef < 0) + LootStoreItem* item = *ieItr; + if (item->mincountOrRef < 0) { - if (!LootTemplates_Reference.GetLootFor(-ieItr->mincountOrRef)) - LootTemplates_Reference.ReportNotExistedId(-ieItr->mincountOrRef); + if (!LootTemplates_Reference.GetLootFor(-item->mincountOrRef)) + LootTemplates_Reference.ReportNotExistedId(-item->mincountOrRef); else if (ref_set) - ref_set->erase(-ieItr->mincountOrRef); + ref_set->erase(-item->mincountOrRef); } } for (LootGroups::const_iterator grItr = Groups.begin(); grItr != Groups.end(); ++grItr) - grItr->CheckLootRefs(store, ref_set); + if (LootGroup* group = *grItr) + group->CheckLootRefs(store, ref_set); } + bool LootTemplate::addConditionItem(Condition* cond) { if (!cond || !cond->isLoaded())//should never happen, checked at loading @@ -1436,41 +1427,48 @@ bool LootTemplate::addConditionItem(Condition* cond) sLog->outError(LOG_FILTER_LOOT, "LootTemplate::addConditionItem: condition is null"); return false; } + if (!Entries.empty()) { for (LootStoreItemList::iterator i = Entries.begin(); i != Entries.end(); ++i) { - if (i->itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - i->conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } + if (!Groups.empty()) { for (LootGroups::iterator groupItr = Groups.begin(); groupItr != Groups.end(); ++groupItr) { - LootStoreItemList* itemList = (*groupItr).GetExplicitlyChancedItemList(); + LootGroup* group = *groupItr; + if (!group) + continue; + + LootStoreItemList* itemList = group->GetExplicitlyChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } } - itemList = (*groupItr).GetEqualChancedItemList(); + + itemList = group->GetEqualChancedItemList(); if (!itemList->empty()) { for (LootStoreItemList::iterator i = itemList->begin(); i != itemList->end(); ++i) { - if ((*i).itemid == uint32(cond->SourceEntry)) + if ((*i)->itemid == uint32(cond->SourceEntry)) { - (*i).conditions.push_back(cond); + (*i)->conditions.push_back(cond); return true; } } @@ -1483,10 +1481,9 @@ bool LootTemplate::addConditionItem(Condition* cond) bool LootTemplate::isReference(uint32 id) { for (LootStoreItemList::const_iterator ieItr = Entries.begin(); ieItr != Entries.end(); ++ieItr) - { - if (ieItr->itemid == id && ieItr->mincountOrRef < 0) + if ((*ieItr)->itemid == id && (*ieItr)->mincountOrRef < 0) return true; - } + return false;//not found or not reference } diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index e51a4607ce1..7474fc87a71 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -27,6 +27,7 @@ #include <map> #include <vector> +#include <list> enum RollType { @@ -173,7 +174,7 @@ class LootTemplate; typedef std::vector<QuestItem> QuestItemList; typedef std::vector<LootItem> LootItemList; typedef std::map<uint32, QuestItemList*> QuestItemMap; -typedef std::vector<LootStoreItem> LootStoreItemList; +typedef std::list<LootStoreItem*> LootStoreItemList; typedef UNORDERED_MAP<uint32, LootTemplate*> LootTemplateMap; typedef std::set<uint32> LootIdSet; @@ -217,11 +218,14 @@ class LootStore class LootTemplate { class LootGroup; // A set of loot definitions for items (refs are not allowed inside) - typedef std::vector<LootGroup> LootGroups; + typedef std::vector<LootGroup*> LootGroups; public: + LootTemplate() { } + ~LootTemplate(); + // Adds an entry to the group (at loading stage) - void AddEntry(LootStoreItem& item); + void AddEntry(LootStoreItem* item); // Rolls for every item in the template and adds the rolled items the the loot void Process(Loot& loot, bool rate, uint16 lootMode, uint8 groupId = 0) const; void CopyConditions(ConditionList conditions); @@ -241,6 +245,10 @@ class LootTemplate private: LootStoreItemList Entries; // not grouped only LootGroups Groups; // groups have own (optimised) processing, grouped entries go there + + // Objects of this class must never be copied, we are storing pointers in container + LootTemplate(LootTemplate const&); + LootTemplate& operator=(LootTemplate const&); }; //===================================================== diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 89ed223545f..6229a30a5f0 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -612,7 +612,7 @@ SpellValue const* SpellScript::GetSpellValue() bool AuraScript::_Validate(SpellInfo const* entry) { for (std::list<CheckAreaTargetHandler>::iterator itr = DoCheckAreaTarget.begin(); itr != DoCheckAreaTarget.end(); ++itr) - if (!entry->HasAreaAuraEffect()) + if (!entry->HasAreaAuraEffect() && !entry->HasEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA)) sLog->outError(LOG_FILTER_TSCR, "Spell `%u` of script `%s` does not have area aura effect - handler bound to hook `DoCheckAreaTarget` of AuraScript won't be executed", entry->Id, m_scriptName->c_str()); for (std::list<AuraDispelHandler>::iterator itr = OnDispel.begin(); itr != OnDispel.end(); ++itr) diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e72910aab76..38637cdde29 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2993,9 +2993,6 @@ void World::ResetMonthlyQuests() time_t nextMonthResetTime = mktime(&localTm); - // last reset time before current moment - time_t resetTime = (curTime < nextMonthResetTime) ? nextMonthResetTime - MONTH : nextMonthResetTime; - // plan next reset time m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp index 0aeba151385..fa1ab5528ca 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_broodlord_lashlayer.cpp @@ -101,10 +101,13 @@ public: if (KnockBack_Timer <= diff) { - DoCast(me->getVictim(), SPELL_KNOCKBACK); - //Drop 50% aggro - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -50); + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_KNOCKBACK); + // Drop 50% aggro + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -50); + } KnockBack_Timer = urand(15000, 30000); } else KnockBack_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp index 7ca74f4ed4f..4c36d78667b 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_firemaw.cpp @@ -68,24 +68,26 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 18000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; //FlameBuffet_Timer if (FlameBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_FLAMEBUFFET); + DoCastVictim(SPELL_FLAMEBUFFET); FlameBuffet_Timer = 5000; } else FlameBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp index a1659330a6f..57215e3f43d 100644 --- a/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp +++ b/src/server/scripts/EasternKingdoms/BlackwingLair/boss_flamegor.cpp @@ -76,17 +76,19 @@ public: //ShadowFlame_Timer if (ShadowFlame_Timer <= diff) { - DoCast(me->getVictim(), SPELL_SHADOWFLAME); + DoCastVictim(SPELL_SHADOWFLAME); ShadowFlame_Timer = urand(15000, 22000); } else ShadowFlame_Timer -= diff; //WingBuffet_Timer if (WingBuffet_Timer <= diff) { - DoCast(me->getVictim(), SPELL_WINGBUFFET); - if (DoGetThreat(me->getVictim())) - DoModifyThreatPercent(me->getVictim(), -75); - + if (Unit* target = me->getVictim()) + { + DoCast(target, SPELL_WINGBUFFET); + if (DoGetThreat(target)) + DoModifyThreatPercent(target, -75); + } WingBuffet_Timer = 25000; } else WingBuffet_Timer -= diff; diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp index a8755c16418..742c80bea39 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kalecgos.cpp @@ -780,8 +780,9 @@ public: if (AgonyCurseTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!target) target = me->getVictim(); + Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); + if (!target) + target = me->getVictim(); DoCast(target, SPELL_AGONY_CURSE); AgonyCurseTimer = 20000; } else AgonyCurseTimer -= diff; diff --git a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp index 1b2512ccf63..f1cb7b4116a 100644 --- a/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp +++ b/src/server/scripts/EasternKingdoms/ZulAman/boss_akilzon.cpp @@ -201,8 +201,11 @@ class boss_akilzon : public CreatureScript //dealdamege for (std::list<Unit*>::const_iterator i = tempUnitMap.begin(); i != tempUnitMap.end(); ++i) { - if (!Cloud->IsWithinDist(*i, 6, false)) - Cloud->CastCustomSpell(*i, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + if (Unit* target = (*i)) + { + if (!Cloud->IsWithinDist(target, 6, false)) + Cloud->CastCustomSpell(target, 43137, &bp0, NULL, NULL, true, 0, 0, me->GetGUID()); + } } // visual float x, y, z; diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp index 36f6f94b324..2eb1b65fefd 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/BattleForMountHyjal/hyjal_trash.cpp @@ -1369,8 +1369,7 @@ public: forcemove = false; if (forcemove) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) me->Attack(target, false); } if (MoveTimer <= diff) diff --git a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp index ea372621026..7ac8d4e783b 100644 --- a/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp +++ b/src/server/scripts/Kalimdor/CavernsOfTime/DarkPortal/boss_chrono_lord_deja.cpp @@ -124,8 +124,8 @@ public: //Arcane Discharge if (ArcaneDischarge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - DoCast(target, SPELL_ARCANE_DISCHARGE); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + DoCast(target, SPELL_ARCANE_DISCHARGE); ArcaneDischarge_Timer = 20000+rand()%10000; } else ArcaneDischarge_Timer -= diff; diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp index 2a9ea4ba4fc..a16e9cfa89d 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_bug_trio.cpp @@ -274,10 +274,11 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000); - if (Summoned && target) - Summoned->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (Creature* Summoned = me->SummonCreature(15621, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ(), 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 90000)) + Summoned->AI()->AttackStart(target); + } } } diff --git a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp index 80fdc111911..52d59efd0df 100644 --- a/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp +++ b/src/server/scripts/Kalimdor/TempleOfAhnQiraj/boss_fankriss.cpp @@ -137,9 +137,7 @@ public: { if (SpawnHatchlings_Timer <= diff) { - Unit* target = NULL; - target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->GetTypeId() == TYPEID_PLAYER) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) { DoCast(target, SPELL_ROOT); diff --git a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp index 1139122f73b..52887928d0a 100644 --- a/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp +++ b/src/server/scripts/Kalimdor/zone_thunder_bluff.cpp @@ -81,8 +81,7 @@ public: if (BerserkerChargeTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_BERSERKER_CHARGE); BerserkerChargeTimer = 25000; } else BerserkerChargeTimer -= diff; diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp index 4dca8b43b7b..ad81f6ef6c1 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_lord_marrowgar.cpp @@ -143,7 +143,7 @@ class boss_lord_marrowgar : public CreatureScript me->RemoveAurasDueToSpell(SPELL_BONE_STORM); me->RemoveAurasDueToSpell(SPELL_BERSERK); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); - events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(10000, 15000), EVENT_GROUP_SPECIAL); + events.ScheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_COLDFLAME, 5000, EVENT_GROUP_SPECIAL); events.ScheduleEvent(EVENT_WARN_BONE_STORM, urand(45000, 50000)); events.ScheduleEvent(EVENT_ENRAGE, 600000); @@ -240,7 +240,7 @@ class boss_lord_marrowgar : public CreatureScript if (!unit) unit = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true); if (unit) - me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ()); + me->GetMotionMaster()->MovePoint(POINT_TARGET_BONESTORM_PLAYER, *unit); break; } case EVENT_BONE_STORM_END: @@ -251,7 +251,7 @@ class boss_lord_marrowgar : public CreatureScript events.CancelEvent(EVENT_BONE_STORM_MOVE); events.ScheduleEvent(EVENT_ENABLE_BONE_SLICE, 10000); if (!IsHeroic()) - events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, urand(15000, 20000), EVENT_GROUP_SPECIAL); + events.RescheduleEvent(EVENT_BONE_SPIKE_GRAVEYARD, 15000, EVENT_GROUP_SPECIAL); break; case EVENT_ENABLE_BONE_SLICE: _boneSlice = true; @@ -364,18 +364,17 @@ class npc_coldflame : public CreatureScript if (owner->GetTypeId() != TYPEID_UNIT) return; - Creature* creOwner = owner->ToCreature(); Position pos; - // random target case + if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, owner->GetAI())) + pos.Relocate(marrowgarAI->GetLastColdflamePosition()); + else + pos.Relocate(owner); + if (owner->HasAura(SPELL_BONE_STORM)) { - if (MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, creOwner->AI())) - { - Position const* ownerPos = marrowgarAI->GetLastColdflamePosition(); - float ang = me->GetAngle(ownerPos) - static_cast<float>(M_PI); - me->SetOrientation(ang); - owner->GetNearPosition(pos, 2.5f, 0.0f); - } + float ang = Position::NormalizeOrientation(pos.GetAngle(me)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 5.0f - owner->GetObjectSize(), ang); } else { @@ -386,11 +385,13 @@ class npc_coldflame : public CreatureScript return; } - me->SetOrientation(owner->GetAngle(target)); - owner->GetNearPosition(pos, owner->GetObjectSize() / 2.0f, 0.0f); + float ang = Position::NormalizeOrientation(pos.GetAngle(target)); + me->SetOrientation(ang); + owner->GetNearPoint2D(pos.m_positionX, pos.m_positionY, 15.0f - owner->GetObjectSize(), ang); } me->NearTeleportTo(pos.GetPositionX(), pos.GetPositionY(), me->GetPositionZ(), me->GetOrientation()); + DoCast(SPELL_COLDFLAME_SUMMON); _events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 500); } @@ -711,16 +712,18 @@ class spell_marrowgar_bone_slice : public SpellScriptLoader GetCaster()->GetAI()->DoAction(ACTION_CLEAR_SPIKE_IMMUNITIES); } - void CountTarget(SpellEffIndex /*effIndex*/) + void CountTargets(std::list<WorldObject*>& targets) { - ++_targetCount; - GetCaster()->GetAI()->SetGUID(GetHitUnit()->GetGUID(), DATA_SPIKE_IMMUNE); + _targetCount = std::min<uint32>(targets.size(), GetSpellInfo()->MaxAffectedTargets); } void SplitDamage() { + // Mark the unit as hit, even if the spell missed or was dodged/parried + GetCaster()->GetAI()->SetGUID(GetHitUnit()->GetGUID(), DATA_SPIKE_IMMUNE); + if (!_targetCount) - return; // why would there be an unit not hit by effect hook and hit by this? + return; // This spell can miss all targets SetHitDamage(GetHitDamage() / _targetCount); } @@ -728,7 +731,7 @@ class spell_marrowgar_bone_slice : public SpellScriptLoader void Register() { BeforeCast += SpellCastFn(spell_marrowgar_bone_slice_SpellScript::ClearSpikeImmunities); - OnEffectLaunchTarget += SpellEffectFn(spell_marrowgar_bone_slice_SpellScript::CountTarget, EFFECT_0, SPELL_EFFECT_WEAPON_PERCENT_DAMAGE); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_marrowgar_bone_slice_SpellScript::CountTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); OnHit += SpellHitFn(spell_marrowgar_bone_slice_SpellScript::SplitDamage); } diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp index 6f017884063..dc0ffcd2c63 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfLightning/boss_ionar.cpp @@ -198,8 +198,7 @@ public: summoned->CastSpell(summoned, DUNGEON_MODE(SPELL_SPARK_VISUAL_TRIGGER, H_SPELL_SPARK_VISUAL_TRIGGER), true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { summoned->SetInCombatWith(target); summoned->GetMotionMaster()->Clear(); diff --git a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp index 7fbf5f3ee79..8accb3182ce 100644 --- a/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp +++ b/src/server/scripts/Northrend/Ulduar/HallsOfStone/boss_maiden_of_grief.cpp @@ -117,9 +117,7 @@ public: { if (PartingSorrowTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_PARTING_SORROW); PartingSorrowTimer = urand(30000, 40000); diff --git a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp index 3a56a0bfed2..53d51e1fd6c 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_bloodboil.cpp @@ -187,9 +187,7 @@ public: void RevertThreatOnTarget(uint64 guid) { - Unit* unit = NULL; - unit = Unit::GetUnit(*me, guid); - if (unit) + if (Unit* unit = Unit::GetUnit(*me, guid)) { if (DoGetThreat(unit)) DoModifyThreatPercent(unit, -100); @@ -279,8 +277,7 @@ public: { if (Phase1) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { Phase1 = false; @@ -308,7 +305,8 @@ public: AcidGeyserTimer = 1000; PhaseChangeTimer = 30000; } - } else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage + } + else // Encounter is a loop pretty much. Phase 1 -> Phase 2 -> Phase 1 -> Phase 2 till death or enrage { if (TargetGUID) RevertThreatOnTarget(TargetGUID); diff --git a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp index b8003761cc7..a91d25fa984 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_illidan.cpp @@ -422,8 +422,7 @@ public: Glaive->InterruptNonMeleeSpells(true); DoCast(me, SPELL_FLAME_ENRAGE, true); DoResetThreat(); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (SelectTarget(SELECT_TARGET_RANDOM, 0)) { me->AddThreat(me->getVictim(), 5000000.0f); AttackStart(me->getVictim()); diff --git a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp index 6c28b058cf7..2dc0517dc49 100644 --- a/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp +++ b/src/server/scripts/Outland/BlackTemple/boss_teron_gorefiend.cpp @@ -468,8 +468,7 @@ public: if (CrushingShadowsTimer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target && target->isAlive()) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_CRUSHING_SHADOWS); CrushingShadowsTimer = urand(10, 26) * 1000; } else CrushingShadowsTimer -= diff; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp index d9ad35f9552..5037f1c4964 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_fathomlord_karathress.cpp @@ -227,9 +227,7 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) { AttackStart(target); GetAdvisors(); @@ -360,12 +358,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); + if (Creature* Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS)))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventSharkkisDeath(); } } @@ -383,12 +377,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -445,12 +435,13 @@ public: pet_id = CREATURE_FATHOM_SPOREBAT; } //DoCast(me, spell_id, true); - Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (Pet && target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { - Pet->AI()->AttackStart(target); - SummonedPet = Pet->GetGUID(); + if (Creature* Pet = DoSpawnCreature(pet_id, 0, 0, 0, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 15000)) + { + Pet->AI()->AttackStart(target); + SummonedPet = Pet->GetGUID(); + } } } else Pet_Timer -= diff; @@ -500,12 +491,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventTidalvessDeath(); } } @@ -524,12 +511,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -627,12 +610,8 @@ public: { if (instance) { - Creature* Karathress = NULL; - Karathress = (Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))); - - if (Karathress) - if (!me->isAlive() && Karathress) - CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); + if (Creature* Karathress = Unit::GetCreature((*me), instance->GetData64(DATA_KARATHRESS))) + CAST_AI(boss_fathomlord_karathress::boss_fathomlord_karathressAI, Karathress->AI())->EventCaribdisDeath(); } } @@ -650,12 +629,8 @@ public: //Only if not incombat check if the event is started if (!me->isInCombat() && instance && instance->GetData(DATA_KARATHRESSEVENT)) { - Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER)); - - if (target) - { + if (Unit* target = Unit::GetUnit(*me, instance->GetData64(DATA_KARATHRESSEVENT_STARTER))) AttackStart(target); - } } //Return since we have no target @@ -697,11 +672,8 @@ public: Cyclone->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); Cyclone->setFaction(me->getFaction()); Cyclone->CastSpell(Cyclone, SPELL_CYCLONE_CYCLONE, true); - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) - { + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) Cyclone->AI()->AttackStart(target); - } } } else Cyclone_Timer -= diff; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp index b31292c4b00..ec85fe7293d 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_hydross_the_unstable.cpp @@ -272,8 +272,7 @@ public: //VileSludge_Timer if (VileSludge_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_VILE_SLUDGE); VileSludge_Timer = 15000; diff --git a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp index 9476bb28f8e..06ea83881c8 100644 --- a/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp +++ b/src/server/scripts/Outland/CoilfangReservoir/SerpentShrine/boss_morogrim_tidewalker.cpp @@ -184,10 +184,9 @@ public: for (uint8 i = 0; i < 10; ++i) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000); - if (target && Murloc) - Murloc->AI()->AttackStart(target); + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + if (Creature* Murloc = me->SummonCreature(NPC_TIDEWALKER_LURKER, MurlocCords[i][0], MurlocCords[i][1], MurlocCords[i][2], MurlocCords[i][3], TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 10000)) + Murloc->AI()->AttackStart(target); } Talk(EMOTE_EARTHQUAKE); Earthquake = false; diff --git a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp index 83596c46936..e2b2425dcfc 100644 --- a/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp +++ b/src/server/scripts/Outland/GruulsLair/boss_high_king_maulgar.cpp @@ -519,8 +519,7 @@ public: //GreaterPolymorph_Timer if (GreaterPolymorph_Timer <= diff) { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) DoCast(target, SPELL_GREATER_POLYMORPH); GreaterPolymorph_Timer = urand(15000, 20000); diff --git a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp index 01ca1636c6b..9ec6691839b 100644 --- a/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp +++ b/src/server/scripts/Outland/TempestKeep/Eye/boss_astromancer.cpp @@ -245,11 +245,13 @@ class boss_high_astromancer_solarian : public CreatureScript } else { - Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0); - if (!me->HasInArc(2.5f, target)) - target = me->getVictim(); - if (target) + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) + { + if (!me->HasInArc(2.5f, target)) + target = me->getVictim(); + DoCast(target, SPELL_ARCANE_MISSILES); + } } ArcaneMissiles_Timer = 3000; } |