diff options
| author | Shauren <shauren.trinity@gmail.com> | 2011-02-22 21:51:38 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2011-02-22 21:51:38 +0100 |
| commit | a8f9936bea6d114de585ab393020c0324c075c8b (patch) | |
| tree | 8e77e86f1835f74730592211e4f1f27621e50aa8 /src | |
| parent | a267e3ade7516a9e73b308af198e8b080af32888 (diff) | |
| parent | bde5adf9bdf77b94757d87aed6f4ba2107f88860 (diff) | |
Merge branch 'master' of github.com:TrinityCore/TrinityCore
Diffstat (limited to 'src')
21 files changed, 631 insertions, 292 deletions
diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index ac142db923d..115f65311b9 100755 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -122,7 +122,7 @@ void PetAI::UpdateAI(const uint32 diff) return; // Autocast (casted only in combat or persistent spells in any state) - if (me->GetGlobalCooldown() == 0 && !me->HasUnitState(UNIT_STAT_CASTING)) + if (!me->HasUnitState(UNIT_STAT_CASTING)) { typedef std::vector<std::pair<Unit*, Spell*> > TargetSpellList; TargetSpellList targetSpellStore; @@ -137,6 +137,9 @@ void PetAI::UpdateAI(const uint32 diff) if (!spellInfo) continue; + if (me->GetCharmInfo() && me->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) + continue; + // ignore some combinations of combat state and combat/noncombat spells if (!me->getVictim()) { diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 422096b3798..cc8bdc00d12 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -793,7 +793,7 @@ void SmartAI::SetFollow(Unit* target, float dist, float angle, uint32 credit, ui void SmartAI::SetScript9(SmartScriptHolder &e, uint32 entry, Unit* invoker) { if (invoker) - GetScript()->mLastInvoker = invoker; + GetScript()->mLastInvoker = invoker->GetGUID(); GetScript()->SetScript9(e, entry); } /* @@ -894,7 +894,7 @@ void SmartGameObjectAI::SetData(uint32 id, uint32 value) void SmartGameObjectAI::SetScript9(SmartScriptHolder &e, uint32 entry, Unit* invoker) { if (invoker) - GetScript()->mLastInvoker = invoker; + GetScript()->mLastInvoker = invoker->GetGUID(); GetScript()->SetScript9(e, entry); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index f9371979a77..4abf17049b2 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -109,7 +109,7 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u e.runOnce = true;//used for repeat check if (unit) - mLastInvoker = unit; + mLastInvoker = unit->GetGUID(); if (e.link && e.link != e.event_id) { @@ -120,6 +120,9 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u sLog->outErrorDb("SmartScript::ProcessAction: Entry %d SourceType %u, Event %u, Link Event %u not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); } + if (Unit* tempInvoker = GetLastInvoker()) + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: Invoker: %s (guidlow: %u)", tempInvoker->GetName(), tempInvoker->GetGUIDLow()); + switch (e.GetActionType()) { case SMART_ACTION_TALK: @@ -139,9 +142,13 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u } mLastTextID = e.action.talk.textGroupID; mTextTimer = e.action.talk.duration; - mTextGUID = IsPlayer(mLastInvoker)? mLastInvoker->GetGUID() : NULL;//invoker, used for $vars in texts + mTextGUID = IsPlayer(GetLastInvoker())? GetLastInvoker()->GetGUID() : NULL;//invoker, used for $vars in texts mUseTextTimer = true; sCreatureTextMgr->SendChat(talker, uint8(e.action.talk.textGroupID), mTextGUID); + + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_TALK: talker: %s (GuidLow: %u), textGuid: %u", + talker->GetName(), talker->GetGUIDLow(), mTextGUID); + break; } case SMART_ACTION_SIMPLE_TALK: @@ -152,12 +159,14 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { if (IsCreature((*itr))) + sCreatureTextMgr->SendChat((*itr)->ToCreature(), uint8(e.action.talk.textGroupID), IsPlayer(GetLastInvoker())? GetLastInvoker()->GetGUID() : NULL); + else if (IsPlayer((*itr))) { - sCreatureTextMgr->SendChat((*itr)->ToCreature(), uint8(e.action.talk.textGroupID), IsPlayer(mLastInvoker)? mLastInvoker->GetGUID() : NULL); - } else if (IsPlayer((*itr))) - { - sCreatureTextMgr->SendChat(me, uint8(e.action.talk.textGroupID),IsPlayer(mLastInvoker)? mLastInvoker->GetGUID() : NULL,CHAT_TYPE_END,LANG_ADDON,TEXT_RANGE_NORMAL,NULL,TEAM_OTHER,false, (*itr)->ToPlayer()); + Unit* templastInvoker = GetLastInvoker(); + sCreatureTextMgr->SendChat(me, uint8(e.action.talk.textGroupID),IsPlayer(templastInvoker)? templastInvoker->GetGUID() : NULL,CHAT_TYPE_END,LANG_ADDON,TEXT_RANGE_NORMAL,NULL,TEAM_OTHER,false, (*itr)->ToPlayer()); } + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SIMPLE_TALK: talker: %s (GuidLow: %u), textGroupId: %u", + (*itr)->GetName(), (*itr)->GetGUIDLow(), uint8(e.action.talk.textGroupID)); } } break; @@ -168,7 +177,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (targets) for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) + { (*itr)->ToUnit()->HandleEmoteCommand(e.action.emote.emote); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_PLAY_EMOTE: target: %s (GuidLow: %u), emote: %u", + (*itr)->GetName(), (*itr)->GetGUIDLow(), e.action.emote.emote); + } break; } case SMART_ACTION_SOUND: @@ -177,7 +190,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (targets) for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsCreature((*itr))) + { sCreatureTextMgr->SendSound((*itr)->ToCreature(), e.action.sound.sound, CHAT_TYPE_SAY, 0, TextRange(e.action.sound.range), Team(NULL), false); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SOUND: source: %s (GuidLow: %u), sound: %u, range: %u", + (*itr)->GetName(), (*itr)->GetGUIDLow(), e.action.sound.sound, e.action.sound.range); + } break; } case SMART_ACTION_SET_FACTION: @@ -190,13 +207,21 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (IsCreature((*itr))) { if (e.action.faction.factionID) + { (*itr)->ToCreature()->setFaction(e.action.faction.factionID); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, GuidLow %u set faction to %u", + (*itr)->GetEntry(), (*itr)->GetGUIDLow(), e.action.faction.factionID); + } else { if (CreatureInfo const* ci = GetCreatureTemplateStore((*itr)->ToCreature()->GetEntry())) { if ((*itr)->ToCreature()->getFaction() != ci->faction_A) + { (*itr)->ToCreature()->setFaction(ci->faction_A); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_FACTION: Creature entry %u, GuidLow %u set faction to %u", + (*itr)->GetEntry(), (*itr)->GetGUIDLow(), ci->faction_A); + } } } } @@ -222,14 +247,24 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u { uint32 display_id = sObjectMgr->ChooseDisplayId(0, ci); (*itr)->ToCreature()->SetDisplayId(display_id); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, GuidLow %u set displayid to %u", + (*itr)->GetEntry(), (*itr)->GetGUIDLow(), display_id); } } //if no param1, then use value from param2 (modelId) else + { (*itr)->ToCreature()->SetDisplayId(e.action.morphOrMount.model); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, GuidLow %u set displayid to %u", + (*itr)->GetEntry(), (*itr)->GetGUIDLow(), e.action.morphOrMount.model); + } } else + { (*itr)->ToCreature()->DeMorph(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_MORPH_TO_ENTRY_OR_MODEL: Creature entry %u, GuidLow %u demorphs.", + (*itr)->GetEntry(), (*itr)->GetGUIDLow()); + } } break; } @@ -240,7 +275,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { if (IsPlayer((*itr))) + { (*itr)->ToPlayer()->FailQuest(e.action.quest.quest); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_FAIL_QUEST: Player guidLow %u fails quest %u", + (*itr)->GetGUIDLow(), e.action.quest.quest); + } } break; } @@ -252,14 +291,23 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u { if (IsPlayer((*itr))) if (const Quest* q = sObjectMgr->GetQuestTemplate(e.action.quest.quest)) + { (*itr)->ToPlayer()->AddQuest(q, NULL); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ADD_QUEST: Player guidLow %u add quest %u", + (*itr)->GetGUIDLow(), e.action.quest.quest); + } } break; } case SMART_ACTION_SET_REACT_STATE: { - if (!me) return; + if (!me) + return; + me->SetReactState(ReactStates(e.action.react.state)); + + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_REACT_STATE: Creature guidLow %u set reactstate %u", + me->GetGUIDLow(), e.action.react.state); break; } case SMART_ACTION_RANDOM_EMOTE: @@ -285,26 +333,43 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u } for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) - (*itr)->ToUnit()->HandleEmoteCommand(temp[urand(0, count)]); + { + uint32 emote = temp[urand(0, count)]; + (*itr)->ToUnit()->HandleEmoteCommand(emote); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_RANDOM_EMOTE: Creature guidLow %u handle random emote %u", + (*itr)->GetGUIDLow(), emote); + } break; } case SMART_ACTION_THREAT_ALL_PCT: { - if (!me) return; + if (!me) + return; + std::list<HostileReference*>& threatList = me->getThreatManager().getThreatList(); for (std::list<HostileReference*>::iterator i = threatList.begin(); i != threatList.end(); ++i) if (Unit* Temp = Unit::GetUnit(*me,(*i)->getUnitGuid())) + { me->getThreatManager().modifyThreatPercent(Temp, e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_THREAT_ALL_PCT: Creature guidLow %u modify threat for unit %u, value %i", + me->GetGUIDLow(), Temp->GetGUIDLow(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + } break; } case SMART_ACTION_THREAT_SINGLE_PCT: { - if (!me) return; + if (!me) + return; + ObjectList* targets = GetTargets(e, unit); if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) + { me->getThreatManager().modifyThreatPercent((*itr)->ToUnit(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_THREAT_SINGLE_PCT: Creature guidLow %u modify threat for unit %u, value %i", + me->GetGUIDLow(), (*itr)->GetGUIDLow(), e.action.threatPCT.threatINC ? (int32)e.action.threatPCT.threatINC : -(int32)e.action.threatPCT.threatDEC); + } break; } case SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: @@ -314,7 +379,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsPlayer((*itr))) + { (*itr)->ToPlayer()->AreaExploredOrEventHappens(e.action.quest.quest); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_CALL_AREAEXPLOREDOREVENTHAPPENS: Player guidLow %u credited quest %u", + (*itr)->GetGUIDLow(), e.action.quest.quest); + } break; } case SMART_ACTION_SEND_CASTCREATUREORGO: @@ -324,12 +393,18 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsPlayer((*itr))) + { (*itr)->ToPlayer()->CastedCreatureOrGO(e.action.castedCreatureOrGO.creature, GetBaseObject()->GetGUID(), e.action.castedCreatureOrGO.spell); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SEND_CASTCREATUREORGO: Player guidLow %u.org Creature: %u, BaseObject GUID: "UI64FMTD" , Spell: %u", + e.action.castedCreatureOrGO.creature, GetBaseObject()->GetGUID(), e.action.castedCreatureOrGO.spell); + } break; } case SMART_ACTION_CAST: { - if (!me) return; + if (!me) + return; + ObjectList* targets = GetTargets(e, unit); if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) @@ -337,45 +412,61 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u { if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) me->InterruptNonMeleeSpells(false); + me->CastSpell((*itr)->ToUnit(), e.action.cast.spell,(e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_CAST:: Creature %u casts spell % on target %u with castflags %u", + me->GetGUIDLow(), (*itr)->GetGUIDLow(), e.action.cast.spell, e.action.cast.flags); } break; } case SMART_ACTION_INVOKER_CAST: { - if (!mLastInvoker) return; + Unit* tempLastInvoker = GetLastInvoker(); + if (!tempLastInvoker) + return; ObjectList* targets = GetTargets(e, unit); if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) { if (e.action.cast.flags & SMARTCAST_INTERRUPT_PREVIOUS) - mLastInvoker->InterruptNonMeleeSpells(false); - mLastInvoker->CastSpell((*itr)->ToUnit(), e.action.cast.spell,(e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false); + tempLastInvoker->InterruptNonMeleeSpells(false); + + tempLastInvoker->CastSpell((*itr)->ToUnit(), e.action.cast.spell,(e.action.cast.flags & SMARTCAST_TRIGGERED) ? true : false); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_INVOKER_CAST: Invoker %u casts spell % on target %u with castflags %u", + tempLastInvoker->GetGUIDLow(), (*itr)->GetGUIDLow(), e.action.cast.spell, e.action.cast.flags); } break; } case SMART_ACTION_ADD_AURA: { ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) { (*itr)->ToUnit()->AddAura(e.action.cast.spell, (*itr)->ToUnit()); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ADD_AURA: Adding aura %u to unit %u", + e.action.cast.spell, (*itr)->GetGUIDLow()); } break; } case SMART_ACTION_ACTIVATE_GOBJECT: { ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsGameObject((*itr))) { // Activate (*itr)->ToGameObject()->SetLootState(GO_READY); (*itr)->ToGameObject()->UseDoorOrButton(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ACTIVATE_GOBJECT. Gameobject %u (entry: %u) activated", + (*itr)->GetGUIDLow(), (*itr)->GetEntry()); } break; } @@ -385,7 +476,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsGameObject((*itr))) + { (*itr)->ToGameObject()->ResetDoorOrButton(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_RESET_GOBJECT. Gameobject %u (entry: %u) reset", + (*itr)->GetGUIDLow(), (*itr)->GetEntry()); + } break; } case SMART_ACTION_SET_EMOTE_STATE: @@ -394,7 +489,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) + { (*itr)->ToUnit()->SetUInt32Value(UNIT_NPC_EMOTESTATE, e.action.emote.emote); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_EMOTE_STATE. Unit %u set emotestate to %u", + (*itr)->GetGUIDLow(), e.action.emote.emote); + } break; } case SMART_ACTION_SET_UNIT_FLAG: @@ -403,7 +502,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) + { (*itr)->ToUnit()->SetFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_UNIT_FLAG. Unit %u added flag %u to UNIT_FIELD_FLAGS", + (*itr)->GetGUIDLow(), e.action.unitFlag.flag); + } break; } case SMART_ACTION_REMOVE_UNIT_FLAG: @@ -412,82 +515,131 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (!targets) return; for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) if (IsUnit((*itr))) + { (*itr)->ToUnit()->RemoveFlag(UNIT_FIELD_FLAGS, e.action.unitFlag.flag); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_REMOVE_UNIT_FLAG. Unit %u removed flag %u to UNIT_FIELD_FLAGS", + (*itr)->GetGUIDLow(), e.action.unitFlag.flag); + } break; } case SMART_ACTION_AUTO_ATTACK: { - if (!IsSmart()) return; + if (!IsSmart()) + return; + CAST_AI(SmartAI, me->AI())->SetAutoAttack(e.action.autoAttack.attack ? true : false); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_AUTO_ATTACK: Creature: %u bool on = %u", + me->GetGUIDLow(), e.action.autoAttack.attack); break; } case SMART_ACTION_ALLOW_COMBAT_MOVEMENT: { - if (!IsSmart()) return; + if (!IsSmart()) + return; + bool move = e.action.combatMove.move ? true : false; CAST_AI(SmartAI, me->AI())->SetCombatMove(move); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_ALLOW_COMBAT_MOVEMENT: Creature %u bool on = %u", + me->GetGUIDLow(), e.action.combatMove.move); break; } case SMART_ACTION_SET_EVENT_PHASE: { SetPhase(e.action.setEventPhase.phase); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_SET_EVENT_PHASE: Creature %u set event phase %u", + me->GetGUIDLow(), e.action.setEventPhase.phase); break; } case SMART_ACTION_INC_EVENT_PHASE: { IncPhase(e.action.incEventPhase.inc); DecPhase(e.action.incEventPhase.dec); + + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_INC_EVENT_PHASE: Creature %u inc event phase by %u, " + "decrease by %u", me->GetGUIDLow(), e.action.incEventPhase.inc, e.action.incEventPhase.dec); break; } case SMART_ACTION_EVADE: { - if (me) me->AI()->EnterEvadeMode(); + if (!me) + return; + + me->AI()->EnterEvadeMode(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_EVADE: Creature %u EnterEvadeMode", me->GetGUIDLow()); return; } case SMART_ACTION_FLEE_FOR_ASSIST: { - if (me) me->DoFleeToGetAssistance(); + if (!me) + return; + + me->DoFleeToGetAssistance(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction:: SMART_ACTION_FLEE_FOR_ASSIST: Creature %u DoFleeToGetAssistance", me->GetGUIDLow()); break; } case SMART_ACTION_CALL_GROUPEVENTHAPPENS: { if (IsPlayer(unit) && GetBaseObject()) + { unit->ToPlayer()->GroupEventHappens(e.action.quest.quest, GetBaseObject()); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_CALL_GROUPEVENTHAPPENS: Player %u, group credit for quest %u", + unit->GetGUIDLow(), e.action.quest.quest); + } break; } case SMART_ACTION_CALL_CASTEDCREATUREORGO: { - if (!GetBaseObject()) return; + if (!GetBaseObject()) + return; + ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { if (IsPlayer((*itr))) + { (*itr)->ToPlayer()->CastedCreatureOrGO(e.action.castedCreatureOrGO.creature, GetBaseObject()->GetGUID(), e.action.castedCreatureOrGO.spell); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_CALL_CASTEDCREATUREORGO: Player %u, target %u, spell %u", + (*itr)->GetGUIDLow(), e.action.castedCreatureOrGO.creature, e.action.castedCreatureOrGO.spell); + } } break; } case SMART_ACTION_REMOVEAURASFROMSPELL: { ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { - if(!IsUnit((*itr))) continue; + if (!IsUnit((*itr))) + continue; + (*itr)->ToUnit()->RemoveAurasDueToSpell(e.action.removeAura.spell); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_REMOVEAURASFROMSPELL: Unit %u, spell %u", + (*itr)->GetGUIDLow(), e.action.removeAura.spell); } break; } case SMART_ACTION_FOLLOW: { - if (!IsSmart()) return; + if (!IsSmart()) + return; + ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { if (IsUnit((*itr))) { CAST_AI(SmartAI, me->AI())->SetFollow((*itr)->ToUnit(), (float)e.action.follow.dist, (float)e.action.follow.angle, e.action.follow.credit, e.action.follow.entry, e.action.follow.creditType); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_FOLLOW: Creature %u following target %u", + me->GetGUIDLow(), (*itr)->GetGUIDLow()); return; } } @@ -496,12 +648,12 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u case SMART_ACTION_RANDOM_PHASE: { uint32 phases[SMART_ACTION_PARAM_COUNT]; - phases[0] = e.action.randomEmote.emote1; - phases[1] = e.action.randomEmote.emote2; - phases[2] = e.action.randomEmote.emote3; - phases[3] = e.action.randomEmote.emote4; - phases[4] = e.action.randomEmote.emote5; - phases[5] = e.action.randomEmote.emote6; + phases[0] = e.action.randomPhase.phase1; + phases[1] = e.action.randomPhase.phase2; + phases[2] = e.action.randomPhase.phase3; + phases[3] = e.action.randomPhase.phase4; + phases[4] = e.action.randomPhase.phase5; + phases[5] = e.action.randomPhase.phase6; uint32 temp[SMART_ACTION_PARAM_COUNT]; uint32 count = 0; for (uint8 i = 0; i < SMART_ACTION_PARAM_COUNT; i++) @@ -512,12 +664,19 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u count++; } } - SetPhase(temp[urand(0, count)]); + + uint32 phase = temp[urand(0, count)]; + SetPhase(phase); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE: Creature %u sets event phase to %u", + me->GetGUIDLow(), phase); break; } case SMART_ACTION_RANDOM_PHASE_RANGE: { - SetPhase(urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax)); + uint32 phase = urand(e.action.randomPhaseRange.phaseMin, e.action.randomPhaseRange.phaseMax); + SetPhase(phase); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_RANDOM_PHASE_RANGE: Creature %u sets event phase to %u", + me->GetGUIDLow(), phase); break; } case SMART_ACTION_CALL_KILLEDMONSTER: @@ -525,20 +684,31 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u Player* pPlayer = NULL; if (me) pPlayer = me->GetLootRecipient(); + if (me && pPlayer) pPlayer->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, pPlayer); + else if (GetBaseObject()) { ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { - if(!IsPlayer((*itr))) continue; + if (!IsPlayer((*itr))) + continue; + (*itr)->ToPlayer()->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, (*itr)->ToPlayer()); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: Player %u, Killcredit: %u", + (*itr)->GetGUIDLow(), e.action.killedMonster.creature); } - }else if (trigger && IsPlayer(unit)) + } + else if (trigger && IsPlayer(unit)) { unit->ToPlayer()->RewardPlayerAndGroupAtEvent(e.action.killedMonster.creature, unit); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_CALL_KILLEDMONSTER: (trigger == true) Player %u, Killcredit: %u", + unit->GetGUIDLow(), e.action.killedMonster.creature); } break; } @@ -547,15 +717,20 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u WorldObject* obj = GetBaseObject(); if (!obj) obj = unit; + if (!obj) return; + InstanceScript* pInst = (InstanceScript*)obj->GetInstanceScript(); if (!pInst) { sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid); return; } + pInst->SetData(e.action.setInstanceData.field, e.action.setInstanceData.data); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA: Field: %u, data: %u", + e.action.setInstanceData.field, e.action.setInstanceData.data); break; } case SMART_ACTION_SET_INST_DATA64: @@ -563,19 +738,26 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u WorldObject* obj = GetBaseObject(); if (!obj) obj = unit; + if (!obj) return; + InstanceScript* pInst = (InstanceScript*)obj->GetInstanceScript(); if (!pInst) { sLog->outErrorDb("SmartScript: Event %u attempt to set instance data without instance script. EntryOrGuid %d", e.GetEventType(), e.entryOrGuid); return; } + ObjectList* targets = GetTargets(e, unit); - if (!targets) return; + if (!targets) + return; + for (ObjectList::const_iterator itr = targets->begin(); itr != targets->end(); itr++) { pInst->SetData64(e.action.setInstanceData64.field, (*itr)->GetGUID()); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_INST_DATA64: Field: %u, data: "UI64FMTD, + e.action.setInstanceData64.field, (*itr)->GetGUID()); return; } @@ -585,31 +767,47 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u { if (!me || me->GetEntry() == e.action.updateTemplate.creature) return; + me->UpdateEntry(e.action.updateTemplate.creature, e.action.updateTemplate.team ? HORDE : ALLIANCE); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_UPDATE_TEMPLATE: Creature %u, Template: %u, Team: %u", + me->GetGUIDLow(), e.action.updateTemplate.team ? HORDE : ALLIANCE); break; } case SMART_ACTION_DIE: { if (me && !me->isDead()) + { me->Kill(me); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_DIE: Creature %u", me->GetGUIDLow()); + } break; } case SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: { if (me) + { me->SetInCombatWithZone(); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_IN_COMBAT_WITH_ZONE: Creature %u", me->GetGUIDLow()); + } break; } case SMART_ACTION_CALL_FOR_HELP: { if (me) + { me->CallForHelp((float)e.action.callHelp.range); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_CALL_FOR_HELP: Creature %u", me->GetGUIDLow()); + } break; } case SMART_ACTION_SET_SHEATH: { if (me) + { me->SetSheath(SheathState(e.action.setSheath.sheath)); + sLog->outDebug(LOG_FILTER_DATABASE_AI, "SmartScript::ProcessAction: SMART_ACTION_SET_SHEATH: Creature %u, State: %u", + me->GetGUIDLow(), e.action.setSheath.sheath); + } break; } case SMART_ACTION_FORCE_DESPAWN: @@ -1073,11 +1271,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (Creature* target = (*itr)->ToCreature()) { if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, e.action.timedActionList.id, mLastInvoker); + CAST_AI(SmartAI, target->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); } else if (GameObject* target = (*itr)->ToGameObject()) { if (IsSmartGO(target)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, e.action.timedActionList.id, mLastInvoker); + CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, e.action.timedActionList.id, GetLastInvoker()); } } } @@ -1166,11 +1364,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (Creature* target = (*itr)->ToCreature()) { if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, id, mLastInvoker); + CAST_AI(SmartAI, target->AI())->SetScript9(e, id, GetLastInvoker()); } else if (GameObject* target = (*itr)->ToGameObject()) { if (IsSmartGO(target)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, mLastInvoker); + CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, GetLastInvoker()); } } } @@ -1192,11 +1390,11 @@ void SmartScript::ProcessAction(SmartScriptHolder &e, Unit* unit, uint32 var0, u if (Creature* target = (*itr)->ToCreature()) { if (IsSmart(target)) - CAST_AI(SmartAI, target->AI())->SetScript9(e, id, mLastInvoker); + CAST_AI(SmartAI, target->AI())->SetScript9(e, id, GetLastInvoker()); } else if (GameObject* target = (*itr)->ToGameObject()) { if (IsSmartGO(target)) - CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, mLastInvoker); + CAST_AI(SmartGameObjectAI, target->AI())->SetScript9(e, id, GetLastInvoker()); } } } @@ -1374,8 +1572,8 @@ ObjectList* SmartScript::GetTargets(SmartScriptHolder e, Unit* invoker) Unit* trigger = NULL; if (invoker) trigger = invoker; - else if (mLastInvoker) - trigger = mLastInvoker; + else if (Unit* tempLastInvoker = GetLastInvoker()) + trigger = tempLastInvoker; ObjectList* l = new ObjectList(); switch (e.GetTargetType()) { @@ -2376,4 +2574,7 @@ void SmartScript::SetScript9(SmartScriptHolder &e, uint32 entry) mResumeActionList = e.action.timedActionList.dontResume ? false : true; InitTimer((*i)); } +}Unit* SmartScript::GetLastInvoker() +{ + return ObjectAccessor::FindUnit(mLastInvoker); } diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 08ee5570a89..a5331672803 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -191,7 +191,8 @@ class SmartScript //TIMED_ACTIONLIST (script type 9 aka script9) void SetScript9(SmartScriptHolder &e, uint32 entry); - Unit* mLastInvoker; + Unit* GetLastInvoker(); + uint64 mLastInvoker; private: void IncPhase(int32 p = 1) { diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 658846c881c..e0844cdcccd 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1034,7 +1034,6 @@ void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPac if (!group->RemoveMember(guid)) // group was disbanded { SetBgRaid(team, NULL); - delete group; } } DecreaseInvitedCount(team); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 0fd48f47ae6..53370170c9e 100755 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -154,7 +154,6 @@ m_formation(NULL) m_CreatureSpellCooldowns.clear(); m_CreatureCategoryCooldowns.clear(); - m_GlobalCooldown = 0; DisableReputationGain = false; //m_unit_movement_flags = MONSTER_MOVE_WALK; @@ -430,11 +429,6 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data) void Creature::Update(uint32 diff) { - if (m_GlobalCooldown <= diff) - m_GlobalCooldown = 0; - else - m_GlobalCooldown -= diff; - if (IsAIEnabled && TriggerJustRespawned) { TriggerJustRespawned = false; @@ -2185,8 +2179,6 @@ void Creature::AddCreatureSpellCooldown(uint32 spellid) if (spellInfo->Category) _AddCreatureCategoryCooldown(spellInfo->Category, time(NULL)); - - m_GlobalCooldown = spellInfo->StartRecoveryTime; } bool Creature::HasCategoryCooldown(uint32 spell_id) const @@ -2195,10 +2187,6 @@ bool Creature::HasCategoryCooldown(uint32 spell_id) const if (!spellInfo) return false; - // check global cooldown if spell affected by it - if (spellInfo->StartRecoveryCategory > 0 && m_GlobalCooldown > 0) - return true; - CreatureSpellCooldowns::const_iterator itr = m_CreatureCategoryCooldowns.find(spellInfo->Category); return(itr != m_CreatureCategoryCooldowns.end() && time_t(itr->second + (spellInfo->CategoryRecoveryTime / IN_MILLISECONDS)) > time(NULL)); } diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 43ff73df08c..4933428bf4e 100755 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -577,7 +577,6 @@ class Creature : public Unit, public GridObject<Creature> uint32 m_spells[CREATURE_MAX_SPELLS]; CreatureSpellCooldowns m_CreatureSpellCooldowns; CreatureSpellCooldowns m_CreatureCategoryCooldowns; - uint32 m_GlobalCooldown; bool canStartAttack(Unit const* u, bool force) const; float GetAttackDistance(Unit const* pl) const; @@ -646,8 +645,6 @@ class Creature : public Unit, public GridObject<Creature> void GetHomePosition(float &x, float &y, float &z, float &ori) { m_homePosition.GetPosition(x, y, z, ori); } Position GetHomePosition() { return m_homePosition; } - uint32 GetGlobalCooldown() const { return m_GlobalCooldown; } - uint32 GetWaypointPath(){return m_path_id;} void LoadPath(uint32 pathid) { m_path_id = pathid; } diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 88ae3306371..6bbb1784ee1 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -1064,7 +1064,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); player->PrepareGossipMenu(this, GetGOInfo()->questgiver.gossipID); player->SendPreparedGossip(this); @@ -1089,7 +1089,7 @@ void GameObject::Use(Unit* user) ChairListSlots[0] = 0; // error in DB, make one default slot } - Player* player = (Player*)user; + Player* player = user->ToPlayer(); // a chair may have n slots. we have to calculate their positions and teleport the player to the nearest one @@ -1167,7 +1167,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() == TYPEID_PLAYER) { - Player* player = (Player*)user; + Player* player = user->ToPlayer(); if (info->goober.pageId) // show page... { @@ -1233,7 +1233,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); if (info->camera.cinematicId) player->SendCinematicStart(info->camera.cinematicId); @@ -1437,7 +1437,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); Player* targetPlayer = ObjectAccessor::FindPlayer(player->GetSelection()); @@ -1466,7 +1466,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); if (player->CanUseBattlegroundObject()) { @@ -1494,7 +1494,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); player->SendLoot(GetGUID(), LOOT_FISHINGHOLE); player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT, GetGOInfo()->id); @@ -1506,7 +1506,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); if (player->CanUseBattlegroundObject()) { @@ -1557,7 +1557,7 @@ void GameObject::Use(Unit* user) if (user->GetTypeId() != TYPEID_PLAYER) return; - Player* player = (Player*)user; + Player* player = user->ToPlayer(); // fallback, will always work player->TeleportTo(GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(),TELE_TO_NOT_LEAVE_TRANSPORT | TELE_TO_NOT_LEAVE_COMBAT | TELE_TO_NOT_UNSUMMON_PET); @@ -1569,7 +1569,8 @@ void GameObject::Use(Unit* user) return; } default: - sLog->outError("Unknown Object Type %u", GetGoType()); + sLog->outError("GameObject::Use(): unit (type: %u, guid: %u) tries to use object (guid: %u) of unknown type (%u)", + user->GetTypeId(), user->GetGUIDLow(), GetGUIDLow(), GetGoType()); break; } @@ -1579,7 +1580,7 @@ void GameObject::Use(Unit* user) SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId); if (!spellInfo) { - if (user->GetTypeId() != TYPEID_PLAYER || !sOutdoorPvPMgr->HandleCustomSpell((Player*)user,spellId,this)) + if (user->GetTypeId() != TYPEID_PLAYER || !sOutdoorPvPMgr->HandleCustomSpell(user->ToPlayer(), spellId, this)) sLog->outError("WORLD: unknown spell id %u at use action for gameobject (Entry: %u GoType: %u)", spellId,GetEntry(),GetGoType()); else sLog->outDebug(LOG_FILTER_OUTDOORPVP, "WORLD: %u non-dbc spell was handled by OutdoorPvP", spellId); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d3d38ffa4aa..1179eef26e6 100755 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2647,12 +2647,12 @@ void Player::UninviteFromGroup() if (group->IsCreated()) { group->Disband(true); - sObjectMgr->RemoveGroup(group); } else + { group->RemoveAllInvites(); - - delete group; + delete group; + } } } @@ -2660,14 +2660,8 @@ void Player::RemoveFromGroup(Group* group, uint64 guid, RemoveMethod method /* = { if (group) { - if (group->RemoveMember(guid, method, kicker, reason) <= 1) - { - // group->Disband(); already disbanded in RemoveMember - sObjectMgr->RemoveGroup(group); - delete group; - group = NULL; - // removemember sets the player's group pointer to NULL - } + group->RemoveMember(guid, method, kicker, reason); + group = NULL; } } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d14082cc864..8ee626d18bb 100755 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1640,6 +1640,8 @@ class Player : public Unit, public GridObject<Player> void RemoveSpellCategoryCooldown(uint32 cat, bool update = false); void SendClearCooldown(uint32 spell_id, Unit* target); + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } + void RemoveCategoryCooldown(uint32 cat); void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns = false); void RemoveAllSpellCooldown(); @@ -2545,6 +2547,8 @@ class Player : public Unit, public GridObject<Player> PlayerTalentMap *m_talents[MAX_TALENT_SPECS]; uint32 m_lastPotionId; // last used health/mana potion in combat, that block next potion use + GlobalCooldownMgr m_GlobalCooldownMgr; + uint8 m_activeSpec; uint8 m_specsCount; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 1ad52613687..81f048771c9 100755 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -192,6 +192,26 @@ m_vehicleKit(NULL), m_unitTypeMask(UNIT_MASK_NONE), m_HostileRefManager(this) m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); } +//////////////////////////////////////////////////////////// +// Methods of class GlobalCooldownMgr +bool GlobalCooldownMgr::HasGlobalCooldown(SpellEntry const* spellInfo) const +{ + GlobalCooldownList::const_iterator itr = m_GlobalCooldowns.find(spellInfo->StartRecoveryCategory); + return itr != m_GlobalCooldowns.end() && itr->second.duration && getMSTimeDiff(itr->second.cast_time, getMSTime()) < itr->second.duration; +} + +void GlobalCooldownMgr::AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd) +{ + m_GlobalCooldowns[spellInfo->StartRecoveryCategory] = GlobalCooldown(gcd, getMSTime()); +} + +void GlobalCooldownMgr::CancelGlobalCooldown(SpellEntry const* spellInfo) +{ + m_GlobalCooldowns[spellInfo->StartRecoveryCategory].duration = 0; +} + +//////////////////////////////////////////////////////////// +// Methods of class Unit Unit::~Unit() { // set current spells as deletable @@ -515,7 +535,7 @@ bool Unit::HasAuraTypeWithFamilyFlags(AuraType auraType, uint32 familyName, uint void Unit::DealDamageMods(Unit *pVictim, uint32 &damage, uint32* absorb) { - if (!pVictim->isAlive() || pVictim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (pVictim->HasUnitState(UNIT_STAT_ONVEHICLE) && pVictim->GetVehicleBase() != this) || (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->ToCreature()->IsInEvadeMode())) + if (!pVictim->isAlive() || pVictim->HasUnitState(UNIT_STAT_IN_FLIGHT) || (pVictim->GetTypeId() == TYPEID_UNIT && pVictim->ToCreature()->IsInEvadeMode())) { if (absorb) *absorb += damage; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index e546af981a3..73d5cae78f0 100755 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -937,6 +937,30 @@ enum CurrentSpellTypes #define CURRENT_FIRST_NON_MELEE_SPELL 1 #define CURRENT_MAX_SPELL 4 +struct GlobalCooldown +{ + explicit GlobalCooldown(uint32 _dur = 0, uint32 _time = 0) : duration(_dur), cast_time(_time) {} + + uint32 duration; + uint32 cast_time; +}; + +typedef UNORDERED_MAP<uint32 /*category*/, GlobalCooldown> GlobalCooldownList; + +class GlobalCooldownMgr // Shared by Player and CharmInfo +{ +public: + GlobalCooldownMgr() {} + +public: + bool HasGlobalCooldown(SpellEntry const* spellInfo) const; + void AddGlobalCooldown(SpellEntry const* spellInfo, uint32 gcd); + void CancelGlobalCooldown(SpellEntry const* spellInfo); + +private: + GlobalCooldownList m_GlobalCooldowns; +}; + enum ActiveStates { ACT_PASSIVE = 0x01, // 0x01 - passive @@ -1057,6 +1081,8 @@ struct CharmInfo CharmSpellEntry* GetCharmSpell(uint8 index) { return &(m_charmspells[index]); } + GlobalCooldownMgr& GetGlobalCooldownMgr() { return m_GlobalCooldownMgr; } + void SetIsCommandAttack(bool val); bool IsCommandAttack(); void SetIsAtStay(bool val); @@ -1088,6 +1114,8 @@ struct CharmInfo float m_stayX; float m_stayY; float m_stayZ; + + GlobalCooldownMgr m_GlobalCooldownMgr; }; // for clearing special attacks diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 41564b49a2e..ea648172a2a 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -3970,9 +3970,9 @@ void ObjectMgr::LoadGroups() uint32 oldMSTime = getMSTime(); // Delete all groups whose leader does not exist - CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_LEADERLESS_GROUPS)); + CharacterDatabase.DirectExecute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_LEADERLESS_GROUPS)); // Delete all groups with less than 2 members - CharacterDatabase.Execute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_TINY_GROUPS)); + CharacterDatabase.DirectExecute(CharacterDatabase.GetPreparedStatement(CHAR_DEL_TINY_GROUPS)); // 0 1 2 3 4 5 6 7 8 9 QueryResult result = CharacterDatabase.PQuery("SELECT leaderGuid, lootMethod, looterGuid, lootThreshold, icon1, icon2, icon3, icon4, icon5, icon6" diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index bef3904bddb..2f7ae3c4d5f 100755 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -405,7 +405,7 @@ bool Group::AddMember(Player *player) return true; } -uint32 Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /* = GROUP_REMOVEMETHOD_DEFAULT */, uint64 kicker /* = 0 */, const char* reason /* = NULL */) +bool Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /*= GROUP_REMOVEMETHOD_DEFAULT*/, uint64 kicker /*= 0*/, const char* reason /*= NULL*/) { BroadcastGroupUpdate(); @@ -505,12 +505,15 @@ uint32 Group::RemoveMember(const uint64 &guid, const RemoveMethod &method /* = G } SendUpdate(); + + return true; } // If group size before player removal <= 2 then disband it else + { Disband(); - - return m_memberSlots.size(); + return false; + } } void Group::ChangeLeader(const uint64 &guid) @@ -634,9 +637,8 @@ void Group::Disband(bool hideDestroy /* = false */) ResetInstances(INSTANCE_RESET_GROUP_DISBAND, true, NULL); } - m_guid = 0; - m_leaderGuid = 0; - m_leaderName = ""; + sObjectMgr->RemoveGroup(this); + delete this; } /*********************************************************/ diff --git a/src/server/game/Groups/Group.h b/src/server/game/Groups/Group.h index e4c4066572a..3928b6ee54a 100755 --- a/src/server/game/Groups/Group.h +++ b/src/server/game/Groups/Group.h @@ -190,7 +190,7 @@ class Group void RemoveAllInvites(); bool AddLeaderInvite(Player *player); bool AddMember(Player *player); - uint32 RemoveMember(const uint64 &guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, uint64 kicker = 0, const char* reason = NULL); + bool RemoveMember(const uint64 &guid, const RemoveMethod &method = GROUP_REMOVEMETHOD_DEFAULT, uint64 kicker = 0, const char* reason = NULL); void ChangeLeader(const uint64 &guid); void SetLootMethod(LootMethod method); void SetLooterGuid(const uint64 &guid); diff --git a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp index 9dd53dd14dc..83d3c1db28c 100755 --- a/src/server/game/Server/Protocol/Handlers/PetHandler.cpp +++ b/src/server/game/Server/Protocol/Handlers/PetHandler.cpp @@ -141,7 +141,8 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid CharmInfo *charmInfo = pet->GetCharmInfo(); if (!charmInfo) { - sLog->outError("WorldSession::HandlePetAction: object (GUID: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", pet->GetGUIDLow(), pet->GetTypeId()); + sLog->outError("WorldSession::HandlePetAction(petGuid: " UI64FMTD ", tagGuid: " UI64FMTD ", spellId: %u, flag: %u): object (entry: %u TypeId: %u) is considered pet-like but doesn't have a charminfo!", + guid1, guid2, spellid, flag, pet->GetGUIDLow(), pet->GetTypeId()); return; } @@ -295,7 +296,7 @@ void WorldSession::HandlePetActionHelper(Unit *pet, uint64 guid1, uint16 spellid } if (spellInfo->StartRecoveryCategory > 0) - if (pet->ToCreature()->GetGlobalCooldown() > 0) + if (pet->GetCharmInfo() && pet->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) return; for (uint32 i = 0; i < MAX_SPELL_EFFECTS; ++i) @@ -753,7 +754,7 @@ void WorldSession::HandlePetCastSpellOpcode(WorldPacket& recvPacket) } if (spellInfo->StartRecoveryCategory > 0) // Check if spell is affected by GCD - if (caster->GetTypeId() == TYPEID_UNIT && caster->ToCreature()->GetGlobalCooldown() > 0) + if (caster->GetTypeId() == TYPEID_UNIT && caster->GetCharmInfo() && caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(spellInfo)) { caster->SendPetCastFail(spellId, SPELL_FAILED_NOT_READY); return; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 95769040dde..4d6459bc66d 100755 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3001,8 +3001,7 @@ void Spell::prepare(SpellCastTargets const* targets, AuraEffect const * triggere m_caster->SetCurrentCastedSpell(this); SendSpellStart(); - if (m_caster->GetTypeId() == TYPEID_PLAYER) - m_caster->ToPlayer()->AddGlobalCooldown(m_spellInfo,this); + TriggerGlobalCooldown(); if (!m_casttime && !m_spellInfo->StartRecoveryTime && !m_castItemGUID //item: first cast may destroy item and second cast causes crash @@ -3027,6 +3026,7 @@ void Spell::cancel() switch (oldState) { case SPELL_STATE_PREPARING: + CancelGlobalCooldown(); case SPELL_STATE_DELAYED: SendInterrupted(0); SendCastResult(SPELL_FAILED_INTERRUPTED); @@ -4680,6 +4680,10 @@ SpellCastResult Spell::CheckCast(bool strict) } } + // Check global cooldown + if (strict && !m_IsTriggeredSpell && HasGlobalCooldown()) + return SPELL_FAILED_NOT_READY; + // only allow triggered spells if at an ended battleground if (!m_IsTriggeredSpell && m_caster->GetTypeId() == TYPEID_PLAYER) if (Battleground * bg = m_caster->ToPlayer()->GetBattleground()) @@ -7285,3 +7289,67 @@ void Spell::CallScriptAfterUnitTargetSelectHandlers(std::list<Unit*>& unitTarget (*scritr)->_FinishScriptCall(); } } + +// Global cooldowns management +enum GCDLimits +{ + MIN_GCD = 1000, + MAX_GCD = 1500 +}; + +bool Spell::HasGlobalCooldown() +{ + // Only player or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + return m_caster->GetCharmInfo()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + return m_caster->ToPlayer()->GetGlobalCooldownMgr().HasGlobalCooldown(m_spellInfo); + else + return false; +} + +void Spell::TriggerGlobalCooldown() +{ + int32 gcd = m_spellInfo->StartRecoveryTime; + if (!gcd) + return; + + // Global cooldown can't leave range 1..1.5 secs + // There are some spells (mostly not casted directly by player) that have < 1 sec and > 1.5 sec global cooldowns + // but as tests show are not affected by any spell mods. + if (m_spellInfo->StartRecoveryTime >= MIN_GCD && m_spellInfo->StartRecoveryTime <= MAX_GCD) + { + // gcd modifier auras are applied only to own spells and only players have such mods + if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this); + + // Apply haste rating + gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED)); + if (gcd < MIN_GCD) + gcd = MIN_GCD; + else if (gcd > MAX_GCD) + gcd = MAX_GCD; + } + + // Only players or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->GetGlobalCooldownMgr().AddGlobalCooldown(m_spellInfo, gcd); +} + +void Spell::CancelGlobalCooldown() +{ + if (!m_spellInfo->StartRecoveryTime) + return; + + // Cancel global cooldown when interrupting current cast + if (m_caster->GetCurrentSpell(CURRENT_GENERIC_SPELL) != this) + return; + + // Only players or controlled units have global cooldown + if (m_caster->GetCharmInfo()) + m_caster->GetCharmInfo()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); + else if (m_caster->GetTypeId() == TYPEID_PLAYER) + m_caster->ToPlayer()->GetGlobalCooldownMgr().CancelGlobalCooldown(m_spellInfo); +} diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h index 34ddf5c1028..d83107f1db3 100755 --- a/src/server/game/Spells/Spell.h +++ b/src/server/game/Spells/Spell.h @@ -543,6 +543,9 @@ class Spell void SetSpellValue(SpellValueMod mod, int32 value); protected: + bool HasGlobalCooldown(); + void TriggerGlobalCooldown(); + void CancelGlobalCooldown(); void SendLoot(uint64 guid, LootType loottype); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9136cf2c9cb..4c0fec17774 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5149,12 +5149,6 @@ void Spell::EffectScriptEffect(SpellEffIndex effIndex) } return; } - case 65594: // Cancel Stone Grip - { - uint32 spellToRemove = unitTarget->GetMap()->GetDifficulty() == RAID_DIFFICULTY_10MAN_NORMAL ? 62166 : 63981; - unitTarget->RemoveAurasDueToSpell(spellToRemove); - return; - } case 60123: // Lightwell { if (m_caster->GetTypeId() != TYPEID_UNIT || !m_caster->ToCreature()->isSummon()) diff --git a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp b/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp index 8b0988b0eee..4b2dab9032e 100644 --- a/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp +++ b/src/server/scripts/Northrend/Ulduar/ulduar/boss_kologarn.cpp @@ -26,19 +26,35 @@ #define SPELL_PETRIFY_BREATH RAID_MODE(62030,63980) #define SPELL_STONE_GRIP RAID_MODE(62166,63981) + +#define NPC_RUBBLE_STALKER RAID_MODE(33809,33942) +#define SPELL_SUMMON_RUBBLE 63633 +#define SPELL_FALLING_RUBBLE 63821 + #define SPELL_STONE_GRIP_CANCEL 65594 + #define SPELL_ARM_SWEEP RAID_MODE(63766,63983) + +#define SPELL_ARM_ENTER_VEHICLE 65343 #define SPELL_ARM_VISUAL 64753 #define SPELL_BERSERK 47008 // guess +#define NPC_LEFT_ARM RAID_MODE(32933,33910) +#define NPC_RIGHT_ARM RAID_MODE(32934,33911) + enum Events { EVENT_NONE = 0, + EVENT_INSTALL_ACCESSORIES, EVENT_MELEE_CHECK, EVENT_SMASH, + EVENT_SWEEP, EVENT_STONE_SHOUT, - EVENT_RESPAWN_ARM, + EVENT_STONE_GRIP, + EVENT_RIGHT_ARM_DEAD, + EVENT_RESPAWN_LEFT_ARM, + EVENT_RESPAWN_RIGHT_ARM, EVENT_ENRAGE, }; @@ -60,22 +76,6 @@ enum ACHIEV_DISARMED_START_EVENT = 21687, }; -void EncounterInCombat(Creature* me, InstanceScript* pInstance) -{ - Creature* c; - c = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(TYPE_KOLOGARN) : 0); - if (c && c != me && c->isAlive()) - c->SetInCombatWithZone(); - - c = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(DATA_RIGHT_ARM) : 0); - if (c && c != me && c->isAlive()) - c->SetInCombatWithZone(); - - c = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(DATA_LEFT_ARM) : 0); - if (c && c != me && c->isAlive()) - c->SetInCombatWithZone(); -} - class boss_kologarn : public CreatureScript { public: @@ -89,7 +89,7 @@ public: struct boss_kologarnAI : public BossAI { boss_kologarnAI(Creature *pCreature) : BossAI(pCreature, TYPE_KOLOGARN), vehicle(pCreature->GetVehicleKit()), - uiArmCount(0) + left(false), right(false) { ASSERT(vehicle); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -99,21 +99,31 @@ public: } Vehicle *vehicle; - uint8 uiArmCount; + bool left, right; - void Reset() - { - _Reset(); - } - - void EnterCombat(Unit * /*who*/) + void EnterCombat(Unit * who) { DoScriptText(SAY_AGGRO, me); - _EnterCombat(); + events.ScheduleEvent(EVENT_MELEE_CHECK, 6000); events.ScheduleEvent(EVENT_SMASH, 5000); + events.ScheduleEvent(EVENT_STONE_GRIP, 25000); events.ScheduleEvent(EVENT_ENRAGE, 600000); - EncounterInCombat(me, instance); + + Unit* arm = NULL; + if (arm = vehicle->GetPassenger(0)) + arm->Attack(who, true); + if (arm = vehicle->GetPassenger(1)) + arm->Attack(who, true); + + _EnterCombat(); + } + + void Reset() + { + _Reset(); + events.ScheduleEvent(EVENT_INSTALL_ACCESSORIES, 1000); + } void JustDied(Unit * /*victim*/) @@ -124,28 +134,53 @@ public: void KilledUnit(Unit* /*who*/) { - DoScriptText(RAND(SAY_SLAY_2,SAY_SLAY_2), me); + DoScriptText(RAND(SAY_SLAY_1,SAY_SLAY_2), me); } void PassengerBoarded(Unit *who, int8 /*seatId*/, bool apply) { - if (who->GetTypeId() == TYPEID_UNIT) + if (who->GetEntry() == NPC_LEFT_ARM) + { + left = apply; + if (!apply) + DoScriptText(SAY_LEFT_ARM_GONE, me); + } + + else if (who->GetEntry() == NPC_RIGHT_ARM) + { + right = apply; + if (!apply) + DoScriptText(SAY_RIGHT_ARM_GONE, me); + } + + if (!apply) { - if (apply) + who->CastSpell(me, SPELL_ARM_DEAD_DAMAGE, true); + DoScriptText(SAY_RIGHT_ARM_GONE, me); + + if (Creature* rubbleStalker = me->FindNearestCreature(NPC_RUBBLE_STALKER, 20.0f)) { - ++uiArmCount; - events.CancelEvent(EVENT_STONE_SHOUT); + if (rubbleStalker) + { + rubbleStalker->CastSpell(rubbleStalker, SPELL_FALLING_RUBBLE, true); + rubbleStalker->CastSpell(rubbleStalker, SPELL_SUMMON_RUBBLE, true); + } } - else - { - if (--uiArmCount == 0) - events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); - events.ScheduleEvent(EVENT_RESPAWN_ARM, 40000); - if (instance) - instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_DISARMED_START_EVENT); - } + if (!right && !left) + events.ScheduleEvent(EVENT_STONE_SHOUT, 5000); + + if (who->GetEntry() == NPC_LEFT_ARM) + events.ScheduleEvent(EVENT_RESPAWN_LEFT_ARM, 40000); + else if (who->GetEntry() == NPC_RIGHT_ARM) + events.ScheduleEvent(EVENT_RESPAWN_RIGHT_ARM, 40000); + + if (instance) + instance->DoStartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_EVENT, ACHIEV_DISARMED_START_EVENT); } + + if (apply) + events.CancelEvent(EVENT_STONE_SHOUT); } void UpdateAI(const uint32 diff) @@ -160,15 +195,23 @@ public: switch (events.GetEvent()) { + case EVENT_INSTALL_ACCESSORIES: // Delayed install, this is needed for IsInWorldCheck in Vehicle code to trigger PassengerBoarded + vehicle->InstallAllAccessories(me->GetEntry()); + events.CancelEvent(EVENT_INSTALL_ACCESSORIES); + break; case EVENT_MELEE_CHECK: if (!me->IsWithinMeleeRange(me->getVictim())) DoCast(SPELL_PETRIFY_BREATH); events.RepeatEvent(1000); break; + case EVENT_SWEEP: + DoCast(SPELL_ARM_SWEEP); + events.RepeatEvent(15000); + break; case EVENT_SMASH: - if (uiArmCount == 2) + if (left && right) DoCastVictim(SPELL_TWO_ARM_SMASH); - else if (uiArmCount == 1) + else if (left || right) DoCastVictim(SPELL_ONE_ARM_SMASH); events.RepeatEvent(15000); break; @@ -180,203 +223,195 @@ public: DoCast(SPELL_BERSERK); DoScriptText(SAY_BERSERK, me); break; - case EVENT_RESPAWN_ARM: + case EVENT_RESPAWN_LEFT_ARM: { - Creature* curArm = Unit::GetCreature(*me, instance ? instance->GetData64(DATA_RIGHT_ARM) : 0); - if (!(curArm && curArm->isAlive())) - curArm = Unit::GetCreature(*me, instance ? instance->GetData64(DATA_LEFT_ARM) : 0); - if (!(curArm && curArm->isAlive())) - break; - - curArm->Respawn(); - curArm->SetInCombatWithZone(); - curArm->EnterVehicle(me); + if (Unit* arm = me->FindNearestCreature(NPC_LEFT_ARM, 20.0f, false)) + RespawnArm(arm); + events.CancelEvent(EVENT_RESPAWN_LEFT_ARM); break; } + case EVENT_RESPAWN_RIGHT_ARM: + { + if (Unit* arm = me->FindNearestCreature(NPC_RIGHT_ARM, 20.0f, false)) + RespawnArm(arm); + events.CancelEvent(EVENT_RESPAWN_RIGHT_ARM); + break; + } + case EVENT_STONE_GRIP: + { + if (right) + { + std::list<Unit*> targetList; + std::list<Unit*>::const_iterator itr; + SelectTargetList(targetList, RAID_MODE(1, 3), SELECT_TARGET_RANDOM, 0.0f, true); + for (itr = targetList.begin(); itr != targetList.end(); ++itr) + { + DoCast((*itr), SPELL_STONE_GRIP, true); + /* 10 man: */ + // Cast 62056 -> HandleAuraLinked (64224) -> Apply 64224 -> Absorb damage + // -> Apply Stun with basepoints 64290 + // Cast 64290 -> Trigger spell (64708) Squeezed Lifeless + // -> Periodic damage + // Cast 63962 -> Visual + } + DoScriptText(SAY_GRAB_PLAYER, me); + } + events.RepeatEvent(25000); + } + break; } DoMeleeAttackIfReady(); } + + void RespawnArm(Unit* arm) + { + arm->ToCreature()->Respawn(); + arm->ToCreature()->SetInCombatWithZone(); + + arm->CastSpell(me, SPELL_ARM_ENTER_VEHICLE, true); + } }; }; -class npc_right_arm : public CreatureScript +class spell_ulduar_rubble_summon : public SpellScriptLoader { public: - npc_right_arm() : CreatureScript("npc_right_arm") { } + spell_ulduar_rubble_summon() : SpellScriptLoader("spell_ulduar_rubble_summon") { } - CreatureAI* GetAI(Creature* pCreature) const + class spell_ulduar_rubble_summonSpellScript : public SpellScript { - return new npc_right_armAI(pCreature); - } + PrepareSpellScript(spell_ulduar_rubble_summonSpellScript); - struct npc_right_armAI : public ScriptedAI - { - npc_right_armAI(Creature* pCreature) : ScriptedAI(pCreature) + void HandleScript(SpellEffIndex /*effIndex*/) { - pInstance = me->GetInstanceScript(); - SetCombatMovement(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - Reset(); - } - - uint32 uiStoneGripTimer; - uint64 uiGrippedTargets[3]; - uint32 uiPermittedDamage; - InstanceScript * pInstance; + Unit* caster = GetCaster(); + if (!caster) + return; - void EnterCombat(Unit* /*who*/) - { - EncounterInCombat(me, pInstance); - uiStoneGripTimer = 30000; + uint32 spellId = GetEffectValue(); + for (uint8 i = 0; i < 5; ++i) + caster->CastSpell(caster, spellId, true); } - void Reset() + void Register() { - memset(&uiGrippedTargets, 0, sizeof(uiGrippedTargets)); - uiPermittedDamage = RAID_MODE(100000, 480000); - uiStoneGripTimer = 0; - DoCast(SPELL_ARM_VISUAL); + OnEffect += SpellEffectFn(spell_ulduar_rubble_summonSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } + }; - void DamageTaken(Unit* /*who*/, uint32& damage) - { - if (uiGrippedTargets[0] == 0) - return; - - if (damage > uiPermittedDamage) - uiPermittedDamage = 0; - else - uiPermittedDamage -= damage; - - if (!uiPermittedDamage) - ReleaseGrabbedPlayers(); - } + SpellScript* GetSpellScript() const + { + return new spell_ulduar_rubble_summonSpellScript(); + } +}; - void JustDied(Unit* /*who*/) - { - ReleaseGrabbedPlayers(); +class spell_ulduar_cancel_stone_grip : public SpellScriptLoader +{ +public: + spell_ulduar_cancel_stone_grip() : SpellScriptLoader("spell_ulduar_cancel_stone_grip") { } - if (Creature* Kologarn = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(TYPE_KOLOGARN) : 0)) - { - if (Kologarn->isAlive()) - { - Kologarn->CastSpell(Kologarn, SPELL_ARM_DEAD_DAMAGE, true); - DoScriptText(SAY_RIGHT_ARM_GONE, Kologarn); - } - } - } + class spell_ulduar_cancel_stone_gripSpellScript : public SpellScript + { + PrepareSpellScript(spell_ulduar_cancel_stone_gripSpellScript); - void UpdateAI(const uint32 diff) + void HandleScript(SpellEffIndex /*effIndex*/) { - if (!UpdateVictim()) + Unit* target = this->GetHitPlayer(); + if (!target) return; - if (uiStoneGripTimer <= diff) + switch (target->GetMap()->GetDifficulty()) { - GrabPlayers(); - if (Creature* Kologarn = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(TYPE_KOLOGARN) : 0)) - DoScriptText(SAY_GRAB_PLAYER, Kologarn); - - uiStoneGripTimer = urand(30000, 35000); - uiPermittedDamage = RAID_MODE(100000, 480000); + case RAID_DIFFICULTY_10MAN_NORMAL: + target->RemoveAura(SpellMgr::CalculateSpellEffectAmount(GetSpellInfo(), EFFECT_0)); + break; + case RAID_DIFFICULTY_25MAN_NORMAL: + target->RemoveAura(SpellMgr::CalculateSpellEffectAmount(GetSpellInfo(), EFFECT_1)); + break; } - else - uiStoneGripTimer -= diff; - - DoMeleeAttackIfReady(); - } - - void ReleaseGrabbedPlayers() - { - for (uint8 i = 0; i < RAID_MODE(1, 3); ++i) - if (Unit* grabbed = Unit::GetUnit(*me, uiGrippedTargets[i])) - me->CastSpell(grabbed, SPELL_STONE_GRIP_CANCEL, false); } - void GrabPlayers() + void Register() { - for (uint8 i = 0; i < RAID_MODE(1, 3); ++i) - { - if (Unit* grabbed = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) - { - DoCast(grabbed, SPELL_STONE_GRIP); - uiGrippedTargets[i] = grabbed->GetGUID(); - } - } + OnEffect += SpellEffectFn(spell_ulduar_cancel_stone_gripSpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); } }; + + SpellScript* GetSpellScript() const + { + return new spell_ulduar_cancel_stone_gripSpellScript(); + } }; -class npc_left_arm : public CreatureScript +class spell_ulduar_stone_grip_absorb : public SpellScriptLoader { public: - npc_left_arm() : CreatureScript("npc_left_arm") { } + spell_ulduar_stone_grip_absorb() : SpellScriptLoader("spell_ulduar_stone_grip_absorb") { } - CreatureAI* GetAI(Creature* pCreature) const + class spell_ulduar_stone_grip_absorb_AuraScript : public AuraScript { - return new npc_left_armAI(pCreature); - } + PrepareAuraScript(spell_ulduar_stone_grip_absorb_AuraScript); - struct npc_left_armAI : public ScriptedAI - { - npc_left_armAI(Creature* pCreature) : ScriptedAI(pCreature) + //! This will be called when Right Arm (vehicle) has sustained a specific amount of damage depending on instance mode + //! What we do here is remove all harmful aura's related and teleport to safe spot. + void OnRemove(AuraEffect const* aurEff, AuraEffectHandleModes /*mode*/) { - pInstance = me->GetInstanceScript(); - SetCombatMovement(false); - me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE); - Reset(); - } - - uint32 uiSweepTimer; - InstanceScript * pInstance; + if (!GetOwner()->ToCreature()) + return; - void EnterCombat(Unit* /*who*/) - { - EncounterInCombat(me, pInstance); - uiSweepTimer = 15000; + uint32 rubbleStalkerEntry = (GetOwner()->GetMap()->GetDifficulty() == DUNGEON_DIFFICULTY_NORMAL ? 33809 : 33942); + Creature* rubbleStalker = GetOwner()->FindNearestCreature(rubbleStalkerEntry, 200.0f, true); + if (rubbleStalker) + rubbleStalker->CastSpell(rubbleStalker, SPELL_STONE_GRIP_CANCEL, true); } - void Reset() + void Register() { - DoCast(SPELL_ARM_VISUAL); - EncounterInCombat(me, pInstance); - uiSweepTimer = 0; + OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_absorb_AuraScript::OnRemove, EFFECT_0, SPELL_AURA_SCHOOL_ABSORB, AURA_EFFECT_HANDLE_REAL); } + }; - void JustDied(Unit* /*who*/) + AuraScript* GetAuraScript() const + { + return new spell_ulduar_stone_grip_absorb_AuraScript(); + } +}; + +class spell_ulduar_stone_grip : public SpellScriptLoader +{ +public: + spell_ulduar_stone_grip() : SpellScriptLoader("spell_ulduar_stone_grip") { } + + class spell_ulduar_stone_grip_AuraScript : public AuraScript + { + PrepareAuraScript(spell_ulduar_stone_grip_AuraScript); + + void OnRemoveStun(AuraEffect const* aurEff, AuraEffectHandleModes mode) { - if (Creature* Kologarn = Unit::GetCreature(*me, pInstance ? pInstance->GetData64(TYPE_KOLOGARN) : 0)) - { - if (Kologarn->isAlive()) - { - Kologarn->CastSpell(Kologarn, SPELL_ARM_DEAD_DAMAGE, true); - DoScriptText(SAY_LEFT_ARM_GONE, Kologarn); - } - } + GetOwner()->ToUnit()->RemoveAurasDueToSpell(SpellMgr::CalculateSpellEffectAmount(GetSpellProto(), EFFECT_2)); + // Spellsystem doesn't recognize EFFECT_0 as actionable effect on dispel for some reason, manually do it here + GetOwner()->ToUnit()->ExitVehicle(); + GetOwner()->ToUnit()->NearTeleportTo(1756.25f + irand(-3, 3), -8.3f + irand(-3, 3), 448.8f, 3.62f); } - void UpdateAI(const uint32 diff) + void Register() { - if (!UpdateVictim()) - return; - - if (uiSweepTimer <= diff) - { - DoCast(SPELL_ARM_SWEEP); - uiSweepTimer = urand(15000, 25000); - } - else - uiSweepTimer -= diff; - - DoMeleeAttackIfReady(); + OnEffectRemove += AuraEffectRemoveFn(spell_ulduar_stone_grip_AuraScript::OnRemoveStun, EFFECT_2, SPELL_AURA_MOD_STUN, AURA_EFFECT_HANDLE_REAL); } }; + + AuraScript* GetAuraScript() const + { + return new spell_ulduar_stone_grip_AuraScript(); + } }; void AddSC_boss_kologarn() { new boss_kologarn(); - new npc_right_arm(); - new npc_left_arm(); + new spell_ulduar_rubble_summon(); + new spell_ulduar_cancel_stone_grip(); + new spell_ulduar_stone_grip_absorb(); + new spell_ulduar_stone_grip(); } diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 44aaeec07ab..8d36973be7f 100755 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -32,8 +32,8 @@ bool CharacterDatabaseConnection::Open() PREPARE_STATEMENT(CHAR_DEL_OLD_GUILD_BANK_EVENT_LOGS, "DELETE FROM guild_bank_eventlog WHERE LogGuid > ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_CHARACTER_GROUP_MEMBERS, "DELETE FROM group_member WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=memberGuid)", CONNECTION_ASYNC) - PREPARE_STATEMENT(CHAR_DEL_LEADERLESS_GROUPS, "DELETE FROM groups WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=leaderGuid)", CONNECTION_ASYNC) - PREPARE_STATEMENT(CHAR_DEL_TINY_GROUPS, "DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)", CONNECTION_ASYNC) + PREPARE_STATEMENT(CHAR_DEL_LEADERLESS_GROUPS, "DELETE FROM groups WHERE NOT EXISTS (SELECT guid FROM characters WHERE guid=leaderGuid)", CONNECTION_SYNCH) + PREPARE_STATEMENT(CHAR_DEL_TINY_GROUPS, "DELETE FROM groups WHERE guid NOT IN (SELECT guid FROM group_member GROUP BY guid HAVING COUNT(guid) > 1)", CONNECTION_SYNCH) PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_GROUP_MEMBERS, "DELETE FROM group_member WHERE guid NOT IN (SELECT guid FROM groups)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_NONEXISTENT_GROUP_INSTANCES, "DELETE FROM group_instance WHERE guid NOT IN (SELECT guid FROM groups)", CONNECTION_ASYNC) PREPARE_STATEMENT(CHAR_DEL_EXPIRED_BANS, "UPDATE character_banned SET active = 0 WHERE unbandate <= UNIX_TIMESTAMP() AND unbandate <> bandate", CONNECTION_ASYNC) |
