void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { Position dest; creature.GetRespawnCoord(dest.x, dest.y, dest.z, &dest.o, &wander_distance); bool is_air_ok = creature.CanFly(); const float angle = frand(0.0f, M_PI*2.0f); const float range = frand(0.0f, wander_distance); creature.GetValidPointInAngle(dest, range, angle, false); static_cast<MovementGenerator*>(this)->_recalculateTravel = false; if (is_air_ok) i_nextMoveTime.Reset(0); else { if (roll_chance_i(MOVEMENT_RANDOM_MMGEN_CHANCE_NO_BREAK)) i_nextMoveTime.Reset(0); else i_nextMoveTime.Reset(urand(500, 10000)); } creature.addUnitState(UNIT_STAT_ROAMING); Movement::MoveSplineInit init(creature); init.MoveTo(dest.x, dest.y, dest.z); init.SetWalk(true); init.Launch(); // Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) creature.GetFormation()->LeaderMoveTo(dest.x, dest.y, dest.z); }
void WaypointMovementGenerator<Creature>::Initialize(Creature &u) { u.StopMoving(); //i_currentNode = -1; // uint32, become 0 in the first update //i_nextMoveTime.Reset(0); StopedByPlayer = false; if (!path_id) path_id = u.GetWaypointPath(); waypoints = sWaypointMgr->GetPath(path_id); i_currentNode = 0; if (waypoints && waypoints->size()) { node = waypoints->front(); Traveller<Creature> traveller(u); InitTraveller(u, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); //Call for creature group update if (u.GetFormation() && u.GetFormation()->getLeader() == &u) u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } else node = NULL; }
static bool HandleNpcAddFormationCommand(ChatHandler* handler, const char* args) { if (!*args) return false; uint32 leaderGUID = (uint32) atoi((char*) args); Creature *pCreature = handler->getSelectedCreature(); if (!pCreature || !pCreature->GetDBTableGUIDLow()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } uint32 lowguid = pCreature->GetDBTableGUIDLow(); if (pCreature->GetFormation()) { handler->PSendSysMessage( "Selected creature is already member of group %u", pCreature->GetFormation()->GetId()); return false; } if (!lowguid) return false; Player *chr = handler->GetSession()->GetPlayer(); FormationInfo *group_member; group_member = new FormationInfo; group_member->follow_angle = (pCreature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI; group_member->follow_dist = sqrtf( pow(chr->GetPositionX() - pCreature->GetPositionX(), int(2)) + pow(chr->GetPositionY() - pCreature->GetPositionY(), int(2))); group_member->leaderGUID = leaderGUID; group_member->groupAI = 0; CreatureGroupMap[lowguid] = group_member; pCreature->SearchFormation(); WorldDatabase.PExecute( "INSERT INTO creature_formations (leaderGUID, memberGUID, dist, angle, groupAI) VALUES ('%u','%u','%f', '%f', '%u')", leaderGUID, lowguid, group_member->follow_dist, group_member->follow_angle, group_member->groupAI); handler->PSendSysMessage( "Creature %u added to formation with leader %u", lowguid, leaderGUID); return true; }
bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) { if (!i_path || i_path->empty()) return false; if (Stopped()) return true; if (m_isArrivalDone) { if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint { creature.SetHomePosition(i_path->at(i_currentNode)->x, i_path->at(i_currentNode)->y, i_path->at(i_currentNode)->z, creature.GetOrientation()); creature.GetMotionMaster()->Initialize(); return false; } i_currentNode = (i_currentNode+1) % i_path->size(); } WaypointData const* node = i_path->at(i_currentNode); if (!node) return false; m_isArrivalDone = false; creature.AddUnitState(UNIT_STATE_ROAMING_MOVE); Movement::MoveSplineInit init(creature); init.MoveTo(node->x, node->y, node->z); //! Accepts angles such as 0.00001 and -0.00001, 0 must be ignored, default value in waypoint table if (node->orientation && node->delay) init.SetFacing(node->orientation); init.SetWalk(!node->run); init.Launch(); //Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) { creature.SetWalk(!node->run); creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } return true; }
void WaypointMovementGenerator<Creature>::MoveToNextNode(CreatureTraveller &traveller) { Creature* owner = &(traveller.i_traveller); const WaypointNode &node = i_path->at(i_currentNode); PathInfo sub_path(owner, node.x, node.y, node.z); PointPath pointPath = sub_path.getFullPath(); float speed = traveller.Speed()*0.001f; // in ms uint32 traveltime = uint32(pointPath.GetTotalLength()/speed); owner->SendMonsterMoveByPath(pointPath, 1, pointPath.size(), owner->GetSplineFlags(), traveltime); if (owner->GetFormation() && (owner->GetFormation())->getLeader() == owner) //Formation movement (owner->GetFormation())->LeaderMoveTo(node.x, node.y, node.z); PathNode p = pointPath[pointPath.size()-1]; i_destinationHolder.SetDestination(traveller, p.x, p.y, p.z, false); i_nextMoveTime.Reset(traveltime); }
bool WaypointMovementGenerator<Creature>::StartMove(Creature &creature) { if (!i_path || i_path->empty()) return false; if (Stopped()) return true; const WaypointData *node = i_path->at(i_currentNode); if (m_isArrivalDone) { if ((i_currentNode == i_path->size() - 1) && !repeating) // If that's our last waypoint { creature.SetHomePosition(node->x, node->y, node->z, creature.GetOrientation()); creature.GetMotionMaster()->Initialize(); return false; } i_currentNode = (i_currentNode+1) % i_path->size(); } m_isArrivalDone = false; creature.AddUnitState(UNIT_STAT_ROAMING_MOVE); Movement::MoveSplineInit init(creature); init.MoveTo(node->x, node->y, node->z); if (node->orientation != 100 && node->delay != 0) init.SetFacing(node->orientation); init.SetWalk(!node->run); init.Launch(); //Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) creature.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); return true; }
static bool HandleNpcAddFormationCommand(ChatHandler* handler, const char* args) { if (!*args) return false; uint32 leaderGUID = (uint32) atoi((char*)args); Creature* creature = handler->getSelectedCreature(); if (!creature || !creature->GetDBTableGUIDLow()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } uint32 lowguid = creature->GetDBTableGUIDLow(); if (creature->GetFormation()) { handler->PSendSysMessage("Selected creature is already member of group %u", creature->GetFormation()->GetId()); return false; } if (!lowguid) return false; Player* chr = handler->GetSession()->GetPlayer(); FormationInfo* group_member; group_member = new FormationInfo; group_member->follow_angle = (creature->GetAngle(chr) - chr->GetOrientation()) * 180 / M_PI; group_member->follow_dist = sqrtf(pow(chr->GetPositionX() - creature->GetPositionX(), int(2))+pow(chr->GetPositionY() - creature->GetPositionY(), int(2))); group_member->leaderGUID = leaderGUID; group_member->groupAI = 0; CreatureGroupMap[lowguid] = group_member; creature->SearchFormation(); PreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_INS_CREATURE_FORMATION); stmt->setUInt32(0, leaderGUID); stmt->setUInt32(1, lowguid); stmt->setFloat(2, group_member->follow_dist); stmt->setFloat(3, group_member->follow_angle); stmt->setUInt32(4, uint32(group_member->groupAI)); WorldDatabase.Execute(stmt); handler->PSendSysMessage("Creature %u added to formation with leader %u", lowguid, leaderGUID); return true; }
void WaypointMovementGenerator<Creature>::Initialize(Creature &u) { u.StopMoving(); StopedByPlayer = false; if (!path_id) path_id = u.GetWaypointPath(); waypoints = sWaypointMgr->GetPath(path_id); i_currentNode = 0; if (waypoints && waypoints->size()) { node = waypoints->front(); Traveller<Creature> traveller(u); InitTraveller(u, *node); MoveToNextNode(traveller); //Call for creature group update if (u.GetFormation() && u.GetFormation()->getLeader() == &u) u.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } else node = NULL; }
bool WaypointMovementGenerator<Creature>::Update(Creature &unit, const uint32 &diff) { if (!&unit) return true; if (!path_id) return false; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (unit.HasUnitState(UNIT_STAT_ROOT | UNIT_STAT_STUNNED | UNIT_STAT_DISTRACTED)) return true; // Clear the generator if the path doesn't exist if (!waypoints || !waypoints->size()) return false; Traveller<Creature> traveller(unit); i_nextMoveTime.Update(diff); i_destinationHolder.UpdateTraveller(traveller, diff, true); if (i_nextMoveTime.GetExpiry() < TIMEDIFF_NEXT_WP) { if (unit.IsStopped()) { if (StopedByPlayer) { ASSERT(node); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); StopedByPlayer = false; return true; } if (i_currentNode == waypoints->size() - 1) // If that's our last waypoint { if (repeating) // If the movement is repeating i_currentNode = 0; // Start moving all over again else { unit.SetHomePosition(node->x, node->y, node->z, unit.GetOrientation()); unit.GetMotionMaster()->Initialize(); return false; // Clear the waypoint movement } } else ++i_currentNode; node = waypoints->at(i_currentNode); InitTraveller(unit, *node); i_destinationHolder.SetDestination(traveller, node->x, node->y, node->z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); //Call for creature group update if (unit.GetFormation() && unit.GetFormation()->getLeader() == &unit) unit.GetFormation()->LeaderMoveTo(node->x, node->y, node->z); } else { //Determine waittime if (node->delay) i_nextMoveTime.Reset(node->delay); //note: disable "start" for mtmap if (node->event_id && urand(0,99) < node->event_chance) unit.GetMap()->ScriptsStart(sWaypointScripts, node->event_id, &unit, NULL/*, false*/); i_destinationHolder.ResetTravelTime(); MovementInform(unit); unit.UpdateWaypointID(i_currentNode); unit.ClearUnitState(UNIT_STAT_ROAMING); unit.Relocate(node->x, node->y, node->z); } } else { if (unit.IsStopped() && !i_destinationHolder.HasArrived()) { if (!StopedByPlayer) { i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); StopedByPlayer = true; } } } return true; }
void RandomMovementGenerator<Creature>::SetRandomLocation(Creature &creature) { float respX, respY, respZ, respO, currZ, destX, destY, destZ, travelDistZ; creature.GetHomePosition(respX, respY, respZ, respO); currZ = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection bool isAirOk = creature.canFly(); const float angle = float(rand_norm()) * static_cast<float>(M_PI*2.0f); const float range = float(rand_norm()) * _wanderDistance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); destX = respX + distanceX; destY = respY + distanceY; // prevent invalid coordinates generation Trinity::NormalizeMapCoord(destX); Trinity::NormalizeMapCoord(destY); travelDistZ = distanceX*distanceX + distanceY*distanceY; if (isAirOk) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = float(rand_norm()) * sqrtf(travelDistZ)/2.0f; destZ = respZ + distanceZ; float levelZ = map->GetWaterOrGroundLevel(destX, destY, destZ-2.0f); // Problem here, we must fly above the ground and water, not under. Let's try on next tick if (levelZ >= destZ) return; } else // 2D only { // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) travelDistZ = travelDistZ >= 100.0f ? 10.0f : sqrtf(travelDistZ); // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, false); if (fabs(destZ - respZ) > travelDistZ) // Map check { // Vmap Horizontal or above destZ = map->GetHeight(destX, destY, respZ - 2.0f, true); if (fabs(destZ - respZ) > travelDistZ) { // Vmap Higher destZ = map->GetHeight(destX, destY, respZ+travelDistZ-2.0f, true); // let's forget this bad coords where a z cannot be find and retry at next tick if (fabs(destZ - respZ) > travelDistZ) return; } } } if (isAirOk) _nextMoveTime.Reset(0); else _nextMoveTime.Reset(urand(500, 10000)); creature.AddUnitState(UNIT_STATE_ROAMING_MOVE); Movement::MoveSplineInit init(creature); init.MoveTo(destX, destY, destZ); init.SetWalk(true); init.Launch(); //Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) creature.GetFormation()->LeaderMoveTo(destX, destY, destZ); }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { float X, Y, Z, z, nx, ny, nz, ori, dist; creature.GetHomePosition(X, Y, Z, ori); z = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection //bool is_land_ok = creature.canWalk(); //bool is_water_ok = creature.canSwim(); bool is_air_ok = creature.canFly(); for (uint32 i = 0; ; ++i) { const float angle = (float)rand_norm()*static_cast<float>(M_PI*2); const float range = (float)rand_norm()*wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); nx = X + distanceX; ny = Y + distanceY; // prevent invalid coordinates generation Trillium::NormalizeMapCoord(nx); Trillium::NormalizeMapCoord(ny); dist = (nx - X)*(nx - X) + (ny - Y)*(ny - Y); if (i == 5) { nz = Z; break; } if (is_air_ok) // 3D system above ground and above water (flying mode) { const float distanceZ = (float)(rand_norm()) * sqrtf(dist)/2; // Limit height change nz = Z + distanceZ; float tz = map->GetHeight(nx, ny, nz-2.0f, false); // Map check only, vmap needed here but need to alter vmaps checks for height. float wz = map->GetWaterLevel(nx, ny); if (tz >= nz || wz >= nz) continue; // Problem here, we must fly above the ground and water, not under. Let's try on next tick } //else if (is_water_ok) // 3D system under water and above ground (swimming mode) else // 2D only { dist = dist >= 100.0f ? 10.0f : sqrtf(dist); // 10.0 is the max that vmap high can check (MAX_CAN_FALL_DISTANCE) // The fastest way to get an accurate result 90% of the time. // Better result can be obtained like 99% accuracy with a ray light, but the cost is too high and the code is too long. nz = map->GetHeight(nx, ny, Z+dist-2.0f, false); // Map check if (fabs(nz-Z)>dist) { nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above if (fabs(nz-Z)>dist) { nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // Vmap Higher if (fabs(nz-Z)>dist) continue; // let's forget this bad coords where a z cannot be find and retry at next tick } } } break; } Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(nx, ny)); i_destinationHolder.SetDestination(traveller, nx, ny, nz); creature.AddUnitState(UNIT_STAT_ROAMING); if (is_air_ok) { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } //else if (is_water_ok) // Swimming mode to be done with more than this check else { i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 5000+i_destinationHolder.GetTotalTravelTime())); creature.AddUnitMovementFlag(MOVEMENTFLAG_WALKING); } //Call for creature group update if (creature.GetFormation() && creature.GetFormation()->getLeader() == &creature) { creature.GetFormation()->LeaderMoveTo(nx, ny, nz); } }