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:
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user