diff --git a/src/main/java/io/luna/LunaContext.java b/src/main/java/io/luna/LunaContext.java index c96de6298..127157891 100644 --- a/src/main/java/io/luna/LunaContext.java +++ b/src/main/java/io/luna/LunaContext.java @@ -9,7 +9,7 @@ * * @author lare96 */ -public final class LunaContext { +public class LunaContext { /** * The world. diff --git a/src/main/java/io/luna/game/model/mob/Player.java b/src/main/java/io/luna/game/model/mob/Player.java index 24f17763f..86fc9b9be 100644 --- a/src/main/java/io/luna/game/model/mob/Player.java +++ b/src/main/java/io/luna/game/model/mob/Player.java @@ -608,19 +608,23 @@ public double getRunEnergy() { /** * Sets the run energy percentage. * - * @param newRunEnergy The value to set to. + * @param runEnergy The value to set to. */ - public void setRunEnergy(double newRunEnergy, boolean update) { - if (newRunEnergy > 100.0) { - newRunEnergy = 100.0; + public void setRunEnergy(double runEnergy) { + if (runEnergy > 100.0) { + runEnergy = 100.0; } - if (runEnergy != newRunEnergy) { - runEnergy = newRunEnergy; - if (update) { - queue(new UpdateRunEnergyMessageWriter((int) runEnergy)); - } + if (runEnergy < 0) { + runEnergy = 0; } + + this.runEnergy = runEnergy; + } + + /** Updates the client with the current run energy. */ + public void updateRunEnergy() { + queue(new UpdateRunEnergyMessageWriter((int) runEnergy)); } /** @@ -635,9 +639,20 @@ public void increaseRunEnergy(double amount) { } else if (newEnergy < 0.0) { newEnergy = 0.0; } - setRunEnergy(newEnergy, true); + setRunEnergy(newEnergy); + updateRunEnergy(); + } + + boolean hasEnoughEnergyToRun() { + return runEnergyAfterReduction() >= 0; } + /** @return the remaining {@code runEnergy} after a running a single step.*/ + double runEnergyAfterReduction() { + double energyReduction = 0.117 * 2 * Math + .pow(Math.E, 0.0027725887222397812376689284858327062723020005374410 * getWeight()); + return getRunEnergy() - energyReduction; + } /** * @return The combined weight of the inventory and equipment. */ diff --git a/src/main/java/io/luna/game/model/mob/PlayerSettings.java b/src/main/java/io/luna/game/model/mob/PlayerSettings.java index d822a94b8..a32d03585 100644 --- a/src/main/java/io/luna/game/model/mob/PlayerSettings.java +++ b/src/main/java/io/luna/game/model/mob/PlayerSettings.java @@ -9,7 +9,7 @@ * * @author lare96 */ -public final class PlayerSettings { +public class PlayerSettings { /** * An enumerated type whose elements represent brightness levels. diff --git a/src/main/java/io/luna/game/model/mob/WalkingQueue.java b/src/main/java/io/luna/game/model/mob/WalkingQueue.java index b74d108eb..58b9839f5 100644 --- a/src/main/java/io/luna/game/model/mob/WalkingQueue.java +++ b/src/main/java/io/luna/game/model/mob/WalkingQueue.java @@ -17,7 +17,7 @@ * @author lare96 * @author Graham */ -public final class WalkingQueue { +public class WalkingQueue { // TODO Rewrite @@ -94,12 +94,12 @@ public int getY() { /** * A deque of current steps. */ - private final Deque current = new ArrayDeque<>(); + private final Deque currentQueue = new ArrayDeque<>(); /** * A deque of previous steps. */ - private final Deque previous = new ArrayDeque<>(); + private final Deque previousQueue = new ArrayDeque<>(); /** * The mob. @@ -115,7 +115,6 @@ public int getY() { * If the current path is a running path. */ private boolean runningPath; - /** * Create a new {@link WalkingQueue}. * @@ -131,45 +130,70 @@ public WalkingQueue(Mob mob) { */ public void process() { // TODO clean up function - Step current = new Step(mob.getPosition()); + Step currentStep = new Step(mob.getPosition()); Direction walkingDirection = Direction.NONE; Direction runningDirection = Direction.NONE; boolean restoreEnergy = true; - Step next = this.current.poll(); - if (next != null) { - previous.add(next); - walkingDirection = Direction.between(current, next); - current = next; + Step nextStep = this.currentQueue.poll(); + if (nextStep != null) { + previousQueue.add(nextStep); + walkingDirection = Direction.between(currentStep, nextStep); + currentStep = nextStep; if (mob.getType() == EntityType.PLAYER) { Player player = mob.asPlr(); if (player.isRunning() || runningPath) { - next = decrementRunEnergy(player) ? this.current.poll() : null; - if (next != null) { + if (player.hasEnoughEnergyToRun()) { + useEnergy(player); + updateEnergy(); + nextStep = this.currentQueue.poll(); + } else { + nextStep = null; + } + if (nextStep != null) { restoreEnergy = false; - previous.add(next); - runningDirection = Direction.between(current, next); - current = next; + previousQueue.add(nextStep); + runningDirection = Direction.between(currentStep, nextStep); + currentStep = nextStep; } } } - - Position newPosition = new Position(current.getX(), current.getY(), mob.getPosition().getZ()); + Position newPosition = new Position(currentStep.getX(), currentStep.getY(), mob.getPosition().getZ()); mob.setPosition(newPosition); } if (restoreEnergy && mob.getType() == EntityType.PLAYER) { - incrementRunEnergy(); + Player player = mob.asPlr(); + incrementRunEnergy(player); + updateEnergy(); } mob.setWalkingDirection(walkingDirection); mob.setRunningDirection(runningDirection); } + void updateEnergy(){ + mob.asPlr().updateRunEnergy(); + } + + /** + * Depletes a player's energy. If the player doesn't have enough energy, the player will stop running. + */ + void useEnergy(Player player) { + double energyLeft = player.runEnergyAfterReduction(); + if (player.hasEnoughEnergyToRun()) { + player.setRunEnergy(energyLeft); + } else { + player.setRunEnergy(0.0); + player.setRunning(false); + runningPath = false; + } + } + /** * Walks to the specified offsets. * @@ -200,23 +224,22 @@ public void walk(Position firstPos, Position... otherPos) { * @param step The step to add. */ public void addFirst(Step step) { - current.clear(); + currentQueue.clear(); runningPath = false; - Queue backtrack = new ArrayDeque<>(); for (; ; ) { - Step prev = previous.pollLast(); + Step prev = previousQueue.pollLast(); if (prev == null) { break; } backtrack.add(prev); if (prev.equals(step)) { backtrack.forEach(this::add); - previous.clear(); + previousQueue.clear(); return; } } - previous.clear(); + previousQueue.clear(); add(step); } @@ -227,7 +250,7 @@ public void addFirst(Step step) { * @param next The step to add. */ public void add(Step next) { - Step last = current.peekLast(); + Step last = currentQueue.peekLast(); if (last == null) { last = new Step(mob.getPosition()); } @@ -251,7 +274,7 @@ public void add(Step next) { } else if (deltaY > 0) { deltaY--; } - current.add(new Step(nextX - deltaX, nextY - deltaY)); + currentQueue.add(new Step(nextX - deltaX, nextY - deltaY)); } } @@ -259,35 +282,14 @@ public void add(Step next) { * Clears the current and previous steps. */ public void clear() { - current.clear(); - previous.clear(); - } - - /** - * A function that implements an algorithm to deplete run energy. - * - * @return {@code false} if the player can no longer run. - */ - private boolean decrementRunEnergy(Player player) { - double totalWeight = player.getWeight(); - double energyReduction = 0.117 * 2 * Math - .pow(Math.E, 0.0027725887222397812376689284858327062723020005374410 * totalWeight); - double newValue = player.getRunEnergy() - energyReduction; - if (newValue <= 0.0) { - player.setRunEnergy(0.0, true); - player.setRunning(false); - runningPath = false; - return false; - } - player.setRunEnergy(newValue, true); - return true; + currentQueue.clear(); + previousQueue.clear(); } /** * A function that implements an algorithm to restore run energy. */ - private void incrementRunEnergy() { - Player player = mob.asPlr(); + void incrementRunEnergy(Player player) { double runEnergy = player.getRunEnergy(); if (runEnergy >= 100.0) { @@ -300,7 +302,7 @@ private void incrementRunEnergy() { double newValue = runEnergy + energyRestoration; newValue = Math.min(newValue, 100.0); - player.setRunEnergy(newValue, true); + player.setRunEnergy(newValue); } /** @@ -309,7 +311,7 @@ private void incrementRunEnergy() { * @return The amount of remaining steps. */ public int getRemainingSteps() { - return current.size(); + return currentQueue.size(); } /** diff --git a/src/main/java/io/luna/game/model/mob/persistence/PlayerData.java b/src/main/java/io/luna/game/model/mob/persistence/PlayerData.java index fcee966ff..d03bd41e5 100644 --- a/src/main/java/io/luna/game/model/mob/persistence/PlayerData.java +++ b/src/main/java/io/luna/game/model/mob/persistence/PlayerData.java @@ -66,7 +66,7 @@ public void load(Player player) { player.getIgnores().addAll(ignores); player.setUnbanDate(unbanDate); player.setUnmuteDate(unmuteDate); - player.setRunEnergy(runEnergy, false); + player.setRunEnergy(runEnergy); player.setWeight(weight, false); player.getAttributes().load(attributes); } diff --git a/src/test/java/io/luna/game/model/mob/NullPlayerSettings.java b/src/test/java/io/luna/game/model/mob/NullPlayerSettings.java new file mode 100644 index 000000000..7c11f731a --- /dev/null +++ b/src/test/java/io/luna/game/model/mob/NullPlayerSettings.java @@ -0,0 +1,50 @@ +package io.luna.game.model.mob; + +/** A {@link PlayerSettings} designed for testing purposes only. */ +public class NullPlayerSettings extends PlayerSettings { + + @Override + public void showRunning() { + return; + } + + @Override + public void showAutoRetaliate() { + return; + } + + @Override + public void showBrightnessLevel() { + return; + } + + @Override + public void showMouseType() { + return; + } + + @Override + public void showChatEffects() { + return; + } + + @Override + public void showSplitPrivateChat() { + return; + } + + @Override + public void showAcceptAid() { + return; + } + + @Override + public void showMusicVolume() { + return; + } + + @Override + public void showEffectsVolume() { + return; + } +} diff --git a/src/test/java/io/luna/game/model/mob/NullWalkingQueue.java b/src/test/java/io/luna/game/model/mob/NullWalkingQueue.java new file mode 100644 index 000000000..594989a5d --- /dev/null +++ b/src/test/java/io/luna/game/model/mob/NullWalkingQueue.java @@ -0,0 +1,20 @@ +package io.luna.game.model.mob; + +/** + * A {@link WalkingQueue} designed for testing purposes only. + */ +class NullWalkingQueue extends WalkingQueue { + /** + * Create a new {@link WalkingQueue}. + * + * @param mob The mob. + */ + NullWalkingQueue(Mob mob) { + super(mob); + } + + @Override + void updateEnergy() { + return; + } +} diff --git a/src/test/java/io/luna/game/model/mob/WalkingQueueTest.java b/src/test/java/io/luna/game/model/mob/WalkingQueueTest.java new file mode 100644 index 000000000..f38f40824 --- /dev/null +++ b/src/test/java/io/luna/game/model/mob/WalkingQueueTest.java @@ -0,0 +1,111 @@ +package io.luna.game.model.mob; + +import io.luna.LunaContext; +import io.luna.game.model.Position; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class WalkingQueueTest { + private final PlayerCredentials credentials = new PlayerCredentials("test", "test"); + private final LunaContext context = mock(LunaContext.class); + private final Player player = new Player(context, credentials); + + private final WalkingQueue queue = new NullWalkingQueue(player); + private final Position startPosition = new Position(0, 0); + + + private WalkingQueueTest() { + player.setSettings(new NullPlayerSettings()); + } + + @BeforeEach + void init() { + player.setPosition(startPosition); + player.setRunning(false); + queue.clear(); + } + + @Test + void whenPlayerIsNotMoving_thenDoNotTakeAnySteps() { + player.setPosition(startPosition); + + //No movement applied + queue.process(); + + assertEquals(startPosition, player.getPosition()); + } + + @Test + void whenPlayerIsWalking_thenTakeOneStep() { + player.setRunEnergy(100); + + queue.walk(2, 2); + queue.process(); + + var stepsTaken = player.getPosition().computeLongestDistance(startPosition); + assertEquals(stepsTaken, 1); + } + + @Test + void whenPlayerIsNotMoving_thenIncreaseRunEnergy() { + var startingEnergy = 0.0; + player.setRunEnergy(startingEnergy); + player.setPosition(startPosition); + + // No movement applied + queue.process(); + + assertTrue(player.getRunEnergy() > startingEnergy); + } + + @Test + void whenPlayerIsWalking_thenIncreaseRunEnergy() { + var startingEnergy = 0.0; + player.setRunEnergy(startingEnergy); + player.setPosition(startPosition); + + queue.walk(1, 1); + queue.process(); + + assertTrue(player.getRunEnergy() > startingEnergy); + } + @Test + void whenPlayerIsRunning_AndHasEnergy_thenDecreaseRunEnergy(){ + var startingEnergy = 100; + player.setRunEnergy(startingEnergy); + player.setRunning(true); + + queue.walk(2, 2); + queue.process(); + + assertTrue(player.getRunEnergy() < startingEnergy); + } + + @Test + void whenPlayerIsRunning_AndHasEnergy_thenTakeTwoSteps() { + player.setRunEnergy(100); + player.setRunning(true); + + queue.walk(2, 2); + queue.process(); + + var stepsTaken = player.getPosition().computeLongestDistance(startPosition); + assertEquals(stepsTaken, 2); + } + + @Test + void whenPlayerIsRunning_AndOutOfEnergy_thenTakeOneStep() { + player.setRunEnergy(0); + player.setRunning(true); + + queue.walk(2, 2); + queue.process(); + + var stepsTaken = player.getPosition().computeLongestDistance(startPosition); + assertEquals(stepsTaken, 1); + } +} \ No newline at end of file