protected void moveToLocation(int x, int y, int z, int offset) { // Get current position of the L2Character final int curX = super.getX(); final int curY = super.getY(); final int curZ = super.getZ(); // Calculate distance (dx,dy) between current position and destination final int dx = (x - curX); final int dy = (y - curY); double distance = Math.sqrt(dx*dx + dy*dy); if (Config.DEBUG) _log.fine("distance to target:" + distance); // Define movement angles needed // ^ // | X (x,y) // | / // | /distance // | / // |/ angle // X ----------> // (curx,cury) double cos; double sin; // Check if a movement offset is defined or no distance to go through if (offset > 0 || distance < 1) { // If no distance to go through, the movement is canceled if (distance < 1 || distance - offset <= 0) { sin = 0; cos = 1; distance = 0; x = curX; y = curY; if (Config.DEBUG) _log.fine("already in range, no movement needed."); // Notify the AI that the L2Character is arrived at destination getAI().notifyEvent(CtrlEvent.EVT_ARRIVED, null); return; } // Calculate movement angles needed sin = dy/distance; cos = dx/distance; distance -= (offset-5); // due to rounding error, we have to move a bit closer to be in range // Calculate the new destination with offset included x = curX + (int)(distance * cos); y = curY + (int)(distance * sin); } else { // Calculate movement angles needed sin = dy/distance; cos = dx/distance; } // Get the Move Speed of the L2Charcater float speed = getStat().getMoveSpeed(); // Create and Init a MoveData object MoveData m = new MoveData(); // Caclulate the Nb of ticks between the current position and the destination m._ticksToMove = (int)(GameTimeController.TICKS_PER_SECOND * distance / speed); // Calculate the xspeed and yspeed in unit/ticks in function of the movement speed m._xSpeedTicks = (float)(cos * speed / GameTimeController.TICKS_PER_SECOND); m._ySpeedTicks = (float)(sin * speed / GameTimeController.TICKS_PER_SECOND); // Calculate and set the heading of the L2Character int heading = (int) (Math.atan2(-sin, -cos) * 10430.378350470452724949566316381); heading += 32768; setHeading(heading); if (Config.DEBUG) _log.fine("dist:"+ distance +"speed:" + speed + " ttt:" +m._ticksToMove + " dx:"+(int)m._xSpeedTicks + " dy:"+(int)m._ySpeedTicks + " heading:" + heading); m._xDestination = x; m._yDestination = y; m._zDestination = z; // this is what was requested from client m._heading = 0; m._moveStartTime = GameTimeController.getGameTicks(); m._xMoveFrom = curX; m._yMoveFrom = curY; m._zMoveFrom = curZ; // If necessary set Nb ticks needed to a min value to ensure small distancies movements if (m._ticksToMove < 1 ) m._ticksToMove = 1; if (Config.DEBUG) _log.fine("time to target:" + m._ticksToMove); // Set the L2Character _move object to MoveData object _move = m; // Add the L2Character to movingObjects of the GameTimeController // The GameTimeController manage objects movement GameTimeController.getInstance().registerMovingObject(this); int tm = m._ticksToMove*GameTimeController.MILLIS_IN_TICK; // Create a task to notify the AI that L2Character arrives at a check point of the movement if (tm > 3000) ThreadPoolManager.getInstance().scheduleAi( new NotifyAITask(CtrlEvent.EVT_ARRIVED_REVALIDATE), 2000); // the CtrlEvent.EVT_ARRIVED will be sent when the character will actually arrive // to destination by GameTimeController }