bool AIController::ProcessMessage(Unit &unit) { std::vector<Message> messagesReceived = unit.GetMessages(); if(!messagesReceived.empty() && unit.GetTarget()== NULL){ float currentLenght = 0; float bestLenght = (messagesReceived[0].sender->GetPosition() - unit.GetPosition()).Length(); Message closestMessage = messagesReceived[0]; for(std::vector<Message>::iterator it = messagesReceived.begin(); it != messagesReceived.end(); ++it) { Message currentObject = *it; currentLenght = (currentObject.sender->GetPosition() - unit.GetPosition()).Length(); if (currentLenght < bestLenght){ closestMessage = currentObject; bestLenght = currentLenght; } } if(!closestMessage.content.compare("attack") && bestLenght < 400){ unit.SetTarget(closestMessage.target); unit.SetNullDestination(); unit.ClearMessages(); return true; } } unit.ClearMessages(); return false; }
void aiBehaviorAttackTarget::Update( Ogre::Any& owner, float dt ) { Unit* pUnit = Ogre::any_cast<Unit*>(owner); Unit* target = pUnit->GetAttackTarget(); AnimatedComponent* anim = pUnit->GetAnim(); if (target) { //³¯ÏòÄ¿±ê POS targetPos = target->GetPosition(); targetPos.y = pUnit->GetPosition().y; pUnit->GetSceneNode()->lookAt(targetPos, Ogre::Node::TS_WORLD, FLOAT3::UNIT_Z); float fLastAttkTime = pUnit->GetLastAttackPastTime(); fLastAttkTime += dt; float cooldown = pUnit->GetAttackInterval(); pUnit->SetLastAttackPastTime(fLastAttkTime); //¹¥»÷ÀäÈ´ if (fLastAttkTime >= cooldown) { anim->PlayAnimation(eAnimation_Attack, false); target->_OnAttacked(pUnit); pUnit->SetLastAttackPastTime(0); } else if(anim->IsAnimationOver()) { anim->PlayAnimation(eAnimation_Idle, true); } } }
void RandomJump(SpellEffIndex effIndex) { PreventHitDefaultEffect(effIndex); Unit* target = GetHitUnit(); if (!target) return; uint8 roll = urand(0, 1); float angle = frand(0, M_PI); float SpeedXY = frand(10.0f, 30.0f); float SpeedZ = frand(10.0f, 15.0f); float x, y; if (!roll) { target->GetPosition(x, y); target->SetOrientation(angle); target->KnockbackFrom(x, y, SpeedXY, SpeedZ); } else { float dist = frand(10.0f, 30.0f); target->GetNearPoint2D(x, y, dist, angle); target->GetMotionMaster()->MoveJump(x, y, FLOR_COORD_Z, SpeedXY, SpeedZ); } }
// Wrapper to handle movement to the closest trigger void DoMoveToClosestTrigger(bool bGround) { if (!m_pInstance) return; Unit* pChosenTrigger = NULL; GuidList lTriggersList; float fX, fY, fZ; // get the list of wanted triggers m_pInstance->GetNightbaneTriggers(lTriggersList, bGround); // calculate the closest trigger from the list for (GuidList::const_iterator itr = lTriggersList.begin(); itr != lTriggersList.end(); ++itr) { if (Creature* pTrigger = m_creature->GetMap()->GetCreature(*itr)) { if (!pChosenTrigger || m_creature->GetDistanceOrder(pTrigger, pChosenTrigger, false)) pChosenTrigger = pTrigger; } } // Move to trigger position if (pChosenTrigger) { pChosenTrigger->GetPosition(fX, fY, fZ); m_creature->GetMotionMaster()->MovePoint(bGround ? POINT_ID_GROUND : POINT_ID_AIR, fX, fY, fZ); } }
Battle::Position Battle::Position::GetCorrect(const Unit & b, s32 head) { Position result; result.first = Board::GetCell(head); if(result.first && b.isWide()) { result.second = Board::GetCell(head, b.isReflect() ? RIGHT : LEFT); if(! result.second || (result.second != b.GetPosition().GetHead() && ! result.second->isPassable1(true))) { result.second = Board::GetCell(head, b.isReflect() ? LEFT : RIGHT); if(! result.second) result.second = Board::GetCell(head, b.isReflect() ? RIGHT : LEFT); if(result.second) std::swap(result.first, result.second); else DEBUG(DBG_BATTLE, DBG_WARN, "NULL pointer, " << b.String() << ", dst: " << head); } } return result; }
void ModDestHeight(SpellDestination& dest) { Unit* caster = GetCaster(); Position pos = caster->GetPosition(); pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f); dest.Relocate(pos); }
void VehicleKit::Dismount(Unit* passenger, VehicleSeatEntry const* seatInfo) { if (!passenger) return; float ox, oy, oz, oo; Unit* base = m_pBase->GetVehicle() ? m_pBase->GetVehicle()->GetBase() : m_pBase; base->GetPosition(ox, oy, oz); oo = base->GetOrientation(); passenger->SetPosition(ox,oy,oz,oo,false); if (b_dstSet) { // parabolic traectory (catapults, explode, other effects). mostly set destination in DummyEffect. // destination Z not checked in this case! only limited on 8.0 delta. requred full correct set in spelleffects. float speed = ((m_dst_speed > M_NULL_F) ? m_dst_speed : ((seatInfo && seatInfo->m_exitSpeed > M_NULL_F) ? seatInfo->m_exitSpeed : BASE_CHARGE_SPEED)); float verticalSpeed = speed * sin(m_dst_elevation); float horisontalSpeed = speed * cos(m_dst_elevation); float moveTimeHalf = verticalSpeed / ((seatInfo && seatInfo->m_exitGravity > 0.0f) ? seatInfo->m_exitGravity : Movement::gravity); float max_height = - Movement::computeFallElevation(moveTimeHalf,false,-verticalSpeed); passenger->GetMotionMaster()->MoveSkyDiving(m_dst_x,m_dst_y,m_dst_z,passenger->GetOrientation(), horisontalSpeed, max_height, true); } else if (seatInfo) { // half-parabolic traectory (unmount) float horisontalSpeed = seatInfo->m_exitSpeed; if (horisontalSpeed < M_NULL_F) horisontalSpeed = BASE_CHARGE_SPEED; // may be under water base->GetClosePoint(m_dst_x, m_dst_y, m_dst_z, base->GetObjectBoundingRadius(), frand(2.0f, 3.0f), frand(M_PI_F/2.0f,3.0f*M_PI_F/2.0f), passenger); if (m_dst_z < oz) m_dst_z = oz; passenger->GetMotionMaster()->MoveSkyDiving(m_dst_x, m_dst_y, m_dst_z + 0.1f, passenger->GetOrientation(), horisontalSpeed, 0.0f); } else { // jump from vehicle without seatInfo (? error case) base->GetClosePoint(m_dst_x, m_dst_y, m_dst_z, base->GetObjectBoundingRadius(), 2.0f, M_PI_F, passenger); passenger->UpdateAllowedPositionZ(m_dst_x, m_dst_y, m_dst_z); if (m_dst_z < oz) m_dst_z = oz; passenger->GetMotionMaster()->MoveSkyDiving(m_dst_x, m_dst_y, m_dst_z + 0.1f, passenger->GetOrientation(), BASE_CHARGE_SPEED, 0.0f); } DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS,"VehicleKit::Dismount %s from %s (%f %f %f), destination point is %f %f %f", passenger->GetObjectGuid().GetString().c_str(), base->GetObjectGuid().GetString().c_str(), ox,oy,oz, m_dst_x,m_dst_y,m_dst_z); SetDestination(); }
void HandleBouncerSpikes() { Unit* caster = GetCaster(); Vehicle* vehicle = caster->GetVehicleKit(); if (!vehicle) return; for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000)) summon->EnterVehicle(caster, i); }
/// Spell Target Handling for type 29: all object around the caster / object (so it seems) void Spell::SpellTargetTypeTAOE(uint32 i, uint32 j) { Unit* Target = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if( Target == NULL ) return; // tranquility if( u_caster != NULL && m_spellInfo->NameHash == SPELL_HASH_TRANQUILITY ) m_targetUnits[i].push_back(u_caster->GetGUID()); else FillAllTargetsInArea( (LocationVector&)Target->GetPosition(), i ); }
void Reset() { Unit* target = me->FindNearestCreature(ENTRY_THROW_TARGET, 50); if (target) { DoCast(me, SPELL_SHADOW_AXE_DAMAGE); float x, y, z; target->GetPosition(x, y, z); me->GetMotionMaster()->MovePoint(0, x, y, z); } uiDespawnTimer = 7000; }
void Reset() { Unit *pTarget = m_creature->FindNearestCreature(ENTRY_THROW_TARGET,50); if (pTarget) { DoCast(m_creature, DUNGEON_MODE(SPELL_SHADOW_AXE_DAMAGE, H_SPELL_SHADOW_AXE_DAMAGE)); float x,y,z; pTarget->GetPosition(x,y,z); m_creature->GetMotionMaster()->MovePoint(0,x,y,z); } Despawn_Timer = 7000; }
void VehicleKit::Dismount(Unit* passenger, VehicleSeatEntry const* seatInfo) { if (!passenger) return; float ox, oy, oz/*, oo*/; /* oo can be used, but not at the moment*/ Unit* base = m_pBase->GetVehicle() ? m_pBase->GetVehicle()->GetBase() : m_pBase; base->GetPosition(ox, oy, oz); /*oo = base->GetOrientation();*/ passenger->m_movementInfo = base->m_movementInfo; if (b_dstSet) { // parabolic traectory (catapults, explode, other effects). mostly set destination in DummyEffect. // destination Z not checked in this case! only limited on 8.0 delta. requred full correct set in spelleffects. float speed = ((m_dst_speed > 0.0f) ? m_dst_speed : (seatInfo ? seatInfo->m_exitSpeed : 28.0f)); float verticalSpeed = speed * sin(m_dst_elevation); float horisontalSpeed = speed * cos(m_dst_elevation); float moveTimeHalf = verticalSpeed / ((seatInfo && seatInfo->m_exitGravity > 0.0f) ? seatInfo->m_exitGravity : Movement::gravity); float max_height = - Movement::computeFallElevation(moveTimeHalf,false,-verticalSpeed); passenger->MonsterMoveJump(m_dst_x, m_dst_y, m_dst_z,passenger->GetOrientation(), horisontalSpeed, max_height, false); } else if (seatInfo) { // half-parabolic traectory (unmount) float horisontalSpeed = seatInfo->m_exitSpeed; // may be under water base->GetClosePoint(m_dst_x, m_dst_y, m_dst_z, base->GetObjectBoundingRadius(), frand(2.0f, 3.0f), frand(M_PI_F/2.0f,3.0f*M_PI_F/2.0f)); if (m_dst_z < oz) m_dst_z = oz; passenger->MonsterMoveJump(m_dst_x, m_dst_y, m_dst_z + 0.1f, passenger->GetOrientation(), horisontalSpeed, 0.0f, false); } else { // jump from vehicle without seatInfo (? error case) base->GetClosePoint(m_dst_x, m_dst_y, m_dst_z, base->GetObjectBoundingRadius(), 2.0f, M_PI_F); passenger->UpdateAllowedPositionZ(m_dst_x, m_dst_y, m_dst_z); if (m_dst_z < oz) m_dst_z = oz; passenger->MonsterMoveWithSpeed(m_dst_x, m_dst_y, m_dst_z + 0.1f, 28.0f); } SetDestination(); }
/// Spell Target Handling for type 53: Target Area by Players CurrentSelection() void Spell::SpellTargetTargetAreaSelectedUnit(uint32 i, uint32 j) { Unit* Target = NULL; if(m_caster->IsInWorld()) { if(p_caster) Target = m_caster->GetMapMgr()->GetUnit(p_caster->GetSelection()); else Target = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); } if(!Target) return; FillAllTargetsInArea((LocationVector&)Target->GetPosition(), i); }
void SpellCast(float val) { if (_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->getNextTarget()) { float comulativeperc = 0; Unit* target = NULL; for (uint8 i = 0; i < nrspells; i++) { spells[i].casttime--; if (m_spellcheck[i]) { spells[i].casttime = spells[i].cooldown; target = _unit->GetAIInterface()->getNextTarget(); switch (spells[i].targettype) { case TARGET_SELF: case TARGET_VARIOUS: _unit->CastSpell(_unit, spells[i].info, spells[i].instant); break; case TARGET_ATTACKING: _unit->CastSpell(target, spells[i].info, spells[i].instant); break; case TARGET_DESTINATION: _unit->CastSpellAoF(target->GetPosition(), spells[i].info, spells[i].instant); break; } if (spells[i].speech != "") { _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, spells[i].speech.c_str()); _unit->PlaySoundToSet(spells[i].soundid); } m_spellcheck[i] = false; return; } if ((val > comulativeperc && val <= (comulativeperc + spells[i].perctrigger)) || !spells[i].casttime) { _unit->setAttackTimer(spells[i].attackstoptimer, false); m_spellcheck[i] = true; } comulativeperc += spells[i].perctrigger; } } }
void SpawnAdds() { for (uint8 i = 0; i < 30; ++i) { Unit* victim = SelectTarget(SELECT_TARGET_RANDOM, 0); if (victim) { Position pos; victim->GetPosition(&pos); me->GetRandomNearPosition(pos, float(urand(5, 80))); me->SummonCreature(NPC_POISONOUS_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); me->GetRandomNearPosition(pos, float(urand(5, 80))); me->SummonCreature(NPC_HEALTHY_MUSHROOM, pos, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30*IN_MILLISECONDS); } } }
void WorldSession::HandleTeleportToUnitOpcode(WorldPacket & recv_data) { uint8 unk; Unit * target; recv_data >> unk; if(!_player->IsInWorld()) return; if(!HasGMPermissions()) { SendNotification("You do not have permission to use this function."); return; } if( (target = _player->GetMapMgr()->GetUnit(_player->GetSelection())) == NULL ) return; _player->SafeTeleport(_player->GetMapId(), _player->GetInstanceID(), target->GetPosition()); }
void OnRemoveVehicle(constAuraEffectPtr /*aurEff*/, AuraEffectHandleModes mode) { PreventDefaultAction(); Unit* caster = GetCaster(); if (!caster) return; Position exitPosition; exitPosition.m_positionX = 1750.0f; exitPosition.m_positionY = -7.5f + frand(-3.0f, 3.0f); exitPosition.m_positionZ = 457.9322f; caster->_ExitVehicle(&exitPosition); caster->RemoveAurasDueToSpell(GetId()); Position oldPos; caster->GetPosition(&oldPos); caster->Relocate(exitPosition); caster->GetMotionMaster()->MoveFall(); caster->Relocate(oldPos); }
void UpdateAI(const uint32 diff) { float x, y, z; me->GetPosition(x, y, z); if(z > WATER_Z) me->Relocate(x, y, WATER_Z, me->GetOrientation()); if(!UpdateVictim()) return; Unit *victim = me->getVictim(); victim->GetPosition(x, y, z); if(z - 0.5f > WATER_Z) { EnterEvadeMode(); return; } DoMeleeAttackIfReady(); }
void IsSummonedBy(Unit* owner) { if (owner->GetTypeId() != TYPEID_UNIT) return; Creature* creOwner = owner->ToCreature(); DoCast(me, SPELL_COLDFLAME_PASSIVE, true); float x, y, z; // random target case if (!owner->HasAura(SPELL_BONE_STORM)) { // select any unit but not the tank (by owners threatlist) Unit* target = creOwner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 1, 40.0f, true); if (!target) target = creOwner->AI()->SelectTarget(SELECT_TARGET_RANDOM, 0, 40.0f, true); // or the tank if its solo if (!target) { me->ForcedDespawn(); return; } target->GetPosition(x, y, z); float scale = 70.0f / me->GetExactDist2d(x, y); x = me->GetPositionX() + (x - me->GetPositionX()) * scale; y = me->GetPositionY() + (y - me->GetPositionY()) * scale; } else { me->GetPosition(x, y, z); MarrowgarAI* marrowgarAI = CAST_AI(MarrowgarAI, creOwner->AI()); Position const* ownerPos = marrowgarAI->GetLastColdflamePosition(); float ang = me->GetAngle(ownerPos) - static_cast<float>(M_PI); MapManager::NormalizeOrientation(ang); x += 50.0f * cosf(ang); y += 50.0f * sinf(ang); } me->GetMotionMaster()->MovePoint(POINT_TARGET_COLDFLAME, x, y, z); events.ScheduleEvent(EVENT_COLDFLAME_TRIGGER, 400); }
void CastSinisterReflection() { DoScriptText(RAND(SAY_KJ_REFLECTION1,SAY_KJ_REFLECTION2), me); for (uint8 i = 0; i < 4; ++i) { float x,y,z; Unit *pTarget = NULL; for (uint8 z = 0; z < 6; ++z) { pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!pTarget || !pTarget->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if (pTarget) { pTarget->GetPosition(x,y,z); if (Creature* pSinisterReflection = me->SummonCreature(CREATURE_SINISTER_REFLECTION, x,y,z,0, TEMPSUMMON_CORPSE_DESPAWN, 0)) { pSinisterReflection->SetDisplayId(pTarget->GetDisplayId()); pSinisterReflection->AI()->AttackStart(pTarget); } } } }
Unit::Unit(const Unit& unit) { // Declare necessary variables Ball* pBall; Ball* pNewBall; // Initialize pimpl object _pPimpl = new UnitPimpl; assert(_pPimpl); // Get Unit Data this->SetPosition (unit.GetPosition ()); this->SetStartPoint (unit.GetStartPoint ()); this->SetCenterPoint (unit.GetCenterPoint ()); this->SetSize (unit.GetSize ()); // Get Ball Data pBall = unit.FirstBall(); if (pBall == NULL) { return; } do { pNewBall = new Ball(*pBall); if (pNewBall == NULL) { continue; } this->InsertBall(pNewBall); } while ((pBall = unit.NextBall()) != NULL); }
void OnRemoveVehicle(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/) { PreventDefaultAction(); Unit* caster = GetCaster(); if (!caster) return; Position exitPosition; exitPosition.m_positionX = 1750.0f; exitPosition.m_positionY = -7.5f + frand(-3.0f, 3.0f); exitPosition.m_positionZ = 457.9322f; // Remove pending passengers before exiting vehicle - might cause an Uninstall GetTarget()->GetVehicleKit()->RemovePendingEventsForPassenger(caster); caster->_ExitVehicle(&exitPosition); caster->RemoveAurasDueToSpell(GetId()); // Temporarily relocate player to vehicle exit dest serverside to send proper fall movement // beats me why blizzard sends these 2 spline packets one after another instantly Position oldPos = caster->GetPosition(); caster->Relocate(exitPosition); caster->GetMotionMaster()->MoveFall(); caster->Relocate(oldPos); }
TargetedMovementGenerator<T>::TargetedMovementGenerator(Unit &target, float offset, float angle, bool _usePathfinding): TargetedMovementGeneratorBase(target), i_offset(offset), i_angle(angle), m_usePathfinding(_usePathfinding), i_recalculateTravel(false), i_path(NULL), m_pathPointsSent(0) { target.GetPosition(i_targetX, i_targetY, i_targetZ); }
void AI::BattleTurn(Arena & arena, const Unit & b, Actions & a) { Board* board = Arena::GetBoard(); // reset quality param for board board->Reset(); // set quality for enemy troop board->SetEnemyQuality(b); const Unit* enemy = NULL; bool attack = false; if(b.isArchers() && !b.isHandFighting()) { enemy = arena.GetEnemyMaxQuality(b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else if(b.isHandFighting()) { enemy = AIGetEnemyAbroadMaxQuality(b); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ attack = true; } else { s16 move = -1; if(b.Modes(SP_BERSERKER)) { const Indexes positions = board->GetNearestTroopIndexes(b.GetHeadIndex(), NULL); if(positions.size()) move = *Rand::Get(positions); } else { if(BattleMagicTurn(arena, b, a, NULL)) return; /* repeat turn: correct spell ability */ // set quality position from enemy board->SetPositionQuality(b); // get passable quality positions const Indexes positions = board->GetPassableQualityPositions(b); attack = true; if(positions.size()) move = AIAttackPosition(arena, b, positions); } if(Board::isValidIndex(move)) { if(b.isFly()) { enemy = AIGetEnemyAbroadMaxQuality(move, b.GetColor()); if(BattleMagicTurn(arena, b, a, enemy)) return; /* repeat turn: correct spell ability */ a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), move)); attack = true; } else { Position dst = Position::GetCorrect(b, move); Indexes path = arena.GetPath(b, dst); if(path.empty()) { const u8 direction = b.GetPosition().GetHead()->GetPos().x > dst.GetHead()->GetPos().x ? RIGHT : LEFT; // find near position while(path.empty() && Board::isValidDirection(dst.GetHead()->GetIndex(), direction)) { const s16 & pos = Board::GetIndexDirection(dst.GetHead()->GetIndex(), direction); if(b.GetHeadIndex() == pos) break; dst.Set(pos, b.isWide(), direction == RIGHT); path = arena.GetPath(b, dst); } } if(path.size()) { if(b.isWide()) { const s16 & head = dst.GetHead()->GetIndex(); const s16 & tail = dst.GetTail()->GetIndex(); if(path.back() == head || path.back() == tail) { enemy = AIGetEnemyAbroadMaxQuality(head, b.GetColor()); if(!enemy) enemy = AIGetEnemyAbroadMaxQuality(tail, b.GetColor()); } } if(! enemy) enemy = AIGetEnemyAbroadMaxQuality(path.back(), b.GetColor()); a.push_back(Battle::Command(MSG_BATTLE_MOVE, b.GetUID(), path.back())); // archers move and short attack only attack = b.isArchers() ? false : true; } } } else enemy = AIGetEnemyAbroadMaxQuality(b); } if(enemy) { if(attack) a.push_back(Battle::Command(MSG_BATTLE_ATTACK, b.GetUID(), enemy->GetUID(), enemy->GetHeadIndex(), 0)); } else { DEBUG(DBG_BATTLE, DBG_TRACE, "enemy: " << "is NULL" << ", board: " << board->AllUnitsInfo()); } // end action a.push_back(Battle::Command(MSG_BATTLE_END_TURN, b.GetUID())); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if(StormCount) { Unit* target = Unit::GetUnit(*m_creature, CloudGUID); if(!target || !target->isAlive()) { EnterEvadeMode(); return; } else if(Unit* Cyclone = Unit::GetUnit(*m_creature, CycloneGUID)) Cyclone->CastSpell(target, 25160, true); // keep casting or... if(StormSequenceTimer < diff) { HandleStormSequence(target); }else StormSequenceTimer -= diff; return; } if (Enrage_Timer < diff) { DoYell(SAY_ONENRAGE, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_ONENRAGE); m_creature->CastSpell(m_creature, SPELL_BERSERK, true); Enrage_Timer = 600000; }else Enrage_Timer -= diff; if (StaticDisruption_Timer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(!target) target = m_creature->getVictim(); TargetGUID = target->GetGUID(); m_creature->CastSpell(target, SPELL_STATIC_DISRUPTION, false); m_creature->SetInFront(m_creature->getVictim()); StaticDisruption_Timer = (10+rand()%8)*1000; // < 20s /*if(float dist = m_creature->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f) dist = 5.0f; SDisruptAOEVisual_Timer = 1000 + floor(dist / 30 * 1000.0f);*/ }else StaticDisruption_Timer -= diff; if (GustOfWind_Timer < diff) { Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 1); if(!target) target = m_creature->getVictim(); DoCast(target, SPELL_GUST_OF_WIND); GustOfWind_Timer = (20+rand()%10)*1000; //20 to 30 seconds(bosskillers) } else GustOfWind_Timer -= diff; if (CallLighting_Timer < diff) { DoCast(m_creature->getVictim(), SPELL_CALL_LIGHTNING); CallLighting_Timer = (12 + rand()%5)*1000; //totaly random timer. can't find any info on this } else CallLighting_Timer -= diff; if (!isRaining && ElectricalStorm_Timer < 8000 + rand()%5000) { SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f); isRaining = true; } if (ElectricalStorm_Timer < diff) { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true); if(!target) { EnterEvadeMode(); return; } target->CastSpell(target, 44007, true);//cloud visual m_creature->CastSpell(target, SPELL_ELECTRICAL_STORM, false);//storm cyclon + visual float x,y,z; target->GetPosition(x,y,z); if (target) { target->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); target->SendMonsterMove(x,y,m_creature->GetPositionZ()+15,0); } Unit *Cloud = m_creature->SummonTrigger(x, y, m_creature->GetPositionZ()+16, 0, 15000); if(Cloud) { CloudGUID = Cloud->GetGUID(); Cloud->SetUnitMovementFlags(MOVEMENTFLAG_LEVITATING); Cloud->StopMoving(); Cloud->SetFloatValue(OBJECT_FIELD_SCALE_X, 1.0f); Cloud->setFaction(35); Cloud->SetMaxHealth(9999999); Cloud->SetHealth(9999999); Cloud->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } ElectricalStorm_Timer = 60000; //60 seconds(bosskillers) StormCount = 1; StormSequenceTimer = 0; } else ElectricalStorm_Timer -= diff; if (SummonEagles_Timer < diff) { DoYell(SAY_ONSUMMON, LANG_UNIVERSAL, NULL); DoPlaySoundToSet(m_creature, SOUND_ONSUMMON); float x, y, z; m_creature->GetPosition(x, y, z); for (uint8 i = 0; i < 8; i++) { Unit* bird = Unit::GetUnit(*m_creature,BirdGUIDs[i]); if(!bird)//they despawned on die { if(Unit* target = SelectUnit(SELECT_TARGET_RANDOM, 0)) { x = target->GetPositionX() + 10 - rand()%20; y = target->GetPositionY() + 10 - rand()%20; z = target->GetPositionZ() + 6 + rand()%5 + 10; if(z > 95) z = 95 - rand()%5; } Creature *pCreature = m_creature->SummonCreature(MOB_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); if (pCreature) { pCreature->AddThreat(m_creature->getVictim(), 1.0f); pCreature->AI()->AttackStart(m_creature->getVictim()); BirdGUIDs[i] = pCreature->GetGUID(); } } } SummonEagles_Timer = 999999; } else SummonEagles_Timer -= diff; DoMeleeAttackIfReady(); }
void UpdateAI(const uint32 diff) { if (!UpdateVictim()) return; if (StormCount) { Unit* pTarget = Unit::GetUnit(*me, CloudGUID); if (!pTarget || !pTarget->IsAlive()) { EnterEvadeMode(); return; } else if (Unit* Cyclone = Unit::GetUnit(*me, CycloneGUID)) Cyclone->CastSpell(pTarget, 25160, true); // keep casting or... if (StormSequenceTimer <= diff) HandleStormSequence(pTarget); else StormSequenceTimer -= diff; return; } if (Enrage_Timer <= diff) { me->MonsterYell(SAY_ONENRAGE, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_ONENRAGE); DoCast(me, SPELL_BERSERK, true); Enrage_Timer = (diff - Enrage_Timer) + 600000; } else Enrage_Timer -= diff; if (StaticDisruption_Timer <= diff) { Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1); if (!pTarget) pTarget = me->GetVictim(); TargetGUID = pTarget->GetGUID(); DoCast(pTarget, SPELL_STATIC_DISRUPTION, false); me->SetInFront(me->GetVictim()); StaticDisruption_Timer = (diff - StaticDisruption_Timer) + (10 + rand() % 8) * 1000; // < 20s /*if (float dist = me->IsWithinDist3d(pTarget->GetPositionX(), pTarget->GetPositionY(), pTarget->GetPositionZ(), 5.0f) dist = 5.0f; SDisruptAOEVisual_Timer = 1000 + floor(dist / 30 * 1000.0f);*/ } else StaticDisruption_Timer -= diff; if (GustOfWind_Timer <= diff) { Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 1); if (!pTarget) pTarget = me->GetVictim(); DoCast(pTarget, SPELL_GUST_OF_WIND); GustOfWind_Timer = (diff - GustOfWind_Timer) + (20 + rand() % 10) * 1000; //20 to 30 seconds(bosskillers) } else GustOfWind_Timer -= diff; if (CallLighting_Timer <= diff) { DoCastVictim( SPELL_CALL_LIGHTNING); CallLighting_Timer = (diff - CallLighting_Timer) + (12 + rand() % 5) * 1000; //totaly random timer. can't find any info on this } else CallLighting_Timer -= diff; if (!isRaining && ElectricalStorm_Timer < 8000 + urand(0, 5000)) { SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f); isRaining = true; } if (ElectricalStorm_Timer <= diff) { Unit* pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true); if (!pTarget) { EnterEvadeMode(); return; } pTarget->CastSpell(pTarget, SPELL_ELECTRICAL_STORM_VISUAL, true);//cloud visual DoCast(pTarget, SPELL_ELECTRICAL_STORM, false);//storm cyclon + visual float x, y, z; pTarget->GetPosition(x, y, z); pTarget->SetLevitate(true); Movement::MoveSplineInit init(*me); init.MoveTo(x, y, me->GetPositionZ() + 15.0f, true); init.Launch(); Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ() + 16, 0, 15000); if (Cloud) { CloudGUID = Cloud->GetGUID(); Cloud->SetLevitate(true); Cloud->StopMoving(); Cloud->SetObjectScale(1.0f); Cloud->setFaction(35); Cloud->SetMaxHealth(9999999); Cloud->SetHealth(9999999); Cloud->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } ElectricalStorm_Timer = (diff - ElectricalStorm_Timer) + 60000; //60 seconds (bosskillers) StormCount = 1; StormSequenceTimer = 0; } else ElectricalStorm_Timer -= diff; if (SummonEagles_Timer <= diff) { if (urand(0, 1)) { me->MonsterYell(SAY_ONSUMMON2, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_ONSUMMON1); } else { me->MonsterYell(SAY_ONSUMMON2, LANG_UNIVERSAL, 0); DoPlaySoundToSet(me, SOUND_ONSUMMON2); } float x, y, z; me->GetPosition(x, y, z); for (uint8 i = 0; i < 8; ++i) { if (!Unit::GetUnit(*me, BirdGUIDs[i])) // they despawn on death { if (Unit* pTarget = SelectUnit(SELECT_TARGET_RANDOM, 0)) { x = pTarget->GetPositionX() + irand(-10, 10); y = pTarget->GetPositionY() + irand(-10, 10); z = pTarget->GetPositionZ() + urand(16, 20); if (z > 95) z = 95 - urand(0, 5); } if (Creature* pCreature = me->SummonCreature(MOB_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0)) { pCreature->AddThreat(me->GetVictim(), 1.0f); pCreature->AI()->AttackStart(me->GetVictim()); BirdGUIDs[i] = pCreature->GetGUID(); } } } SummonEagles_Timer = (diff - SummonEagles_Timer) + 999999; } else SummonEagles_Timer -= diff; DoMeleeAttackIfReady(); }
void ChargeMovementGenerator<T>::ComputePath(T& attacker, Unit& victim) { Vector3 attackPos; // attacker position Vector3 victimPos; // victim position Vector3 chargeVect; // vector of the charge Vector3 victimSpd; // speed vector of victim float o; if (Transport* t = attacker.GetTransport()) path.SetTransport(t); if (_speed == 0) _speed = attacker.GetSpeed(MOVE_RUN) * 4; if (_speed > 24.0f) _speed = 24.0f; attacker.GetPosition(attackPos.x, attackPos.y, attackPos.z); victim.GetPosition(victimPos.x, victimPos.y, victimPos.z); chargeVect = victimPos - attackPos; chargeVect = chargeVect.direction(); // unit vector // Base path is to current victim position path.calculate(victimPos.x, victimPos.y, victimPos.z, false); // Improved path to victim future estimated position if (Player* victimPlayer = victim.ToPlayer()) { PlayerAnticheatInterface* data = victimPlayer->GetCheatData(); if ((data->InterpolateMovement(victimPlayer->m_movementInfo, 1000, victimSpd.x, victimSpd.y, victimSpd.z, o)) && (data->InterpolateMovement(victimPlayer->m_movementInfo, 0, victimPos.x, victimPos.y, victimPos.z, o))) { // Victim speed per sec. victimSpd -= victimPos; // We get only the component of the speed in the direction of charge vector float victimSpeed = victimSpd.dot(chargeVect); // dot product if (abs(victimSpeed) > 0.1f) { float currDistance = path.Length(); uint32 pathTravelTime; // Equation when matching collision distance, to get collision time: // _speed * t = currDistance + victimSpeed * t // t = currDistance / (_speed - victimSpeed) if (_speed > 2 * victimSpeed) // we don't want to reach target if target speed is more than half charge speed pathTravelTime = (uint32)(1000 * currDistance / (_speed - victimSpeed)); else pathTravelTime = (uint32)(1000 * 2 * currDistance / _speed); pathTravelTime *= 0.45f; // Attenuation factor (empirical) _interpolateDelay = (WorldTimer::getMSTime() - victimPlayer->m_movementInfo.time) + pathTravelTime; if (_interpolateDelay > 1500) _interpolateDelay = 1500; if (data->InterpolateMovement(victimPlayer->m_movementInfo, _interpolateDelay, victimPos.x, victimPos.y, victimPos.z, o)) { victim.UpdateAllowedPositionZ(victimPos.x, victimPos.y, victimPos.z); path.calculate(victimPos.x, victimPos.y, victimPos.z, false); } } else path.UpdateForMelee(&victim, attacker.GetMeleeReach()); } } else { // TODO: PvE victim position prediction? // Relocate last path point to hitbox rather than exact position of victim path.UpdateForMelee(&victim, attacker.GetMeleeReach()); } }
void UpdateAI(const uint32 diff) { if (!UpdateVictim() || Phase < PHASE_NORMAL) return; if (IsWaiting) { if (WaitTimer <= diff) { IsWaiting = false; ChangeTimers(false, 0); } else WaitTimer -= diff; } for (uint8 t = 0; t < ActiveTimers; ++t) { if (Timer[t] <= diff && !TimerIsDeactivated[t]) { switch(t) { case TIMER_SPEECH: if (SpeechBegins) { SpeechBegins=false; switch(Phase) { case PHASE_NORMAL: speechPhaseEnd=1; break; case PHASE_DARKNESS: speechPhaseEnd=4; break; case PHASE_ARMAGEDDON: speechPhaseEnd=7; break; case PHASE_SACRIFICE: speechPhaseEnd=12; break; } } if (Speeches[speechCount].timer < SpeechTimer) { SpeechTimer = 0; if (pInstance) if (Creature* pSpeechCreature = Unit::GetCreature(*me, pInstance->GetData64(Speeches[speechCount].pCreature))) DoScriptText(Speeches[speechCount].textid, pSpeechCreature); if (speechCount == 12) if (Creature* pAnveena = Unit::GetCreature(*me, pInstance->GetData64(DATA_ANVEENA))) pAnveena->CastSpell(me, SPELL_SACRIFICE_OF_ANVEENA, false); // ChangeTimers(true, 10000); // Kil should do an emote while screaming without attacking for 10 seconds if (speechCount == speechPhaseEnd) TimerIsDeactivated[TIMER_SPEECH]=true; speechCount++; } SpeechTimer += diff; break; case TIMER_SOUL_FLAY: if (!me->IsNonMeleeSpellCasted(false)) { DoCast(me->getVictim(), SPELL_SOUL_FLAY_SLOW, false); DoCast(me->getVictim(), SPELL_SOUL_FLAY, false); Timer[TIMER_SOUL_FLAY] = 3500; } break; case TIMER_LEGION_LIGHTNING: if (!me->IsNonMeleeSpellCasted(false)) { Unit* pRandomPlayer = NULL; me->RemoveAurasDueToSpell(SPELL_SOUL_FLAY); for (uint8 z = 0; z < 6; ++z) { pRandomPlayer = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!pRandomPlayer || !pRandomPlayer->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if (pRandomPlayer) DoCast(pRandomPlayer, SPELL_LEGION_LIGHTNING, false); else error_log("try to cast SPELL_LEGION_LIGHTNING on invalid target"); Timer[TIMER_LEGION_LIGHTNING] = (Phase == PHASE_SACRIFICE) ? 18000 : 30000; // 18 seconds in PHASE_SACRIFICE Timer[TIMER_SOUL_FLAY] = 2500; } break; case TIMER_FIRE_BLOOM: if (!me->IsNonMeleeSpellCasted(false)) { me->RemoveAurasDueToSpell(SPELL_SOUL_FLAY); DoCastAOE(SPELL_FIRE_BLOOM, false); Timer[TIMER_FIRE_BLOOM] = (Phase == PHASE_SACRIFICE) ? 25000 : 40000; // 25 seconds in PHASE_SACRIFICE Timer[TIMER_SOUL_FLAY] = 1000; } break; case TIMER_SUMMON_SHILEDORB: for (uint8 i = 1; i < Phase; ++i) { float sx, sy; sx = ShieldOrbLocations[0][0] + sin(ShieldOrbLocations[i][0]); sy = ShieldOrbLocations[0][1] + sin(ShieldOrbLocations[i][1]); me->SummonCreature(CREATURE_SHIELD_ORB, sx, sy, SHIELD_ORB_Z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 45000); } Timer[TIMER_SUMMON_SHILEDORB] = urand(30000,60000); // 30-60seconds cooldown Timer[TIMER_SOUL_FLAY] = 2000; break; case TIMER_SHADOW_SPIKE: //Phase 3 if (!me->IsNonMeleeSpellCasted(false)) { CastSinisterReflection(); DoCastAOE(SPELL_SHADOW_SPIKE, false); ChangeTimers(true, 30000); Timer[TIMER_SHADOW_SPIKE] = 0; TimerIsDeactivated[TIMER_SPEECH] = false; } break; case TIMER_FLAME_DART: //Phase 3 DoCastAOE(SPELL_FLAME_DART, false); Timer[TIMER_FLAME_DART] = 3000; //TODO Timer break; case TIMER_DARKNESS: //Phase 3 if (!me->IsNonMeleeSpellCasted(false)) { // Begins to channel for 8 seconds, then deals 50'000 damage to all raid members. if (!IsInDarkness) { DoScriptText(EMOTE_KJ_DARKNESS, me); DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS, false); ChangeTimers(true, 9000); Timer[TIMER_DARKNESS] = 8750; TimerIsDeactivated[TIMER_DARKNESS] = false; if (Phase == PHASE_SACRIFICE) TimerIsDeactivated[TIMER_ARMAGEDDON] = false; IsInDarkness = true; } else { Timer[TIMER_DARKNESS] = (Phase == PHASE_SACRIFICE) ? 15000 : urand(40000,70000); IsInDarkness = false; DoCastAOE(SPELL_DARKNESS_OF_A_THOUSAND_SOULS_DAMAGE); DoScriptText(RAND(SAY_KJ_DARKNESS1,SAY_KJ_DARKNESS2,SAY_KJ_DARKNESS3), me); } Timer[TIMER_SOUL_FLAY] = 9000; } break; case TIMER_ORBS_EMPOWER: //Phase 3 if (pInstance) if (Creature* pKalec = Unit::GetCreature(*me, pInstance->GetData64(DATA_KALECGOS_KJ))) { switch (Phase) { case PHASE_SACRIFICE: CAST_AI(boss_kalecgos_kjAI, pKalec->AI())->EmpowerOrb(true); break; default: CAST_AI(boss_kalecgos_kjAI, pKalec->AI())->EmpowerOrb(false); break; } } OrbActivated = true; TimerIsDeactivated[TIMER_ORBS_EMPOWER] = true; break; case TIMER_ARMAGEDDON: //Phase 4 Unit *pTarget = NULL; for (uint8 z = 0; z < 6; ++z) { pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true); if (!pTarget || !pTarget->HasAura(SPELL_VENGEANCE_OF_THE_BLUE_FLIGHT,0)) break; } if (pTarget) { float x, y, z; pTarget->GetPosition(x, y, z); me->SummonCreature(CREATURE_ARMAGEDDON_TARGET, x,y,z,0, TEMPSUMMON_TIMED_DESPAWN,15000); } Timer[TIMER_ARMAGEDDON] = 2000; // No, I'm not kidding break; } } } DoMeleeAttackIfReady(); //Time runs over! for (uint8 i = 0; i < ActiveTimers; ++i) if (!TimerIsDeactivated[i]) { Timer[i] -= diff; if (((int32)Timer[i]) < 0) Timer[i] = 0; } //Phase 3 if (Phase <= PHASE_NORMAL && !IsInDarkness) { if (Phase == PHASE_NORMAL && HealthBelowPct(85)) { Phase = PHASE_DARKNESS; ActiveTimers = 9; EnterNextPhase(); } else return; } //Phase 4 if (Phase <= PHASE_DARKNESS && !IsInDarkness) { if (Phase == PHASE_DARKNESS && HealthBelowPct(55)) { Phase = PHASE_ARMAGEDDON; ActiveTimers = 10; EnterNextPhase(); } else return; } //Phase 5 specific spells all we can if (Phase <= PHASE_ARMAGEDDON && !IsInDarkness) { if (Phase == PHASE_ARMAGEDDON && HealthBelowPct(25)) { Phase = PHASE_SACRIFICE; EnterNextPhase(); } else return; } }
TargetedMovementGenerator<T>::TargetedMovementGenerator(Unit &target, float offset, float angle) : TargetedMovementGeneratorBase(target) , i_offset(offset), i_angle(angle), i_recalculateTravel(false) { target.GetPosition(i_targetX, i_targetY, i_targetZ); }
void UpdateAI(uint32 diff) override { if (!UpdateVictim()) return; events.Update(diff); while (uint32 eventId = events.ExecuteEvent()) { switch (eventId) { case EVENT_STATIC_DISRUPTION: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); if (!target) target = me->GetVictim(); if (target) { TargetGUID = target->GetGUID(); DoCast(target, SPELL_STATIC_DISRUPTION, false); me->SetInFront(me->GetVictim()); } /*if (float dist = me->IsWithinDist3d(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 5.0f) dist = 5.0f; SDisruptAOEVisual_Timer = 1000 + floor(dist / 30 * 1000.0f);*/ events.ScheduleEvent(EVENT_STATIC_DISRUPTION, urand(10000, 18000)); break; } case EVENT_GUST_OF_WIND: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 1); if (!target) target = me->GetVictim(); if (target) DoCast(target, SPELL_GUST_OF_WIND); events.ScheduleEvent(EVENT_GUST_OF_WIND, urand(20000, 30000)); break; } case EVENT_CALL_LIGHTNING: DoCastVictim(SPELL_CALL_LIGHTNING); events.ScheduleEvent(EVENT_CALL_LIGHTNING, urand(12000, 17000)); // totaly random timer. can't find any info on this break; case EVENT_ELECTRICAL_STORM: { Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 50, true); if (!target) { EnterEvadeMode(); return; } target->CastSpell(target, 44007, true); // cloud visual DoCast(target, SPELL_ELECTRICAL_STORM, false); // storm cyclon + visual float x, y, z; target->GetPosition(x, y, z); /// @todo: fix it in correct way, that causes player to can fly until logout /* if (target) { target->SetDisableGravity(true); target->MonsterMoveWithSpeed(x, y, me->GetPositionZ()+15, 0); } */ Unit* Cloud = me->SummonTrigger(x, y, me->GetPositionZ()+16, 0, 15000); if (Cloud) { CloudGUID = Cloud->GetGUID(); Cloud->SetDisableGravity(true); Cloud->StopMoving(); Cloud->SetObjectScale(1.0f); Cloud->setFaction(35); Cloud->SetMaxHealth(9999999); Cloud->SetHealth(9999999); Cloud->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); } StormCount = 1; events.ScheduleEvent(EVENT_ELECTRICAL_STORM, 60000); // 60 seconds(bosskillers) events.ScheduleEvent(EVENT_RAIN, urand(47000, 52000)); break; } case EVENT_RAIN: if (!isRaining) { SetWeather(WEATHER_STATE_HEAVY_RAIN, 0.9999f); isRaining = true; } else events.ScheduleEvent(EVENT_RAIN, 1000); break; case EVENT_STORM_SEQUENCE: { Unit* target = ObjectAccessor::GetUnit(*me, CloudGUID); if (!target || !target->IsAlive()) { EnterEvadeMode(); return; } else if (Unit* Cyclone = ObjectAccessor::GetUnit(*me, CycloneGUID)) Cyclone->CastSpell(target, SPELL_SAND_STORM, true); // keep casting or... HandleStormSequence(target); break; } case EVENT_SUMMON_EAGLES: Talk(SAY_SUMMON); float x, y, z; me->GetPosition(x, y, z); for (uint8 i = 0; i < 8; ++i) { Unit* bird = ObjectAccessor::GetUnit(*me, BirdGUIDs[i]); if (!bird) //they despawned on die { if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0)) { x = target->GetPositionX() + irand(-10, 10); y = target->GetPositionY() + irand(-10, 10); z = target->GetPositionZ() + urand(16, 20); if (z > 95) z = 95.0f - urand(0, 5); } Creature* creature = me->SummonCreature(NPC_SOARING_EAGLE, x, y, z, 0, TEMPSUMMON_CORPSE_DESPAWN, 0); if (creature) { creature->AddThreat(me->GetVictim(), 1.0f); creature->AI()->AttackStart(me->GetVictim()); BirdGUIDs[i] = creature->GetGUID(); } } } break; case EVENT_ENRAGE: Talk(SAY_ENRAGE); DoCast(me, SPELL_BERSERK, true); events.ScheduleEvent(EVENT_ENRAGE, 600000); break; default: break; } } DoMeleeAttackIfReady(); }