/** * FleeFromNpcWithAuraIfCan() * return boolean Check if the bot can move from a creature having a specific aura, then try to find a proper destination and move towards it * * params: goEntry uint32 the ID of the hostile trap the bot is supposed to move from. It is used to find the radius of the trap * params: spellId uint32 the spell ID of the aura the creature is supposed to have (directly or from triggered spell). It is used to find the radius of the aura * params: pTarget Unit* the creature or gameobject the bot will use to define one of the prefered direction in which to flee * * return true if bot has found a proper destination, false if none was found */ bool PlayerbotClassAI::FleeFromNpcWithAuraIfCan(uint32 NpcEntry, uint32 spellId, Unit* pTarget) { if (!m_bot) return false; if (!NpcEntry) return false; if (!spellId) return false; // Step 1: Get radius from hostile aura spell float radius = 0; SpellEntry const* spellproto = sSpellTemplate.LookupEntry<SpellEntry>(spellId); if (spellproto) radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellproto->EffectRadiusIndex[EFFECT_INDEX_0])); if (radius == 0) return false; // Step 2: find a close creature with the right entry: Creature* pCreature = nullptr; MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck creature_check(*m_bot, NpcEntry, false, false, radius, true); MaNGOS::CreatureLastSearcher<MaNGOS::NearestCreatureEntryWithLiveStateInObjectRangeCheck> searcher(pCreature, creature_check); Cell::VisitGridObjects(m_bot, searcher, radius); if (!pCreature) return false; // Force to flee on a direction opposite to the position of the creature (fleeing from it, not only avoiding it) return FleeFromPointIfCan(radius, pTarget, pCreature->GetPositionX(), pCreature->GetPositionY(), pCreature->GetPositionZ(), M_PI_F); }
/** * FleeFromAoEIfCan() * return boolean Check if the bot can move out of the hostile AoE spell then try to find a proper destination and move towards it * The AoE is assumed to be centered on the current bot location (this is the case most of the time) * * params: spellId uint32 the spell ID of the hostile AoE the bot is supposed to move from. It is used to find the radius of the AoE spell * params: pTarget Unit* the creature or gameobject the bot will use to define one of the prefered direction in which to flee * * return true if bot has found a proper destination, false if none was found */ bool PlayerbotClassAI::FleeFromAoEIfCan(uint32 spellId, Unit* pTarget) { if (!m_bot) return false; if (!spellId) return false; // Step 1: Get radius from hostile AoE spell float radius = 0; SpellEntry const* spellproto = sSpellTemplate.LookupEntry<SpellEntry>(spellId); if (spellproto) radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellproto->EffectRadiusIndex[EFFECT_INDEX_0])); // Step 2: Get current bot position to move from it float curr_x, curr_y, curr_z; m_bot->GetPosition(curr_x, curr_y, curr_z); return FleeFromPointIfCan(radius, pTarget, curr_x, curr_y, curr_z); }
void GameObject::Update(uint32 diff) { if (IS_MO_TRANSPORT(GetGUID())) { //((Transport*)this)->Update(p_time); return; } switch (m_lootState) { case GO_NOT_READY: { switch(GetGoType()) { case GAMEOBJECT_TYPE_TRAP: { // Arming Time for GAMEOBJECT_TYPE_TRAP (6) Unit* owner = GetOwner(); if (owner && ((Player*)owner)->isInCombat()) m_cooldownTime = time(NULL) + GetGOInfo()->trap.startDelay; m_lootState = GO_READY; break; } case GAMEOBJECT_TYPE_FISHINGNODE: { // fishing code (bobber ready) if( time(NULL) > m_respawnTime - FISHING_BOBBER_READY_TIME ) { // splash bobber (bobber ready now) Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { SetGoState(0); SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); UpdateData udata; WorldPacket packet; BuildValuesUpdateBlockForPlayer(&udata,((Player*)caster)); udata.BuildPacket(&packet); ((Player*)caster)->GetSession()->SendPacket(&packet); WorldPacket data(SMSG_GAMEOBJECT_CUSTOM_ANIM,8+4); data << GetGUID(); data << (uint32)(0); ((Player*)caster)->SendMessageToSet(&data,true); } m_lootState = GO_READY; // can be successfully open with some chance } return; } default: m_lootState = GO_READY; // for other GOis same switched without delay to GO_READY break; } // NO BREAK for switch (m_lootState) } case GO_READY: { if (m_respawnTime > 0) // timer on { if (m_respawnTime <= time(NULL)) // timer expired { m_respawnTime = 0; m_SkillupList.clear(); m_usetimes = 0; switch (GetGoType()) { case GAMEOBJECT_TYPE_FISHINGNODE: // can't fish now { Unit* caster = GetOwner(); if(caster && caster->GetTypeId()==TYPEID_PLAYER) { if(caster->m_currentSpells[CURRENT_CHANNELED_SPELL]) { caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->SendChannelUpdate(0); caster->m_currentSpells[CURRENT_CHANNELED_SPELL]->finish(false); } WorldPacket data(SMSG_FISH_NOT_HOOKED,0); ((Player*)caster)->GetSession()->SendPacket(&data); } // can be delete m_lootState = GO_JUST_DEACTIVATED; return; } case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: //we need to open doors if they are closed (add there another condition if this code breaks some usage, but it need to be here for battlegrounds) if( !GetGoState() ) SwitchDoorOrButton(false); //flags in AB are type_button and we need to add them here so no break! default: if(!m_spawnedByDefault) // despawn timer { // can be despawned or destroyed SetLootState(GO_JUST_DEACTIVATED); return; } // respawn timer MapManager::Instance().GetMap(GetMapId(), this)->Add(this); break; } } } // traps can have time and can not have GameObjectInfo const* goInfo = GetGOInfo(); if(goInfo->type == GAMEOBJECT_TYPE_TRAP) { // traps Unit* owner = GetOwner(); Unit* ok = NULL; // pointer to appropriate target if found any if(m_cooldownTime >= time(NULL)) return; bool IsBattleGroundTrap = false; //FIXME: this is activation radius (in different casting radius that must be selected from spell data) //TODO: move activated state code (cast itself) to GO_ACTIVATED, in this place only check activating and set state float radius = goInfo->trap.radius; if(!radius) { if(goInfo->trap.cooldown != 3) // cast in other case (at some triggering/linked go/etc explicit call) { // try to read radius from trap spell if(const SpellEntry *spellEntry = sSpellStore.LookupEntry(goInfo->trap.spellId)) radius = GetSpellRadius(spellEntry,0,false); // radius = GetSpellRadius(sSpellRadiusStore.LookupEntry(spellEntry->EffectRadiusIndex[0])); if(!radius) break; } else { if(m_respawnTime > 0) break; radius = goInfo->trap.cooldown; // battlegrounds gameobjects has data2 == 0 && data5 == 3 IsBattleGroundTrap = true; } } bool NeedDespawn = (goInfo->trap.charges != 0); CellPair p(Trinity::ComputeCellPair(GetPositionX(),GetPositionY())); Cell cell(p); cell.data.Part.reserved = ALL_DISTRICT; // Note: this hack with search required until GO casting not implemented // search unfriendly creature if(owner && NeedDespawn) // hunter trap { Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck u_check(this, owner, radius); Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck> checker(ok, u_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, GridTypeMapContainer > grid_object_checker(checker); cell_lock->Visit(cell_lock, grid_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); // or unfriendly player/pet if(!ok) { TypeContainerVisitor<Trinity::UnitSearcher<Trinity::AnyUnfriendlyNoTotemUnitInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); } } else // environmental trap { // environmental damage spells already have around enemies targeting but this not help in case not existed GO casting support // affect only players Player* p_ok = NULL; Trinity::AnyPlayerInObjectRangeCheck p_check(this, radius); Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck> checker(p_ok, p_check); CellLock<GridReadGuard> cell_lock(cell, p); TypeContainerVisitor<Trinity::PlayerSearcher<Trinity::AnyPlayerInObjectRangeCheck>, WorldTypeMapContainer > world_object_checker(checker); cell_lock->Visit(cell_lock, world_object_checker, *MapManager::Instance().GetMap(GetMapId(), this)); ok = p_ok; } if (ok) { //Unit *caster = owner ? owner : ok; //caster->CastSpell(ok, goInfo->trap.spellId, true); CastSpell(ok, goInfo->trap.spellId); m_cooldownTime = time(NULL) + 4; // 4 seconds if(NeedDespawn) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed if(IsBattleGroundTrap && ok->GetTypeId() == TYPEID_PLAYER) { //BattleGround gameobjects case if(((Player*)ok)->InBattleGround()) if(BattleGround *bg = ((Player*)ok)->GetBattleGround()) bg->HandleTriggerBuff(GetGUID()); } } } if (m_charges && m_usetimes >= m_charges) SetLootState(GO_JUST_DEACTIVATED); // can be despawned or destroyed break; } case GO_ACTIVATED: { switch(GetGoType()) { case GAMEOBJECT_TYPE_DOOR: case GAMEOBJECT_TYPE_BUTTON: if(GetAutoCloseTime() && (m_cooldownTime < time(NULL))) { SwitchDoorOrButton(false); SetLootState(GO_JUST_DEACTIVATED); } break; case GAMEOBJECT_TYPE_CHEST: if(m_groupLootTimer && lootingGroupLeaderGUID) { if(diff <= m_groupLootTimer) { m_groupLootTimer -= diff; } else { Group* group = objmgr.GetGroupByLeader(lootingGroupLeaderGUID); if (group) group->EndRoll(); m_groupLootTimer = 0; lootingGroupLeaderGUID = 0; } } break; } break; } case GO_JUST_DEACTIVATED: { //if Gameobject should cast spell, then this, but some GOs (type = 10) should be destroyed if (GetGoType() == GAMEOBJECT_TYPE_GOOBER) { uint32 spellId = GetGOInfo()->goober.spellId; if(spellId) { std::set<uint32>::iterator it = m_unique_users.begin(); std::set<uint32>::iterator end = m_unique_users.end(); for (; it != end; it++) { Unit* owner = Unit::GetUnit(*this, uint64(*it)); if (owner) owner->CastSpell(owner, spellId, false); } m_unique_users.clear(); m_usetimes = 0; } //any return here in case battleground traps } if(GetOwnerGUID()) { m_respawnTime = 0; Delete(); return; } //burning flags in some battlegrounds, if you find better condition, just add it if (GetGoAnimProgress() > 0) { SendObjectDeSpawnAnim(this->GetGUID()); //reset flags SetUInt32Value(GAMEOBJECT_FLAGS, GetGOInfo()->flags); } loot.clear(); SetLootState(GO_READY); if(!m_respawnDelayTime) return; if(!m_spawnedByDefault) { m_respawnTime = 0; return; } m_respawnTime = time(NULL) + m_respawnDelayTime; // if option not set then object will be saved at grid unload if(sWorld.getConfig(CONFIG_SAVE_RESPAWN_TIME_IMMEDIATELY)) SaveRespawnTime(); ObjectAccessor::UpdateObjectVisibility(this); break; } } }