/** * Handle direction press to invoke or disable auto-walk. * * @param direction The direction to move/face * @param user The entity to set/check */ private synchronized void processAutoWalk(final Direction direction, final User user) { RPAction walkAction = new RPAction(); final boolean facing = direction == user.getDirection(); /* Correct facing direction if necessary. */ if (!facing) { RPAction faceAction = new RPAction(); faceAction.put(TYPE, FACE); faceAction.put(DIR, direction.get()); this.client.send(faceAction); } /* Check if player is already using auto-walk. */ if (!user.getRPObject().has(AUTOWALK)) { walkAction.put(TYPE, WALK); } else if (facing) { /* Player can press key of current walking direction to toggle * auto-walk off. */ walkAction.put(TYPE, WALK); walkAction.put(MODE, "stop"); } /* Send auto-walk action to the server. */ if (walkAction.has(TYPE)) { /* Toggle auto-walk. */ this.client.send(walkAction); } }
/** * Initialize this entity for an object. * * @param base The object. * @see #release() */ @Override public void initialize(final RPObject base) { double speed; super.initialize(base); if (base.has("dir")) { setDirection(Direction.build(base.getInt("dir"))); } if (base.has("speed")) { speed = base.getDouble("speed"); } else { speed = 0.0; } dx = direction.getdx() * speed; dy = direction.getdy() * speed; }
/** * When entity moves, it will be called with the data. * * @param x new x coordinate * @param y new y coordinate * @param direction new direction * @param speed new speed */ private void onMove(final int x, final int y, final Direction direction, final double speed) { double oldx = this.x; double oldy = this.y; setSpeed(direction.getdx() * speed, direction.getdy() * speed); if ((Direction.LEFT.equals(direction)) || (Direction.RIGHT.equals(direction))) { this.y = y; if (compareDouble(this.x, x, 1.0)) { // make the movement look more nicely: + this.dx * 0.1 this.dx = calcDeltaMovement(this.x + this.dx * 0.1, x, direction.getdx()) * speed; } else { this.x = x; } this.dy = 0; } else if ((Direction.UP.equals(direction)) || (Direction.DOWN.equals(direction))) { this.x = x; this.dx = 0; if (compareDouble(this.y, y, 1.0)) { // make the movement look more nicely: + this.dy * 0.1 this.dy = calcDeltaMovement(this.y + this.dy * 0.1, y, direction.getdy()) * speed; } else { this.y = y; } } else { // placing entities this.x = x; this.y = y; } // Call onPosition only if the entity actually moved. Also always call // on partial coordinates - those are always predicted rather than real // and thus should always be a result of prediction. However, the // client collision detection does not always agree with that of the // server, so relying on just the coordinate change checks can miss // entities stopping when they collide with each other. if (!compareDouble(this.x, oldx, EPSILON) || !compareDouble(this.y, oldy, EPSILON) || !compareDouble(oldx, (int) oldx, EPSILON) || !compareDouble(oldy, (int) oldy, EPSILON)) { onPosition(x, y); } }
/** * Process attribute changes that may affect positioning. This is needed because different * entities may want to process coordinate changes more gracefully. * * @param base The previous values. * @param diff The changes. */ @Override protected void processPositioning(final RPObject base, final RPObject diff) { // Real movement case final int oldx = base.getInt("x"); final int oldy = base.getInt("y"); int newX = oldx; int newY = oldy; if (diff.has("x")) { newX = diff.getInt("x"); } if (diff.has("y")) { newY = diff.getInt("y"); } Direction tempDirection; if (diff.has("dir")) { tempDirection = Direction.build(diff.getInt("dir")); setDirection(tempDirection); } else if (base.has("dir")) { tempDirection = Direction.build(base.getInt("dir")); setDirection(tempDirection); } else { tempDirection = Direction.STOP; } double speed; /* * Speed change must be fired only after the new speed has been stored * (done in onMove()) */ boolean speedChanged = false; if (diff.has("speed")) { speed = diff.getDouble("speed"); speedChanged = true; } else if (base.has("speed")) { speed = base.getDouble("speed"); } else { speed = 0; } onMove(newX, newY, tempDirection, speed); if (speedChanged) { fireChange(PROP_SPEED); } boolean positionChanged = false; if ((Direction.STOP.equals(tempDirection)) || (speed == 0)) { setSpeed(0.0, 0.0); /* * Try to ensure relocation in the case the client and server were * in disagreement about the position at the moment of stopping. */ if (!(compareDouble(y, newY, EPSILON) && compareDouble(x, newX, EPSILON))) { positionChanged = true; } // Store the new position before signaling it with onPosition(). x = newX; y = newY; } /* * Change in position? */ if (positionChanged || ((oldx != newX) && (oldy != newY))) { onPosition(newX, newY); } }
@Override public void keyPressed(final KeyEvent e) { final int keyCode = e.getKeyCode(); /* Ignore if the key is already pressed down. */ if (!client.keyIsPressed(keyCode)) { /* Add keyCode to pressedStateKeys list. */ client.onKeyPressed(keyCode); if (e.isShiftDown()) { /* * We are going to use shift to move to previous/next line of text * with arrows so we just ignore the keys if shift is pressed. */ return; } switch (keyCode) { case KeyEvent.VK_R: if (e.isControlDown()) { /* * Ctrl+R Remove text bubbles */ screen.clearTexts(); } break; case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: /* * Ctrl means face, otherwise move. Alt turns on auto-walk. */ final Direction direction = keyCodeToDirection(e.getKeyCode()); /* TODO: Remove MOTION condition when auto-walk testing is * finished. * * Check if the player is currently using auto-walk or the Alt * key is pressed. */ User user = User.get(); if ((user.getRPObject().has(AUTOWALK) || e.isAltDown()) && Testing.MOVEMENT) { /* Face direction pressed and toggle auto-walk. */ this.processAutoWalk(direction, user); } else { if (e.isAltGraphDown()) { if (System.currentTimeMillis() - lastAction > 1000) { final EntityView<?> view = screen.getEntityViewAt( user.getX() + direction.getdx(), user.getY() + direction.getdy()); if (view != null) { final IEntity entity = view.getEntity(); if (!entity.equals(user)) { view.onAction(); lastAction = System.currentTimeMillis(); } } } } this.processDirectionPress(direction, e.isControlDown()); } break; case KeyEvent.VK_0: case KeyEvent.VK_1: case KeyEvent.VK_2: case KeyEvent.VK_3: case KeyEvent.VK_4: case KeyEvent.VK_5: case KeyEvent.VK_6: case KeyEvent.VK_7: case KeyEvent.VK_8: case KeyEvent.VK_9: switchToSpellCastingState(e); break; } } }