/* * Copyright (C) 2016+ AzerothCore , released under GNU GPL v2 license: http://github.com/azerothcore/azerothcore-wotlk/LICENSE-GPL2 * Copyright (C) 2008-2016 TrinityCore * Copyright (C) 2005-2009 MaNGOS */ #include "MoveSplineInit.h" #include "MoveSpline.h" #include "MovementPacketBuilder.h" #include "Unit.h" #include "Transport.h" #include "Vehicle.h" #include "WorldPacket.h" #include "Opcodes.h" namespace Movement { UnitMoveType SelectSpeedType(uint32 moveFlags) { if (moveFlags & MOVEMENTFLAG_FLYING) { if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.flight >= speed_obj.flight_back*/) return MOVE_FLIGHT_BACK; else return MOVE_FLIGHT; } else if (moveFlags & MOVEMENTFLAG_SWIMMING) { if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.swim >= speed_obj.swim_back*/) return MOVE_SWIM_BACK; else return MOVE_SWIM; } else if (moveFlags & MOVEMENTFLAG_WALKING) { //if (speed_obj.run > speed_obj.walk) return MOVE_WALK; } else if (moveFlags & MOVEMENTFLAG_BACKWARD /*&& speed_obj.run >= speed_obj.run_back*/) return MOVE_RUN_BACK; // Flying creatures use MOVEMENTFLAG_CAN_FLY or MOVEMENTFLAG_DISABLE_GRAVITY // Run speed is their default flight speed. return MOVE_RUN; } int32 MoveSplineInit::Launch() { MoveSpline& move_spline = *unit->movespline; bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); Location real_position; // there is a big chance that current position is unknown if current state is not finalized, need compute it // this also allows CalculatePath spline position and update map position in much greater intervals // Don't compute for transport movement if the unit is in a motion between two transports if (!move_spline.Finalized() && move_spline.onTransport == transport) real_position = move_spline.ComputePosition(); else { Position const* pos; if (!transport) pos = unit; else pos = &unit->m_movementInfo.transport.pos; real_position.x = pos->GetPositionX(); real_position.y = pos->GetPositionY(); real_position.z = pos->GetPositionZ(); real_position.orientation = unit->GetOrientation(); } // should i do the things that user should do? - no. if (args.path.empty()) return 0; // corrent first vertex args.path[0] = real_position; args.initialOrientation = real_position.orientation; move_spline.onTransport = transport; uint32 moveFlags = unit->m_movementInfo.GetMovementFlags(); moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD); if (moveFlags & MOVEMENTFLAG_ROOT) moveFlags &= ~MOVEMENTFLAG_MASK_MOVING; if (!args.HasVelocity) { // If spline is initialized with SetWalk method it only means we need to select // walk move speed for it but not add walk flag to unit uint32 moveFlagsForSpeed = moveFlags; if (args.flags.walkmode) moveFlagsForSpeed |= MOVEMENTFLAG_WALKING; else moveFlagsForSpeed &= ~MOVEMENTFLAG_WALKING; args.velocity = unit->GetSpeed(SelectSpeedType(moveFlagsForSpeed)); } if (!args.Validate(unit)) return 0; unit->m_movementInfo.SetMovementFlags(moveFlags); move_spline.Initialize(args); WorldPacket data(SMSG_MONSTER_MOVE, 64); data.append(unit->GetPackGUID()); if (transport) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data.appendPackGUID(unit->GetTransGUID()); data << int8(unit->GetTransSeat()); } Movement::SplineBase::ControlArray* visualPoints = const_cast(move_spline._Spline().allocateVisualPoints()); visualPoints->resize(move_spline._Spline().getPointCount()); // Xinef: Apply hover in creature movement packet if (unit->IsHovering()) std::transform(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin(), HoverMovementTransform(unit->GetHoverHeight())); else std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin()); PacketBuilder::WriteMonsterMove(move_spline, data); unit->SendMessageToSet(&data,true); return move_spline.Duration(); } void MoveSplineInit::Stop() { MoveSpline& move_spline = *unit->movespline; // No need to stop if we are not moving if (move_spline.Finalized()) return; bool transport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); Location loc; if (move_spline.onTransport == transport) loc = move_spline.ComputePosition(); else { Position const* pos; if (!transport) pos = unit; else pos = &unit->m_movementInfo.transport.pos; loc.x = pos->GetPositionX(); loc.y = pos->GetPositionY(); loc.z = pos->GetPositionZ(); loc.orientation = unit->GetOrientation(); } args.flags = MoveSplineFlag::Done; unit->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FORWARD | MOVEMENTFLAG_SPLINE_ENABLED); move_spline.onTransport = transport; move_spline.Initialize(args); WorldPacket data(SMSG_MONSTER_MOVE, 64); data.append(unit->GetPackGUID()); if (transport) { data.SetOpcode(SMSG_MONSTER_MOVE_TRANSPORT); data.appendPackGUID(unit->GetTransGUID()); data << int8(unit->GetTransSeat()); } // Xinef: increase z position in packet loc.z += unit->GetHoverHeight(); PacketBuilder::WriteStopMovement(loc, args.splineId, data); unit->SendMessageToSet(&data, true); } MoveSplineInit::MoveSplineInit(Unit* m) : unit(m) { args.splineId = splineIdGen.NewId(); args.TransformForTransport = unit->HasUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && unit->GetTransGUID(); // mix existing state into new args.flags.walkmode = unit->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_WALKING); args.flags.flying = unit->m_movementInfo.HasMovementFlag((MovementFlags)(MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_DISABLE_GRAVITY)); } void MoveSplineInit::SetFacing(const Unit* target) { args.flags.EnableFacingTarget(); args.facing.target = target->GetGUID(); } void MoveSplineInit::SetFacing(float angle) { if (args.TransformForTransport) { if (Unit* vehicle = unit->GetVehicleBase()) angle -= vehicle->GetOrientation(); else if (Transport* transport = unit->GetTransport()) angle -= transport->GetOrientation(); } args.facing.angle = G3D::wrap(angle, 0.f, (float)G3D::twoPi()); args.flags.EnableFacingAngle(); } void MoveSplineInit::MoveTo(const Vector3& dest, bool generatePath, bool forceDestination) { if (generatePath) { PathGenerator path(unit); bool result = path.CalculatePath(dest.x, dest.y, dest.z, forceDestination); if (result && !(path.GetPathType() & PATHFIND_NOPATH)) { MovebyPath(path.GetPath()); return; } } args.path_Idx_offset = 0; args.path.resize(2); TransportPathTransform transform(unit, args.TransformForTransport); args.path[1] = transform(dest); } Vector3 TransportPathTransform::operator()(Vector3 input) { if (_transformForTransport) if (TransportBase* transport = _owner->GetDirectTransport()) transport->CalculatePassengerOffset(input.x, input.y, input.z); return input; } }