diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp index 0d5b1919b..5f62e542c 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp @@ -27,304 +27,31 @@ #define MIN_QUIET_DISTANCE 28.0f #define MAX_QUIET_DISTANCE 43.0f -template -void FleeingMovementGenerator::_setTargetLocation(T* owner) -{ - if (!owner) - return; - - if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) - { - return; - } - - if (!_setMoveData(owner)) - return; - - float x, y, z; - if (!_getPoint(owner, x, y, z)) { - i_nextCheckTime.Reset(100); - return; - } - - owner->AddUnitState(UNIT_STATE_FLEEING_MOVE); - - Movement::MoveSplineInit init(owner); - init.MoveTo(x, y, z, true); - init.SetWalk(false); - init.Launch(); -} - -template -bool FleeingMovementGenerator::_getPoint(T* owner, float& x, float& y, float& z) -{ - if (!owner) - return false; - - const Map* _map = owner->GetMap(); - - x = owner->GetPositionX(); - y = owner->GetPositionY(); - z = owner->GetPositionZ(); - - float temp_x, temp_y, angle; - // primitive path-finding - for (uint8 i = 0; i < 18; ++i) - { - if (i_only_forward && i > 2) - break; - - float distance = 5.0f; - - switch (i) - { - case 0: - angle = i_cur_angle; - break; - case 1: - angle = i_cur_angle; - distance /= 2; - break; - case 2: - angle = i_cur_angle; - distance /= 4; - break; - case 3: - angle = i_cur_angle + static_cast(M_PI / 4); - break; - case 4: - angle = i_cur_angle - static_cast(M_PI / 4); - break; - case 5: - angle = i_cur_angle + static_cast(M_PI / 4); - distance /= 2; - break; - case 6: - angle = i_cur_angle - static_cast(M_PI / 4); - distance /= 2; - break; - case 7: - angle = i_cur_angle + static_cast(M_PI / 2); - break; - case 8: - angle = i_cur_angle - static_cast(M_PI / 2); - break; - case 9: - angle = i_cur_angle + static_cast(M_PI / 2); - distance /= 2; - break; - case 10: - angle = i_cur_angle - static_cast(M_PI / 2); - distance /= 2; - break; - case 11: - angle = i_cur_angle + static_cast(M_PI / 4); - distance /= 4; - break; - case 12: - angle = i_cur_angle - static_cast(M_PI / 4); - distance /= 4; - break; - case 13: - angle = i_cur_angle + static_cast(M_PI / 2); - distance /= 4; - break; - case 14: - angle = i_cur_angle - static_cast(M_PI / 2); - distance /= 4; - break; - case 15: - angle = i_cur_angle + static_cast(3 * M_PI / 4); - distance /= 2; - break; - case 16: - angle = i_cur_angle - static_cast(3 * M_PI / 4); - distance /= 2; - break; - case 17: - angle = i_cur_angle + static_cast(M_PI); - distance /= 2; - break; - default: - angle = 0.0f; - distance = 0.0f; - break; - } - - temp_x = x + distance * cos(angle); - temp_y = y + distance * std::sin(angle); - float temp_z = z; - - if (!_map->CanReachPositionAndGetValidCoords(owner, temp_x, temp_y, temp_z, true, true)) - { - break; - } - - if (!(temp_z - z) || distance / std::fabs(temp_z - z) > 1.0f) - { - float temp_z_left = _map->GetHeight(owner->GetPhaseMask(), temp_x + 1.0f * cos(angle + static_cast(M_PI / 2)), temp_y + 1.0f * std::sin(angle + static_cast(M_PI / 2)), z, true); - float temp_z_right = _map->GetHeight(owner->GetPhaseMask(), temp_x + 1.0f * cos(angle - static_cast(M_PI / 2)), temp_y + 1.0f * std::sin(angle - static_cast(M_PI / 2)), z, true); - if (std::fabs(temp_z_left - temp_z) < 1.2f && std::fabs(temp_z_right - temp_z) < 1.2f) - { - // use new values - x = temp_x; - y = temp_y; - z = temp_z; - return true; - } - } - } - i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500, 1000)); - return false; -} - -template -bool FleeingMovementGenerator::_setMoveData(T* owner) -{ - float cur_dist_xyz = owner->GetDistance(i_caster_x, i_caster_y, i_caster_z); - - if (i_to_distance_from_caster > 0.0f) - { - if ((i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz < i_to_distance_from_caster) || - // if we reach lower distance - (i_last_distance_from_caster > i_to_distance_from_caster && cur_dist_xyz > i_last_distance_from_caster) || - // if we can't be close - (i_last_distance_from_caster < i_to_distance_from_caster && cur_dist_xyz > i_to_distance_from_caster) || - // if we reach bigger distance - (cur_dist_xyz > MAX_QUIET_DISTANCE) || // if we are too far - (i_last_distance_from_caster > MIN_QUIET_DISTANCE && cur_dist_xyz < MIN_QUIET_DISTANCE)) - // if we leave 'quiet zone' - { - // we are very far or too close, stopping - i_to_distance_from_caster = 0.0f; - i_nextCheckTime.Reset(urand(500, 1000)); - return false; - } - else - { - // now we are running, continue - i_last_distance_from_caster = cur_dist_xyz; - return true; - } - } - - float cur_dist; - float angle_to_caster; - - if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID)) - { - cur_dist = fright->GetDistance(owner); - if (cur_dist < cur_dist_xyz) - { - i_caster_x = fright->GetPositionX(); - i_caster_y = fright->GetPositionY(); - i_caster_z = fright->GetPositionZ(); - angle_to_caster = fright->GetAngle(owner); - } - else - { - cur_dist = cur_dist_xyz; - angle_to_caster = owner->GetAngle(i_caster_x, i_caster_y) + static_cast(M_PI); - } - } - else - { - cur_dist = cur_dist_xyz; - angle_to_caster = owner->GetAngle(i_caster_x, i_caster_y) + static_cast(M_PI); - } - - // if we too close may use 'path-finding' else just stop - i_only_forward = cur_dist >= MIN_QUIET_DISTANCE / 3; - - //get angle and 'distance from caster' to run - float angle; - - if (i_cur_angle == 0.0f && i_last_distance_from_caster == 0.0f) //just started, first time - { - angle = (float)rand_norm() * (1.0f - cur_dist / MIN_QUIET_DISTANCE) * static_cast(M_PI / 3) + (float)rand_norm() * static_cast(M_PI * 2 / 3); - i_to_distance_from_caster = MIN_QUIET_DISTANCE; - i_only_forward = true; - } - else if (cur_dist < MIN_QUIET_DISTANCE) - { - angle = static_cast(M_PI / 6) + (float)rand_norm() * static_cast(M_PI * 2 / 3); - i_to_distance_from_caster = cur_dist * 2 / 3 + (float)rand_norm() * (MIN_QUIET_DISTANCE - cur_dist * 2 / 3); - } - else if (cur_dist > MAX_QUIET_DISTANCE) - { - angle = (float)rand_norm() * static_cast(M_PI / 3) + static_cast(M_PI * 2 / 3); - i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); - } - else - { - angle = (float)rand_norm() * static_cast(M_PI); - i_to_distance_from_caster = MIN_QUIET_DISTANCE + 2.5f + (float)rand_norm() * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE - 2.5f); - } - - int8 sign = (float)rand_norm() > 0.5f ? 1 : -1; - i_cur_angle = sign * angle + angle_to_caster; - - // current distance - i_last_distance_from_caster = cur_dist; - - return true; -} - template void FleeingMovementGenerator::DoInitialize(T* owner) { if (!owner) + { return; + } + _path = nullptr; owner->SetUnitFlag(UNIT_FLAG_FLEEING); - owner->AddUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); - - _Init(owner); - - if (Unit* fright = ObjectAccessor::GetUnit(*owner, i_frightGUID)) - { - i_caster_x = fright->GetPositionX(); - i_caster_y = fright->GetPositionY(); - i_caster_z = fright->GetPositionZ(); - } - else - { - i_caster_x = owner->GetPositionX(); - i_caster_y = owner->GetPositionY(); - i_caster_z = owner->GetPositionZ(); - } - - i_only_forward = true; - i_cur_angle = 0.0f; - i_last_distance_from_caster = 0.0f; - i_to_distance_from_caster = 0.0f; - _setTargetLocation(owner); + owner->AddUnitState(UNIT_STATE_FLEEING); + SetTargetLocation(owner); } -template<> -void FleeingMovementGenerator::_Init(Creature* owner) +template +void FleeingMovementGenerator::DoFinalize(T*) { - if (!owner) - return; - - //owner->SetTargetGuid(ObjectGuid()); - is_water_ok = owner->CanEnterWater(); - is_land_ok = owner->CanWalk(); -} - -template<> -void FleeingMovementGenerator::_Init(Player* ) -{ - is_water_ok = true; - is_land_ok = true; } template<> void FleeingMovementGenerator::DoFinalize(Player* owner) { owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); - owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); + owner->ClearUnitState(UNIT_STATE_FLEEING); + owner->StopMoving(); } template<> @@ -332,8 +59,11 @@ void FleeingMovementGenerator::DoFinalize(Creature* owner) { owner->RemoveUnitFlag(UNIT_FLAG_FLEEING); owner->ClearUnitState(UNIT_STATE_FLEEING | UNIT_STATE_FLEEING_MOVE); - if (owner->GetVictim()) - owner->SetTarget(owner->GetVictim()->GetGUID()); + + if (Unit* victim = owner->GetVictim()) + { + owner->SetTarget(victim->GetGUID()); + } } template @@ -343,36 +73,140 @@ void FleeingMovementGenerator::DoReset(T* owner) } template -bool FleeingMovementGenerator::DoUpdate(T* owner, uint32 time_diff) +bool FleeingMovementGenerator::DoUpdate(T* owner, uint32 diff) { if (!owner || !owner->IsAlive()) + { return false; + } if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) { + _path = nullptr; + _interrupt = true; owner->StopMoving(); return true; } + else + _interrupt = false; - i_nextCheckTime.Update(time_diff); - if (i_nextCheckTime.Passed() && owner->movespline->Finalized()) - _setTargetLocation(owner); + _timer.Update(diff); + if (!_interrupt && _timer.Passed() && owner->movespline->Finalized()) + { + SetTargetLocation(owner); + } return true; } +template +void FleeingMovementGenerator::SetTargetLocation(T* owner) +{ + if (!owner) + { + return; + } + + if (owner->HasUnitState(UNIT_STATE_NOT_MOVE) || owner->IsMovementPreventedByCasting()) + { + _path = nullptr; + _interrupt = true; + owner->StopMoving(); + return; + } + + owner->AddUnitState(UNIT_STATE_FLEEING_MOVE); + + Position destination = owner->GetPosition(); + GetPoint(owner, destination); + + // Add LOS check for target point + if (!owner->IsWithinLOS(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ())) + { + _timer.Reset(200); + return; + } + + if (!_path) + { + _path = std::make_unique(owner); + } + else + { + _path->Clear(); + } + + _path->SetPathLengthLimit(30.0f); + bool result = _path->CalculatePath(destination.GetPositionX(), destination.GetPositionY(), destination.GetPositionZ()); + if (!result || (_path->GetPathType() & PathType(PATHFIND_NOPATH | PATHFIND_SHORTCUT | PATHFIND_FARFROMPOLY))) + { + _timer.Reset(100); + return; + } + + Movement::MoveSplineInit init(owner); + init.MovebyPath(_path->GetPath()); + init.SetWalk(false); + int32 traveltime = init.Launch(); + _timer.Reset(traveltime + urand(800, 1500)); +} + +template +void FleeingMovementGenerator::GetPoint(T* owner, Position& position) +{ + float casterDistance, casterAngle; + if (Unit* fleeTarget = ObjectAccessor::GetUnit(*owner, _fleeTargetGUID)) + { + casterDistance = fleeTarget->GetDistance(owner); + if (casterDistance > 0.2f) + { + casterAngle = fleeTarget->GetAngle(owner); + } + else + { + casterAngle = frand(0.0f, 2.0f * float(M_PI)); + } + } + else + { + casterDistance = 0.0f; + casterAngle = frand(0.0f, 2.0f * float(M_PI)); + } + + float distance, angle; + if (casterDistance < MIN_QUIET_DISTANCE) + { + distance = frand(0.4f, 1.3f) * (MIN_QUIET_DISTANCE - casterDistance); + angle = casterAngle + frand(-float(M_PI) / 8.0f, float(M_PI) / 8.0f); + } + else if (casterDistance > MAX_QUIET_DISTANCE) + { + distance = frand(0.4f, 1.0f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE); + angle = -casterAngle + frand(-float(M_PI) / 4.0f, float(M_PI) / 4.0f); + } + else // we are inside quiet range + { + distance = frand(0.6f, 1.2f) * (MAX_QUIET_DISTANCE - MIN_QUIET_DISTANCE); + angle = frand(0.0f, 2.0f * float(M_PI)); + } + + // In MovePositionToFirstCollision we have added owner's orientation + // so now let's subtract it + angle -= owner->GetOrientation(); + + owner->MovePositionToFirstCollision(position, distance, angle); +} + template void FleeingMovementGenerator::DoInitialize(Player*); template void FleeingMovementGenerator::DoInitialize(Creature*); -template bool FleeingMovementGenerator::_setMoveData(Player*); -template bool FleeingMovementGenerator::_setMoveData(Creature*); -template bool FleeingMovementGenerator::_getPoint(Player*, float&, float&, float&); -template bool FleeingMovementGenerator::_getPoint(Creature*, float&, float&, float&); -template void FleeingMovementGenerator::_setTargetLocation(Player*); -template void FleeingMovementGenerator::_setTargetLocation(Creature*); template void FleeingMovementGenerator::DoReset(Player*); template void FleeingMovementGenerator::DoReset(Creature*); template bool FleeingMovementGenerator::DoUpdate(Player*, uint32); template bool FleeingMovementGenerator::DoUpdate(Creature*, uint32); +template void FleeingMovementGenerator::SetTargetLocation(Player*); +template void FleeingMovementGenerator::SetTargetLocation(Creature*); +template void FleeingMovementGenerator::GetPoint(Player*, Position&); +template void FleeingMovementGenerator::GetPoint(Creature*, Position&); void TimedFleeingMovementGenerator::Finalize(Unit* owner) { diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h index 734486026..dfd59a255 100644 --- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h +++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.h @@ -23,34 +23,24 @@ template class FleeingMovementGenerator : public MovementGeneratorMedium< T, FleeingMovementGenerator > { -public: - FleeingMovementGenerator(ObjectGuid fright) : i_frightGUID(fright), i_nextCheckTime(0) {} + public: + explicit FleeingMovementGenerator(ObjectGuid fleeTargetGUID) : _path(nullptr), _fleeTargetGUID(fleeTargetGUID), _timer(0), _interrupt(false) {} - void DoInitialize(T*); - void DoFinalize(T*); - void DoReset(T*); - bool DoUpdate(T*, uint32); + MovementGeneratorType GetMovementGeneratorType() override { return FLEEING_MOTION_TYPE; } - MovementGeneratorType GetMovementGeneratorType() { return FLEEING_MOTION_TYPE; } + void DoInitialize(T*); + void DoFinalize(T*); + void DoReset(T*); + bool DoUpdate(T*, uint32); -private: - void _setTargetLocation(T*); - bool _getPoint(T*, float& x, float& y, float& z); - bool _setMoveData(T* owner); - void _Init(T* ); + private: + void SetTargetLocation(T*); + void GetPoint(T*, Position& position); - bool is_water_ok : 1; - bool is_land_ok : 1; - bool i_only_forward: 1; - - float i_caster_x; - float i_caster_y; - float i_caster_z; - float i_last_distance_from_caster; - float i_to_distance_from_caster; - float i_cur_angle; - ObjectGuid i_frightGUID; - TimeTracker i_nextCheckTime; + std::unique_ptr _path; + ObjectGuid _fleeTargetGUID; + TimeTracker _timer; + bool _interrupt; }; class TimedFleeingMovementGenerator : public FleeingMovementGenerator