From a878a4f3f95f035950776f0551d40b190c4128df Mon Sep 17 00:00:00 2001 From: Noir Date: Mon, 17 Jun 2024 18:48:13 -0400 Subject: [PATCH 1/2] Fix minimum HP and MP checks on AP reset --- .../processor/stat/AssignAPProcessor.java | 128 ++++++++-- .../processor/stat/AssignAPProcessorTest.java | 237 ++++++++++++++++++ 2 files changed, 345 insertions(+), 20 deletions(-) create mode 100644 src/test/java/client/processor/stat/AssignAPProcessorTest.java diff --git a/src/main/java/client/processor/stat/AssignAPProcessor.java b/src/main/java/client/processor/stat/AssignAPProcessor.java index bc42c06cc5..c7897ce810 100644 --- a/src/main/java/client/processor/stat/AssignAPProcessor.java +++ b/src/main/java/client/processor/stat/AssignAPProcessor.java @@ -552,9 +552,7 @@ public class AssignAPProcessor { return false; } - int hp = player.getMaxHp(); - int level_ = player.getLevel(); - if (hp < level_ * 14 + 148) { + if (player.getMaxHp() < getMinHp(player.getJob(), player.getLevel())) { player.message("You don't have the minimum HP pool required to swap."); c.sendPacket(PacketCreator.enableActions()); return false; @@ -583,29 +581,14 @@ public class AssignAPProcessor { return false; } - int mp = player.getMaxMp(); - int level = player.getLevel(); - Job job = player.getJob(); - - boolean canWash = true; - if (job.isA(Job.SPEARMAN) && mp < 4 * level + 156) { - canWash = false; - } else if ((job.isA(Job.FIGHTER) || job.isA(Job.ARAN1)) && mp < 4 * level + 56) { - canWash = false; - } else if (job.isA(Job.THIEF) && job.getId() % 100 > 0 && mp < level * 14 - 4) { - canWash = false; - } else if (mp < level * 14 + 148) { - canWash = false; - } - - if (!canWash) { + if (player.getMaxMp() < getMinMp(player.getJob(), player.getLevel())) { player.message("You don't have the minimum MP pool required to swap."); c.sendPacket(PacketCreator.enableActions()); return false; } int curMp = player.getMp(); - int mplose = -takeMp(job); + int mplose = -takeMp(player.getJob()); player.assignMP(mplose, -1); if (!YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) { player.updateMp(Math.max(0, curMp + mplose)); @@ -896,4 +879,109 @@ public class AssignAPProcessor { return MaxMP; } + public static int getMinHp(Job job, int level) { + int multiplier = 0; + int offset = 0; + + if (job == Job.WARRIOR || + job.isA(Job.PAGE) || + job.isA(Job.SPEARMAN) || + job == Job.DAWNWARRIOR1 || + job == Job.ARAN1) { + multiplier = 24; offset = 118; + + } else if (job.isA(Job.FIGHTER) || + job.isA(Job.DAWNWARRIOR2) || + job.isA(Job.ARAN2)) { + multiplier = 24; offset = 418; + + } else if (job.isA(Job.MAGICIAN) || + job.isA(Job.BLAZEWIZARD1)) { + multiplier = 10; offset = 54; + + } else if (job == Job.BOWMAN || + job == Job.THIEF || + job == Job.WINDARCHER1 || + job == Job.NIGHTWALKER1) { + multiplier = 20; offset = 58; + + } else if (job.isA(Job.HUNTER) || + job.isA(Job.CROSSBOWMAN) || + job.isA(Job.ASSASSIN) || + job.isA(Job.BANDIT) || + job.isA(Job.WINDARCHER2) || + job.isA(Job.NIGHTWALKER2)) { + multiplier = 20; offset = 358; + + } else if (job == Job.PIRATE || + job == Job.THUNDERBREAKER1) { + multiplier = 22; offset = 38; + + } else if (job.isA(Job.BRAWLER) || + job.isA(Job.GUNSLINGER) || + job.isA(Job.THUNDERBREAKER2)) { + multiplier = 22; offset = 338; + + } else if (job == Job.BEGINNER || + job == Job.NOBLESSE) { + multiplier = 12; offset = 38; + } + + return (multiplier * level) + offset; + } + + public static int getMinMp(Job job, int level) { + int multiplier = 0; + int offset = 0; + + if (job == Job.WARRIOR || + job.isA(Job.FIGHTER) || + job.isA(Job.DAWNWARRIOR1) || + job.isA(Job.ARAN1)) { + multiplier = 4; offset = 55; + + } else if (job.isA(Job.PAGE) || + job.isA(Job.SPEARMAN)) { + multiplier = 4; offset = 155; + + } else if (job == Job.MAGICIAN || + job == Job.BLAZEWIZARD1) { + multiplier = 22; offset = -1; + + } else if (job.isA(Job.FP_WIZARD) || + job.isA(Job.IL_WIZARD) || + job.isA(Job.CLERIC) || + job.isA(Job.BLAZEWIZARD2)) { + multiplier = 22; offset = 449; + + } else if (job == Job.BOWMAN || + job == Job.THIEF || + job == Job.WINDARCHER1 || + job == Job.NIGHTWALKER1) { + multiplier = 14; offset = -15; + + } else if (job.isA(Job.HUNTER) || + job.isA(Job.CROSSBOWMAN) || + job.isA(Job.ASSASSIN) || + job.isA(Job.BANDIT) || + job.isA(Job.WINDARCHER2) || + job.isA(Job.NIGHTWALKER2)) { + multiplier = 14; offset = 135; + + } else if (job == Job.PIRATE || + job == Job.THUNDERBREAKER1) { + multiplier = 18; offset = -55; + + } else if (job.isA(Job.BRAWLER) || + job.isA(Job.GUNSLINGER) || + job.isA(Job.THUNDERBREAKER2)) { + multiplier = 18; offset = 95; + + } else if (job == Job.BEGINNER || + job == Job.NOBLESSE) { + multiplier = 10; offset = -5; + } + + return (multiplier * level) + offset; + } } diff --git a/src/test/java/client/processor/stat/AssignAPProcessorTest.java b/src/test/java/client/processor/stat/AssignAPProcessorTest.java new file mode 100644 index 0000000000..d565bbb3f9 --- /dev/null +++ b/src/test/java/client/processor/stat/AssignAPProcessorTest.java @@ -0,0 +1,237 @@ +package client.processor.stat; + +import client.Job; +import org.junit.jupiter.api.Test; + +import java.util.function.BiFunction; + +import static org.junit.jupiter.api.Assertions.*; + +class AssignAPProcessorTest { + + @Test + void getMinHp() { + int max_level = 200; + int cygnus_max_level = 120; + + BiFunction f = AssignAPProcessor::getMinHp; + + assertAll( + // Beginners + () -> assertEquals(2438, f.apply(Job.BEGINNER, max_level)), + () -> assertEquals(1478, f.apply(Job.NOBLESSE, cygnus_max_level)), + + // Warrior (Explorer) + () -> assertEquals(4918, f.apply(Job.WARRIOR, max_level)), + + () -> assertEquals(5218, f.apply(Job.FIGHTER, max_level)), + () -> assertEquals(5218, f.apply(Job.CRUSADER, max_level)), + () -> assertEquals(5218, f.apply(Job.HERO, max_level)), + + () -> assertEquals(4918, f.apply(Job.PAGE, max_level)), + () -> assertEquals(4918, f.apply(Job.WHITEKNIGHT, max_level)), + () -> assertEquals(4918, f.apply(Job.PALADIN, max_level)), + + () -> assertEquals(4918, f.apply(Job.SPEARMAN, max_level)), + () -> assertEquals(4918, f.apply(Job.DRAGONKNIGHT, max_level)), + () -> assertEquals(4918, f.apply(Job.DARKKNIGHT, max_level)), + + // Warrior (Cygnus) + () -> assertEquals(2998, f.apply(Job.DAWNWARRIOR1, cygnus_max_level)), + () -> assertEquals(3298, f.apply(Job.DAWNWARRIOR2, cygnus_max_level)), + () -> assertEquals(3298, f.apply(Job.DAWNWARRIOR3, cygnus_max_level)), + () -> assertEquals(3298, f.apply(Job.DAWNWARRIOR4, cygnus_max_level)), + + // Warrior (Aran) + () -> assertEquals(4918, f.apply(Job.ARAN1, max_level)), + () -> assertEquals(5218, f.apply(Job.ARAN2, max_level)), + () -> assertEquals(5218, f.apply(Job.ARAN3, max_level)), + () -> assertEquals(5218, f.apply(Job.ARAN4, max_level)), + + // Magician (Explorer) + () -> assertEquals(2054, f.apply(Job.MAGICIAN, max_level)), + + () -> assertEquals(2054, f.apply(Job.FP_WIZARD, max_level)), + () -> assertEquals(2054, f.apply(Job.FP_MAGE, max_level)), + () -> assertEquals(2054, f.apply(Job.FP_ARCHMAGE, max_level)), + + () -> assertEquals(2054, f.apply(Job.IL_WIZARD, max_level)), + () -> assertEquals(2054, f.apply(Job.IL_MAGE, max_level)), + () -> assertEquals(2054, f.apply(Job.IL_ARCHMAGE, max_level)), + + () -> assertEquals(2054, f.apply(Job.CLERIC, max_level)), + () -> assertEquals(2054, f.apply(Job.PRIEST, max_level)), + () -> assertEquals(2054, f.apply(Job.BISHOP, max_level)), + + // Magician (Cygnus) + () -> assertEquals(1254, f.apply(Job.BLAZEWIZARD1, cygnus_max_level)), + () -> assertEquals(1254, f.apply(Job.BLAZEWIZARD2, cygnus_max_level)), + () -> assertEquals(1254, f.apply(Job.BLAZEWIZARD3, cygnus_max_level)), + () -> assertEquals(1254, f.apply(Job.BLAZEWIZARD4, cygnus_max_level)), + + // Bowman (Explorer) + () -> assertEquals(4058, f.apply(Job.BOWMAN, max_level)), + + () -> assertEquals(4358, f.apply(Job.HUNTER, max_level)), + () -> assertEquals(4358, f.apply(Job.RANGER, max_level)), + () -> assertEquals(4358, f.apply(Job.BOWMASTER, max_level)), + + () -> assertEquals(4358, f.apply(Job.CROSSBOWMAN, max_level)), + () -> assertEquals(4358, f.apply(Job.SNIPER, max_level)), + () -> assertEquals(4358, f.apply(Job.MARKSMAN, max_level)), + + // Bowman (Cygnus) + () -> assertEquals(2458, f.apply(Job.WINDARCHER1, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.WINDARCHER2, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.WINDARCHER3, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.WINDARCHER4, cygnus_max_level)), + + // Thief (Explorer) + () -> assertEquals(4058, f.apply(Job.THIEF, max_level)), + + () -> assertEquals(4358, f.apply(Job.ASSASSIN, max_level)), + () -> assertEquals(4358, f.apply(Job.HERMIT, max_level)), + () -> assertEquals(4358, f.apply(Job.NIGHTLORD, max_level)), + + () -> assertEquals(4358, f.apply(Job.BANDIT, max_level)), + () -> assertEquals(4358, f.apply(Job.CHIEFBANDIT, max_level)), + () -> assertEquals(4358, f.apply(Job.SHADOWER, max_level)), + + // Thief (Cygnus) + () -> assertEquals(2458, f.apply(Job.NIGHTWALKER1, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.NIGHTWALKER2, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.NIGHTWALKER3, cygnus_max_level)), + () -> assertEquals(2758, f.apply(Job.NIGHTWALKER4, cygnus_max_level)), + + // Pirate (Explorer) + () -> assertEquals(4438, f.apply(Job.PIRATE, max_level)), + + () -> assertEquals(4738, f.apply(Job.BRAWLER, max_level)), + () -> assertEquals(4738, f.apply(Job.MARAUDER, max_level)), + () -> assertEquals(4738, f.apply(Job.BUCCANEER, max_level)), + + () -> assertEquals(4738, f.apply(Job.GUNSLINGER, max_level)), + () -> assertEquals(4738, f.apply(Job.OUTLAW, max_level)), + () -> assertEquals(4738, f.apply(Job.CORSAIR, max_level)), + + // Pirate (Cygnus) + () -> assertEquals(2678, f.apply(Job.THUNDERBREAKER1, cygnus_max_level)), + () -> assertEquals(2978, f.apply(Job.THUNDERBREAKER2, cygnus_max_level)), + () -> assertEquals(2978, f.apply(Job.THUNDERBREAKER3, cygnus_max_level)), + () -> assertEquals(2978, f.apply(Job.THUNDERBREAKER4, cygnus_max_level)) + ); + } + + @Test + void getMinMp() { + int max_level = 200; + int cygnus_max_level = 120; + + BiFunction f = AssignAPProcessor::getMinMp; + + assertAll( + // Beginners + () -> assertEquals(1995, f.apply(Job.BEGINNER, max_level)), + () -> assertEquals(1195, f.apply(Job.NOBLESSE, cygnus_max_level)), + + // Warrior (Explorer) + () -> assertEquals(855, f.apply(Job.WARRIOR, max_level)), + + () -> assertEquals(855, f.apply(Job.FIGHTER, max_level)), + () -> assertEquals(855, f.apply(Job.CRUSADER, max_level)), + () -> assertEquals(855, f.apply(Job.HERO, max_level)), + + () -> assertEquals(955, f.apply(Job.PAGE, max_level)), + () -> assertEquals(955, f.apply(Job.WHITEKNIGHT, max_level)), + () -> assertEquals(955, f.apply(Job.PALADIN, max_level)), + + () -> assertEquals(955, f.apply(Job.SPEARMAN, max_level)), + () -> assertEquals(955, f.apply(Job.DRAGONKNIGHT, max_level)), + () -> assertEquals(955, f.apply(Job.DARKKNIGHT, max_level)), + + // Warrior (Cygnus) + () -> assertEquals(535, f.apply(Job.DAWNWARRIOR1, cygnus_max_level)), + () -> assertEquals(535, f.apply(Job.DAWNWARRIOR2, cygnus_max_level)), + () -> assertEquals(535, f.apply(Job.DAWNWARRIOR3, cygnus_max_level)), + () -> assertEquals(535, f.apply(Job.DAWNWARRIOR4, cygnus_max_level)), + + // Warrior (Aran) + () -> assertEquals(855, f.apply(Job.ARAN1, max_level)), + () -> assertEquals(855, f.apply(Job.ARAN2, max_level)), + () -> assertEquals(855, f.apply(Job.ARAN3, max_level)), + () -> assertEquals(855, f.apply(Job.ARAN4, max_level)), + + // Magician (Explorer) + () -> assertEquals(4399, f.apply(Job.MAGICIAN, max_level)), + + () -> assertEquals(4849, f.apply(Job.FP_WIZARD, max_level)), + () -> assertEquals(4849, f.apply(Job.FP_MAGE, max_level)), + () -> assertEquals(4849, f.apply(Job.FP_ARCHMAGE, max_level)), + + () -> assertEquals(4849, f.apply(Job.IL_WIZARD, max_level)), + () -> assertEquals(4849, f.apply(Job.IL_MAGE, max_level)), + () -> assertEquals(4849, f.apply(Job.IL_ARCHMAGE, max_level)), + + () -> assertEquals(4849, f.apply(Job.CLERIC, max_level)), + () -> assertEquals(4849, f.apply(Job.PRIEST, max_level)), + () -> assertEquals(4849, f.apply(Job.BISHOP, max_level)), + + // Magician (Cygnus) + () -> assertEquals(2639, f.apply(Job.BLAZEWIZARD1, cygnus_max_level)), + () -> assertEquals(3089, f.apply(Job.BLAZEWIZARD2, cygnus_max_level)), + () -> assertEquals(3089, f.apply(Job.BLAZEWIZARD3, cygnus_max_level)), + () -> assertEquals(3089, f.apply(Job.BLAZEWIZARD4, cygnus_max_level)), + + // Bowman (Explorer) + () -> assertEquals(2785, f.apply(Job.BOWMAN, max_level)), + + () -> assertEquals(2935, f.apply(Job.HUNTER, max_level)), + () -> assertEquals(2935, f.apply(Job.RANGER, max_level)), + () -> assertEquals(2935, f.apply(Job.BOWMASTER, max_level)), + + () -> assertEquals(2935, f.apply(Job.CROSSBOWMAN, max_level)), + () -> assertEquals(2935, f.apply(Job.SNIPER, max_level)), + () -> assertEquals(2935, f.apply(Job.MARKSMAN, max_level)), + + // Bowman (Cygnus) + () -> assertEquals(1665, f.apply(Job.WINDARCHER1, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.WINDARCHER2, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.WINDARCHER3, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.WINDARCHER4, cygnus_max_level)), + + // Thief (Explorer) + () -> assertEquals(2785, f.apply(Job.THIEF, max_level)), + + () -> assertEquals(2935, f.apply(Job.ASSASSIN, max_level)), + () -> assertEquals(2935, f.apply(Job.HERMIT, max_level)), + () -> assertEquals(2935, f.apply(Job.NIGHTLORD, max_level)), + + () -> assertEquals(2935, f.apply(Job.BANDIT, max_level)), + () -> assertEquals(2935, f.apply(Job.CHIEFBANDIT, max_level)), + () -> assertEquals(2935, f.apply(Job.SHADOWER, max_level)), + + // Thief (Cygnus) + () -> assertEquals(1665, f.apply(Job.NIGHTWALKER1, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.NIGHTWALKER2, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.NIGHTWALKER3, cygnus_max_level)), + () -> assertEquals(1815, f.apply(Job.NIGHTWALKER4, cygnus_max_level)), + + // Pirate (Explorer) + () -> assertEquals(3545, f.apply(Job.PIRATE, max_level)), + + () -> assertEquals(3695, f.apply(Job.BRAWLER, max_level)), + () -> assertEquals(3695, f.apply(Job.MARAUDER, max_level)), + () -> assertEquals(3695, f.apply(Job.BUCCANEER, max_level)), + + () -> assertEquals(3695, f.apply(Job.GUNSLINGER, max_level)), + () -> assertEquals(3695, f.apply(Job.OUTLAW, max_level)), + () -> assertEquals(3695, f.apply(Job.CORSAIR, max_level)), + + // Pirate (Cygnus) + () -> assertEquals(2105, f.apply(Job.THUNDERBREAKER1, cygnus_max_level)), + () -> assertEquals(2255, f.apply(Job.THUNDERBREAKER2, cygnus_max_level)), + () -> assertEquals(2255, f.apply(Job.THUNDERBREAKER3, cygnus_max_level)), + () -> assertEquals(2255, f.apply(Job.THUNDERBREAKER4, cygnus_max_level)) + ); + } +} \ No newline at end of file From 94a08d86a01fc2767b689808a96a14695aa86aa6 Mon Sep 17 00:00:00 2001 From: Noir Date: Tue, 18 Jun 2024 21:42:52 -0400 Subject: [PATCH 2/2] Min HP / MP needs to check against post-AP-reset value --- .../java/client/processor/stat/AssignAPProcessor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/client/processor/stat/AssignAPProcessor.java b/src/main/java/client/processor/stat/AssignAPProcessor.java index c7897ce810..1af21574f7 100644 --- a/src/main/java/client/processor/stat/AssignAPProcessor.java +++ b/src/main/java/client/processor/stat/AssignAPProcessor.java @@ -552,14 +552,14 @@ public class AssignAPProcessor { return false; } - if (player.getMaxHp() < getMinHp(player.getJob(), player.getLevel())) { + int hplose = -takeHp(player.getJob()); + if (player.getMaxHp() + hplose < getMinHp(player.getJob(), player.getLevel())) { player.message("You don't have the minimum HP pool required to swap."); c.sendPacket(PacketCreator.enableActions()); return false; } int curHp = player.getHp(); - int hplose = -takeHp(player.getJob()); player.assignHP(hplose, -1); if (!YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) { player.updateHp(Math.max(1, curHp + hplose)); @@ -581,14 +581,14 @@ public class AssignAPProcessor { return false; } - if (player.getMaxMp() < getMinMp(player.getJob(), player.getLevel())) { + int mplose = -takeMp(player.getJob()); + if (player.getMaxMp() + mplose < getMinMp(player.getJob(), player.getLevel())) { player.message("You don't have the minimum MP pool required to swap."); c.sendPacket(PacketCreator.enableActions()); return false; } int curMp = player.getMp(); - int mplose = -takeMp(player.getJob()); player.assignMP(mplose, -1); if (!YamlConfig.config.server.USE_FIXED_RATIO_HPMP_UPDATE) { player.updateMp(Math.max(0, curMp + mplose));