Compare commits

...

17 Commits

Author SHA1 Message Date
Ponk
a5b572023b Merge pull request #275 from nutnnut/fix-monster-crystal-level #patch
fix maker monster crystal level calculation
2024-10-19 13:52:08 +02:00
Ponk
380e4284ee Merge pull request #276 from JalenJaceX2/command-list #patch
Create Commands.txt
2024-10-19 13:44:27 +02:00
JalenJaceX2
16ff5a6f54 Create Commands.txt 2024-10-14 02:02:50 -07:00
Sirinut Euaungkanakul
cced80991f fix maker monster crystal level calculation
(cherry picked from commit 0f3611a41b449e195de6eceb686a97a40196b919)
2024-10-07 14:39:20 +07:00
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
11 changed files with 605 additions and 48 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.

200
handbook/Commands.txt Normal file
View File

@@ -0,0 +1,200 @@
Common Commands:
@help - Show available commands.
@commands - Show available commands.
@droplimit - Check drop limit of current map.
@time - Show current server time.
@credits - Show credits. These people made the server possible.
@uptime - Show server online time.
@gacha - Show gachapon rewards.
@dispose - Dispose to fix NPC chat.
@changel - Change language settings
@equiplv - Show levels of all equipped items.
@showrates - Show all world/character rates.
@rates - Show your rates.
@online - Show all online players.
@gm- Send a message to the game masters.
@reportbug - Send in a bug report.
@points - Show point total.
@joinevent - Join active event.
@leaveevent-Leave active event.
@ranks - Show player rankings.
@str - Assign AP into STR.
@dex - Assign AP into DEX.
@int - Assign AP into INT.
@luk - Assign AP into LUK.
@enableauth - Enable PIC code by resetting the cooldown.
@toggleexp - Toggle enable/disable all exp gain.
@mylawn - Claim ownership of the current map.
@bosshp - Show HP of bosses on current map.
@mobhp - Show HP of mobs on current map.
Donator Commands:
@whatdropsfrom - Show what items drop from a mob.
@whodrops - Show what drops an item.
@buffme - Activate GM buffs on self.
@goto - Warp to a predefined map.
JrGM Commands:
!recharge - Recharge and refill all USE items.
!whereami - Show info about objects on current map.
!hide - Hide from players.
!unhide - Toggle Hide.
!sp - Set available SP.
!ap - Set available AP.
!empowerme - Activate all useful buffs.
!buffmap - Give GM buffs to the whole map.
!buff - Activate a buff.
!bomb - Bomb a player, dealing damage.
!dc - Disconnect a player.
!cleardrops - Clear drops by player.
!clearslot - Clear all items in an inventory tab.
!clearsavelocs - Clear saved locations for a player.
!warp - Warp to a map.
!warphere - Move a player to your location.
!summon - Move a player to your location.
!warpto - Warp to a player.
!reach - Warp to a player.
!follow - Warp to a player.
!gmshop - Open the GM shop.
!heal - Fully heal your HP/MP.
!item - Spawn an item into your inventory.
!drop - Spawn an item onto the ground.
!level - Set your level.
!levelpro - Set your level, one by one.
!setslot - Set amount of inventory slots in all tabs.
!setstat - Set all primary stats to new value.
!maxstat - Max out all character stats.
!maxskill - Max out all job skills.
!resetskill Set all skill levels to 0.
!search - Search String.wz.
!jail - Move a player to the jail.
!unjail- Free a player from jail.
!job - Change job of a player.
!unbug - Unbug self.
!id - Search in handbook.
!gachalist - Show gachapon rewards.
!loot - Loots all items that belong to you.
!mobskill - Apply a mob skill to all mobs on the map.
Args: <mob skill id> <skill level>
GM Commands:
!debuff - Put a debuff on all nearby players.
!fly - Enable/disable fly feature.
!spawn - Spawn mob(s) on your location.
!mutemap - Toggle mute players in the map.
!checkdmg - Show stats and damage of a player.
!inmap - Show all players in the map.
!reloadevents - Reload all event data.
!reloaddrops - Reload all drop data.
!reloadportals - Reload all portal scripts.
!reloadmap - Reload the map.
!reloadshops - Reload popup shops and NPC shops.
!hpmp - Set HP/MP of a player.
!maxhpmp - Set base HP/MP of a player.
!music - Play a song.
!monitor - Toggle monitored packet logging of a character.
!monitors - Show all characters being monitored for packet logging.
!ignore - Toggle ignore a character from auto-ban alerts.
!ignored - Show all characters being ignored in auto-ban alerts.
!pos - Show current position and foothold.
!togglecoupon - Toggle enable/disable a coupon.
!togglewhitechat - Toggle white GM chat.
!fame - Set new fame value of a player.
!givenx - Give NX to a player.
!givevp - Give vote points to a player.
!givems - Give mesos to a player.
!giverp - Give reward points to a player.
!expeds - Show all ongoing boss expeditions.
!kill - Kill a player.
!seed - Drop all seeds inside Henesys PQ.
!maxenergy - Set dojo energy to max value.
!killall - Kill all mobs in the map.
!notice - Send a blue message to everyone on the server.
!rip - Send a RIP notice.
!openportal - Open a portal on the map.
!closeportal - Close a portal.
!pe - Handle synthesized packets from file, and handle them as if sent from a client.
!startevent - Start an event on current map.
!endevent - Close entry for ongoing event.
!startmapevent - Start a "classic" event on current map.
!stopmapevent - Stop ongoing "classic" event.
!online2 - Show all online players.
!ban - Ban a player.
!unban - Unban a player.
!healmap - Heal all HP/MP of all players in the map.
!healperson - Heal all HP/MP of a player.
!hurt - Nearly kill a player.
!killmap - Kill all players in the map.
!night - Set sky background to black.
!npc - Spawn an NPC on your location.
!face - Change face of a player.
!hair - Change hair of a player.
!startquest - Start a quest.
!completequest - Complete an active quest.
!resetquest - Reset a completed quest.
!timer - Set timer on a player in current map.
!timermap - Set timer on all players in current map.
!timerall Set a server wide timer.
!warpmap - Warp all characters on current map to a new map.
!warparea - Warp all nearby players to a new map.
SuperGM Commands:
!servermessage - Set scrolling server message.
!proitem - Spawn an item with custom stats.
!seteqstat-Set stats of all equips in inventory.
!exprate - Set world exp rate.
!mesorate - Set world meso rate.
!droprate - Set world drop rate.
!bossdroprate - Set world boss drop rate.
!questrate - Set world quest rate.
!travelrate - Set world travel rate.
!fishrate - Set fishing rate.
!itemvac - Loot all drops on the map.
!forcevac-Loot all drops on the map.
!zakum - Spawn Zakum on your location.
!horntail - Spawn Horntail on your location.
!pinkbean - Spawn Pink Bean on your location.
!pap - Spawn Papulatus on your location.
!pianus - Spawn Pianus (R) on your location.
!cake - Spawn Cake boss with specified HP.
!playernpc - Spawn a player NPC of an online player.
!playernpcremove - Remove a "Iv 200" player NPC.
!pnpc - Spawn a permanent NPC on your location.
!pnpcremove - Remove a permanent NPC on the map.
!pmob - Spawn a permanent mob on your location.
!pmobremove - Remove all permanent mobs of the same type on the map.
Developer Commands:
!debug - Show a debug message.
!set - Store value in an array, for testing.
!showpackets - Toggle show received packets in console.
!showmovelife - Toggle show move life in console.
!showsessions - Show online sessions.
!iplist - Show IP of all players.
Admin Commands:
!setgmlevel - Set GM level of a player.
!warpworld - Warp to a different world.
!saveall - Save all characters.
!dcall - Disconnect all players (online or logged in).
!mapplayers - Show all players on the map.
!getacc - Show account name of an online player.
!shutdown - Shut down the server.
!clearquestcache - Clear all quest cache.
!clearquest - Clear cache of a quest.
!supplyratecoupon - Set availability of coupons in Cash Shop.
!spawnallpnpcs - Spawn player NPCs of all existing players.
!eraseallpnpcs - Remove all player NPCs.
!addchannel - Add a new channel to a world.
!addworld - Add a new world.
!removechannel - Remove channel from a world.
!removeworld - Remove a world.
!devtest - Runs devtest.js. Developer utility - test stuff without restarting the server.

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

@@ -2063,7 +2063,7 @@ public class ItemInformationProvider {
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
int dropperid = rs.getInt("dropperid");
itemid = getCrystalForLevel(LifeFactory.getMonsterLevel(dropperid) - 1);
itemid = getCrystalForLevel(LifeFactory.getMonsterLevel(dropperid));
}
}
}

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));
}
}