void RandomMovementGenerator<Creature>::Initialize(Creature &creature) { if (!creature.isAlive()) return; if (creature.CanFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); else creature.AddSplineFlag(SPLINEFLAG_WALKMODE); creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); _setRandomLocation(creature); }
void RandomMovementGenerator<Creature>::Initialize(Creature &creature) { if (!creature.isAlive()) return; if (creature.canFly() && !(creature.canWalk() && creature.IsAtGroundLevel(creature.GetPositionX(), creature.GetPositionY(), creature.GetPositionZ()))) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); else creature.AddSplineFlag(SPLINEFLAG_WALKMODE); creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); _setRandomLocation(creature); }
//-----------------------------------------------// void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature) { //DETAIL_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "LoadPath: loading waypoint path for creature %u, %u", creature.GetGUIDLow(), creature.GetDBTableGUIDLow()); i_path = sWaypointMgr.GetPath(creature.GetDBTableGUIDLow()); // We may LoadPath() for several occasions: // 1: When creature.MovementType=2 // 1a) Path is selected by creature.guid == creature_movement.id // 1b) Path for 1a) does not exist and then use path from creature.GetEntry() == creature_movement_template.entry // 2: When creature_template.MovementType=2 // 2a) Creature is summoned and has creature_template.MovementType=2 // Creators need to be sure that creature_movement_template is always valid for summons. // Mob that can be summoned anywhere should not have creature_movement_template for example. // No movement found for guid if (!i_path) { sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path", creature.GetName(), creature.GetEntry(), creature.GetDBTableGUIDLow()); return; } if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // We have to set the destination here (for the first point), right after Initialize. Without, we may not have valid xyz for GetResetPosition CreatureTraveller traveller(creature); MoveToNextNode(traveller); }
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff) { CreatureTraveller traveller( owner); i_destinationHolder.UpdateTraveller(traveller, time_diff, false); if (time_diff > i_travel_timer) { owner.AddSplineFlag(SPLINEFLAG_WALKMODE); // restore orientation of not moving creature at returning to home if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE) { if(CreatureData const* data = sObjectMgr.GetCreatureData(owner.GetDBTableGUIDLow())) { owner.SetOrientation(data->orientation); WorldPacket packet; owner.BuildHeartBeatMsg(&packet); owner.SendMessageToSet(&packet, false); } } owner.AI()->JustReachedHome(); return false; } i_travel_timer -= time_diff; return true; }
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff) { CreatureTraveller traveller( owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } if (time_diff > i_travel_timer) { owner.AddSplineFlag(SPLINEFLAG_WALKMODE); // restore orientation of not moving creature at returning to home if(owner.GetDefaultMovementType()==IDLE_MOTION_TYPE) { if(CreatureData const* data = sObjectMgr.GetCreatureData(owner.GetDBTableGUIDLow())) { owner.SetOrientation(data->orientation); WorldPacket packet; owner.BuildHeartBeatMsg(&packet); owner.SendMessageToSet(&packet, false); } } owner.LoadCreatureAddon(true); owner.AI()->JustReachedHome(); return false; } i_travel_timer -= time_diff; return true; }
bool HomeMovementGenerator<Creature>::Update(Creature &owner, const uint32& time_diff) { CreatureTraveller traveller( owner); if (i_destinationHolder.UpdateTraveller(traveller, time_diff, false)) { if (!IsActive(owner)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } if (time_diff > i_travel_time) { owner.AddSplineFlag(SPLINEFLAG_WALKMODE); // restore orientation of not moving creature at returning to home if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE) { // such a mob might need very exact spawning point, hence relocate to spawn-position if (CreatureData const* data = sObjectMgr.GetCreatureData(owner.GetGUIDLow())) { owner.Relocate(data->posX, data->posY, data->posZ, data->orientation); owner.SendHeartBeat(false); } } owner.LoadCreatureAddon(true); owner.AI()->JustReachedHome(); return false; } i_travel_time -= time_diff; return true; }
void WaypointMovementGenerator<Creature>::StartMove(Creature &creature) { if (!i_path || i_path->empty()) return; if (Stopped()) return; if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } if (m_isArrivalDone) i_currentNode = (i_currentNode+1) % i_path->size(); m_isArrivalDone = false; if (creature.CanFly()) creature.AddSplineFlag(SPLINEFLAG_FLYING); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); const WaypointNode &node = i_path->at(i_currentNode); CreatureTraveller traveller(creature); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); }
bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } i_nextMoveTime.Update(diff); if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly()) creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); if (!i_destinationHolder.HasArrived() && creature.IsStopped()) creature.addUnitState(UNIT_STAT_ROAMING_MOVE); CreatureTraveller traveller(creature); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost if (i_nextMoveTime.Passed()) { float x,y,z; if(i_destinationHolder.HasDestination()) i_destinationHolder.GetLocationNowNoMicroMovement(x,y,z); else creature.GetPosition(x,y,z); if (creature.canFly() && !(creature.canWalk() && creature.IsAtGroundLevel(x,y,z))) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); else creature.AddSplineFlag(SPLINEFLAG_WALKMODE); _setRandomLocation(creature); } else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f)) { creature.AddSplineFlag(SPLINEFLAG_WALKMODE); _setRandomLocation(creature); } } return true; }
void RandomCircleMovementGenerator<Creature>::Initialize(Creature &creature) { if (!creature.isAlive()) return; if (creature.canFly() && !(creature.canWalk() && creature.IsAtGroundLevel(creature.GetPositionX(), creature.GetPositionY(), creature.GetPositionZ()))) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); else creature.AddSplineFlag(SPLINEFLAG_WALKMODE); creature.addUnitState(UNIT_STAT_ROAMING|UNIT_STAT_ROAMING_MOVE); m_bClockWise = urand(0, 1) ? true : false; i_wpId = 0; fillSplineWayPoints(creature); SplineFlags flags = SplineFlags(SPLINEFLAG_FORWARD | SPLINEFLAG_UNKNOWN7 | SPLINEFLAG_FLYING | creature.GetSplineFlags()); creature.SendSplineMove(&m_splineMap, SPLINETYPE_NORMAL, flags, 500, NULL); }
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner) { owner.addUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE); if (((Creature*)&owner)->canFly()) owner.AddSplineFlag(SPLINEFLAG_UNKNOWN7); _setTargetLocation(owner); }
void FollowMovementGenerator<Creature>::Initialize(Creature &owner) { owner.addUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); _updateWalkMode(owner); _updateSpeed(owner); if (((Creature*)&owner)->canFly()) owner.AddSplineFlag(SPLINEFLAG_UNKNOWN7); _setTargetLocation(owner); }
void ChaseMovementGenerator<Creature>::Initialize(Creature &owner) { owner.addUnitState(UNIT_STAT_CHASE|UNIT_STAT_CHASE_MOVE); owner.RemoveSplineFlag(SPLINEFLAG_WALKMODE); _setTargetLocation(owner); float x,y,z; i_destinationHolder.GetDestination(x,y,z); if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly() && !(((Creature*)&owner)->canWalk() && ((Creature*)&owner)->IsAtGroundLevel(x,y,z))) owner.AddSplineFlag(SPLINEFLAG_UNKNOWN7); }
bool RandomMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (creature.hasUnitState(UNIT_STAT_NOT_MOVE & ~UNIT_STAT_ON_VEHICLE)) { i_nextMoveTime.Update(i_nextMoveTime.GetExpiry()); // Expire the timer creature.clearUnitState(UNIT_STAT_ROAMING_MOVE);; return true; } i_nextMoveTime.Update(diff); if (i_destinationHolder.HasArrived() && !creature.IsStopped() && !creature.canFly()) creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); if (!i_destinationHolder.HasArrived() && creature.IsStopped()) creature.addUnitState(UNIT_STAT_ROAMING_MOVE); CreatureTraveller traveller(creature); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (i_nextMoveTime.Passed()) { if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); else creature.AddSplineFlag(SPLINEFLAG_WALKMODE); _setRandomLocation(creature); } else if (creature.isPet() && creature.GetOwner() && !creature.IsWithinDist(creature.GetOwner(), PET_FOLLOW_DIST+2.5f)) { creature.AddSplineFlag(SPLINEFLAG_WALKMODE); _setRandomLocation(creature); } } return true; }
void FollowMovementGenerator<Creature>::Initialize(Creature &owner) { owner.addUnitState(UNIT_STAT_FOLLOW|UNIT_STAT_FOLLOW_MOVE); _updateWalkMode(owner); _updateSpeed(owner); _setTargetLocation(owner); float x,y,z; i_destinationHolder.GetDestination(x,y,z); if (owner.GetTypeId() == TYPEID_UNIT && ((Creature*)&owner)->canFly() && !(((Creature*)&owner)->canWalk() && ((Creature*)&owner)->IsAtGroundLevel(x,y,z))) owner.AddSplineFlag(SPLINEFLAG_UNKNOWN7); }
//-----------------------------------------------// void WaypointMovementGenerator<Creature>::LoadPath(Creature &creature) { DETAIL_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "LoadPath: loading waypoint path for %s", creature.GetGuidStr().c_str()); i_path = sWaypointMgr.GetPath(creature.GetGUIDLow()); // We may LoadPath() for several occasions: // 1: When creature.MovementType=2 // 1a) Path is selected by creature.guid == creature_movement.id // 1b) Path for 1a) does not exist and then use path from creature.GetEntry() == creature_movement_template.entry // 2: When creature_template.MovementType=2 // 2a) Creature is summoned and has creature_template.MovementType=2 // Creators need to be sure that creature_movement_template is always valid for summons. // Mob that can be summoned anywhere should not have creature_movement_template for example. // No movement found for guid if (!i_path) { i_path = sWaypointMgr.GetPathTemplate(creature.GetEntry()); // No movement found for entry if (!i_path) { sLog.outErrorDb("WaypointMovementGenerator::LoadPath: creature %s (Entry: %u GUID: %u) doesn't have waypoint path", creature.GetName(), creature.GetEntry(), creature.GetGUIDLow()); return; } } // We have to set the destination here (for the first point), right after Initialize. Without, we may not have valid xyz for GetResetPosition CreatureTraveller traveller(creature); if (creature.CanFly()) creature.AddSplineFlag(SPLINEFLAG_FLYING); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); }
void HomeMovementGenerator<Creature>::Finalize(Creature& owner) { if (i_travel_timer == 0) { owner.AddSplineFlag(SPLINEFLAG_WALKMODE); // restore orientation of not moving creature at returning to home if (owner.GetDefaultMovementType() == IDLE_MOTION_TYPE) { // such a mob might need very exact spawning point, hence relocate to spawn-position if (CreatureData const* data = sObjectMgr.GetCreatureData(owner.GetGUIDLow())) { owner.Relocate(data->posX, data->posY, data->posZ, data->orientation); owner.SendHeartBeat(false); } } if (owner.GetTemporaryFactionFlags() & TEMPFACTION_RESTORE_REACH_HOME) owner.ClearTemporaryFaction(); owner.LoadCreatureAddon(true); owner.AI()->JustReachedHome(); } }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } if (i_currentNode >= i_path->size()) i_currentNode = 0; CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped() && !i_hasDone) // creature is waiting on a waypoint and hasn't done the behavior yet { uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (WaypointBehavior *behavior = i_path->at(idx).behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for(; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // behavior done i_hasDone = true; MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } // i_creature.IsStopped() // This is at the end of waypoint segment or has been stopped by player if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); uint32 idx = i_currentNode > 0 ? i_currentNode-1 : i_path->size()-1; if (i_path->at(idx).orientation != 100) creature.SetOrientation(i_path->at(idx).orientation); if (WaypointBehavior *behavior = i_path->at(idx).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } } else { // If not stopped then stop it and set the reset of TimeTracker to waittime creature.StopMoving(); SetStoppedByPlayer(false); i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); ++i_currentNode; i_hasDone = false; if (i_currentNode >= i_path->size()) i_currentNode = 0; } } return true; }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { float X,Y,Z,z,nx,ny,nz,wander_distance,ori,dist; creature.GetRespawnCoord(X, Y, Z, &ori, &wander_distance); z = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection //bool is_land_ok = creature.canWalk(); // not used? //bool is_water_ok = creature.canSwim(); // not used? bool is_air_ok = creature.canFly(); const float angle = rand_norm_f()*(M_PI_F*2.0f); const float range = rand_norm_f()*wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); nx = X + distanceX; ny = Y + distanceY; // prevent invalid coordinates generation MaNGOS::NormalizeMapCoord(nx); MaNGOS::NormalizeMapCoord(ny); dist = distanceX*distanceX + distanceY*distanceY; if (is_air_ok) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = rand_norm_f() * sqrtf(dist)/2.0f; 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); // Problem here, we must fly above the ground and water, not under. Let's try on next tick if (tz >= nz || wz >= nz) return; } //else if (is_water_ok) // 3D system under water and above ground (swimming mode) else // 2D only { nz = Z; if (!map->IsNextZcoordOK(nx, ny, nz, dist)) return; // let's forget this bad coords where a z cannot be find and retry at next tick creature.UpdateGroundPositionZ(nx, ny, nz, dist); } Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(nx, ny)); i_destinationHolder.SetDestination(traveller, nx, ny, nz); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (is_air_ok && !(creature.canWalk() && creature.IsAtGroundLevel(nx, ny, nz))) { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); } //else if (is_water_ok) // Swimming mode to be done with more than this check else { i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime())); creature.AddSplineFlag(SPLINEFLAG_WALKMODE); } }
void ConfusedMovementGenerator<Creature>::Finalize(Creature &unit) { unit.clearUnitState(UNIT_STAT_CONFUSED|UNIT_STAT_CONFUSED_MOVE); unit.AddSplineFlag(SPLINEFLAG_WALKMODE); }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ; creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance); currZ = creature.GetPositionZ(); TerrainInfo const* map = creature.GetTerrain(); // For 2D/3D system selection //bool is_land_ok = creature.CanWalk(); // not used? //bool is_water_ok = creature.CanSwim(); // not used? bool is_air_ok = creature.CanFly(); const float angle = rand_norm_f() * (M_PI_F*2.0f); const float range = rand_norm_f() * wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); destX = respX + distanceX; destY = respY + distanceY; // prevent invalid coordinates generation MaNGOS::NormalizeMapCoord(destX); MaNGOS::NormalizeMapCoord(destY); travelDistZ = distanceX*distanceX + distanceY*distanceY; if (is_air_ok) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = rand_norm_f() * 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 if (is_water_ok) // 3D system under water and above ground (swimming mode) 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; } } } Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(destX, destY)); i_destinationHolder.SetDestination(traveller, destX, destY, destZ); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (is_air_ok) { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); creature.AddSplineFlag(SPLINEFLAG_FLYING); } //else if (is_water_ok) // Swimming mode to be done with more than this check else { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime() + urand(500, 10000)); creature.AddSplineFlag(SPLINEFLAG_WALKMODE); } }
bool WaypointMovementGenerator<Creature>::Update(Creature &creature, const uint32 &diff) { if (!&creature) return true; // Waypoint movement can be switched on/off // This is quite handy for escort quests and other stuff if (creature.hasUnitState(UNIT_STAT_NOT_MOVE)) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } // prevent a crash at empty waypoint path. if (!i_path || i_path->empty()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } if (i_currentNode >= i_path->size()) { sLog.outError("WaypointMovement currentNode (%u) is equal or bigger than path size (creature entry %u)", i_currentNode, creature.GetEntry()); i_currentNode = 0; } CreatureTraveller traveller(creature); i_nextMoveTime.Update(diff); if (i_destinationHolder.UpdateTraveller(traveller, diff, false, true)) { if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost } // creature has been stopped in middle of the waypoint segment if (!i_destinationHolder.HasArrived() && creature.IsStopped()) { // Timer has elapsed, meaning this part controlled it if (i_nextMoveTime.Passed()) { SetStoppedByPlayer(false); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); // Now we re-set destination to same node and start travel const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else // if( !i_nextMoveTime.Passed()) { // unexpected end of timer && creature stopped && not at end of segment if (!IsStoppedByPlayer()) { // Put 30 seconds delay i_destinationHolder.IncreaseTravelTime(STOP_TIME_FOR_PLAYER); i_nextMoveTime.Reset(STOP_TIME_FOR_PLAYER); SetStoppedByPlayer(true); // Mark we did it } } return true; // Abort here this update } if (creature.IsStopped()) { if (!m_isArrivalDone) { if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); if (i_path->at(i_currentNode).script_id) { DEBUG_FILTER_LOG(LOG_FILTER_AI_AND_MOVEGENSS, "Creature movement start script %u at point %u for creature %u (entry %u).", i_path->at(i_currentNode).script_id, i_currentNode, creature.GetDBTableGUIDLow(), creature.GetEntry()); creature.GetMap()->ScriptsStart(sCreatureMovementScripts, i_path->at(i_currentNode).script_id, &creature, &creature); } // We have reached the destination and can process behavior if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->emote != 0) creature.HandleEmote(behavior->emote); if (behavior->spell != 0) { creature.CastSpell(&creature, behavior->spell, false); if (!IsActive(creature)) // force stop processing (cast can change movegens list) return true; // not expire now, but already lost } if (behavior->model1 != 0) creature.SetDisplayId(behavior->model1); if (behavior->textid[0]) { // Not only one text is set if (behavior->textid[1]) { // Select one from max 5 texts (0 and 1 already checked) int i = 2; for(; i < MAX_WAYPOINT_TEXT; ++i) { if (!behavior->textid[i]) break; } creature.Say(behavior->textid[rand() % i], 0, 0); } else creature.Say(behavior->textid[0], 0, 0); } } // wpBehaviour found // Can only do this once for the node m_isArrivalDone = true; // Inform script MovementInform(creature); if (!IsActive(creature)) // force stop processing (movement can move out active zone with cleanup movegens list) return true; // not expire now, but already lost // prevent a crash at empty waypoint path. if (!i_path || i_path->empty() || i_currentNode >= i_path->size()) { creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); return true; } } } // i_creature.IsStopped() // This is at the end of waypoint segment (incl. was previously stopped by player, extending the time) if (i_nextMoveTime.Passed()) { // If stopped then begin a new move segment if (creature.IsStopped()) { creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (creature.canFly()) creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); if (WaypointBehavior *behavior = i_path->at(i_currentNode).behavior) { if (behavior->model2 != 0) creature.SetDisplayId(behavior->model2); creature.SetUInt32Value(UNIT_NPC_EMOTESTATE, 0); } // behavior for "departure" of the current node is done m_isArrivalDone = false; // Proceed with increment current node and then send to the next destination ++i_currentNode; // Oops, end of the line so need to start from the beginning if (i_currentNode >= i_path->size()) i_currentNode = 0; if (i_path->at(i_currentNode).orientation != 100) creature.SetOrientation(i_path->at(i_currentNode).orientation); const WaypointNode &node = i_path->at(i_currentNode); i_destinationHolder.SetDestination(traveller, node.x, node.y, node.z); i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); } else { // If not stopped then stop it creature.clearUnitState(UNIT_STAT_ROAMING_MOVE); SetStoppedByPlayer(false); // Set TimeTracker to waittime for the current node i_nextMoveTime.Reset(i_path->at(i_currentNode).delay); } } return true; }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { float X,Y,Z,z,nx,ny,nz,wander_distance,ori,dist; creature.GetRespawnCoord(X, Y, Z, &ori, &wander_distance); z = creature.GetPositionZ(); Map const* map = creature.GetBaseMap(); // For 2D/3D system selection //bool is_land_ok = creature.canWalk(); // not used? //bool is_water_ok = creature.canSwim(); // not used? bool is_air_ok = creature.canFly(); const float angle = rand_norm_f()*(M_PI_F*2.0f); const float range = rand_norm_f()*wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); nx = X + distanceX; ny = Y + distanceY; // prevent invalid coordinates generation MaNGOS::NormalizeMapCoord(nx); MaNGOS::NormalizeMapCoord(ny); dist = distanceX*distanceX + distanceY*distanceY; if (is_air_ok) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = rand_norm_f() * sqrtf(dist)/2.0f; 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); // Problem here, we must fly above the ground and water, not under. Let's try on next tick if (tz >= nz || wz >= nz) return; } //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); if (fabs(nz-Z) > dist) // Map check { nz = map->GetHeight(nx, ny, Z-2.0f, true); // Vmap Horizontal or above if (fabs(nz-Z) > dist) { // Vmap Higher nz = map->GetHeight(nx, ny, Z+dist-2.0f, true); // let's forget this bad coords where a z cannot be find and retry at next tick if (fabs(nz-Z) > dist) return; } } } Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(nx, ny)); i_destinationHolder.SetDestination(traveller, nx, ny, nz); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (is_air_ok && !(creature.canWalk() && creature.IsAtGroundLevel(nx, ny, nz))) { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); } //else if (is_water_ok) // Swimming mode to be done with more than this check else { i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime())); creature.AddSplineFlag(SPLINEFLAG_WALKMODE); } }
void FleeingMovementGenerator<Creature>::Finalize(Creature& owner) { owner.AddSplineFlag(SPLINEFLAG_WALKMODE); owner.clearUnitState(UNIT_STAT_FLEEING | UNIT_STAT_FLEEING_MOVE); }
void RandomMovementGenerator<Creature>::_setRandomLocation(Creature &creature) { float respX, respY, respZ, respO, currZ, destX, destY, destZ, wander_distance, travelDistZ; creature.GetRespawnCoord(respX, respY, respZ, &respO, &wander_distance); currZ = creature.GetPositionZ(); TerrainInfo const* map = creature.GetTerrain(); // For 2D/3D system selection //bool is_land_ok = creature.CanWalk(); // not used? //bool is_water_ok = creature.CanSwim(); // not used? bool is_air_ok = creature.CanFly(); const float angle = rand_norm_f() * (M_PI_F*2.0f); const float range = rand_norm_f() * wander_distance; const float distanceX = range * cos(angle); const float distanceY = range * sin(angle); destX = respX + distanceX; destY = respY + distanceY; // prevent invalid coordinates generation MaNGOS::NormalizeMapCoord(destX); MaNGOS::NormalizeMapCoord(destY); travelDistZ = distanceX*distanceX + distanceY*distanceY; if (is_air_ok) // 3D system above ground and above water (flying mode) { // Limit height change const float distanceZ = rand_norm_f() * 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 if (is_water_ok) // 3D system under water and above ground (swimming mode) else // 2D only { destZ = respZ; if(!map->IsNextZcoordOK(destX, destY, destZ, travelDistZ)) return; // let's forget this bad coords where a z cannot be find and retry at next tick creature.UpdateGroundPositionZ(destX, destY, destZ, travelDistZ); } Traveller<Creature> traveller(creature); creature.SetOrientation(creature.GetAngle(destX, destY)); i_destinationHolder.SetDestination(traveller, destX, destY, destZ); creature.addUnitState(UNIT_STAT_ROAMING_MOVE); if (is_air_ok) { i_nextMoveTime.Reset(i_destinationHolder.GetTotalTravelTime()); creature.AddSplineFlag(SPLINEFLAG_UNKNOWN7); } //else if (is_water_ok) // Swimming mode to be done with more than this check else { i_nextMoveTime.Reset(urand(500+i_destinationHolder.GetTotalTravelTime(), 10000+i_destinationHolder.GetTotalTravelTime())); creature.AddSplineFlag(SPLINEFLAG_WALKMODE); } }