diff options
Diffstat (limited to 'src/server')
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) | 
