/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package illarion.client.world.movement;
import illarion.client.util.UpdateTask;
import illarion.client.world.CharMovementMode;
import illarion.client.world.World;
import illarion.common.types.Direction;
import illarion.common.types.ServerCoordinate;
import illarion.common.util.FastMath;
import org.illarion.engine.input.Input;
import org.illarion.engine.input.Key;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* This keyboard movement handler simply handles the keyboard input to perform the walking operations.
*
* @author Martin Karing <nitram@illarion.org>
*/
class SimpleKeyboardMovementHandler extends AbstractMovementHandler implements KeyboardMovementHandler {
@Nonnull
private final Input input;
@Nonnull
private final Set<Direction> activeDirections;
private boolean delayedMove;
@Nonnull
private final ScheduledExecutorService delayedMoveExecutor;
@Nullable
private ScheduledFuture<Void> delayedMoveTask;
@Nonnull
private final UpdateTask updateMovementTask = (container, delta) -> getMovement().update();
SimpleKeyboardMovementHandler(@Nonnull Movement movement, @Nonnull Input input) {
super(movement);
activeDirections = EnumSet.noneOf(Direction.class);
this.input = input;
delayedMoveExecutor = new ScheduledThreadPoolExecutor(0);
}
@Override
public void startMovingTowards(@Nonnull Direction direction) {
if (activeDirections.add(direction)) {
if (delayedMoveTask != null) {
delayedMoveTask.cancel(false);
delayedMoveTask = null;
}
if (!getMovement().isMoving()) {
delayedMoveTask = delayedMoveExecutor.schedule(() -> {
delayedMove = false;
World.getUpdateTaskManager().addTask(updateMovementTask);
return null;
}, 100, TimeUnit.MILLISECONDS);
delayedMove = true;
}
}
}
@Override
public void stopMovingTowards(@Nonnull Direction direction) {
activeDirections.remove(direction);
}
@Nullable
@Override
public StepData getNextStep(@Nonnull ServerCoordinate currentLocation) {
return new DefaultStepData(getMovementMode(), getMovementDirection());
}
@Nullable
private Direction getMovementDirection() {
if (delayedMove) {
return null;
}
if (activeDirections.isEmpty() || (activeDirections.size() > 2)) {
return null;
}
return getCombined(activeDirections);
}
@Nullable
public static Direction getCombined(@Nonnull Iterable<Direction> activeDirections) {
int xVec = 0;
int yVec = 0;
for (Direction activeDir : activeDirections) {
xVec += activeDir.getDirectionVectorX();
yVec += activeDir.getDirectionVectorY();
}
xVec = FastMath.sign(xVec);
yVec = FastMath.sign(yVec);
//noinspection ConstantConditions
for (Direction dir : Direction.values()) {
if ((dir.getDirectionVectorX() == xVec) && (dir.getDirectionVectorY() == yVec)) {
return dir;
}
}
return null;
}
@Nonnull
private CharMovementMode getMovementMode() {
if (input.isKeyDown(Key.LeftAlt)) {
return CharMovementMode.None;
}
if (!World.getPlayer().getCarryLoad().isRunningPossible()) {
return CharMovementMode.Walk;
}
CharMovementMode mode = getMovement().getDefaultMovementMode();
if (getMovement().isMovementModePossible(mode)) {
return mode;
}
return CharMovementMode.Walk;
}
@Nonnull
@Override
public String toString() {
return "Simple keyboard movement handler";
}
}