Lower-bracket equip levelup & Channel/World capacity patch

Rebalanced the low level section of the equipment level up system.
Fixed EQUIP_EXP_RATE not acting as expected to be.
Changed chscroll system, now using a new flag instead of the SCROLL_CHANCE_RATE.
Optimized PlayerStorage, now using a proper name map when searching for a character name.
Tweaked some aspects of the BalrogPQ.
Improved the channel capacity bar and world server capacity checks throughout the source.
This commit is contained in:
ronancpl
2018-04-25 12:01:24 -03:00
parent b7a259e2c4
commit 7d448cce4f
31 changed files with 446 additions and 90 deletions

View File

@@ -161,9 +161,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private static NumberFormat nf = new DecimalFormat("#,###,###,###");
private static MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!";
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay",
"nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm",
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"};
"operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "yata", "AsiaSoft", "henesys"};
private int world;
private int accountid, id;
@@ -5766,17 +5766,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
announce(MaplePacketCreator.sendYellowTip(m));
}
public void mobKilled(int id) {
public void updateQuestMobCount(int id) {
// It seems nexon uses monsters that don't exist in the WZ (except string) to merge multiple mobs together for these 3 monsters.
// We also want to run mobKilled for both since there are some quest that don't use the updated ID...
if (id == 1110100 || id == 1110130) {
mobKilled(9101000);
updateQuestMobCount(9101000);
} else if (id == 2230101 || id == 2230131) {
mobKilled(9101001);
updateQuestMobCount(9101001);
} else if (id == 1140100 || id == 1140130) {
mobKilled(9101002);
updateQuestMobCount(9101002);
}
int lastQuestProcessed = 0;
int lastQuestProcessed = 0;
try {
synchronized (quests) {
for (MapleQuestStatus q : quests.values()) {

View File

@@ -294,6 +294,7 @@ public class Commands {
gotomaps.put("herb", 251000000);
gotomaps.put("omega", 221000000);
gotomaps.put("korean", 222000000);
gotomaps.put("ellin", 300000000);
gotomaps.put("nlc", 600000000);
gotomaps.put("excavation", 990000000);
gotomaps.put("pianus", 230040420);

View File

@@ -273,7 +273,7 @@ public class Equip extends Item {
this.level = level;
}
private int getStatModifier(boolean isAttribute) {
private static int getStatModifier(boolean isAttribute) {
// each set of stat points grants a chance for a bonus stat point upgrade at equip level up.
if(ServerConstants.USE_EQUIPMNT_LVLUP_POWER) {
@@ -286,7 +286,7 @@ public class Equip extends Item {
}
}
private int randomizeStatUpgrade(int top) {
private static int randomizeStatUpgrade(int top) {
int limit = Math.min(top, ServerConstants.MAX_EQUIPMNT_LVLUP_STAT_UP);
int poolCount = (limit * (limit + 1) / 2) + limit;
@@ -310,7 +310,7 @@ public class Equip extends Item {
stats.add(new Pair<>(name, maxUpgrade));
}
private void getUnitSlotUpgrade(List<Pair<StatUpgrade, Integer>> stats, StatUpgrade name) {
private static void getUnitSlotUpgrade(List<Pair<StatUpgrade, Integer>> stats, StatUpgrade name) {
if(Math.random() < 0.1) {
stats.add(new Pair<>(name, 1)); // 10% success on getting a slot upgrade.
}
@@ -482,16 +482,18 @@ public class Equip extends Item {
return (int) itemExp;
}
private double normalizedMasteryExp(int reqLevel) {
private static double normalizedMasteryExp(int reqLevel) {
// Conversion factor between mob exp and equip exp gain. Through many calculations, the expected for equipment levelup
// from level 1 to 2 is killing about 100~200 mobs of the same level range, on a 1x EXP rate scenario.
if(reqLevel >= 78) {
return Math.max(ServerConstants.EQUIP_EXP_RATE * (10413.648 * Math.exp(reqLevel * 0.03275)), 15);
return Math.max((10413.648 * Math.exp(reqLevel * 0.03275)), 15);
} else if(reqLevel >= 38) {
return Math.max(ServerConstants.EQUIP_EXP_RATE * ( 4985.818 * Math.exp(reqLevel * 0.02007)), 15);
return Math.max(( 4985.818 * Math.exp(reqLevel * 0.02007)), 15);
} else if(reqLevel >= 18) {
return Math.max(( 248.219 * Math.exp(reqLevel * 0.11093)), 15);
} else {
return Math.max(ServerConstants.EQUIP_EXP_RATE * ( 248.219 * Math.exp(reqLevel * 0.11093)), 15);
return Math.max(((1334.564 * Math.log(reqLevel)) - 1731.976), 15);
}
}
@@ -501,7 +503,7 @@ public class Equip extends Item {
int reqLevel = ii.getEquipStats(this.getItemId()).get("reqLevel");
float masteryModifier = (float)ExpTable.getExpNeededForLevel(1) / (float)normalizedMasteryExp(reqLevel);
float masteryModifier = (float)(ServerConstants.EQUIP_EXP_RATE * ExpTable.getExpNeededForLevel(1)) / (float)normalizedMasteryExp(reqLevel);
float elementModifier = (isElemental) ? 0.85f : 0.6f;
float baseExpGain = gain * elementModifier * masteryModifier;
@@ -552,7 +554,7 @@ public class Equip extends Item {
return "'" + eqpName + "' -> LV: #e#b" + itemLevel + "#k#n " + eqpInfo + "\r\n";
}
public final void showLevelupMessage(String msg, MapleClient c) {
private static void showLevelupMessage(String msg, MapleClient c) {
c.getPlayer().showHint(msg, 300);
}

View File

@@ -19,7 +19,7 @@ public class ServerConstants {
public static String[] WORLD_NAMES = {"Scania", "Bera", "Broa", "Windia", "Khaini", "Bellocan", "Mardia", "Kradia", "Yellonde", "Demethos", "Galicia", "El Nido", "Zenith", "Arcenia", "Kastia", "Judis", "Plana", "Kalluna", "Stius", "Croa", "Medere"};
//Login Configuration
public static final int CHANNEL_LOAD = 100; //Max players per channel.
public static final int CHANNEL_LOAD = 100; //Max players per channel (limit actually used to calculate the World server capacity).
public static final long RESPAWN_INTERVAL = 10 * 1000; //10 seconds, 10000.
public static final long PURGING_INTERVAL = 5 * 60 * 1000;
@@ -82,7 +82,7 @@ public class ServerConstants {
public static final int MESO_RATE = 10;
public static final int DROP_RATE = 10;
public static final int QUEST_RATE = 5; //Multiplier for Exp & Meso gains when completing a quest. Only available when USE_QUEST_RATE is true. Stacks with server Exp & Meso rates.
public static final double EQUIP_EXP_RATE = 10.0; //Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
public static final double EQUIP_EXP_RATE = 1.0; //Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
public static final double PARTY_BONUS_EXP_RATE = 1.0; //Rate for the party exp reward.
public static final double PQ_BONUS_EXP_RATE = 0.5; //Rate for the PQ exp reward.
@@ -114,6 +114,7 @@ public class ServerConstants {
public static final boolean USE_ENHANCED_CHSCROLL = true; //Equips even more powerful with chaos upgrade.
public static final boolean USE_ENHANCED_CRAFTING = true; //Apply chaos scroll on every equip crafted.
public static final int SCROLL_CHANCE_RATE = 0; //Number of rolls for success on a scroll, set 0 for default.
public static final int CHSCROLL_STAT_RATE = 1; //Number of rolls of stat upgrade on a successfully applied chaos scroll, set 1 for default.
public static final int CHSCROLL_STAT_RANGE = 6; //Stat upgrade range (-N, N) on chaos scrolls.
//Beginner Skills Configuration

View File

@@ -37,11 +37,13 @@ public class PlayerStorage {
private final ReadLock rlock = locks.readLock();
private final WriteLock wlock = locks.writeLock();
private final Map<Integer, MapleCharacter> storage = new LinkedHashMap<>();
private final Map<String, MapleCharacter> nameStorage = new LinkedHashMap<>();
public void addPlayer(MapleCharacter chr) {
wlock.lock();
try {
storage.put(chr.getId(), chr);
nameStorage.put(chr.getName().toLowerCase(), chr);
} finally {
wlock.unlock();
}
@@ -50,7 +52,10 @@ public class PlayerStorage {
public MapleCharacter removePlayer(int chr) {
wlock.lock();
try {
return storage.remove(chr);
MapleCharacter mc = storage.remove(chr);
if(mc != null) nameStorage.remove(mc.getName().toLowerCase());
return mc;
} finally {
wlock.unlock();
}
@@ -59,11 +64,7 @@ public class PlayerStorage {
public MapleCharacter getCharacterByName(String name) {
rlock.lock();
try {
for (MapleCharacter chr : storage.values()) {
if (chr.getName().toLowerCase().equals(name.toLowerCase()))
return chr;
}
return null;
return nameStorage.get(name.toLowerCase());
} finally {
rlock.unlock();
}

View File

@@ -77,7 +77,7 @@ import server.quest.MapleQuest;
import tools.locks.MonitoredLockType;
import tools.AutoJCE;
public class Server implements Runnable {
public class Server {
private static final Set<Integer> activeFly = new HashSet<>();
private static final Map<Integer, Integer> couponRates = new HashMap<>(30);
private static final List<Integer> activeCoupons = new LinkedList<>();
@@ -262,8 +262,7 @@ public class Server implements Runnable {
}
}
@Override
public void run() {
public void init() {
Properties p = new Properties();
try {
p.load(new FileInputStream("world.ini"));
@@ -388,7 +387,7 @@ public class Server implements Runnable {
System.setProperty("wzpath", "wz");
Security.setProperty("crypto.policy", "unlimited");
AutoJCE.removeCryptographyRestrictions();
Server.getInstance().run();
Server.getInstance().init();
}
public Properties getSubnetInfo() {
@@ -973,7 +972,7 @@ public class Server implements Runnable {
}
instance = null;
System.gc();
getInstance().run();//DID I DO EVERYTHING?! D:
getInstance().init();//DID I DO EVERYTHING?! D:
}
} finally {
srvLock.unlock();

View File

@@ -194,9 +194,9 @@ public final class Channel {
public void removePlayer(MapleCharacter chr) {
players.removePlayer(chr.getId());
}
public int getConnectedClients() {
return players.getAllCharacters().size();
public int getChannelCapacity() {
return (int)(Math.ceil(((float) players.getAllCharacters().size() / ServerConstants.CHANNEL_LOAD) * 800));
}
public void broadcastPacket(final byte[] data) {

View File

@@ -98,16 +98,22 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
boolean allowLogin = true;
Channel cserv = c.getChannelServer();
/* is this check really necessary?
if (state == MapleClient.LOGIN_SERVER_TRANSITION || state == MapleClient.LOGIN_NOTLOGGEDIN) {
for (String charName : c.loadCharacterNames(c.getWorld())) {
for (Channel ch : c.getWorldServer().getChannels()) {
if (ch.isConnected(charName)) {
allowLogin = false;
}
List<String> charNames = c.loadCharacterNames(c.getWorld());
if(!newcomer) {
charNames.remove(player.getName());
}
for (String charName : charNames) {
if(c.getWorldServer().getPlayerStorage().getCharacterByName(charName) != null) {
allowLogin = false;
break;
}
break;
}
}
*/
if (state != MapleClient.LOGIN_SERVER_TRANSITION || !allowLogin) {
c.setPlayer(null);
c.announce(MaplePacketCreator.getAfterLoginError(7));

View File

@@ -51,6 +51,11 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
return;
}
if(c.getWorldServer().isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);

View File

@@ -33,6 +33,11 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
}
if (c.checkPic(pic)) {
if(c.getWorldServer().isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getAfterLoginError(10));
return;
}
server.unregisterLoginState(c);
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId);

View File

@@ -23,6 +23,8 @@ package net.server.handlers.login;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CharlistRequestHandler extends AbstractMaplePacketHandler {
@@ -32,6 +34,12 @@ public final class CharlistRequestHandler extends AbstractMaplePacketHandler {
slea.readByte();
int world = slea.readByte();
c.setWorld(world);
if(Server.getInstance().getWorld(world).isWorldCapacityFull()) {
c.announce(MaplePacketCreator.getServerStatus(2));
return;
}
c.setChannel(slea.readByte() + 1);
c.sendCharList(world);
}

View File

@@ -22,10 +22,9 @@
package net.server.handlers.login;
import client.MapleClient;
import constants.ServerConstants;
import net.AbstractMaplePacketHandler;
import net.server.world.World;
import net.server.Server;
import net.server.channel.Channel;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
@@ -34,18 +33,9 @@ public final class ServerStatusRequestHandler extends AbstractMaplePacketHandler
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte world = (byte) slea.readShort();//Wuuu? ):
int status;
int num = 0;
for (Channel ch : Server.getInstance().getWorld(world).getChannels()) {
num += ch.getConnectedClients();
}
if (num >= ServerConstants.CHANNEL_LOAD) {
status = 2;
} else if (num >= ServerConstants.CHANNEL_LOAD * .8) { // More than 80 percent o___o
status = 1;
} else {
status = 0;
}
World wserv = Server.getInstance().getWorld(world);
int status = wserv.getWorldCapacityStatus();
c.announce(MaplePacketCreator.getServerStatus(status));
}
}

View File

@@ -264,6 +264,26 @@ public class World {
return g;
}
public boolean isWorldCapacityFull() {
return getWorldCapacityStatus() == 2;
}
public int getWorldCapacityStatus() {
int worldCap = channels.size() * ServerConstants.CHANNEL_LOAD;
int num = players.getSize();
int status;
if (num >= worldCap) {
status = 2;
} else if (num >= worldCap * .8) { // More than 80 percent o___o
status = 1;
} else {
status = 0;
}
return status;
}
public MapleGuildSummary getGuildSummary(int gid, int wid) {
if (gsStore.containsKey(gid)) {
return gsStore.get(gid);

View File

@@ -23,6 +23,7 @@ package scripting;
import java.awt.Point;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@@ -89,11 +90,15 @@ public class AbstractPlayerInteraction {
return c.getPlayer().getMap();
}
public static int getHourOfDay() {
return Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
}
public int getMarketPortalId(int mapId) {
return getMarketPortalId(getWarpMap(mapId));
}
private int getMarketPortalId(MapleMap map) {
private static int getMarketPortalId(MapleMap map) {
return (map.findMarketPortal() != null) ? map.findMarketPortal().getId() : map.getRandomPlayerSpawnpoint().getId();
}
@@ -221,7 +226,7 @@ public class AbstractPlayerInteraction {
return getPlayer().canHold(itemid, quantity);
}
private List<Integer> convertToIntegerArray(List<Double> list) {
private static List<Integer> convertToIntegerArray(List<Double> list) {
List<Integer> intList = new LinkedList<>();
for(Double d: list) intList.add(d.intValue());
@@ -507,8 +512,8 @@ public class AbstractPlayerInteraction {
}
public void gainFame(int delta) {
c.getPlayer().addFame(delta);
c.announce(MaplePacketCreator.getShowFameGain(delta));
c.getPlayer().addFame(delta);
c.announce(MaplePacketCreator.getShowFameGain(delta));
}
public void changeMusic(String songName) {
@@ -783,7 +788,7 @@ public class AbstractPlayerInteraction {
c.announce(MaplePacketCreator.modifyInventory(false, Collections.singletonList(new ModifyInventory(0, newItem))));
}
public void spawnNpc(int npcId, Point pos, MapleMap map) {
public static void spawnNpc(int npcId, Point pos, MapleMap map) {
MapleNPC npc = MapleLifeFactory.getNPC(npcId);
if (npc != null) {
npc.setPosition(pos);
@@ -802,9 +807,13 @@ public class AbstractPlayerInteraction {
getPlayer().getMap().spawnMonster(monster);
}
public MapleMonster getMonsterLifeFactory(int mid) {
public static MapleMonster getMonsterLifeFactory(int mid) {
return MapleLifeFactory.getMonster(mid);
}
public static MobSkill getMobSkill(int skill, int level) {
return MobSkillFactory.getMobSkill(skill, level);
}
public void spawnGuide() {
c.announce(MaplePacketCreator.spawnGuide(true));
@@ -861,10 +870,6 @@ public class AbstractPlayerInteraction {
return c.getPlayer().containsAreaInfo(area, info);
}
public MobSkill getMobSkill(int skill, int level) {
return MobSkillFactory.getMobSkill(skill, level);
}
public void earnTitle(String msg) {
c.announce(MaplePacketCreator.earnTitleMessage(msg));
}

View File

@@ -913,6 +913,21 @@ public class EventInstanceManager {
}
}
public void dispatchUpdateQuestMobCount(int mobid, int mapid) {
Map<Integer, MapleCharacter> mapChars = getInstanceMap(mapid).getMapPlayers();
if(!mapChars.isEmpty()) {
List<MapleCharacter> eventMembers = getPlayers();
for (MapleCharacter evChr : eventMembers) {
MapleCharacter chr = mapChars.get(evChr.getId());
if(chr != null && chr.isLoggedin() && !chr.isAwayFromWorld()) {
chr.updateQuestMobCount(mobid);
}
}
}
}
public MapleMonster getMonster(int mid) {
return(MapleLifeFactory.getMonster(mid));
}

View File

@@ -651,7 +651,7 @@ public class MapleItemInformationProvider {
}
private void scrollEquipWithChaos(Equip nEquip, int range) {
if(ServerConstants.SCROLL_CHANCE_RATE > 0) {
if(ServerConstants.CHSCROLL_STAT_RATE > 0) {
int temp;
short curStr, curDex, curInt, curLuk, curWatk, curWdef, curMatk, curMdef, curAcc, curAvoid, curSpeed, curJump, curHp, curMp;
@@ -687,7 +687,7 @@ public class MapleItemInformationProvider {
curMp = Short.MIN_VALUE;
}
for(int i = 0; i < ServerConstants.SCROLL_CHANCE_RATE; i++) {
for(int i = 0; i < ServerConstants.CHSCROLL_STAT_RATE; i++) {
if (nEquip.getStr() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curStr + chscrollRandomizedStat(range);
else temp = nEquip.getStr() + chscrollRandomizedStat(range);

View File

@@ -35,7 +35,6 @@ import constants.skills.ILMage;
import constants.skills.NightLord;
import constants.skills.NightWalker;
import constants.skills.Shadower;
import constants.skills.SuperGM;
import java.awt.Point;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -47,7 +46,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.LinkedHashSet;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -384,7 +383,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
Collection<MapleCharacter> chrs = map.getCharacters();
Set<MapleCharacter> underleveled = new LinkedHashSet<>();
Set<MapleCharacter> underleveled = new HashSet<>();
for (MapleCharacter mc : chrs) {
if (expDist.containsKey(mc.getId())) {
boolean isKiller = (mc.getId() == killerId);
@@ -452,7 +451,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
attacker.gainExp(personalExp, partyExp, true, false, isKiller);
attacker.increaseEquipExp(personalExp);
attacker.mobKilled(getId());
attacker.updateQuestMobCount(getId());
}
}
@@ -543,7 +542,29 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return looter != null ? looter : killer;
}
private void dispatchUpdateQuestMobCount() {
Set<Integer> attackerChrids = takenDamage.keySet();
if(!attackerChrids.isEmpty()) {
Map<Integer, MapleCharacter> mapChars = map.getMapPlayers();
if(!mapChars.isEmpty()) {
int mobid = getId();
for (Integer chrid : attackerChrids) {
MapleCharacter chr = mapChars.get(chrid);
if(chr != null && chr.isLoggedin() && !chr.isAwayFromWorld()) {
chr.updateQuestMobCount(mobid);
}
}
}
}
}
public void dispatchMonsterKilled(boolean hasKiller) {
if(!hasKiller) {
dispatchUpdateQuestMobCount();
}
if (getMap().getEventInstance() != null) {
if (!this.getStats().isFriendly()) {
getMap().getEventInstance().monsterKilled(this, hasKiller);
@@ -569,8 +590,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}
// should only really be used to determine drop owner
private int getHighestDamagerId() {
public int getHighestDamagerId() {
int curId = 0;
int curDmg = 0;

View File

@@ -1077,7 +1077,7 @@ public class MapleMap {
}
}
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) {
killMonster(monster, chr, withDrops, 1);
}
@@ -1180,17 +1180,34 @@ public class MapleMap {
}
public void killMonster(int mobId) {
List<MapleMapObject> mmoL = new LinkedList(getMapObjects());
MapleCharacter chr = (MapleCharacter) getPlayers().get(0);
List<MapleMonster> mobList = getMonsters();
for (MapleMapObject mmo : mmoL) {
if (mmo instanceof MapleMonster) {
if (((MapleMonster) mmo).getId() == mobId) {
this.killMonster((MapleMonster) mmo, (MapleCharacter) getPlayers().get(0), false);
for (MapleMonster mob : mobList) {
if (mob.getId() == mobId) {
this.killMonster(mob, chr, false);
}
}
}
public void killMonsterWithDrops(int mobId) {
Map<Integer, MapleCharacter> mapChars = this.getMapPlayers();
if(!mapChars.isEmpty()) {
MapleCharacter defaultChr = mapChars.entrySet().iterator().next().getValue();
List<MapleMonster> mobList = getMonsters();
for (MapleMonster mob : mobList) {
if (mob.getId() == mobId) {
MapleCharacter chr = mapChars.get(mob.getHighestDamagerId());
if(chr == null) chr = defaultChr;
this.killMonster(mob, chr, true);
}
}
}
}
public void monsterCloakingDevice() {
for (MapleMapObject monstermo : getMapObjectsInRange(new Point(0, 0), Double.POSITIVE_INFINITY, Arrays.asList(MapleMapObjectType.MONSTER))) {
MapleMonster monster = (MapleMonster) monstermo;
@@ -2678,6 +2695,22 @@ public class MapleMap {
}
}
public Map<Integer, MapleCharacter> getMapPlayers() {
chrRLock.lock();
try {
Map<Integer, MapleCharacter> mapChars = new HashMap<>(characters.size());
for(MapleCharacter chr : characters) {
mapChars.put(chr.getId(), chr);
}
return mapChars;
}
finally {
chrRLock.unlock();
}
}
public Collection<MapleCharacter> getCharacters() {
chrRLock.lock();
try {

View File

@@ -773,7 +773,7 @@ public class MaplePacketCreator {
mplew.write(channelLoad.size());
for (Channel ch : channelLoad) {
mplew.writeMapleAsciiString(serverName + "-" + ch.getId());
mplew.writeInt((ch.getConnectedClients() * 1200) / ServerConstants.CHANNEL_LOAD);
mplew.writeInt(ch.getChannelCapacity());
mplew.write(1);
mplew.writeShort(ch.getId() - 1);
}
@@ -2582,7 +2582,7 @@ public class MaplePacketCreator {
}
/**
* It is important that statups is in the correct order (see decleration
* It is important that statups is in the correct order (see declaration
* order in MapleBuffStat) since this method doesn't do automagical
* reordering.
*