Compare commits

...

13 Commits

Author SHA1 Message Date
Ponk
5fabbaf7ab Merge pull request #261 from pimittens/vanillafixes #patch
chaos scroll fix
2024-09-13 21:25:51 +02:00
pimittens
215dc42294 Create RandomizerTest.java 2024-09-10 13:49:16 -07:00
Ponk
314916279a Merge pull request #271 from P0nk/fix/global-drop-concurrency #patch
Fix global drops thread issue
2024-08-28 21:30:39 +02:00
P0nk
dbf1a1bb36 Fix global drops thread issue
This randomly caused global drops to stop working after a while.
Originally reported by Crabo of MapleHorizons.
2024-08-28 21:22:47 +02:00
Ponk
8f2b8dd013 Merge pull request #248 from HarkuLi/fix/vard-plastic-surgery #patch
NPC (Vard): Fix "Plastic Surgery" option
2024-08-28 19:57:04 +02:00
Ponk
8039852aa3 Merge pull request #247 from NoirReverie/master #patch
Fix minimum HP and MP checks on AP reset
2024-08-28 18:30:15 +02:00
Ponk
d3b567953d Merge pull request #270 from P0nk/fix/exploded-meso-delay #patch
Fix staggered exploding mesos
2024-08-27 07:47:31 +02:00
P0nk
5064ee936a Fix staggered exploding mesos
Thanks teto: "the staggering should only go up to 400ms [attack.attackDelay + (index++ % 5) * 100], and the total delay should be capped at 1000ms according to the BMS implementation"
2024-08-27 07:41:24 +02:00
pimittens
ec90df9c58 chaos scroll fix
The intention of the rand method is to return a pseudorandom uniformly distributed int between lbound and ubound (both inclusive). The previous implementation did not work as intended when the lower bound was negative since java round up instead of down when casting a negative double to an int. Adding the lower bound after the cast rather than before fixes this.

Also changed the CHSCROLL_STAT_RANGE from 6 to 5 to be consistent with gms.
2024-08-06 20:42:23 -07:00
HarkuLi
0245e7d1af NPC (Vard): Fix "Plastic Surgery" option
Correct typos for variable `fface_v`.
2024-06-19 18:56:14 +08:00
Noir
94a08d86a0 Min HP / MP needs to check against post-AP-reset value 2024-06-18 21:42:52 -04:00
NoirReverie
bcc7bedbc9 Merge branch 'P0nk:master' into master 2024-06-17 18:53:21 -04:00
Noir
a878a4f3f9 Fix minimum HP and MP checks on AP reset 2024-06-17 18:48:13 -04:00
9 changed files with 404 additions and 47 deletions

View File

@@ -344,7 +344,7 @@ server:
USE_ENHANCED_CRAFTING: false #Apply chaos scroll on every equip crafted.
SCROLL_CHANCE_ROLLS: 1 #Number of rolls for success on a scroll, set 1 for default.
CHSCROLL_STAT_RATE: 1 #Number of rolls of stat upgrade on a successfully applied chaos scroll, set 1 for default.
CHSCROLL_STAT_RANGE: 6 #Stat upgrade range (-N, N) on chaos scrolls.
CHSCROLL_STAT_RANGE: 5 #Stat upgrade range (-N, N) on chaos scrolls.
#Beginner Skills Configuration
USE_ULTRA_NIMBLE_FEET: false #Massive speed & jump upgrade.

View File

@@ -58,8 +58,8 @@ function action(mode, type, selection) {
}
}
if (cm.getChar().getGender() == 1) {
for (var i = 0; i < fface.length; i++) {
pushIfItemExists(facenew, fface[i] + cm.getChar().getFace()
for (var i = 0; i < fface_v.length; i++) {
pushIfItemExists(facenew, fface_v[i] + cm.getChar().getFace()
% 1000 - (cm.getChar().getFace()
% 100));
}

View File

@@ -552,16 +552,14 @@ public class AssignAPProcessor {
return false;
}
int hp = player.getMaxHp();
int level_ = player.getLevel();
if (hp < level_ * 14 + 148) {
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));
@@ -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) {
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(job);
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;
}
}

View File

@@ -112,6 +112,8 @@ import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
private static final int EXPLODED_MESO_SPREAD_DELAY = 100;
private static final int EXPLODED_MESO_MAX_DELAY = 1000;
public static class AttackInfo {
@@ -936,7 +938,7 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
}
private void removeExplodedMesos(MapleMap map, AttackInfo attack) {
short delay = attack.attackDelay;
int index = 0;
for (Integer mesoId : attack.explodedMesos) {
MapObject mapobject = map.getMapObject(mesoId);
if (!(mapobject instanceof MapItem mapItem)) {
@@ -951,11 +953,12 @@ public abstract class AbstractDealDamageHandler extends AbstractPacketHandler {
if (mapItem.isPickedUp()) {
return;
}
map.pickItemDrop(PacketCreator.removeExplodedMesoFromMap(mapItem.getObjectId(), delay), mapItem);
int delay = attack.attackDelay + (index++ % 5) * EXPLODED_MESO_SPREAD_DELAY;
delay = Math.min(delay, EXPLODED_MESO_MAX_DELAY);
map.pickItemDrop(PacketCreator.removeExplodedMesoFromMap(mapItem.getObjectId(), (short) delay), mapItem);
} finally {
mapItem.unlockItem();
}
delay += 100;
}
}
}

View File

@@ -58,7 +58,7 @@ public class MonsterInformationProvider {
private final Map<Integer, List<MonsterDropEntry>> drops = new HashMap<>();
private final List<MonsterGlobalDropEntry> globaldrops = new ArrayList<>();
private final Map<Integer, List<MonsterGlobalDropEntry>> continentdrops = new HashMap<>();
private final Map<Integer, List<MonsterGlobalDropEntry>> continentDrops = new HashMap<>();
private final Map<Integer, List<Integer>> dropsChancePool = new HashMap<>(); // thanks to ronan
private final Set<Integer> hasNoMultiEquipDrops = new HashSet<>();
@@ -76,23 +76,15 @@ public class MonsterInformationProvider {
retrieveGlobal();
}
public final List<MonsterGlobalDropEntry> getRelevantGlobalDrops(int mapid) {
int continentid = mapid / 100000000;
public final List<MonsterGlobalDropEntry> getRelevantGlobalDrops(int mapId) {
final int continentId = mapId / 100000000;
return continentDrops.computeIfAbsent(continentId, this::loadContinentDrops);
}
List<MonsterGlobalDropEntry> contiItems = continentdrops.get(continentid);
if (contiItems == null) { // continent separated global drops found thanks to marcuswoon
contiItems = new ArrayList<>();
for (MonsterGlobalDropEntry e : globaldrops) {
if (e.continentid < 0 || e.continentid == continentid) {
contiItems.add(e);
}
}
continentdrops.put(continentid, contiItems);
}
return contiItems;
private List<MonsterGlobalDropEntry> loadContinentDrops(int continentId) {
return globaldrops.stream()
.filter(dropEntry -> dropEntry.continentid < 0 || dropEntry.continentid == continentId)
.toList();
}
private void retrieveGlobal() {
@@ -291,7 +283,7 @@ public class MonsterInformationProvider {
extraMultiEquipDrops.clear();
dropsChancePool.clear();
globaldrops.clear();
continentdrops.clear();
continentDrops.clear();
retrieveGlobal();
}
}

View File

@@ -751,7 +751,7 @@ public class MapleMap {
}
final MonsterInformationProvider mi = MonsterInformationProvider.getInstance();
final List<MonsterGlobalDropEntry> globalEntry = mi.getRelevantGlobalDrops(this.getId());
final List<MonsterGlobalDropEntry> globalEntry = new ArrayList<>(mi.getRelevantGlobalDrops(mapid));
final List<MonsterDropEntry> dropEntry = new ArrayList<>();
final List<MonsterDropEntry> visibleQuestEntry = new ArrayList<>();

View File

@@ -35,6 +35,6 @@ public class Randomizer {
}
public static int rand(final int lbound, final int ubound) {
return (int) ((rand.nextDouble() * (ubound - lbound + 1)) + lbound);
return ((int) (rand.nextDouble() * (ubound - lbound + 1))) + lbound;
}
}

View File

@@ -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<Job,Integer,Integer> 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<Job,Integer,Integer> 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))
);
}
}

View File

@@ -0,0 +1,37 @@
package tools;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class RandomizerTest {
@Test
void randShouldIncludeEntireRange() {
Map<Integer, Integer> rands = new HashMap<>();
final int rounds = 100_000;
for (int i = 0; i < rounds; i++) {
int randomValue = Randomizer.rand(-5, 5);
rands.compute(randomValue, (k, v) -> v == null ? 0 : v + 1);
}
assertFalse(rands.containsKey(-6));
assertTrue(rands.containsKey(-5));
assertTrue(rands.containsKey(-4));
assertTrue(rands.containsKey(-3));
assertTrue(rands.containsKey(-2));
assertTrue(rands.containsKey(-1));
assertTrue(rands.containsKey(0));
assertTrue(rands.containsKey(1));
assertTrue(rands.containsKey(2));
assertTrue(rands.containsKey(3));
assertTrue(rands.containsKey(4));
assertTrue(rands.containsKey(5));
assertFalse(rands.containsKey(6));
}
}