Player* GetClosestPlayer(Creature* m_creature, float fDistance) { ThreatList const& t_list = m_creature->getThreatManager().getThreatList(); if (t_list.empty()) return NULL; Player* pTemp = NULL; for(ThreatList::const_iterator itr = t_list.begin(); itr!= t_list.end(); ++itr) { Unit *pUnit = m_creature->GetMap()->GetUnit((*itr)->getUnitGuid()); if (!pUnit || !pUnit->isAlive()) continue; if (pUnit->GetTypeId() == TYPEID_PLAYER && pUnit->GetDistance(m_creature) < fDistance) { pTemp = (Player*)pUnit; fDistance = pUnit->GetDistance(m_creature); } } if (pTemp) return pTemp; return NULL; }
void HandlePeriodic(constAuraEffectPtr aurEff) { Unit* caster = GetCaster(); Unit* target = GetTarget(); const SpellInfo* spell = GetSpellInfo(); Player* linkedPlayer = sObjectAccessor->GetPlayer(*target, playerLinkedGuid); if (!caster || !target || !spell || !linkedPlayer || !linkedPlayer->isAlive() || !linkedPlayer->HasAura(spell->Id)) if (AuraPtr myaura = GetAura()) { myaura->Remove(); return; } if (target->GetDistance(linkedPlayer) > spell->Effects[EFFECT_0].BasePoints) { if (AuraPtr aura = target->GetAura(spell->Id)) { if (aura->GetStackAmount() >= 15) { aura->Remove(); return; } } caster->AddAura(spell->Id, target); target->CastSpell(linkedPlayer, SPELL_JASPER_CHAINS_DAMAGE, true); } else target->CastSpell(linkedPlayer, SPELL_JASPER_CHAINS_VISUAL, true); }
//Gets the first found attacker of Unit if not nearestToAttacked > finds the one nearest to bot Unit *PlayerbotClassAI::GetNearestAttackerOf(Unit *pAttacked, bool nearestToAttacked) { if (!pAttacked) { pAttacked = m_bot; if (!pAttacked) return NULL;} Unit::AttackerSet fAttackerSet = pAttacked->getAttackers(); if (fAttackerSet.size() <= 0) { return NULL; } Unit *nearestTo = m_bot; if (nearestToAttacked) { nearestTo = pAttacked; } Unit *curAtt = NULL; float minDist = 30; for (Unit::AttackerSet::const_iterator itr = fAttackerSet.begin(); itr != fAttackerSet.end(); ++itr) { Unit *tAtt = (*itr); if (!tAtt) break; // Something is wrong.. How can a non existing mob attack? if (tAtt->isDead()) break; if (m_bot->GetDistance(tAtt) >= minDist) continue; //Get the nearest one curAtt = tAtt; minDist = tAtt->GetDistance(nearestTo); } return curAtt; }
void HandleTriggerSpell(AuraEffect const* aurEff) { PreventDefaultAction(); Unit* target = GetTarget(); uint32 triggerSpellId = GetSpellProto()->EffectTriggerSpell[aurEff->GetEffIndex()]; target->CastSpell(target, triggerSpellId, true); if (Unit* caster = GetCaster()) if (target->GetDistance(caster) <= 12.0f) target->CastSpell(caster, SPELL_SIPHONED_MIGHT, true); }
void HandlePull(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); Unit* target = GetHitUnit(); if (!target) return; Position pos; if (target->GetDistance(GetCaster()) < 5.0f) { float o = frand(0, 2*M_PI); pos.Relocate(GetCaster()->GetPositionX() + 4.0f*cos(o), GetCaster()->GetPositionY() + 4.0f*sin(o), GetCaster()->GetPositionZ()+frand(10.0f, 15.0f)); } else pos.Relocate(GetCaster()->GetPositionX(), GetCaster()->GetPositionY(), GetCaster()->GetPositionZ()+1.0f); float speedXY = float(GetSpellInfo()->Effects[effIndex].MiscValue) * 0.1f; float speedZ = target->GetDistance(pos) / speedXY * 0.5f * Movement::gravity; target->GetMotionMaster()->MoveJump(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), speedXY, speedZ); }
SpellCastResult CheckCast() { Unit* caster = GetCaster(); // Death Grip should not be castable while jumping/falling if (caster->HasUnitState(UNIT_STATE_JUMPING) || caster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING)) return SPELL_FAILED_MOVING; // Patch 3.3.3 (2010-03-23): Minimum range has been changed to 8 yards in PvP. Unit* target = GetExplTargetUnit(); if (target && target->GetTypeId() == TYPEID_PLAYER) if (caster->GetDistance(target) < 8.f) return SPELL_FAILED_TOO_CLOSE; return SPELL_CAST_OK; }
void TryHealBrother(uint32 diff) { if (IAmVeklor()) // this spell heals caster and the other brother so let VN cast it return; if (Heal_Timer < diff) { Unit *pOtherBoss = GetOtherBoss(); if (pOtherBoss && (pOtherBoss->GetDistance((const Creature *)m_creature) <= 60)) { DoCast(pOtherBoss, SPELL_HEAL_BROTHER); Heal_Timer = 1000; } } else Heal_Timer -= diff; }
Unit *PickNearestPlayer() { Unit *nearp = NULL; float neardist = 0.0f; std::list<HostileReference*>::iterator i; for (i = m_creature->getThreatManager().getThreatList().begin();i != m_creature->getThreatManager().getThreatList().end(); ++i) { Unit* pUnit = NULL; pUnit = Unit::GetUnit((*m_creature), (*i)->getUnitGuid()); if (!pUnit) continue; float pudist = pUnit->GetDistance((const Creature *)m_creature); if (!nearp || (neardist > pudist)) { nearp = pUnit; neardist = pudist; } } return nearp; }
Unit *PickNearestPlayer() { Unit *nearp = NULL; float neardist = 0.0f; ThreatList const& tList = m_creature->getThreatManager().getThreatList(); for (ThreatList::const_iterator i = tList.begin();i != tList.end(); ++i) { Unit* pUnit = NULL; pUnit = m_creature->GetMap()->GetUnit( (*i)->getUnitGuid()); if (!pUnit) continue; float pudist = pUnit->GetDistance((const Creature *)m_creature); if (!nearp || (neardist > pudist)) { nearp = pUnit; neardist = pudist; } } return nearp; }
void UpdateAI(uint32 const diff) { if (!_entered) { if (_enterTimer <= diff) { uint32 spellId = 0; _entered = true; switch (me->GetEntry()) { case NPC_EMERALD_DRAKE: spellId = 49346; break; case NPC_AMBER_DRAKE: spellId = 49460; break; case NPC_RUBY_DRAKE: spellId = 49464; break; } if (!me->ToTempSummon()) return; Unit* summoner = me->ToTempSummon()->GetSummoner(); if (summoner && summoner->isAlive() && summoner->GetDistance(me) < 30.0f && !summoner->isInCombat()) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); summoner->CastSpell(me, spellId, true); } else me->DespawnOrUnsummon(); } else _enterTimer -= diff; } }
void MoveInLineOfSight(Unit * who) { if (!who || me->getVictim()) return; Unit * pTarget = who; if (!introDone && pTarget->GetDistance(me) <= 100) { DoAction(ACTION_INTRO_BALTHARUS); return; } // Keine NPCs angreifen, die nicht zu einem Spieler gehören! if (pTarget->GetTypeId() == TYPEID_UNIT && !pTarget->GetOwner()) return; // Nur Spieler angreifen, die keine GMs sind! if (pTarget->GetTypeId() == TYPEID_PLAYER) if (!AccountMgr::IsPlayerAccount(pTarget->ToPlayer()->GetSession()->GetSecurity())) return; if (me->canStartAttack(pTarget, true)) AttackStart(pTarget); }
void UpdateAI(const uint32 uiDiff) { // Return since we have no target if (!m_creature->SelectHostileTarget() || !m_creature->getVictim()) return; if(m_creature->GetZoneId() != ZONE_ASZHARA) { ResetToHome(); return; } // Enrage if (!m_bEnraged && HealthBelowPct(25)) { DoCastSpellIfCan(m_creature, SPELL_ENRAGE); m_bEnraged = true; } // Cleave if (m_uiCleaveTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CLEAVE); m_uiCleaveTimer = 7000; } else m_uiCleaveTimer -= uiDiff; // Frost Breath if (m_uiFrostBreathTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_FROST_BREATH); m_uiFrostBreathTimer = urand(10000, 15000); } else m_uiFrostBreathTimer -= uiDiff; // Chill if (m_uiChillTimer < uiDiff) { DoCastSpellIfCan(m_creature->getVictim(), SPELL_CHILL); m_uiChillTimer = urand(13000, 22000); } else m_uiChillTimer -= uiDiff; // Manastorm if (m_uiManastormTimer < uiDiff) { Unit* pTarget = m_creature->SelectAttackingTarget(ATTACKING_TARGET_RANDOM,0); if (pTarget && pTarget->GetTypeId() == TYPEID_PLAYER) { DoCastSpellIfCan(pTarget, SPELL_MANASTORM); m_uiManastormTimer = urand(7500, 12500); } } else m_uiManastormTimer -= uiDiff; // Reflection if (m_uiReflectionTimer < uiDiff) { DoCastSpellIfCan(m_creature, SPELL_REFLECTION); m_uiReflectionTimer = urand(15000, 25000); } else m_uiReflectionTimer -= uiDiff; // Teleport if (m_uiTeleportTimer < uiDiff) { DoScriptText(SAY_TELEPORT, m_creature); float fX, fY, fZ; m_creature->GetPosition(fX, fY, fZ); std::vector<ObjectGuid> vGuids; m_creature->FillGuidsListFromThreatList(vGuids); for (std::vector<ObjectGuid>::const_iterator itr = vGuids.begin(); itr != vGuids.end(); ++itr) { Unit* pUnit = m_creature->GetMap()->GetUnit(*itr); if (pUnit && pUnit->GetTypeId() == TYPEID_PLAYER && pUnit->GetDistance(m_creature) <= 30.0f) { DoTeleportPlayer(pUnit, fX, fY, fZ+3, pUnit->GetOrientation()); m_creature->getThreatManager().modifyThreatPercent(pUnit, -100); } } if (m_uiChillTimer > 3000) m_uiChillTimer = urand(1500,2000); m_uiTeleportTimer = 30000; } else m_uiTeleportTimer -= uiDiff; DoMeleeAttackIfReady(); }
/// Process queued scripts void Map::ScriptsProcess() { if (m_scriptSchedule.empty()) return; ///- Process overdue queued scripts ScriptScheduleMap::iterator iter = m_scriptSchedule.begin(); // ok as multimap is a *sorted* associative container while (!m_scriptSchedule.empty() && (iter->first <= sWorld->GetGameTime())) { ScriptAction const& step = iter->second; Object* source = NULL; if (!step.sourceGUID.IsEmpty()) { switch (step.sourceGUID.GetHigh()) { case HighGuid::Item: // as well as HIGHGUID_CONTAINER if (Player* player = HashMapHolder<Player>::Find(step.ownerGUID)) source = player->GetItemByGuid(step.sourceGUID); break; case HighGuid::Creature: case HighGuid::Vehicle: source = GetCreature(step.sourceGUID); break; case HighGuid::Pet: source = GetPet(step.sourceGUID); break; case HighGuid::Player: source = HashMapHolder<Player>::Find(step.sourceGUID); break; case HighGuid::GameObject: case HighGuid::Transport: source = GetGameObject(step.sourceGUID); break; case HighGuid::Corpse: source = GetCorpse(step.sourceGUID); break; default: TC_LOG_ERROR("scripts", "%s source with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.sourceGUID.ToString().c_str()); break; } } WorldObject* target = NULL; if (!step.targetGUID.IsEmpty()) { switch (step.targetGUID.GetHigh()) { case HighGuid::Creature: case HighGuid::Vehicle: target = GetCreature(step.targetGUID); break; case HighGuid::Pet: target = GetPet(step.targetGUID); break; case HighGuid::Player: target = HashMapHolder<Player>::Find(step.targetGUID); break; case HighGuid::GameObject: case HighGuid::Transport: target = GetGameObject(step.targetGUID); break; case HighGuid::Corpse: target = GetCorpse(step.targetGUID); break; default: TC_LOG_ERROR("scripts", "%s target with unsupported high guid %s.", step.script->GetDebugInfo().c_str(), step.targetGUID.ToString().c_str()); break; } } switch (step.script->command) { case SCRIPT_COMMAND_TALK: { if (step.script->Talk.ChatType > CHAT_TYPE_BOSS_WHISPER) { TC_LOG_ERROR("scripts", "%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->Talk.ChatType); break; } if (step.script->Talk.Flags & SF_TALK_USE_PLAYER) source = _GetScriptPlayerSourceOrTarget(source, target, step.script); else source = _GetScriptCreatureSourceOrTarget(source, target, step.script); if (source) { Unit* sourceUnit = source->ToUnit(); if (!sourceUnit) { TC_LOG_ERROR("scripts", "%s source object (%s) is not an unit, skipping.", step.script->GetDebugInfo().c_str(), source->GetGUID().ToString().c_str()); break; } switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: sourceUnit->Say(step.script->Talk.TextID, target); break; case CHAT_TYPE_YELL: sourceUnit->Yell(step.script->Talk.TextID, target); break; case CHAT_TYPE_TEXT_EMOTE: case CHAT_TYPE_BOSS_EMOTE: sourceUnit->TextEmote(step.script->Talk.TextID, target, step.script->Talk.ChatType == CHAT_TYPE_BOSS_EMOTE); break; case CHAT_TYPE_WHISPER: case CHAT_TYPE_BOSS_WHISPER: { Player* receiver = target ? target->ToPlayer() : nullptr; if (!receiver) TC_LOG_ERROR("scripts", "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else sourceUnit->Whisper(step.script->Talk.TextID, receiver, step.script->Talk.ChatType == CHAT_TYPE_BOSS_WHISPER); break; } default: break; // must be already checked at load } } break; } case SCRIPT_COMMAND_EMOTE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (step.script->Emote.Flags & SF_EMOTE_USE_STATE) cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->Emote.EmoteID); else cSource->HandleEmoteCommand(step.script->Emote.EmoteID); } break; case SCRIPT_COMMAND_FIELD_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FieldSet.FieldID <= OBJECT_FIELD_ENTRY || step.script->FieldSet.FieldID >= cSource->GetValuesCount()) TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FieldSet.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetGUID().ToString().c_str()); else cSource->SetUInt32Value(step.script->FieldSet.FieldID, step.script->FieldSet.FieldValue); } break; case SCRIPT_COMMAND_MOVE_TO: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { Unit* unit = (Unit*)cSource; if (step.script->MoveTo.TravelTime != 0) { float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed); } else unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation()); } break; case SCRIPT_COMMAND_FLAG_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) { TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else cSource->SetFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_FLAG_REMOVE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) { TC_LOG_ERROR("scripts", "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, %s) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else cSource->RemoveFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_TELEPORT_TO: if (step.script->TeleportTo.Flags & SF_TELEPORT_USE_CREATURE) { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } else { // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) player->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } break; case SCRIPT_COMMAND_QUEST_EXPLORED: { if (!source) { TC_LOG_ERROR("scripts", "%s source object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (!target) { TC_LOG_ERROR("scripts", "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } // when script called for item spell casting then target == (unit or GO) and source is player WorldObject* worldObject; Player* player = target->ToPlayer(); if (player) { if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) { TC_LOG_ERROR("scripts", "%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUID().ToString().c_str()); break; } worldObject = dynamic_cast<WorldObject*>(source); } else { player = source->ToPlayer(); if (player) { if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) { TC_LOG_ERROR("scripts", "%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } worldObject = dynamic_cast<WorldObject*>(target); } else { TC_LOG_ERROR("scripts", "%s neither source nor target is player (Entry: %u, GUID: %s; target: Entry: %u, GUID: %s), skipping.", step.script->GetDebugInfo().c_str(), source->GetEntry(), source->GetGUID().ToString().c_str(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } } // quest id and flags checked at script loading if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->IsAlive()) && (step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(player, float(step.script->QuestExplored.Distance)))) player->AreaExploredOrEventHappens(step.script->QuestExplored.QuestID); else player->FailQuest(step.script->QuestExplored.QuestID); break; } case SCRIPT_COMMAND_KILL_CREDIT: // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { if (step.script->KillCredit.Flags & SF_KILLCREDIT_REWARD_GROUP) player->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, player); else player->KilledMonsterCredit(step.script->KillCredit.CreatureEntry); } break; case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: if (!step.script->RespawnGameobject.GOGuid) { TC_LOG_ERROR("scripts", "%s gameobject guid (datalong) is not specified.", step.script->GetDebugInfo().c_str()); break; } // Source or target must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { GameObject* pGO = _FindGameObject(pSummoner, step.script->RespawnGameobject.GOGuid); if (!pGO) { TC_LOG_ERROR("scripts", "%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->RespawnGameobject.GOGuid); break; } if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP) { TC_LOG_ERROR("scripts", "%s can not be used with gameobject of type %u (guid: %u).", step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->RespawnGameobject.GOGuid); break; } // Check that GO is not spawned if (!pGO->isSpawned()) { int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay)); pGO->SetLootState(GO_READY); pGO->SetRespawnTime(nTimeToDespawn); pGO->GetMap()->AddToMap(pGO); } } break; case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: { // Source must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { if (!step.script->TempSummonCreature.CreatureEntry) TC_LOG_ERROR("scripts", "%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str()); else { float x = step.script->TempSummonCreature.PosX; float y = step.script->TempSummonCreature.PosY; float z = step.script->TempSummonCreature.PosZ; float o = step.script->TempSummonCreature.Orientation; if (!pSummoner->SummonCreature(step.script->TempSummonCreature.CreatureEntry, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->TempSummonCreature.DespawnDelay)) TC_LOG_ERROR("scripts", "%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->TempSummonCreature.CreatureEntry); } } break; } case SCRIPT_COMMAND_OPEN_DOOR: case SCRIPT_COMMAND_CLOSE_DOOR: _ScriptProcessDoor(source, target, step.script); break; case SCRIPT_COMMAND_ACTIVATE_OBJECT: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { // Target must be GameObject. if (!target) { TC_LOG_ERROR("scripts", "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (target->GetTypeId() != TYPEID_GAMEOBJECT) { TC_LOG_ERROR("scripts", "%s target object is not gameobject (TypeId: %u, Entry: %u, %s), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUID().ToString().c_str()); break; } if (GameObject* pGO = target->ToGameObject()) pGO->Use(unit); } break; case SCRIPT_COMMAND_REMOVE_AURA: { // Source (datalong2 != 0) or target (datalong2 == 0) must be Unit. bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE; if (Unit* unit = _GetScriptUnit(bReverse ? source : target, bReverse, step.script)) unit->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID); break; } case SCRIPT_COMMAND_CAST_SPELL: { /// @todo Allow gameobjects to be targets and casters if (!source && !target) { TC_LOG_ERROR("scripts", "%s source and target objects are NULL.", step.script->GetDebugInfo().c_str()); break; } Unit* uSource = NULL; Unit* uTarget = NULL; // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s switch (step.script->CastSpell.Flags) { case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target uSource = source ? source->ToUnit() : NULL; uTarget = target ? target->ToUnit() : NULL; break; case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source uSource = source ? source->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target uSource = target ? target->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source uSource = target ? target->ToUnit() : NULL; uTarget = source ? source->ToUnit() : NULL; break; case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry uSource = source ? source->ToUnit() : NULL; uTarget = uSource ? uSource->FindNearestCreature(abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius) : NULL; break; } if (!uSource || !uSource->isType(TYPEMASK_UNIT)) { TC_LOG_ERROR("scripts", "%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) { TC_LOG_ERROR("scripts", "%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } bool triggered = (step.script->CastSpell.Flags != 4) ? step.script->CastSpell.CreatureEntry & SF_CASTSPELL_TRIGGERED : step.script->CastSpell.CreatureEntry < 0; uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered); break; } case SCRIPT_COMMAND_PLAY_SOUND: // Source must be WorldObject. if (WorldObject* object = _GetScriptWorldObject(source, true, step.script)) { // PlaySound.Flags bitmask: 0/1=anyone/target Player* player = NULL; if (step.script->PlaySound.Flags & SF_PLAYSOUND_TARGET_PLAYER) { // Target must be Player. player = _GetScriptPlayer(target, false, step.script); if (!target) break; } // PlaySound.Flags bitmask: 0/2=without/with distance dependent if (step.script->PlaySound.Flags & SF_PLAYSOUND_DISTANCE_SOUND) object->PlayDistanceSound(step.script->PlaySound.SoundID, player); else object->PlayDirectSound(step.script->PlaySound.SoundID, player); } break; case SCRIPT_COMMAND_CREATE_ITEM: // Target or source must be Player. if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { ItemPosCountVec dest; InventoryResult msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount); if (msg == EQUIP_ERR_OK) { if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true)) pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true); } else pReceiver->SendEquipError(msg, NULL, NULL, step.script->CreateItem.ItemEntry); } break; case SCRIPT_COMMAND_DESPAWN_SELF: // Target or source must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->DespawnOrUnsummon(step.script->DespawnSelf.DespawnDelay); break; case SCRIPT_COMMAND_LOAD_PATH: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID)) TC_LOG_ERROR("scripts", "%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->LoadPath.PathID); else unit->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable != 0); } break; case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: { if (!step.script->CallScript.CreatureEntry) { TC_LOG_ERROR("scripts", "%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } if (!step.script->CallScript.ScriptID) { TC_LOG_ERROR("scripts", "%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } Creature* cTarget = NULL; auto creatureBounds = _creatureBySpawnIdStore.equal_range(step.script->CallScript.CreatureEntry); if (creatureBounds.first != creatureBounds.second) { // Prefer alive (last respawned) creature auto creatureItr = std::find_if(creatureBounds.first, creatureBounds.second, [](Map::CreatureBySpawnIdContainer::value_type const& pair) { return pair.second->IsAlive(); }); cTarget = creatureItr != creatureBounds.second ? creatureItr->second : creatureBounds.first->second; } if (!cTarget) { TC_LOG_ERROR("scripts", "%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->CallScript.CreatureEntry); break; } //Lets choose our ScriptMap map ScriptMapMap* datamap = GetScriptsMapByType(ScriptsType(step.script->CallScript.ScriptType)); //if no scriptmap present... if (!datamap) { TC_LOG_ERROR("scripts", "%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->CallScript.ScriptType); break; } // Insert script into schedule but do not start it ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, NULL); break; } case SCRIPT_COMMAND_KILL: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (cSource->isDead()) { TC_LOG_ERROR("scripts", "%s creature is already dead (Entry: %u, %s)", step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUID().ToString().c_str()); } else { cSource->setDeathState(JUST_DIED); if (step.script->Kill.RemoveCorpse == 1) cSource->RemoveCorpse(); } } break; case SCRIPT_COMMAND_ORIENTATION: // Source must be Unit. if (Unit* sourceUnit = _GetScriptUnit(source, true, step.script)) { if (step.script->Orientation.Flags & SF_ORIENTATION_FACE_TARGET) { // Target must be Unit. Unit* targetUnit = _GetScriptUnit(target, false, step.script); if (!targetUnit) break; sourceUnit->SetFacingToObject(targetUnit); } else sourceUnit->SetFacingTo(step.script->Orientation.Orientation); } break; case SCRIPT_COMMAND_EQUIP: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->LoadEquipment(step.script->Equip.EquipmentID); break; case SCRIPT_COMMAND_MODEL: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->SetDisplayId(step.script->Model.ModelID); break; case SCRIPT_COMMAND_CLOSE_GOSSIP: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->PlayerTalkClass->SendCloseGossip(); break; case SCRIPT_COMMAND_PLAYMOVIE: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->SendMovieStart(step.script->PlayMovie.MovieID); break; case SCRIPT_COMMAND_MOVEMENT: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) { if (!cSource->IsAlive()) return; cSource->GetMotionMaster()->MovementExpired(); cSource->GetMotionMaster()->MoveIdle(); switch (step.script->Movement.MovementType) { case RANDOM_MOTION_TYPE: cSource->GetMotionMaster()->MoveRandom((float)step.script->Movement.MovementDistance); break; case WAYPOINT_MOTION_TYPE: cSource->GetMotionMaster()->MovePath(step.script->Movement.Path, false); break; } } break; case SCRIPT_COMMAND_PLAY_ANIMKIT: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->PlayOneShotAnimKitId(step.script->PlayAnimKit.AnimKitID); break; default: TC_LOG_ERROR("scripts", "Unknown script command %s.", step.script->GetDebugInfo().c_str()); break; } m_scriptSchedule.erase(iter); iter = m_scriptSchedule.begin(); sMapMgr->DecreaseScheduledScriptCount(); } }
/// Process queued scripts void Map::ScriptsProcess() { if (m_scriptSchedule.empty()) return; ///- Process overdue queued scripts ScriptScheduleMap::iterator iter = m_scriptSchedule.begin(); // ok as multimap is a *sorted* associative container while (!m_scriptSchedule.empty() && (iter->first <= sWorld->GetGameTime())) { ScriptAction const& step = iter->second; Object* source = NULL; if (step.sourceGUID) { switch (GUID_HIPART(step.sourceGUID)) { case HIGHGUID_ITEM: // as well as HIGHGUID_CONTAINER if (Player* player = HashMapHolder<Player>::Find(step.ownerGUID)) source = player->GetItemByGuid(step.sourceGUID); break; case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: source = HashMapHolder<Creature>::Find(step.sourceGUID); break; case HIGHGUID_PET: source = HashMapHolder<Pet>::Find(step.sourceGUID); break; case HIGHGUID_PLAYER: source = HashMapHolder<Player>::Find(step.sourceGUID); break; case HIGHGUID_GAMEOBJECT: source = HashMapHolder<GameObject>::Find(step.sourceGUID); break; case HIGHGUID_CORPSE: source = HashMapHolder<Corpse>::Find(step.sourceGUID); break; case HIGHGUID_MO_TRANSPORT: for (MapManager::TransportSet::iterator itr2 = sMapMgr->m_Transports.begin(); itr2 != sMapMgr->m_Transports.end(); ++itr2) { if ((*itr2)->GetGUID() == step.sourceGUID) { source = *itr2; break; } } break; default: sLog->outError(LOG_FILTER_TSCR, "%s source with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).", step.script->GetDebugInfo().c_str(), step.sourceGUID, GUID_HIPART(step.sourceGUID)); break; } } Object* target = NULL; if (step.targetGUID) { switch (GUID_HIPART(step.targetGUID)) { case HIGHGUID_UNIT: case HIGHGUID_VEHICLE: target = HashMapHolder<Creature>::Find(step.targetGUID); break; case HIGHGUID_PET: target = HashMapHolder<Pet>::Find(step.targetGUID); break; case HIGHGUID_PLAYER: // empty GUID case also target = HashMapHolder<Player>::Find(step.targetGUID); break; case HIGHGUID_GAMEOBJECT: target = HashMapHolder<GameObject>::Find(step.targetGUID); break; case HIGHGUID_CORPSE: target = HashMapHolder<Corpse>::Find(step.targetGUID); break; default: sLog->outError(LOG_FILTER_TSCR, "%s target with unsupported high guid (GUID: " UI64FMTD ", high guid: %u).", step.script->GetDebugInfo().c_str(), step.targetGUID, GUID_HIPART(step.targetGUID)); break; } } switch (step.script->command) { case SCRIPT_COMMAND_TALK: if (step.script->Talk.ChatType > CHAT_TYPE_WHISPER && step.script->Talk.ChatType != CHAT_MSG_RAID_BOSS_WHISPER) { sLog->outError(LOG_FILTER_TSCR, "%s invalid chat type (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->Talk.ChatType); break; } if (step.script->Talk.Flags & SF_TALK_USE_PLAYER) { if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { LocaleConstant loc_idx = player->GetSession()->GetSessionDbLocaleIndex(); std::string text(sObjectMgr->GetTrinityString(step.script->Talk.TextID, loc_idx)); switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: player->Say(text, LANG_UNIVERSAL); break; case CHAT_TYPE_YELL: player->Yell(text, LANG_UNIVERSAL); break; case CHAT_TYPE_TEXT_EMOTE: case CHAT_TYPE_BOSS_EMOTE: player->TextEmote(text); break; case CHAT_TYPE_WHISPER: case CHAT_MSG_RAID_BOSS_WHISPER: { uint64 targetGUID = target ? target->GetGUID() : 0; if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else player->Whisper(text, LANG_UNIVERSAL, targetGUID); break; } default: break; // must be already checked at load } } } else { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { uint64 targetGUID = target ? target->GetGUID() : 0; switch (step.script->Talk.ChatType) { case CHAT_TYPE_SAY: cSource->Say(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID); break; case CHAT_TYPE_YELL: cSource->Yell(step.script->Talk.TextID, LANG_UNIVERSAL, targetGUID); break; case CHAT_TYPE_TEXT_EMOTE: cSource->TextEmote(step.script->Talk.TextID, targetGUID); break; case CHAT_TYPE_BOSS_EMOTE: cSource->MonsterTextEmote(step.script->Talk.TextID, targetGUID, true); break; case CHAT_TYPE_WHISPER: if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to whisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else cSource->Whisper(step.script->Talk.TextID, targetGUID); break; case CHAT_MSG_RAID_BOSS_WHISPER: if (!targetGUID || !IS_PLAYER_GUID(targetGUID)) sLog->outError(LOG_FILTER_TSCR, "%s attempt to raidbosswhisper to non-player unit, skipping.", step.script->GetDebugInfo().c_str()); else cSource->MonsterWhisper(step.script->Talk.TextID, targetGUID, true); break; default: break; // must be already checked at load } } } break; case SCRIPT_COMMAND_EMOTE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (step.script->Emote.Flags & SF_EMOTE_USE_STATE) cSource->SetUInt32Value(UNIT_NPC_EMOTESTATE, step.script->Emote.EmoteID); else cSource->HandleEmoteCommand(step.script->Emote.EmoteID); } break; case SCRIPT_COMMAND_FIELD_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FieldSet.FieldID <= OBJECT_FIELD_ENTRY || step.script->FieldSet.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FieldSet.FieldID, cSource->GetValuesCount(), cSource->GetTypeId(), cSource->GetEntry(), cSource->GetGUIDLow()); else cSource->SetUInt32Value(step.script->FieldSet.FieldID, step.script->FieldSet.FieldValue); } break; case SCRIPT_COMMAND_MOVE_TO: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { Unit * unit = (Unit*)cSource; if (step.script->MoveTo.TravelTime != 0) { float speed = unit->GetDistance(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ) / ((float)step.script->MoveTo.TravelTime * 0.001f); unit->MonsterMoveWithSpeed(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, speed); } else unit->NearTeleportTo(step.script->MoveTo.DestX, step.script->MoveTo.DestY, step.script->MoveTo.DestZ, unit->GetOrientation()); } break; case SCRIPT_COMMAND_FLAG_SET: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); else cSource->SetFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_FLAG_REMOVE: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { // Validate field number. if (step.script->FlagToggle.FieldID <= OBJECT_FIELD_ENTRY || step.script->FlagToggle.FieldID >= cSource->GetValuesCount()) sLog->outError(LOG_FILTER_TSCR, "%s wrong field %u (max count: %u) in object (TypeId: %u, Entry: %u, GUID: %u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->FlagToggle.FieldID, source->GetValuesCount(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); else cSource->RemoveFlag(step.script->FlagToggle.FieldID, step.script->FlagToggle.FieldValue); } break; case SCRIPT_COMMAND_TELEPORT_TO: if (step.script->TeleportTo.Flags & SF_TELEPORT_USE_CREATURE) { // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->NearTeleportTo(step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } else { // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) player->TeleportTo(step.script->TeleportTo.MapID, step.script->TeleportTo.DestX, step.script->TeleportTo.DestY, step.script->TeleportTo.DestZ, step.script->TeleportTo.Orientation); } break; case SCRIPT_COMMAND_QUEST_EXPLORED: { if (!source) { sLog->outError(LOG_FILTER_TSCR, "%s source object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (!target) { sLog->outError(LOG_FILTER_TSCR, "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } // when script called for item spell casting then target == (unit or GO) and source is player WorldObject* worldObject; Player* player = target->ToPlayer(); if (player) { if (source->GetTypeId() != TYPEID_UNIT && source->GetTypeId() != TYPEID_GAMEOBJECT && source->GetTypeId() != TYPEID_PLAYER) { sLog->outError(LOG_FILTER_TSCR, "%s source is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow()); break; } worldObject = dynamic_cast<WorldObject*>(source); } else { player = source->ToPlayer(); if (player) { if (target->GetTypeId() != TYPEID_UNIT && target->GetTypeId() != TYPEID_GAMEOBJECT && target->GetTypeId() != TYPEID_PLAYER) { sLog->outError(LOG_FILTER_TSCR, "%s target is not unit, gameobject or player (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } worldObject = dynamic_cast<WorldObject*>(target); } else { sLog->outError(LOG_FILTER_TSCR, "%s neither source nor target is player (source: TypeId: %u, Entry: %u, GUID: %u; target: TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), source->GetTypeId(), source->GetEntry(), source->GetGUIDLow(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } } // quest id and flags checked at script loading if ((worldObject->GetTypeId() != TYPEID_UNIT || ((Unit*)worldObject)->isAlive()) && (step.script->QuestExplored.Distance == 0 || worldObject->IsWithinDistInMap(player, float(step.script->QuestExplored.Distance)))) player->AreaExploredOrEventHappens(step.script->QuestExplored.QuestID); else player->FailQuest(step.script->QuestExplored.QuestID); break; } case SCRIPT_COMMAND_KILL_CREDIT: // Source or target must be Player. if (Player* player = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { if (step.script->KillCredit.Flags & SF_KILLCREDIT_REWARD_GROUP) player->RewardPlayerAndGroupAtEvent(step.script->KillCredit.CreatureEntry, player); else player->KilledMonsterCredit(step.script->KillCredit.CreatureEntry, 0); } break; case SCRIPT_COMMAND_RESPAWN_GAMEOBJECT: if (!step.script->RespawnGameobject.GOGuid) { sLog->outError(LOG_FILTER_TSCR, "%s gameobject guid (datalong) is not specified.", step.script->GetDebugInfo().c_str()); break; } // Source or target must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { GameObject* pGO = _FindGameObject(pSummoner, step.script->RespawnGameobject.GOGuid); if (!pGO) { sLog->outError(LOG_FILTER_TSCR, "%s gameobject was not found (guid: %u).", step.script->GetDebugInfo().c_str(), step.script->RespawnGameobject.GOGuid); break; } if (pGO->GetGoType() == GAMEOBJECT_TYPE_FISHINGNODE || pGO->GetGoType() == GAMEOBJECT_TYPE_DOOR || pGO->GetGoType() == GAMEOBJECT_TYPE_BUTTON || pGO->GetGoType() == GAMEOBJECT_TYPE_TRAP) { sLog->outError(LOG_FILTER_TSCR, "%s can not be used with gameobject of type %u (guid: %u).", step.script->GetDebugInfo().c_str(), uint32(pGO->GetGoType()), step.script->RespawnGameobject.GOGuid); break; } // Check that GO is not spawned if (!pGO->isSpawned()) { int32 nTimeToDespawn = std::max(5, int32(step.script->RespawnGameobject.DespawnDelay)); pGO->SetLootState(GO_READY); pGO->SetRespawnTime(nTimeToDespawn); pGO->GetMap()->AddToMap(pGO); } } break; case SCRIPT_COMMAND_TEMP_SUMMON_CREATURE: { // Source must be WorldObject. if (WorldObject* pSummoner = _GetScriptWorldObject(source, true, step.script)) { if (!step.script->TempSummonCreature.CreatureEntry) sLog->outError(LOG_FILTER_TSCR, "%s creature entry (datalong) is not specified.", step.script->GetDebugInfo().c_str()); else { float x = step.script->TempSummonCreature.PosX; float y = step.script->TempSummonCreature.PosY; float z = step.script->TempSummonCreature.PosZ; float o = step.script->TempSummonCreature.Orientation; if (!pSummoner->SummonCreature(step.script->TempSummonCreature.CreatureEntry, x, y, z, o, TEMPSUMMON_TIMED_OR_DEAD_DESPAWN, step.script->TempSummonCreature.DespawnDelay)) sLog->outError(LOG_FILTER_TSCR, "%s creature was not spawned (entry: %u).", step.script->GetDebugInfo().c_str(), step.script->TempSummonCreature.CreatureEntry); } } break; } case SCRIPT_COMMAND_OPEN_DOOR: case SCRIPT_COMMAND_CLOSE_DOOR: _ScriptProcessDoor(source, target, step.script); break; case SCRIPT_COMMAND_ACTIVATE_OBJECT: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { // Target must be GameObject. if (!target) { sLog->outError(LOG_FILTER_TSCR, "%s target object is NULL.", step.script->GetDebugInfo().c_str()); break; } if (target->GetTypeId() != TYPEID_GAMEOBJECT) { sLog->outError(LOG_FILTER_TSCR, "%s target object is not gameobject (TypeId: %u, Entry: %u, GUID: %u), skipping.", step.script->GetDebugInfo().c_str(), target->GetTypeId(), target->GetEntry(), target->GetGUIDLow()); break; } if (GameObject* pGO = target->ToGameObject()) pGO->Use(unit); } break; case SCRIPT_COMMAND_REMOVE_AURA: { // Source (datalong2 != 0) or target (datalong2 == 0) must be Unit. bool bReverse = step.script->RemoveAura.Flags & SF_REMOVEAURA_REVERSE; if (Unit* unit = _GetScriptUnit(bReverse ? source : target, bReverse, step.script)) unit->RemoveAurasDueToSpell(step.script->RemoveAura.SpellID); break; } case SCRIPT_COMMAND_CAST_SPELL: { // TODO: Allow gameobjects to be targets and casters if (!source && !target) { sLog->outError(LOG_FILTER_TSCR, "%s source and target objects are NULL.", step.script->GetDebugInfo().c_str()); break; } Unit* uSource = NULL; Unit* uTarget = NULL; // source/target cast spell at target/source (script->datalong2: 0: s->t 1: s->s 2: t->t 3: t->s switch (step.script->CastSpell.Flags) { case SF_CASTSPELL_SOURCE_TO_TARGET: // source -> target uSource = source ? source->ToUnit() : NULL; uTarget = target ? target->ToUnit() : NULL; break; case SF_CASTSPELL_SOURCE_TO_SOURCE: // source -> source uSource = source ? source->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_TARGET: // target -> target uSource = target ? target->ToUnit() : NULL; uTarget = uSource; break; case SF_CASTSPELL_TARGET_TO_SOURCE: // target -> source uSource = target ? target->ToUnit() : NULL; uTarget = source ? source->ToUnit() : NULL; break; case SF_CASTSPELL_SEARCH_CREATURE: // source -> creature with entry uSource = source ? source->ToUnit() : NULL; uTarget = uSource ? GetClosestCreatureWithEntry(uSource, abs(step.script->CastSpell.CreatureEntry), step.script->CastSpell.SearchRadius) : NULL; break; } if (!uSource || !uSource->isType(TYPEMASK_UNIT)) { sLog->outError(LOG_FILTER_TSCR, "%s no source unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } if (!uTarget || !uTarget->isType(TYPEMASK_UNIT)) { sLog->outError(LOG_FILTER_TSCR, "%s no target unit found for spell %u", step.script->GetDebugInfo().c_str(), step.script->CastSpell.SpellID); break; } bool triggered = (step.script->CastSpell.Flags != 4) ? step.script->CastSpell.CreatureEntry & SF_CASTSPELL_TRIGGERED : step.script->CastSpell.CreatureEntry < 0; uSource->CastSpell(uTarget, step.script->CastSpell.SpellID, triggered); break; } case SCRIPT_COMMAND_PLAY_SOUND: // Source must be WorldObject. if (WorldObject* object = _GetScriptWorldObject(source, true, step.script)) { // PlaySound.Flags bitmask: 0/1=anyone/target Player* player = NULL; if (step.script->PlaySound.Flags & SF_PLAYSOUND_TARGET_PLAYER) { // Target must be Player. player = _GetScriptPlayer(target, false, step.script); if (!target) break; } // PlaySound.Flags bitmask: 0/2=without/with distance dependent if (step.script->PlaySound.Flags & SF_PLAYSOUND_DISTANCE_SOUND) object->PlayDistanceSound(step.script->PlaySound.SoundID, player); else object->PlayDirectSound(step.script->PlaySound.SoundID, player); } break; case SCRIPT_COMMAND_CREATE_ITEM: // Target or source must be Player. if (Player* pReceiver = _GetScriptPlayerSourceOrTarget(source, target, step.script)) { ItemPosCountVec dest; InventoryResult msg = pReceiver->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, step.script->CreateItem.ItemEntry, step.script->CreateItem.Amount); if (msg == EQUIP_ERR_OK) { if (Item* item = pReceiver->StoreNewItem(dest, step.script->CreateItem.ItemEntry, true)) pReceiver->SendNewItem(item, step.script->CreateItem.Amount, false, true); } else pReceiver->SendEquipError(msg, NULL, NULL, step.script->CreateItem.ItemEntry); } break; case SCRIPT_COMMAND_DESPAWN_SELF: // Target or source must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script, true)) cSource->DespawnOrUnsummon(step.script->DespawnSelf.DespawnDelay); break; case SCRIPT_COMMAND_LOAD_PATH: // Source must be Unit. if (Unit* unit = _GetScriptUnit(source, true, step.script)) { if (!sWaypointMgr->GetPath(step.script->LoadPath.PathID)) sLog->outError(LOG_FILTER_TSCR, "%s source object has an invalid path (%u), skipping.", step.script->GetDebugInfo().c_str(), step.script->LoadPath.PathID); else unit->GetMotionMaster()->MovePath(step.script->LoadPath.PathID, step.script->LoadPath.IsRepeatable); } break; case SCRIPT_COMMAND_CALLSCRIPT_TO_UNIT: { if (!step.script->CallScript.CreatureEntry) { sLog->outError(LOG_FILTER_TSCR, "%s creature entry is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } if (!step.script->CallScript.ScriptID) { sLog->outError(LOG_FILTER_TSCR, "%s script id is not specified, skipping.", step.script->GetDebugInfo().c_str()); break; } Creature* cTarget = NULL; if (source) //using grid searcher { WorldObject* wSource = dynamic_cast <WorldObject*> (source); CellCoord p(MistCore::ComputeCellCoord(wSource->GetPositionX(), wSource->GetPositionY())); Cell cell(p); MistCore::CreatureWithDbGUIDCheck target_check(wSource, step.script->CallScript.CreatureEntry); MistCore::CreatureSearcher<MistCore::CreatureWithDbGUIDCheck> checker(wSource, cTarget, target_check); TypeContainerVisitor<MistCore::CreatureSearcher <MistCore::CreatureWithDbGUIDCheck>, GridTypeMapContainer > unit_checker(checker); cell.Visit(p, unit_checker, *wSource->GetMap(), *wSource, wSource->GetGridActivationRange()); } else //check hashmap holders { if (CreatureData const* data = sObjectMgr->GetCreatureData(step.script->CallScript.CreatureEntry)) cTarget = ObjectAccessor::GetObjectInWorld<Creature>(data->mapid, data->posX, data->posY, MAKE_NEW_GUID(step.script->CallScript.CreatureEntry, data->id, HIGHGUID_UNIT), cTarget); } if (!cTarget) { sLog->outError(LOG_FILTER_TSCR, "%s target was not found (entry: %u)", step.script->GetDebugInfo().c_str(), step.script->CallScript.CreatureEntry); break; } //Lets choose our ScriptMap map ScriptMapMap* datamap = GetScriptsMapByType(ScriptsType(step.script->CallScript.ScriptType)); //if no scriptmap present... if (!datamap) { sLog->outError(LOG_FILTER_TSCR, "%s unknown scriptmap (%u) specified, skipping.", step.script->GetDebugInfo().c_str(), step.script->CallScript.ScriptType); break; } // Insert script into schedule but do not start it ScriptsStart(*datamap, step.script->CallScript.ScriptID, cTarget, NULL); break; } case SCRIPT_COMMAND_KILL: // Source or target must be Creature. if (Creature* cSource = _GetScriptCreatureSourceOrTarget(source, target, step.script)) { if (cSource->isDead()) sLog->outError(LOG_FILTER_TSCR, "%s creature is already dead (Entry: %u, GUID: %u)", step.script->GetDebugInfo().c_str(), cSource->GetEntry(), cSource->GetGUIDLow()); else { cSource->setDeathState(JUST_DIED); if (step.script->Kill.RemoveCorpse == 1) cSource->RemoveCorpse(); } } break; case SCRIPT_COMMAND_ORIENTATION: // Source must be Unit. if (Unit* sourceUnit = _GetScriptUnit(source, true, step.script)) { if (step.script->Orientation.Flags & SF_ORIENTATION_FACE_TARGET) { // Target must be Unit. Unit* targetUnit = _GetScriptUnit(target, false, step.script); if (!targetUnit) break; sourceUnit->SetInFront(targetUnit); } else sourceUnit->SetOrientation(step.script->Orientation.Orientation); sourceUnit->SendMovementFlagUpdate(); } break; case SCRIPT_COMMAND_EQUIP: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->LoadEquipment(step.script->Equip.EquipmentID); break; case SCRIPT_COMMAND_MODEL: // Source must be Creature. if (Creature* cSource = _GetScriptCreature(source, true, step.script)) cSource->SetDisplayId(step.script->Model.ModelID); break; case SCRIPT_COMMAND_CLOSE_GOSSIP: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->PlayerTalkClass->SendCloseGossip(); break; case SCRIPT_COMMAND_PLAYMOVIE: // Source must be Player. if (Player* player = _GetScriptPlayer(source, true, step.script)) player->SendMovieStart(step.script->PlayMovie.MovieID); break; default: sLog->outError(LOG_FILTER_TSCR, "Unknown script command %s.", step.script->GetDebugInfo().c_str()); break; } m_scriptSchedule.erase(iter); iter = m_scriptSchedule.begin(); sScriptMgr->DecreaseScheduledScriptCount(); } }
void UpdateAI(const uint32 diff) { //Check if we have a target if (!UpdateVictim()) { //No target so we'll use this section to do our random wispers instance wide //WisperTimer if (WisperTimer <= diff) { Map *map = me->GetMap(); if (!map->IsDungeon()) return; Map::PlayerList const &PlayerList = map->GetPlayers(); for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) { if (Player* i_pl = i->getSource()) { //Play random sound to the zone i_pl->SendPlaySound(RANDOM_SOUND_WHISPER, true); } } //One random wisper every 90 - 300 seconds WisperTimer = 90000 + (rand()% 210000); } else WisperTimer -= diff; return; } me->SetUInt64Value(UNIT_FIELD_TARGET, 0); //No instance if (!pInst) return; switch (pInst->GetData(DATA_CTHUN_PHASE)) { //Transition phase case 2: { //PhaseTimer if (PhaseTimer <= diff) { //Switch pInst->SetData(DATA_CTHUN_PHASE, 3); //Switch to c'thun model me->InterruptNonMeleeSpells(false); DoCast(me, SPELL_TRANSFORM, false); me->SetHealth(me->GetMaxHealth()); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE | UNIT_FLAG_NON_ATTACKABLE); //Emerging phase //AttackStart(Unit::GetUnit(*me, HoldPlayer)); DoZoneInCombat(); //Place all units in threat list on outside of stomach Stomach_Map.clear(); std::list<HostileReference*>::iterator i = me->getThreatManager().getThreatList().begin(); for (; i != me->getThreatManager().getThreatList().end(); ++i) { //Outside stomach Stomach_Map[(*i)->getUnitGuid()] = false; } //Spawn 2 flesh tentacles FleshTentaclesKilled = 0; Creature* Spawned; //Spawn flesh tentacle Spawned = (Creature*)me->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); if (!Spawned) FleshTentaclesKilled++; else ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(me->GetGUID()); //Spawn flesh tentacle Spawned = (Creature*)me->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); if (!Spawned) FleshTentaclesKilled++; else ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(me->GetGUID()); PhaseTimer = 0; } else PhaseTimer -= diff; }break; //Body Phase case 3: { //Remove Target field me->SetUInt64Value(UNIT_FIELD_TARGET, 0); //Weaken if (FleshTentaclesKilled > 1) { pInst->SetData(DATA_CTHUN_PHASE, 4); DoScriptText(EMOTE_WEAKENED, me); PhaseTimer = 45000; DoCast(me, SPELL_RED_COLORATION, true); UNORDERED_MAP<uint64, bool>::iterator i = Stomach_Map.begin(); //Kick all players out of stomach while (i != Stomach_Map.end()) { //Check for valid player Unit* pUnit = Unit::GetUnit(*me, i->first); //Only move units in stomach if (pUnit && i->second == true) { //Teleport each player out DoTeleportPlayer(pUnit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+10, float(rand()%6)); //Cast knockback on them DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); //Remove the acid debuff pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); i->second = false; } ++i; } return; } //Stomach acid if (StomachAcidTimer <= diff) { //Apply aura to all players in stomach UNORDERED_MAP<uint64, bool>::iterator i = Stomach_Map.begin(); while (i != Stomach_Map.end()) { //Check for valid player Unit* pUnit = Unit::GetUnit(*me, i->first); //Only apply to units in stomach if (pUnit && i->second == true) { //Cast digestive acid on them DoCast(pUnit, SPELL_DIGESTIVE_ACID, true); //Check if player should be kicked from stomach if (pUnit->GetDistance(KICK_X, KICK_Y, KICK_Z) < 15) { //Teleport each player out DoTeleportPlayer(pUnit, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ()+10, float(rand()%6)); //Cast knockback on them DoCast(pUnit, SPELL_EXIT_STOMACH_KNOCKBACK, true); //Remove the acid debuff pUnit->RemoveAurasDueToSpell(SPELL_DIGESTIVE_ACID); i->second = false; } } ++i; } StomachAcidTimer = 4000; } else StomachAcidTimer -= diff; //Stomach Enter Timer if (StomachEnterTimer <= diff) { Unit* pTarget = NULL; pTarget = SelectRandomNotStomach(); if (pTarget) { //Set target in stomach Stomach_Map[pTarget->GetGUID()] = true; pTarget->InterruptNonMeleeSpells(false); pTarget->CastSpell(pTarget, SPELL_MOUTH_TENTACLE, true, NULL, NULL, me->GetGUID()); StomachEnterTarget = pTarget->GetGUID(); StomachEnterVisTimer = 3800; } StomachEnterTimer = 13800; } else StomachEnterTimer -= diff; if (StomachEnterVisTimer && StomachEnterTarget) { if (StomachEnterVisTimer <= diff) { //Check for valid player Unit* pUnit = Unit::GetUnit(*me, StomachEnterTarget); if (pUnit) { DoTeleportPlayer(pUnit, STOMACH_X, STOMACH_Y, STOMACH_Z, STOMACH_O); } StomachEnterTarget = 0; StomachEnterVisTimer = 0; } else StomachEnterVisTimer -= diff; } //GientClawTentacleTimer if (GiantClawTentacleTimer <= diff) { Unit* pTarget = NULL; pTarget = SelectRandomNotStomach(); if (pTarget) { Creature* Spawned = NULL; //Spawn claw tentacle on the random target Spawned = (Creature*)me->SummonCreature(MOB_GIANT_CLAW_TENTACLE,pTarget->GetPositionX(),pTarget->GetPositionY(),pTarget->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); if (Spawned) Spawned->AI()->AttackStart(pTarget); } //One giant claw tentacle every minute GiantClawTentacleTimer = 60000; } else GiantClawTentacleTimer -= diff; //GiantEyeTentacleTimer if (GiantEyeTentacleTimer <= diff) { Unit* pTarget = NULL; pTarget = SelectRandomNotStomach(); if (pTarget) { Creature* Spawned = NULL; //Spawn claw tentacle on the random target Spawned = (Creature*)me->SummonCreature(MOB_GIANT_EYE_TENTACLE,pTarget->GetPositionX(),pTarget->GetPositionY(),pTarget->GetPositionZ(),0,TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT,500); if (Spawned) Spawned->AI()->AttackStart(pTarget); } //One giant eye tentacle every minute GiantEyeTentacleTimer = 60000; } else GiantEyeTentacleTimer -= diff; //EyeTentacleTimer if (EyeTentacleTimer <= diff) { //Spawn the 8 Eye Tentacles in the corret spots SpawnEyeTentacle(0, 25); //south SpawnEyeTentacle(12, 12); //south west SpawnEyeTentacle(25, 0); //west SpawnEyeTentacle(12, -12); //north west SpawnEyeTentacle(0, -25); //north SpawnEyeTentacle(-12, -12); //north east SpawnEyeTentacle(-25, 0); // east SpawnEyeTentacle(-12, 12); // south east //These spawn at every 30 seconds EyeTentacleTimer = 30000; } else EyeTentacleTimer -= diff; }break; //Weakened state case 4: { //PhaseTimer if (PhaseTimer <= diff) { //Switch pInst->SetData(DATA_CTHUN_PHASE, 3); //Remove red coloration me->RemoveAurasDueToSpell(SPELL_RED_COLORATION); //Spawn 2 flesh tentacles FleshTentaclesKilled = 0; Creature* Spawned; //Spawn flesh tentacle Spawned = (Creature*)me->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS1_X, TENTACLE_POS1_Y, TENTACLE_POS1_Z, TENTACLE_POS1_O, TEMPSUMMON_CORPSE_DESPAWN, 0); if (!Spawned) FleshTentaclesKilled++; else ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(me->GetGUID()); //Spawn flesh tentacle Spawned = (Creature*)me->SummonCreature(MOB_FLESH_TENTACLE, TENTACLE_POS2_X, TENTACLE_POS2_Y, TENTACLE_POS2_Z, TENTACLE_POS2_O, TEMPSUMMON_CORPSE_DESPAWN, 0); if (!Spawned) FleshTentaclesKilled++; else ((flesh_tentacleAI*)(Spawned->AI()))->SpawnedByCthun(me->GetGUID()); PhaseTimer = 0; } else PhaseTimer -= diff; } } }
bool FleeingMovementGenerator<T>::_setMoveData(T &owner) { float cur_dist_xyz = owner.GetDistance(i_caster_x, i_caster_y, i_caster_z); if(i_to_distance_from_caster > 0.0f) { if((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) || // if we reach lower distance (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) || // if we can't be close (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) || // if we reach bigger distance (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE) ) // if we leave 'quiet zone' { // we are very far or too close, stopping i_to_distance_from_caster = 0.0f; i_nextCheckTime.Reset( urand(500,1000) ); return false; } else { // now we are running, continue i_last_distance_from_caster = cur_dist_xyz; return true; } } float cur_dist; float angle_to_caster; Unit * fright = ObjectAccessor::GetUnit(owner, i_frightGUID); if(fright) { cur_dist = fright->GetDistance(&owner); if(cur_dist < cur_dist_xyz) { i_caster_x = fright->GetPositionX(); i_caster_y = fright->GetPositionY(); i_caster_z = fright->GetPositionZ(); angle_to_caster = fright->GetAngle(&owner); } else { cur_dist = cur_dist_xyz; angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI; } } else { cur_dist = cur_dist_xyz; angle_to_caster = owner.GetAngle(i_caster_x, i_caster_y) + M_PI; } // if we too close may use 'path-finding' else just stop i_only_forward = cur_dist >= MIN_QUIET_DISTANCE/3; //get angle and 'distance from caster' to run float angle; if(i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time { angle = rand_norm()*(1.0f - cur_dist/MIN_QUIET_DISTANCE) * M_PI/3 + rand_norm()*M_PI*2/3; i_to_distance_from_caster = MIN_QUIET_DISTANCE; i_only_forward = true; } else if(cur_dist < MIN_QUIET_DISTANCE) { angle = M_PI/6 + rand_norm()*M_PI*2/3; i_to_distance_from_caster = cur_dist*2/3 + rand_norm()*(MIN_QUIET_DISTANCE - cur_dist*2/3); } else if(cur_dist > MAX_QUIET_DISTANCE) { angle = rand_norm()*M_PI/3 + M_PI*2/3; i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); } else { angle = rand_norm()*M_PI; i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + rand_norm()*(MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); } int8 sign = rand_norm() > 0.5f ? 1 : -1; i_cur_angle = sign*angle + angle_to_caster; // current distance i_last_distance_from_caster = cur_dist; return true; }
void DoNormalAttack(uint32 diff) { opponent = me->GetVictim(); if (opponent) { if (!IsCasting()) StartAttack(opponent); } else return; AttackerSet m_attackers = master->getAttackers(); AttackerSet b_attackers = me->getAttackers(); Unit* u = me->SelectNearestTarget(20); //ICE_BARRIER if (ICE_BARRIER && Ice_Barrier_cd <= diff && u && u->GetVictim() == me && u->GetDistance(me) < 8 && !me->HasAura(ICE_BARRIER)) { if (me->IsNonMeleeSpellCast(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, ICE_BARRIER)) { Ice_Barrier_cd = 25000; GC_Timer = 800; return; } } if ((!ICE_BARRIER || Ice_Barrier_cd > diff) && BLINK && Blink_cd < 3000 && u && u->GetVictim() == me && u->GetDistance(me) < 6 && !me->HasAura(ICE_BARRIER)) { if (me->IsNonMeleeSpellCast(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, BLINK)) { Blink_cd = 13000; GC_Timer = 800; return; } } if (me->HasAura(ICEBLOCK)) if (((GetManaPCT(me) > 45 && GetHealthPCT(me) > 80) || b_attackers.empty()) && Iceblock_cd <= 57000 && tank) me->RemoveAurasDueToSpell(ICEBLOCK); //ICEBLOCK if (ICEBLOCK && Rand() < 50 && !b_attackers.empty() && tank && Iceblock_cd <= diff && (GetManaPCT(me) < 15 || GetHealthPCT(me) < 45 || b_attackers.size() > 4) && !me->HasAura(ICEBLOCK)) { if (me->IsNonMeleeSpellCast(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, ICEBLOCK)) { Iceblock_cd = 60000; Nova_cd = 0; //Glyph of Iceblock return; } } if (IsCasting()) return; float dist = me->GetExactDist(opponent); BOLT = (CCed(opponent, true) || !FROSTBOLT) ? FIREBALL : FROSTBOLT; NOVA = BOLT == FROSTBOLT && BLASTWAVE && dist > 5 ? BLASTWAVE : FROSTNOVA ? FROSTNOVA : 0; ////Combustion doesn't work properly on 434 (14.08.13) //if (COMBUSTION && Combustion_cd <= diff && Rand() < 15 && dist < 40) //{ // if (opponent->HasAuraTypeWithCaster(SPELL_AURA_PERIODIC_DAMAGE, me->GetGUID())) // { // temptimer = GC_Timer; // if (doCast(me, COMBUSTION)) // { // Combustion_cd = 60000; // Nova_cd = 0; FireBlast_cd = 0; DragonBreath_cd = 0; // } // GC_Timer = temptimer; // } //} //DAMAGE //PYROBLAST if (PYROBLAST && Pyroblast_cd <= diff && GC_Timer <= diff && Rand() < 95 && (b_attackers.size() < 2 || (*b_attackers.begin()) == opponent) && dist < 40 && opponent->IsPolymorphed() && doCast(opponent, PYROBLAST)) { Pyroblast_cd = 7500; //debug DragonBreath_cd = std::max<uint32>(DragonBreath_cd, 450); Nova_cd = std::max<uint32>(Nova_cd, 450); return; } //nova //TODO: SEPARATE u = me->SelectNearestTarget(6.3f); if (NOVA && Nova_cd <= diff && u && Rand() < 75 && !CCed(u, true) && IsInBotParty(u->GetVictim())) { if (doCast(me, NOVA)) { Nova_cd = 15000; GetInPosition(true); return; } } //living bomb if (LIVINGBOMB && Living_Bomb_cd <= diff && GC_Timer <= diff && Rand() < 45 && dist < 40 && opponent->GetHealth() > me->GetHealth()/2 && !opponent->HasAura(LIVINGBOMB, me->GetGUID()) && doCast(opponent, LIVINGBOMB)) { Living_Bomb_cd = 6000; GC_Timer = 500; return; } //cone of cold if (CONEOFCOLD && ConeofCold_cd <= diff && GC_Timer <= diff && Rand() < 50 && dist < 7 && me->HasInArc(M_PI*0.75f, opponent) && doCast(opponent, CONEOFCOLD)) { ConeofCold_cd = 8000; GC_Timer = 500; GetInPosition(true); return; } //dragon's breath if (DRAGONBREATH && DragonBreath_cd <= diff && GC_Timer <= diff && !CCed(opponent, true) && ((me->HasInArc(M_PI*0.75f, opponent) && dist < 7) || (u && u != opponent && me->HasInArc(M_PI*0.75f, u) && IsInBotParty(u->GetVictim()))) && doCast(/*opponent*/me, DRAGONBREATH)) { DragonBreath_cd = 15000; GC_Timer = 800; return; } /*//blast wave //TODO Separate again u = me->SelectNearestTarget(8); if (BLASTWAVE != 0 && u && isTimerReady(BlastWave_cd) && !HasAuraName(u, FROSTNOVA) && !HasAuraName(u, DRAGONBREATH) && doCast(me, BLASTWAVE)) { BlastWave_cd = BLASTWAVE_CD; GC_Timer = 800; }*/ //fire blast if (FIREBLAST && FireBlast_cd <= diff && GC_Timer <= diff && dist < 40) { if (Rand() < 20 + 80*(!opponent->isFrozen() && !opponent->HasAuraType(SPELL_AURA_MOD_STUN) && me->HasAura(IMPACT_BUFF))) { if (doCast(opponent, FIREBLAST)) { FireBlast_cd = 6000; GC_Timer = 500; return; } } } //flamestrike - use Improved Flamestrike for instant cast if (FLAMESTRIKE && GC_Timer <= diff && me->getLevel() >= 50 && Rand() < 25) { Unit* FStarget = FindAOETarget(40, true, false); if (FStarget && doCast(FStarget, FLAMESTRIKE, true)) return; } //blizzard if (BLIZZARD && Blizzard_cd <= diff && !me->isMoving() && Rand() < 40) { Unit* blizztarget = FindAOETarget(35, true); if (blizztarget && doCast(blizztarget, BLIZZARD)) { Blizzard_cd = 5000; return; } Blizzard_cd = 1500; //fail } //Frost of Fire Bolt if (BOLT && Bolt_cd <= diff && Rand() < 75 && dist < 35 && doCast(opponent, BOLT)) { Bolt_cd = uint32(float(sSpellMgr->GetSpellInfo(BOLT)->CalcCastTime()/100) * me->GetFloatValue(UNIT_MOD_CAST_SPEED) + 200); //debug DragonBreath_cd = std::max<uint32>(DragonBreath_cd, 450); Nova_cd = std::max<uint32>(Nova_cd, 450); return; } ////Arcane Missiles //if (Rand() < 15 && GC_Timer <= diff && !me->isMoving() && dist < 40 && // doCast(opponent, ARCANEMISSILES)) // return; }
void DoNormalAttack(uint32 diff) { opponent = me->GetVictim(); if (opponent) { if (!IsCasting()) StartAttack(opponent); } else return; AttackerSet m_attackers = master->getAttackers(); AttackerSet b_attackers = me->getAttackers(); Unit* u = me->SelectNearestTarget(20); //ICE_BARRIER if (ICE_BARRIER && Ice_Barrier_cd <= diff && u && u->GetVictim() == me && u->GetDistance(me) < 8 && !me->HasAura(ICE_BARRIER)) { if (me->IsNonMeleeSpellCasted(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, ICE_BARRIER)) { Ice_Barrier_cd = 41000 - me->getLevel()*200;//down to 25 sec on 80 GC_Timer = 800; return; } } if ((!ICE_BARRIER || Ice_Barrier_cd > diff) && BLINK && Blink_cd < 3000 && u && u->GetVictim() == me && !me->HasAura(ICE_BARRIER) && u->GetDistance(me) < 6) { if (me->IsNonMeleeSpellCasted(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, BLINK)) { Blink_cd = 15000 - me->getLevel()/4 * 100; GC_Timer = 800; return; } } if (me->HasAura(ICEBLOCK)) if (((GetManaPCT(me) > 45 && GetHealthPCT(me) > 80) || b_attackers.empty()) && Iceblock_cd <= 57000 && tank) me->RemoveAurasDueToSpell(ICEBLOCK); //ICEBLOCK if (ICEBLOCK && Rand() < 50 && !b_attackers.empty() && tank && Iceblock_cd <= diff && (GetManaPCT(me) < 15 || GetHealthPCT(me) < 45 || b_attackers.size() > 4) && !me->HasAura(ICEBLOCK)) { if (me->IsNonMeleeSpellCasted(true)) me->InterruptNonMeleeSpells(true); if (doCast(me, ICEBLOCK)) { Iceblock_cd = 60000; return; } } if (IsCasting()) return; BOLT = (CCed(opponent, true) || (opponent->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISARMED) && me->HasAura(COMBUSTION))) ? FIREBALL : FROSTBOLT; NOVA = BOLT == FIREBALL && BLASTWAVE ? BLASTWAVE : FROSTNOVA ? FROSTNOVA : 0; float dist = me->GetExactDist(opponent); if (dist > 30) return; if (COMBUSTION && Rand() < 15 && (opponent->GetMaxHealth() > master->GetMaxHealth()*10 || m_attackers.size() > 1 || b_attackers.size() > 2)) { if (!HasAuraName(me, "Combustion") && Combustion_cd <= diff) { temptimer = GC_Timer; if (doCast(me, COMBUSTION)) { Combustion_cd = 60000; //Reset timers for fun Nova_cd = 0; FireBlast_cd = 0; DragonBreath_cd = 0; } GC_Timer = temptimer; } } //DAMAGE //PYROBLAST if (PYROBLAST && Rand() < 75 && Pyroblast_cd <= diff && GC_Timer <= diff && b_attackers.size() < 2 && dist < 30 && opponent->IsPolymorphed() && doCast(opponent, PYROBLAST)) Pyroblast_cd = 50; //nova //TODO: SEPARATE u = me->SelectNearestTarget(7); if (u && NOVA && Nova_cd <= diff && !CCed(u, true) && IsInBotParty(u->GetVictim())) { Unit* tar = u->GetVictim(); if (tar && IsInBotParty(tar) && doCast(me, NOVA)) { Nova_cd = 15000; return; } } //living bomb if (LIVINGBOMB && Rand() < 25 && Living_Bomb_cd <= diff && GC_Timer <= diff && dist < 30 && opponent->GetHealth() > me->GetHealth()/2 && !opponent->HasAura(LIVINGBOMB, me->GetGUID()) && doCast(opponent, LIVINGBOMB)) { Living_Bomb_cd = 6000; GC_Timer = 500; return; } //cone of cold if (CONEOFCOLD && ConeofCold_cd <= diff && GC_Timer <= diff && dist < 7 && me->HasInArc(M_PI, opponent) && doCast(opponent, CONEOFCOLD)) { ConeofCold_cd = 14000; GC_Timer = 500; return; } //dragon's breath u = me->SelectNearestTarget(7); if (DRAGONBREATH && u && DragonBreath_cd <= diff && GC_Timer <= diff && me->HasInArc(M_PI, opponent) && !HasAuraName(u, FROSTNOVA) && doCast(opponent, DRAGONBREATH)) { DragonBreath_cd = 25000; GC_Timer = 800; return; } /*//blast wave //TODO Separate again u = me->SelectNearestTarget(8); if (BLASTWAVE != 0 && u && isTimerReady(BlastWave_cd) && !HasAuraName(u, FROSTNOVA) && !HasAuraName(u, DRAGONBREATH) && doCast(me, BLASTWAVE)) { BlastWave_cd = BLASTWAVE_CD; GC_Timer = 800; }*/ //fire blast if (FireBlast_cd <= diff && GC_Timer <= diff && dist < 20 && Rand() < 20 + 80*(!opponent->HasAuraType(SPELL_AURA_MOD_STUN) && me->HasAura(IMPACT_BUFF)) && doCast(opponent, FIREBLAST)) { FireBlast_cd = 6000; GC_Timer = 500; return; } //flamestrike if (GC_Timer <= diff && Rand() < 60 && me->HasAura(FIRESTARTERBUFF)) { Unit* FStarget = FindAOETarget(30, true, false); if (FStarget && doCast(FStarget, FLAMESTRIKE, true)) { me->RemoveAurasDueToSpell(FIRESTARTERBUFF); GC_Timer = 0; return; } } //blizzard if (BLIZZARD && Rand() < 80 && Blizzard_cd <= diff) { Unit* blizztarget = FindAOETarget(30, true); if (blizztarget && doCast(blizztarget, BLIZZARD)) { Blizzard_cd = 5000; return; } Blizzard_cd = 2000;//fail } //Frost of Fire Bolt if (Rand() < 75 && Bolt_cd <= diff && dist < 30 && doCast(opponent, BOLT)) { Bolt_cd = uint32(float(sSpellMgr->GetSpellInfo(BOLT)->CalcCastTime()/100) * me->GetFloatValue(UNIT_MOD_CAST_SPEED) + 200); return; } //Arcane Missiles if (Rand() < 10 && GC_Timer <= diff && !me->isMoving() && dist < 20 && doCast(opponent, ARCANEMISSILES)) return; }
// functor for operator "<" bool operator()(const Unit* _Left, const Unit* _Right) const { return (MainTarget->GetDistance(_Left) < MainTarget->GetDistance(_Right)); }