Exp gain & Chaos scroll fix + Diet's MK Overhaul

Fixed issues with negative experience being distributed to characters
when killing a mob, rendering "Exp reset". Fixed chaos scroll behaving
oddly. Refactored debuff expirations to manage one list with registered
debuffs and expire times, thus lifting some load from the TimerManager.
Added concurrency protection on how World deals with parties. Thanks to
the DietStory dev team, fixed some issues with the MK maps.
This commit is contained in:
ronancpl
2017-10-04 02:35:52 -03:00
parent 6445f0b4e4
commit 3a882c7f31
141 changed files with 1719 additions and 524 deletions

View File

@@ -242,6 +242,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Map<Integer, Integer> activeCouponRates = new LinkedHashMap<>();
private EnumMap<MapleBuffStat, MapleBuffStatValueHolder> effects = new EnumMap<>(MapleBuffStat.class);
private Map<MapleBuffStat, Byte> buffEffectsCount = new LinkedHashMap<>();
private Map<MapleDisease, Long> diseaseExpires = new LinkedHashMap<>();
private Map<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> buffEffects = new LinkedHashMap<>();
private Map<Integer, Long> buffExpires = new LinkedHashMap<>();
private Map<Integer, MapleKeyBinding> keymap = new LinkedHashMap<>();
@@ -255,6 +256,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private ScheduledFuture<?> skillCooldownTask = null;
private ScheduledFuture<?> buffExpireTask = null;
private ScheduledFuture<?> itemExpireTask = null;
private ScheduledFuture<?> diseaseExpireTask = null;
private ScheduledFuture<?> recoveryTask = null;
private ScheduledFuture<?> extraRecoveryTask = null;
private ScheduledFuture<?> chairRecoveryTask = null;
@@ -263,6 +265,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Lock chrLock = new ReentrantLock();
private Lock effLock = new ReentrantLock();
private Lock petLock = new ReentrantLock();
private Lock prtLock = new ReentrantLock();
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
private Set<Integer> excludedItems = new LinkedHashSet<>();
private List<MapleRing> crushRings = new ArrayList<>();
@@ -866,8 +869,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public static boolean canCreateChar(String name) {
String lname = name.toLowerCase();
for (String nameTest : BLOCKED_NAMES) {
if (name.toLowerCase().contains(nameTest)) {
if (lname.contains(nameTest)) {
return false;
}
}
@@ -1056,10 +1060,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public MapleMap getWarpMap(int map) {
MapleMap target;
if (getEventInstance() == null) {
EventInstanceManager eim = getEventInstance();
if (eim == null) {
target = client.getChannelServer().getMapFactory().getMap(map);
} else {
target = getEventInstance().getMapInstance(map);
target = eim.getMapInstance(map);
}
return target;
}
@@ -1070,11 +1075,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
private void eventChangedMap(int map) {
if (getEventInstance() != null) getEventInstance().changedMap(this, map);
EventInstanceManager eim = getEventInstance();
if (eim != null) eim.changedMap(this, map);
}
private void eventAfterChangedMap(int map) {
if (getEventInstance() != null) getEventInstance().afterChangedMap(this, map);
EventInstanceManager eim = getEventInstance();
if (eim != null) eim.afterChangedMap(this, map);
}
public boolean canRecoverLastBanish() {
@@ -1117,8 +1124,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void changeMap(int map) {
MapleMap warpMap;
if (getEventInstance() != null) {
warpMap = getEventInstance().getMapInstance(map);
EventInstanceManager eim = getEventInstance();
if (eim != null) {
warpMap = eim.getMapInstance(map);
} else {
warpMap = client.getChannelServer().getMapFactory().getMap(map);
}
@@ -1128,8 +1137,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void changeMap(int map, int portal) {
MapleMap warpMap;
if (getEventInstance() != null) {
warpMap = getEventInstance().getMapInstance(map);
EventInstanceManager eim = getEventInstance();
if (eim != null) {
warpMap = eim.getMapInstance(map);
} else {
warpMap = client.getChannelServer().getMapFactory().getMap(map);
}
@@ -1139,8 +1150,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void changeMap(int map, String portal) {
MapleMap warpMap;
if (getEventInstance() != null) {
warpMap = getEventInstance().getMapInstance(map);
EventInstanceManager eim = getEventInstance();
if (eim != null) {
warpMap = eim.getMapInstance(map);
} else {
warpMap = client.getChannelServer().getMapFactory().getMap(map);
}
@@ -1150,8 +1163,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void changeMap(int map, MaplePortal portal) {
MapleMap warpMap;
if (getEventInstance() != null) {
warpMap = getEventInstance().getMapInstance(map);
EventInstanceManager eim = getEventInstance();
if (eim != null) {
warpMap = eim.getMapInstance(map);
} else {
warpMap = client.getChannelServer().getMapFactory().getMap(map);
}
@@ -1231,11 +1246,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
map = to;
setPosition(pos);
map.addPlayer(this);
if (party != null) {
mpc.setMapId(to.getId());
silentPartyUpdate();
client.announce(MaplePacketCreator.updateParty(client.getChannel(), party, PartyOperation.SILENT_UPDATE, null));
updatePartyMemberHP();
prtLock.lock();
try {
if (party != null) {
mpc.setMapId(to.getId());
silentPartyUpdateInternal();
client.announce(MaplePacketCreator.updateParty(client.getChannel(), party, PartyOperation.SILENT_UPDATE, null));
updatePartyMemberHPInternal();
}
} finally {
prtLock.unlock();
}
if (getMap().getHPDec() > 0) resetHpDecreaseTask();
@@ -1254,8 +1275,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
// if this event map has a gate already opened, render it
if(getEventInstance() != null) {
getEventInstance().recoverOpenedGate(this, map.getId());
EventInstanceManager eim = getEventInstance();
if(eim != null) {
eim.recoverOpenedGate(this, map.getId());
}
// if this map has obstacle components moving, make it do so for this client
@@ -1446,27 +1468,32 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return;
}
if (mapitem.getMeso() > 0) {
if (this.getParty() != null) {
int mesosamm = mapitem.getMeso();
if (mesosamm > 50000 * this.getMesoRate()) {
return;
}
int partynum = 0;
for (MaplePartyCharacter partymem : this.getParty().getMembers()) {
if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId() && partymem.getChannel() == client.getChannel()) {
partynum++;
prtLock.lock();
try {
if (this.party != null) {
int mesosamm = mapitem.getMeso();
if (mesosamm > 50000 * this.getMesoRate()) {
return;
}
}
for (MaplePartyCharacter partymem : this.getParty().getMembers()) {
if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId()) {
MapleCharacter somecharacter = client.getChannelServer().getPlayerStorage().getCharacterById(partymem.getId());
if (somecharacter != null) {
somecharacter.gainMeso(mesosamm / partynum, true, true, false);
int partynum = 0;
for (MaplePartyCharacter partymem : this.party.getMembers()) {
if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId() && partymem.getChannel() == client.getChannel()) {
partynum++;
}
}
for (MaplePartyCharacter partymem : this.party.getMembers()) {
if (partymem.isOnline() && partymem.getMapId() == this.getMap().getId()) {
MapleCharacter somecharacter = client.getChannelServer().getPlayerStorage().getCharacterById(partymem.getId());
if (somecharacter != null) {
somecharacter.gainMeso(mesosamm / partynum, true, true, false);
}
}
}
} else {
this.gainMeso(mapitem.getMeso(), true, true, false);
}
} else {
this.gainMeso(mapitem.getMeso(), true, true, false);
} finally {
prtLock.unlock();
}
} else if (mapitem.getItem().getItemId() / 10000 == 243) {
MapleItemInformationProvider.scriptedItem info = ii.getScriptedItemInfo(mapitem.getItem().getItemId());
@@ -1930,16 +1957,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
dispelDebuff(disease);
}
}, skill.getDuration());
chrLock.lock();
try {
diseases.put(disease, new MapleDiseaseValueHolder(System.currentTimeMillis(), skill.getDuration()));
long curTime = System.currentTimeMillis();
diseaseExpires.put(disease, curTime + skill.getDuration());
diseases.put(disease, new MapleDiseaseValueHolder(curTime, skill.getDuration()));
} finally {
chrLock.unlock();
}
@@ -1959,6 +1981,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
chrLock.lock();
try {
diseases.remove(debuff);
diseaseExpires.remove(debuff);
} finally {
chrLock.unlock();
}
@@ -2092,6 +2115,41 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
public void cancelDiseaseExpireTask() {
if (diseaseExpireTask != null) {
diseaseExpireTask.cancel(false);
diseaseExpireTask = null;
}
}
public void diseaseExpireTask() {
if (diseaseExpireTask == null) {
diseaseExpireTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
Set<MapleDisease> toExpire = new LinkedHashSet<>();
chrLock.lock();
try {
long curTime = System.currentTimeMillis();
for(Entry<MapleDisease, Long> d : diseaseExpires.entrySet()) {
if(d.getValue() < curTime) {
toExpire.add(d.getKey());
}
}
} finally {
chrLock.unlock();
}
for(MapleDisease d : toExpire) {
dispelDebuff(d);
}
}
}, 1500);
}
}
public void cancelBuffExpireTask() {
if (buffExpireTask != null) {
buffExpireTask.cancel(false);
@@ -2285,7 +2343,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if(party < 0) party = Integer.MAX_VALUE; // integer overflow, heh.
int equip = (int)Math.min((long)((gain / 10) * pendantExp), Integer.MAX_VALUE);
long total = gain + equip + party;
long total = (long)gain + equip + party;
gainExpInternal(total, equip, party, show, inChat, white);
}
@@ -2918,12 +2976,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
destroyDoor.getTownDoor().sendDestroyData(chr.getClient());
}
if (party != null) {
for (MaplePartyCharacter partyMembers : getParty().getMembers()) {
partyMembers.getPlayer().removeDoor(this.getId());
partyMembers.removeDoor(this.getId());
prtLock.lock();
try {
if (party != null) {
for (MaplePartyCharacter partyMembers : party.getMembers()) {
partyMembers.getPlayer().removeDoor(this.getId());
partyMembers.removeDoor(this.getId());
}
silentPartyUpdateInternal();
}
silentPartyUpdate();
} finally {
prtLock.unlock();
}
}
}
@@ -3816,7 +3879,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public int getDoorSlot() {
if(doorSlot == -1) {
doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId());
prtLock.lock();
try {
doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId());
} finally {
prtLock.unlock();
}
}
return doorSlot;
@@ -3906,20 +3974,35 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public MapleParty getParty() {
return party;
prtLock.lock();
try {
return party;
} finally {
prtLock.unlock();
}
}
public int getPartyId() {
return (party != null ? party.getId() : -1);
prtLock.lock();
try {
return (party != null ? party.getId() : -1);
} finally {
prtLock.unlock();
}
}
public List<MapleCharacter> getPartyMembers() {
List<MapleCharacter> list = new LinkedList<>();
if(party != null) {
for(MaplePartyCharacter partyMembers: party.getMembers()) {
list.add(partyMembers.getPlayer());
prtLock.lock();
try {
if(party != null) {
for(MaplePartyCharacter partyMembers: party.getMembers()) {
list.add(partyMembers.getPlayer());
}
}
} finally {
prtLock.unlock();
}
return list;
@@ -3929,10 +4012,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
List<MapleCharacter> list = new LinkedList<>();
int thisMapHash = this.getMap().hashCode();
if(party != null) {
for(MaplePartyCharacter partyMembers: party.getMembers()) {
if(partyMembers.getPlayer().getMap().hashCode() == thisMapHash) list.add(partyMembers.getPlayer());
prtLock.lock();
try {
if(party != null) {
for(MaplePartyCharacter partyMembers: party.getMembers()) {
if(partyMembers.getPlayer().getMap().hashCode() == thisMapHash) list.add(partyMembers.getPlayer());
}
}
} finally {
prtLock.unlock();
}
return list;
@@ -4593,7 +4681,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public boolean isPartyLeader() {
return party.getLeaderId() == getId();
prtLock.lock();
try {
return party.getLeaderId() == getId();
} finally {
prtLock.unlock();
}
}
public boolean isGuildLeader() { // true on guild master or jr. master
@@ -5545,8 +5638,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private void playerDead() {
cancelAllBuffs(false);
dispelDebuffs();
if (getEventInstance() != null) {
getEventInstance().playerKilled(this);
EventInstanceManager eim = getEventInstance();
if (eim != null) {
eim.playerKilled(this);
}
int[] charmID = {5130000, 4031283, 4140903};
int possesed = 0;
@@ -5741,16 +5836,21 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void receivePartyMemberHP() {
if (party != null) {
int channel = client.getChannel();
for (MaplePartyCharacter partychar : party.getMembers()) {
if (partychar.getMapId() == getMapId() && partychar.getChannel() == channel) {
MapleCharacter other = Server.getInstance().getWorld(world).getChannel(channel).getPlayerStorage().getCharacterByName(partychar.getName());
if (other != null) {
client.announce(MaplePacketCreator.updatePartyMemberHP(other.getId(), other.getHp(), other.getCurrentMaxHp()));
prtLock.lock();
try {
if (party != null) {
int channel = client.getChannel();
for (MaplePartyCharacter partychar : party.getMembers()) {
if (partychar.getMapId() == getMapId() && partychar.getChannel() == channel) {
MapleCharacter other = Server.getInstance().getWorld(world).getChannel(channel).getPlayerStorage().getCharacterByName(partychar.getName());
if (other != null) {
client.announce(MaplePacketCreator.updatePartyMemberHP(other.getId(), other.getHp(), other.getCurrentMaxHp()));
}
}
}
}
} finally {
prtLock.unlock();
}
}
@@ -6128,11 +6228,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setInt(24, 0);
}
}
if (party != null) {
ps.setInt(25, party.getId());
} else {
ps.setInt(25, -1);
prtLock.lock();
try {
if (party != null) {
ps.setInt(25, party.getId());
} else {
ps.setInt(25, -1);
}
} finally {
prtLock.unlock();
}
ps.setInt(26, buddylist.getCapacity());
if (messenger != null) {
ps.setInt(27, messenger.getId());
@@ -6782,15 +6889,20 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
public void setParty(MapleParty party) {
if (party == null) {
this.mpc = null;
doorSlot = -1;
this.party = null;
//cancelMagicDoor(); // cancel magic doors if kicked out / quitted from party.
} else {
this.party = party;
public void setParty(MapleParty p) {
prtLock.lock();
try {
if (p == null) {
this.mpc = null;
doorSlot = -1;
party = null;
//cancelMagicDoor(); // cancel magic doors if kicked out / quitted from party.
} else {
party = p;
}
} finally {
prtLock.unlock();
}
}
@@ -6998,6 +7110,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void silentPartyUpdate() {
prtLock.lock();
try {
silentPartyUpdateInternal();
} finally {
prtLock.unlock();
}
}
private void silentPartyUpdateInternal() {
if (party != null) {
Server.getInstance().getWorld(world).updateParty(party.getId(), PartyOperation.SILENT_UPDATE, getMPC());
}
@@ -7118,6 +7239,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public void updatePartyMemberHP() {
prtLock.lock();
try {
updatePartyMemberHPInternal();
} finally {
prtLock.unlock();
}
}
private void updatePartyMemberHPInternal() {
if (party != null) {
int channel = client.getChannel();
for (MaplePartyCharacter partychar : party.getMembers()) {
@@ -7628,8 +7758,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
cancelBuffExpireTask();
cancelDiseaseExpireTask();
cancelSkillCooldownTask();
cancelExpirationTask();
for (ScheduledFuture<?> sf : timers) {
sf.cancel(false);
}

View File

@@ -88,7 +88,7 @@ public class MapleClient {
public static final String CLIENT_KEY = "CLIENT";
private MapleAESOFB send;
private MapleAESOFB receive;
private IoSession session;
private final IoSession session;
private MapleCharacter player;
private int channel = 1;
private int accId = 1;
@@ -123,15 +123,15 @@ public class MapleClient {
this.session = session;
}
public synchronized MapleAESOFB getReceiveCrypto() {
public MapleAESOFB getReceiveCrypto() {
return receive;
}
public synchronized MapleAESOFB getSendCrypto() {
public MapleAESOFB getSendCrypto() {
return send;
}
public synchronized IoSession getSession() {
public IoSession getSession() {
return session;
}
@@ -459,7 +459,7 @@ public class MapleClient {
public boolean checkPin(String other) {
pinattempt++;
if (pinattempt > 5) {
getSession().close(true);
session.close(false);
}
if (pin.equals(other)) {
pinattempt = 0;
@@ -493,7 +493,7 @@ public class MapleClient {
picattempt++;
if (picattempt > 5) {
getSession().close(true);
session.close(false);
}
if (pic.equals(other)) {
picattempt = 0;
@@ -505,7 +505,7 @@ public class MapleClient {
public int login(String login, String pwd) {
loginattempt++;
if (loginattempt > 4) {
getSession().close(true);
session.close(false);
}
int loginok = 5;
Connection con = null;
@@ -934,12 +934,12 @@ public class MapleClient {
if (!serverTransition && isLoggedIn()) {
updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN);
session.removeAttribute(MapleClient.CLIENT_KEY); // prevents double dcing during login
session.close();
session.close(false);
}
engines.clear();
}
private void clear() {
private void clear() { //usable when defining client = null shortly after
this.accountName = null;
this.macs = null;
this.hwid = null;
@@ -1013,8 +1013,8 @@ public class MapleClient {
public void run() {
try {
if (lastPong < then) {
if (getSession() != null && getSession().isConnected()) {
getSession().close(true);
if (session != null && session.isConnected()) {
session.close(false);
}
}
} catch (NullPointerException e) {
@@ -1307,6 +1307,7 @@ public class MapleClient {
server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
player.cancelAllBuffs(true);
player.cancelBuffExpireTask();
player.cancelDiseaseExpireTask();
player.cancelSkillCooldownTask();
//Cancelling magicdoor? Nope
//Cancelling mounts? Noty

View File

@@ -1424,12 +1424,12 @@ public class Commands {
String sendStr = "";
if(sub[1].equalsIgnoreCase("on")) {
sendStr += "GM Fly feature enabled. With fly active, GM's cannot attack.";
sendStr += "Enabled Fly feature (F1). With fly active, you cannot attack.";
if(!srv.canFly(accid)) sendStr += " Re-login to take effect.";
srv.changeFly(c.getAccID(), true);
} else {
player.dropMessage(6, "GM Fly feature disabled. GM's can now attack.");
sendStr += "Disabled Fly feature. You can now attack.";
if(srv.canFly(accid)) sendStr += " Re-login to take effect.";
srv.changeFly(c.getAccID(), false);

View File

@@ -53,6 +53,7 @@ public class ServerConstants {
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
public static final boolean USE_UNDERLEVELED_EXP_GAIN = false; //Players below the threshold level will gain no experience from defeating higher leveled mobs.
//Server Rates And Experience
public static final int EXP_RATE = 10;
@@ -77,10 +78,12 @@ public class ServerConstants {
//Some Gameplay Enhancing Configurations
//Scroll Configuration
public static final boolean USE_PERFECT_GM_SCROLL = true; //Scrolls from GMs never uses up slots nor fails.
public static final boolean USE_PERFECT_SCROLLING = true; //Scrolls doesn't use slots upon failure.
public static final boolean USE_ENHANCED_CHSCROLL = true; //Equips even more powerful with chaos upgrade.
public static final boolean USE_PERFECT_GM_SCROLL = false; //Scrolls from GMs never uses up slots nor fails.
public static final boolean USE_PERFECT_SCROLLING = false; //Scrolls doesn't use slots upon failure.
public static final boolean USE_ENHANCED_CHSCROLL = false; //Equips even more powerful with chaos upgrade.
public static final boolean USE_ENHANCED_CRAFTING = true; //Applys 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_RANGE = 6; //Stat upgrade range (-N, N) on chaos scrolls.
//Beginner Skills Configuration
public static final boolean USE_ULTRA_NIMBLE_FEET = true; //Haste-like speed & jump upgrade.
@@ -93,7 +96,6 @@ public class ServerConstants {
public static final boolean USE_STACK_COUPON_RATES = true; //Multiple coupons effects builds up together.
public static final boolean USE_PERFECT_PITCH = true; //For lvl 30 or above, each lvlup grants player 1 perfect pitch.
public static final int FAME_GAIN_BY_QUEST = 4; //Fame gain each N quest completes, set 0 to disable.
public static final int SCROLL_CHANCE_RATE = 10; //Number of rolls for success on a scroll, set 0 for default.
//Equipment Configuration
public static final boolean USE_EQUIPMNT_LVLUP_SLOTS = true;//Equips can upgrade slots at level up.

View File

@@ -38,14 +38,21 @@ public class MaplePacketDecoder extends CumulativeProtocolDecoder {
@Override
protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
final MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
if(client == null) {
session.close(true);
return false;
}
DecoderState decoderState = (DecoderState) session.getAttribute(DECODER_STATE_KEY);
if (decoderState == null) {
decoderState = new DecoderState();
session.setAttribute(DECODER_STATE_KEY, decoderState);
}
MapleAESOFB rcvdCrypto = client.getReceiveCrypto();
if (in.remaining() >= 4 && decoderState.packetlength == -1) {
int packetHeader = in.getInt();
if (!client.getReceiveCrypto().checkPacket(packetHeader)) {
if (!rcvdCrypto.checkPacket(packetHeader)) {
session.close(true);
return false;
}
@@ -57,7 +64,7 @@ public class MaplePacketDecoder extends CumulativeProtocolDecoder {
byte decryptedPacket[] = new byte[decoderState.packetlength];
in.get(decryptedPacket, 0, decoderState.packetlength);
decoderState.packetlength = -1;
client.getReceiveCrypto().crypt(decryptedPacket);
rcvdCrypto.crypt(decryptedPacket);
MapleCustomEncryption.decryptData(decryptedPacket);
out.write(decryptedPacket);
return true;

View File

@@ -62,6 +62,5 @@ public class MaplePacketEncoder implements ProtocolEncoder {
}
@Override
public void dispose(IoSession session) throws Exception {
}
public void dispose(IoSession session) throws Exception {}
}

View File

@@ -52,6 +52,7 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(mc.getId(), mc.getAllBuffs());
mc.cancelAllBuffs(true);
mc.cancelBuffExpireTask();
mc.cancelDiseaseExpireTask();
mc.cancelSkillCooldownTask();
mc.cancelExpirationTask();

View File

@@ -61,6 +61,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
chr.cancelAllBuffs(true);
chr.cancelBuffExpireTask();
chr.cancelDiseaseExpireTask();
chr.cancelSkillCooldownTask();
chr.cancelExpirationTask();
chr.saveToDB();

View File

@@ -30,6 +30,8 @@ import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleCharacter;
import client.MapleClient;
import scripting.event.EventInstanceManager;
import server.maps.MapleMap;
public final class PartyOperationHandler extends AbstractMaplePacketHandler {
@@ -50,6 +52,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
party = world.createParty(partyplayer);
player.setParty(party);
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
player.silentPartyUpdate();
c.announce(MaplePacketCreator.partyCreated(partyplayer));
} else {
@@ -59,17 +62,22 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
}
case 2: {
if (party != null && partyplayer != null) {
if (partyplayer.equals(party.getLeader())) {
world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().disbandParty();
}
} else {
world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().leftParty(player);
}
if (partyplayer.getId() == party.getLeaderId()) {
c.getWorldServer().removeMapPartyMembers(party.getId());
world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().disbandParty();
}
} else {
player.getMap().removePartyMember(player);
world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer);
if (player.getEventInstance() != null) {
player.getEventInstance().leftParty(player);
}
}
player.setParty(null);
}
break;
@@ -81,6 +89,8 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
if (party != null) {
if (party.getMembers().size() < 6) {
partyplayer = new MaplePartyCharacter(player);
player.getMap().addPartyMember(player);
world.updateParty(party.getId(), PartyOperation.JOIN, partyplayer);
player.receivePartyMemberHP();
player.updatePartyMemberHP();
@@ -109,6 +119,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
party = world.createParty(partyplayer);
player.setParty(party);
player.setMPC(partyplayer);
player.getMap().addPartyMember(player);
c.announce(MaplePacketCreator.partyCreated(partyplayer));
}
if (party.getMembers().size() < 6) {
@@ -129,12 +140,20 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler {
if (partyplayer.equals(party.getLeader())) {
MaplePartyCharacter expelled = party.getMemberById(cid);
if (expelled != null) {
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
if (player.getEventInstance() != null) {
if (expelled.isOnline()) {
player.getEventInstance().disbandParty();
MapleCharacter emc = expelled.getPlayer();
if(emc != null) {
MapleMap map = emc.getMap();
if(map != null) map.removePartyMember(emc);
EventInstanceManager eim = emc.getEventInstance();
if(eim != null) {
eim.leftParty(emc);
}
emc.setParty(null);
}
world.updateParty(party.getId(), PartyOperation.EXPEL, expelled);
}
}
break;

View File

@@ -263,6 +263,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
player.changeSkillLevel(SkillFactory.getSkill(10000000 * player.getJobType() + 12), (byte) (player.getLinkedLevel() / 10), 20, -1);
player.checkBerserk(player.isHidden());
player.buffExpireTask();
player.diseaseExpireTask();
player.skillCooldownTask();
player.expirationTask();
if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) {

View File

@@ -29,17 +29,21 @@ import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Map;
import java.util.Comparator;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.Lock;
public class MapleParty {
private int id;
private int leaderId;
private List<MaplePartyCharacter> members = new LinkedList<MaplePartyCharacter>();
private List<MaplePartyCharacter> members = new LinkedList<>();
private List<MaplePartyCharacter> pqMembers = null;
private Map<Integer, Integer> histMembers = new HashMap<>();
private int nextEntry = 0;
private int id;
private Lock lock = new ReentrantLock();
public MapleParty(int id, MaplePartyCharacter chrfor) {
this.leaderId = chrfor.getId();
this.members.add(chrfor);
@@ -47,20 +51,35 @@ public class MapleParty {
}
public boolean containsMembers(MaplePartyCharacter member) {
return members.contains(member);
lock.lock();
try {
return members.contains(member);
} finally {
lock.unlock();
}
}
public void addMember(MaplePartyCharacter member) {
histMembers.put(member.getId(), nextEntry);
nextEntry++;
members.add(member);
lock.lock();
try {
histMembers.put(member.getId(), nextEntry);
nextEntry++;
members.add(member);
} finally {
lock.unlock();
}
}
public void removeMember(MaplePartyCharacter member) {
histMembers.remove(member.getId());
members.remove(member);
lock.lock();
try {
histMembers.remove(member.getId());
members.remove(member);
} finally {
lock.unlock();
}
}
public void setLeader(MaplePartyCharacter victim) {
@@ -68,28 +87,48 @@ public class MapleParty {
}
public void updateMember(MaplePartyCharacter member) {
for (int i = 0; i < members.size(); i++) {
if (members.get(i).getId() == member.getId()) {
members.set(i, member);
lock.lock();
try {
for (int i = 0; i < members.size(); i++) {
if (members.get(i).getId() == member.getId()) {
members.set(i, member);
}
}
} finally {
lock.unlock();
}
}
public MaplePartyCharacter getMemberById(int id) {
for (MaplePartyCharacter chr : members) {
if (chr.getId() == id) {
return chr;
lock.lock();
try {
for (MaplePartyCharacter chr : members) {
if (chr.getId() == id) {
return chr;
}
}
return null;
} finally {
lock.unlock();
}
return null;
}
public Collection<MaplePartyCharacter> getMembers() {
return Collections.unmodifiableList(members);
lock.lock();
try {
return Collections.unmodifiableList(members);
} finally {
lock.unlock();
}
}
public List<MaplePartyCharacter> getPartyMembers() {
return members;
lock.lock();
try {
return Collections.unmodifiableList(members);
} finally {
lock.unlock();
}
}
// used whenever entering PQs: will draw every party member that can attempt a target PQ while ingnoring those unfit.
@@ -114,17 +153,30 @@ public class MapleParty {
}
public MaplePartyCharacter getLeader() {
for(MaplePartyCharacter mpc: members) {
if(mpc.getId() == leaderId) {
return mpc;
lock.lock();
try {
for(MaplePartyCharacter mpc: members) {
if(mpc.getId() == leaderId) {
return mpc;
}
}
return null;
} finally {
lock.unlock();
}
return null;
}
public byte getPartyDoor(int cid) {
List<Entry<Integer, Integer>> histList = new LinkedList<>(histMembers.entrySet());
List<Entry<Integer, Integer>> histList;
lock.lock();
try {
histList = new LinkedList<>(histMembers.entrySet());
} finally {
lock.unlock();
}
Collections.sort(histList, new Comparator<Entry<Integer, Integer>>()
{
@Override
@@ -133,13 +185,13 @@ public class MapleParty {
return ( o1.getValue() ).compareTo( o2.getValue() );
}
});
byte slot = 0;
for(Entry<Integer, Integer> e: histList) {
if(e.getKey() == cid) break;
slot++;
}
return slot;
}

View File

@@ -45,8 +45,10 @@ import java.util.Set;
import java.util.HashSet;
import java.util.concurrent.ScheduledFuture;
import scripting.event.EventInstanceManager;
import server.TimerManager;
import server.maps.MapleHiredMerchant;
import server.maps.MapleMap;
import server.MaplePlayerShop;
import net.server.worker.CharacterAutosaverWorker;
import net.server.worker.MountTirednessWorker;
@@ -357,16 +359,22 @@ public class World {
public MapleParty createParty(MaplePartyCharacter chrfor) {
int partyid = runningPartyId.getAndIncrement();
MapleParty party = new MapleParty(partyid, chrfor);
parties.put(party.getId(), party);
synchronized(parties) {
parties.put(party.getId(), party);
}
return party;
}
public MapleParty getParty(int partyid) {
return parties.get(partyid);
synchronized(parties) {
return parties.get(partyid);
}
}
public MapleParty disbandParty(int partyid) {
return parties.remove(partyid);
synchronized(parties) {
return parties.remove(partyid);
}
}
public void updateParty(MapleParty party, PartyOperation operation, MaplePartyCharacter target) {
@@ -419,8 +427,10 @@ public class World {
break;
case CHANGE_LEADER:
MapleCharacter mc = party.getLeader().getPlayer();
if(mc.getEventInstance() != null && mc.getEventInstance().isEventLeader(mc)) {
mc.getEventInstance().changedLeader(target.getPlayer());
EventInstanceManager eim = mc.getEventInstance();
if(eim != null && eim.isEventLeader(mc)) {
eim.changedLeader(target.getPlayer());
}
party.setLeader(target);
break;
@@ -430,6 +440,21 @@ public class World {
updateParty(party, operation, target);
}
public void removeMapPartyMembers(int partyid) {
MapleParty party = getParty(partyid);
if(party == null) return;
for(MaplePartyCharacter mpc : party.getMembers()) {
MapleCharacter mc = mpc.getPlayer();
if(mc != null) {
MapleMap map = mc.getMap();
if(map != null) {
map.removeParty(partyid);
}
}
}
}
public int find(String name) {
int channel = -1;
MapleCharacter chr = getPlayerStorage().getCharacterByName(name);

View File

@@ -449,10 +449,14 @@ public class AbstractPlayerInteraction {
if(item != null) {
Equip it = (Equip)item;
if(isAccessory(item.getItemId()) && it.getUpgradeSlots() <= 0) it.setUpgradeSlots(3);
}
if(ServerConstants.USE_ENHANCED_CRAFTING == true && c.getPlayer().getCS() == true)
item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, 0, c.getPlayer().isGM());
if(ServerConstants.USE_ENHANCED_CRAFTING == true && c.getPlayer().getCS() == true) {
Equip eqp = (Equip)item;
eqp.setUpgradeSlots((byte)(eqp.getUpgradeSlots() + 1));
item = MapleItemInformationProvider.getInstance().scrollEquipWithId(item, 2049100, true, 0, c.getPlayer().isGM());
}
}
} else {
item = new Item(id, (short) 0, quantity, petId);
}

View File

@@ -568,6 +568,223 @@ public class MapleItemInformationProvider {
return (short)Math.min(Short.MAX_VALUE, value);
}
private static short chscrollRandomizedStat() {
return (short) Randomizer.rand(-ServerConstants.CHSCROLL_STAT_RANGE, ServerConstants.CHSCROLL_STAT_RANGE);
}
private void scrollEquipWithChaos(Equip nEquip) {
if(ServerConstants.SCROLL_CHANCE_RATE > 0) {
int temp;
short curStr, curDex, curInt, curLuk, curWatk, curWdef, curMatk, curMdef, curAcc, curAvoid, curSpeed, curJump, curHp, curMp;
if(ServerConstants.USE_ENHANCED_CHSCROLL) {
curStr = nEquip.getStr();
curDex = nEquip.getDex();
curInt = nEquip.getInt();
curLuk = nEquip.getLuk();
curWatk = nEquip.getWatk();
curWdef = nEquip.getWdef();
curMatk = nEquip.getMatk();
curMdef = nEquip.getMdef();
curAcc = nEquip.getAcc();
curAvoid = nEquip.getAvoid();
curSpeed = nEquip.getSpeed();
curJump = nEquip.getJump();
curHp = nEquip.getHp();
curMp = nEquip.getMp();
} else {
curStr = Short.MIN_VALUE;
curDex = Short.MIN_VALUE;
curInt = Short.MIN_VALUE;
curLuk = Short.MIN_VALUE;
curWatk = Short.MIN_VALUE;
curWdef = Short.MIN_VALUE;
curMatk = Short.MIN_VALUE;
curMdef = Short.MIN_VALUE;
curAcc = Short.MIN_VALUE;
curAvoid = Short.MIN_VALUE;
curSpeed = Short.MIN_VALUE;
curJump = Short.MIN_VALUE;
curHp = Short.MIN_VALUE;
curMp = Short.MIN_VALUE;
}
for(int i = 0; i < ServerConstants.SCROLL_CHANCE_RATE; i++) {
if (nEquip.getStr() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curStr + chscrollRandomizedStat();
else temp = nEquip.getStr() + chscrollRandomizedStat();
curStr = getMaximumShortMaxIfOverflow(temp, curStr);
}
if (nEquip.getDex() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curDex + chscrollRandomizedStat();
else temp = nEquip.getDex() + chscrollRandomizedStat();
curDex = getMaximumShortMaxIfOverflow(temp, curDex);
}
if (nEquip.getInt() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curInt + chscrollRandomizedStat();
else temp = nEquip.getInt() + chscrollRandomizedStat();
curInt = getMaximumShortMaxIfOverflow(temp, curInt);
}
if (nEquip.getLuk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curLuk + chscrollRandomizedStat();
else temp = nEquip.getLuk() + chscrollRandomizedStat();
curLuk = getMaximumShortMaxIfOverflow(temp, curLuk);
}
if (nEquip.getWatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curWatk + chscrollRandomizedStat();
else temp = nEquip.getWatk() + chscrollRandomizedStat();
curWatk = getMaximumShortMaxIfOverflow(temp, curWatk);
}
if (nEquip.getWdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curWdef + chscrollRandomizedStat();
else temp = nEquip.getWdef() + chscrollRandomizedStat();
curWdef = getMaximumShortMaxIfOverflow(temp, curWdef);
}
if (nEquip.getMatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curMatk + chscrollRandomizedStat();
else temp = nEquip.getMatk() + chscrollRandomizedStat();
curMatk = getMaximumShortMaxIfOverflow(temp, curMatk);
}
if (nEquip.getMdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curMdef + chscrollRandomizedStat();
else temp = nEquip.getMdef() + chscrollRandomizedStat();
curMdef = getMaximumShortMaxIfOverflow(temp, curMdef);
}
if (nEquip.getAcc() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curAcc + chscrollRandomizedStat();
else temp = nEquip.getAcc() + chscrollRandomizedStat();
curAcc = getMaximumShortMaxIfOverflow(temp, curAcc);
}
if (nEquip.getAvoid() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curAvoid + chscrollRandomizedStat();
else temp = nEquip.getAvoid() + chscrollRandomizedStat();
curAvoid = getMaximumShortMaxIfOverflow(temp, curAvoid);
}
if (nEquip.getSpeed() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curSpeed + chscrollRandomizedStat();
else temp = nEquip.getSpeed() + chscrollRandomizedStat();
curSpeed = getMaximumShortMaxIfOverflow(temp, curSpeed);
}
if (nEquip.getJump() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curJump + chscrollRandomizedStat();
else temp = nEquip.getJump() + chscrollRandomizedStat();
curJump = getMaximumShortMaxIfOverflow(temp, curJump);
}
if (nEquip.getHp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curHp + chscrollRandomizedStat();
else temp = nEquip.getHp() + chscrollRandomizedStat();
curHp = getMaximumShortMaxIfOverflow(temp, curHp);
}
if (nEquip.getMp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) temp = curMp + chscrollRandomizedStat();
else temp = nEquip.getMp() + chscrollRandomizedStat();
curMp = getMaximumShortMaxIfOverflow(temp, curMp);
}
}
nEquip.setStr((short) Math.max(0, curStr));
nEquip.setDex((short) Math.max(0, curDex));
nEquip.setInt((short) Math.max(0, curInt));
nEquip.setLuk((short) Math.max(0, curLuk));
nEquip.setWatk((short) Math.max(0, curWatk));
nEquip.setWdef((short) Math.max(0, curWdef));
nEquip.setMatk((short) Math.max(0, curMatk));
nEquip.setMdef((short) Math.max(0, curMdef));
nEquip.setAcc((short) Math.max(0, curAcc));
nEquip.setAvoid((short) Math.max(0, curAvoid));
nEquip.setSpeed((short) Math.max(0, curSpeed));
nEquip.setJump((short) Math.max(0, curJump));
nEquip.setHp((short) Math.max(0, curHp));
nEquip.setMp((short) Math.max(0, curMp));
}
else {
if (nEquip.getStr() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setStr(getMaximumShortMaxIfOverflow(nEquip.getStr(), (nEquip.getStr() + chscrollRandomizedStat())));
else nEquip.setStr(getMaximumShortMaxIfOverflow(0, (nEquip.getStr() + chscrollRandomizedStat())));
}
if (nEquip.getDex() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setDex(getMaximumShortMaxIfOverflow(nEquip.getDex(), (nEquip.getDex() + chscrollRandomizedStat())));
else nEquip.setDex(getMaximumShortMaxIfOverflow(0, (nEquip.getDex() + chscrollRandomizedStat())));
}
if (nEquip.getInt() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setInt(getMaximumShortMaxIfOverflow(nEquip.getInt(), (nEquip.getInt() + chscrollRandomizedStat())));
else nEquip.setInt(getMaximumShortMaxIfOverflow(0, (nEquip.getInt() + chscrollRandomizedStat())));
}
if (nEquip.getLuk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setLuk(getMaximumShortMaxIfOverflow(nEquip.getLuk(), (nEquip.getLuk() + chscrollRandomizedStat())));
else nEquip.setLuk(getMaximumShortMaxIfOverflow(0, (nEquip.getLuk() + chscrollRandomizedStat())));
}
if (nEquip.getWatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setWatk(getMaximumShortMaxIfOverflow(nEquip.getWatk(), (nEquip.getWatk() + chscrollRandomizedStat())));
else nEquip.setWatk(getMaximumShortMaxIfOverflow(0, (nEquip.getWatk() + chscrollRandomizedStat())));
}
if (nEquip.getWdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setWdef(getMaximumShortMaxIfOverflow(nEquip.getWdef(), (nEquip.getWdef() + chscrollRandomizedStat())));
else nEquip.setWdef(getMaximumShortMaxIfOverflow(0, (nEquip.getWdef() + chscrollRandomizedStat())));
}
if (nEquip.getMatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setMatk(getMaximumShortMaxIfOverflow(nEquip.getMatk(), (nEquip.getMatk() + chscrollRandomizedStat())));
else nEquip.setMatk(getMaximumShortMaxIfOverflow(0, (nEquip.getMatk() + chscrollRandomizedStat())));
}
if (nEquip.getMdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setMdef(getMaximumShortMaxIfOverflow(nEquip.getMdef(), (nEquip.getMdef() + chscrollRandomizedStat())));
else nEquip.setMdef(getMaximumShortMaxIfOverflow(0, (nEquip.getMdef() + chscrollRandomizedStat())));
}
if (nEquip.getAcc() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setAcc(getMaximumShortMaxIfOverflow(nEquip.getAcc(), (nEquip.getAcc() + chscrollRandomizedStat())));
else nEquip.setAcc(getMaximumShortMaxIfOverflow(0, (nEquip.getAcc() + chscrollRandomizedStat())));
}
if (nEquip.getAvoid() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setAvoid(getMaximumShortMaxIfOverflow(nEquip.getAvoid(), (nEquip.getAvoid() + chscrollRandomizedStat())));
else nEquip.setAvoid(getMaximumShortMaxIfOverflow(0, (nEquip.getAvoid() + chscrollRandomizedStat())));
}
if (nEquip.getSpeed() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setSpeed(getMaximumShortMaxIfOverflow(nEquip.getSpeed(), (nEquip.getSpeed() + chscrollRandomizedStat())));
else nEquip.setSpeed(getMaximumShortMaxIfOverflow(0, (nEquip.getSpeed() + chscrollRandomizedStat())));
}
if (nEquip.getJump() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setJump(getMaximumShortMaxIfOverflow(nEquip.getJump(), (nEquip.getJump() + chscrollRandomizedStat())));
else nEquip.setJump(getMaximumShortMaxIfOverflow(0, (nEquip.getJump() + chscrollRandomizedStat())));
}
if (nEquip.getHp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setHp(getMaximumShortMaxIfOverflow(nEquip.getHp(), (nEquip.getHp() + chscrollRandomizedStat())));
else nEquip.setHp(getMaximumShortMaxIfOverflow(0, (nEquip.getHp() + chscrollRandomizedStat())));
}
if (nEquip.getMp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL) nEquip.setMp(getMaximumShortMaxIfOverflow(nEquip.getMp(), (nEquip.getMp() + chscrollRandomizedStat())));
else nEquip.setMp(getMaximumShortMaxIfOverflow(0, (nEquip.getMp() + chscrollRandomizedStat())));
}
}
}
public Item scrollEquipWithId(Item equip, int scrollId, boolean usingWhiteScroll, int vegaItemId, boolean isGM) {
boolean assertGM = (isGM && ServerConstants.USE_PERFECT_GM_SCROLL);
@@ -607,256 +824,7 @@ public class MapleItemInformationProvider {
case 2049100:
case 2049101:
case 2049102:
int inc, i;
if(ServerConstants.SCROLL_CHANCE_RATE > 0) {
//int tempStr, tempDex, tempInt, tempLuk, tempWatk, tempWdef, tempMatk, tempMdef, tempAcc, tempAvoid, tempSpeed, tempJump, tempHp, tempMp;
int temp;
int mdStr = nEquip.getStr(), mdDex = nEquip.getDex(), mdInt = nEquip.getInt(), mdLuk = nEquip.getLuk(), mdWatk = nEquip.getWatk(), mdWdef = nEquip.getWdef(), mdMatk = nEquip.getMatk(), mdMdef = nEquip.getMdef(), mdAcc = nEquip.getAcc(), mdAvoid = nEquip.getAvoid(), mdSpeed = nEquip.getSpeed(), mdJump = nEquip.getJump(), mdHp = nEquip.getHp(), mdMp = nEquip.getMp();
inc = 1;
if (Randomizer.nextInt(2) == 0) {
inc = -1;
}
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) inc = 1;
for(i = 0; i < ServerConstants.SCROLL_CHANCE_RATE; i++) {
if (nEquip.getStr() > 0) {
temp = (nEquip.getStr() + Randomizer.nextInt(6) * inc);
nEquip.setStr(getMaximumShortMaxIfOverflow(mdStr, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdStr = nEquip.getStr();
}
else {
temp = (mdStr + temp) / 2;
if(temp > mdStr) mdStr = temp;
}
}
if (nEquip.getDex() > 0) {
temp = (nEquip.getDex() + Randomizer.nextInt(6) * inc);
nEquip.setDex(getMaximumShortMaxIfOverflow(mdDex, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdDex = nEquip.getDex();
}
else {
temp = (mdDex + temp) / 2;
if(temp > mdDex) mdDex = temp;
}
}
if (nEquip.getInt() > 0) {
temp = (nEquip.getInt() + Randomizer.nextInt(6) * inc);
nEquip.setInt(getMaximumShortMaxIfOverflow(mdInt, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdInt = nEquip.getInt();
}
else {
temp = (mdInt + temp) / 2;
if(temp > mdInt) mdInt = temp;
}
}
if (nEquip.getLuk() > 0) {
temp = (nEquip.getLuk() + Randomizer.nextInt(6) * inc);
nEquip.setLuk(getMaximumShortMaxIfOverflow(mdLuk, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdLuk = nEquip.getLuk();
}
else {
temp = (mdLuk + temp) / 2;
if(temp > mdLuk) mdLuk = temp;
}
}
if (nEquip.getWatk() > 0) {
temp = (nEquip.getWatk() + Randomizer.nextInt(6) * inc);
nEquip.setWatk(getMaximumShortMaxIfOverflow(mdWatk, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdWatk = nEquip.getWatk();
}
else {
temp = (mdWatk + temp) / 2;
if(temp > mdWatk) mdWatk = temp;
}
}
if (nEquip.getWdef() > 0) {
temp = (nEquip.getWdef() + Randomizer.nextInt(6) * inc);
nEquip.setWdef(getMaximumShortMaxIfOverflow(mdWdef, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdWdef = nEquip.getWdef();
}
else {
temp = (mdWdef + temp) / 2;
if(temp > mdWdef) mdWdef = temp;
}
}
if (nEquip.getMatk() > 0) {
temp = (nEquip.getMatk() + Randomizer.nextInt(6) * inc);
nEquip.setMatk(getMaximumShortMaxIfOverflow(mdMatk, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdMatk = nEquip.getMatk();
}
else {
temp = (mdMatk + temp) / 2;
if(temp > mdMatk) mdMatk = temp;
}
}
if (nEquip.getMdef() > 0) {
temp = (nEquip.getMdef() + Randomizer.nextInt(6) * inc);
nEquip.setMdef(getMaximumShortMaxIfOverflow(mdMdef, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdMdef = nEquip.getMdef();
}
else {
temp = (mdMdef + temp) / 2;
if(temp > mdMdef) mdMdef = temp;
}
}
if (nEquip.getAcc() > 0) {
temp = (nEquip.getAcc() + Randomizer.nextInt(6) * inc);
nEquip.setAcc(getMaximumShortMaxIfOverflow(mdAcc, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdAcc = nEquip.getAcc();
}
else {
temp = (mdAcc + temp) / 2;
if(temp > mdAcc) mdAcc = temp;
}
}
if (nEquip.getAvoid() > 0) {
temp = (nEquip.getAvoid() + Randomizer.nextInt(6) * inc);
nEquip.setAvoid(getMaximumShortMaxIfOverflow(mdAvoid, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdAvoid = nEquip.getAvoid();
}
else {
temp = (mdAvoid + temp) / 2;
if(temp > mdAvoid) mdAvoid = temp;
}
}
if (nEquip.getSpeed() > 0) {
temp = (nEquip.getSpeed() + Randomizer.nextInt(6) * inc);
nEquip.setSpeed(getMaximumShortMaxIfOverflow(mdSpeed, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdSpeed = nEquip.getSpeed();
}
else {
temp = (mdSpeed + temp) / 2;
if(temp > mdSpeed) mdSpeed = temp;
}
}
if (nEquip.getJump() > 0) {
temp = (nEquip.getJump() + Randomizer.nextInt(6) * inc);
nEquip.setJump(getMaximumShortMaxIfOverflow(mdJump, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdJump = nEquip.getJump();
}
else {
temp = (mdJump + temp) / 2;
if(temp > mdJump) mdJump = temp;
}
}
if (nEquip.getHp() > 0) {
temp = (nEquip.getHp() + Randomizer.nextInt(6) * inc);
nEquip.setHp(getMaximumShortMaxIfOverflow(mdHp, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdHp = nEquip.getHp();
}
else {
temp = (mdHp + temp) / 2;
if(temp > mdHp) mdHp = temp;
}
}
if (nEquip.getMp() > 0) {
temp = (nEquip.getMp() + Randomizer.nextInt(6) * inc);
nEquip.setMp(getMaximumShortMaxIfOverflow(mdMp, temp));
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) {
mdMp = nEquip.getMp();
}
else {
temp = (mdMp + temp) / 2;
if(temp > mdMp) mdMp = temp;
}
}
}
}
else {
inc = 1;
if (Randomizer.nextInt(2) == 0) {
inc = -1;
}
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) inc = 1;
if (nEquip.getStr() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setStr(getMaximumShortMaxIfOverflow(nEquip.getStr(), (nEquip.getStr() + Randomizer.nextInt(6) * inc)));
else nEquip.setStr(getMaximumShortMaxIfOverflow(0, (nEquip.getStr() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getDex() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setDex(getMaximumShortMaxIfOverflow(nEquip.getDex(), (nEquip.getDex() + Randomizer.nextInt(6) * inc)));
else nEquip.setDex(getMaximumShortMaxIfOverflow(0, (nEquip.getDex() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getInt() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setInt(getMaximumShortMaxIfOverflow(nEquip.getInt(), (nEquip.getInt() + Randomizer.nextInt(6) * inc)));
else nEquip.setInt(getMaximumShortMaxIfOverflow(0, (nEquip.getInt() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getLuk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setLuk(getMaximumShortMaxIfOverflow(nEquip.getLuk(), (nEquip.getLuk() + Randomizer.nextInt(6) * inc)));
else nEquip.setLuk(getMaximumShortMaxIfOverflow(0, (nEquip.getLuk() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getWatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setWatk(getMaximumShortMaxIfOverflow(nEquip.getWatk(), (nEquip.getWatk() + Randomizer.nextInt(6) * inc)));
else nEquip.setWatk(getMaximumShortMaxIfOverflow(0, (nEquip.getWatk() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getWdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setWdef(getMaximumShortMaxIfOverflow(nEquip.getWdef(), (nEquip.getWdef() + Randomizer.nextInt(6) * inc)));
else nEquip.setWdef(getMaximumShortMaxIfOverflow(0, (nEquip.getWdef() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getMatk() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setMatk(getMaximumShortMaxIfOverflow(nEquip.getMatk(), (nEquip.getMatk() + Randomizer.nextInt(6) * inc)));
else nEquip.setMatk(getMaximumShortMaxIfOverflow(0, (nEquip.getMatk() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getMdef() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setMdef(getMaximumShortMaxIfOverflow(nEquip.getMdef(), (nEquip.getMdef() + Randomizer.nextInt(6) * inc)));
else nEquip.setMdef(getMaximumShortMaxIfOverflow(0, (nEquip.getMdef() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getAcc() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setAcc(getMaximumShortMaxIfOverflow(nEquip.getAcc(), (nEquip.getAcc() + Randomizer.nextInt(6) * inc)));
else nEquip.setAcc(getMaximumShortMaxIfOverflow(0, (nEquip.getAcc() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getAvoid() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setAvoid(getMaximumShortMaxIfOverflow(nEquip.getAvoid(), (nEquip.getAvoid() + Randomizer.nextInt(6) * inc)));
else nEquip.setAvoid(getMaximumShortMaxIfOverflow(0, (nEquip.getAvoid() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getSpeed() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setSpeed(getMaximumShortMaxIfOverflow(nEquip.getSpeed(), (nEquip.getSpeed() + Randomizer.nextInt(6) * inc)));
else nEquip.setSpeed(getMaximumShortMaxIfOverflow(0, (nEquip.getSpeed() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getJump() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setJump(getMaximumShortMaxIfOverflow(nEquip.getJump(), (nEquip.getJump() + Randomizer.nextInt(6) * inc)));
else nEquip.setJump(getMaximumShortMaxIfOverflow(0, (nEquip.getJump() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getHp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setHp(getMaximumShortMaxIfOverflow(nEquip.getHp(), (nEquip.getHp() + Randomizer.nextInt(6) * inc)));
else nEquip.setHp(getMaximumShortMaxIfOverflow(0, (nEquip.getHp() + Randomizer.nextInt(6) * inc)));
}
if (nEquip.getMp() > 0) {
if(ServerConstants.USE_ENHANCED_CHSCROLL == true) nEquip.setMp(getMaximumShortMaxIfOverflow(nEquip.getMp(), (nEquip.getMp() + Randomizer.nextInt(6) * inc)));
else nEquip.setMp(getMaximumShortMaxIfOverflow(0, (nEquip.getMp() + Randomizer.nextInt(6) * inc)));
}
}
scrollEquipWithChaos(nEquip);
break;
default:
@@ -911,13 +879,13 @@ public class MapleItemInformationProvider {
break;
}
if (!ItemConstants.isCleanSlate(scrollId)) {
if (ServerConstants.USE_PERFECT_SCROLLING == true && !assertGM && !usingWhiteScroll) {
if (!assertGM && !usingWhiteScroll) {
nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
}
nEquip.setLevel((byte) (nEquip.getLevel() + 1));
}
} else {
if (ServerConstants.USE_PERFECT_SCROLLING == false && !usingWhiteScroll && !ItemConstants.isCleanSlate(scrollId) && !assertGM) {
} else {
if (!ServerConstants.USE_PERFECT_SCROLLING && !usingWhiteScroll && !ItemConstants.isCleanSlate(scrollId) && !assertGM) {
nEquip.setUpgradeSlots((byte) (nEquip.getUpgradeSlots() - 1));
}
if (Randomizer.nextInt(101) < stats.get("cursed")) {

View File

@@ -48,6 +48,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import net.server.world.MapleParty;
@@ -257,26 +258,33 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
private void distributeExperienceToParty(int pid, int exp, int killer, Map<Integer, Integer> expDist) {
LinkedList<MapleCharacter> members = new LinkedList<>();
Collection<MapleCharacter> chrs = map.getCharacters();
for (MapleCharacter mc : chrs) {
if (mc.getPartyId() == pid) {
members.add(mc);
}
List<MapleCharacter> members = new LinkedList<>();
MapleCharacter pchar = getMap().getAnyCharacterFromParty(pid);
if(pchar != null) {
for(MapleCharacter chr : pchar.getPartyMembersOnSameMap()) {
members.add(chr);
}
} else {
MapleCharacter chr = getMap().getCharacterById(killer);
if(chr == null) return;
members.add(chr);
}
final int minLevel = getLevel() - 5;
int partyLevel = 0;
int leechMinLevel = 0;
for (MapleCharacter mc : members) {
if (mc.getLevel() >= minLevel) {
leechMinLevel = Math.min(mc.getLevel() - 5, minLevel);
if(!ServerConstants.USE_UNDERLEVELED_EXP_GAIN) { //NO EXP WILL BE GIVEN for those who are underleveled!
leechMinLevel = minLevel;
for (MapleCharacter mc : members) {
if (mc.getLevel() >= minLevel) {
leechMinLevel = Math.min(mc.getLevel() - 5, leechMinLevel);
}
}
}
int leechCount = 0;
for (MapleCharacter mc : members) {
if (mc.getLevel() >= leechMinLevel) {
@@ -290,13 +298,12 @@ public class MapleMonster extends AbstractLoadedMapleLife {
for (MapleCharacter mc : members) {
int id = mc.getId();
int level = mc.getLevel();
if (expDist.containsKey(id)
|| level >= leechMinLevel) {
if (expDist.containsKey(id) || level >= leechMinLevel) {
boolean isKiller = killer == id;
boolean mostDamage = mostDamageCid == id;
int xp = (int) (exp * 0.80f * level / partyLevel);
int xp = (int) ((0.80f * exp * level) / partyLevel);
if (mostDamage) {
xp += (exp * 0.20f);
xp += (0.20f * exp);
}
giveExpToCharacter(mc, xp, isKiller, leechCount);
}
@@ -311,26 +318,32 @@ public class MapleMonster extends AbstractLoadedMapleLife {
int totalHealth = getMaxHp();
Map<Integer, Integer> expDist = new HashMap<>();
Map<Integer, Integer> partyExp = new HashMap<>();
// 80% of pool is split amongst all the damagers
float exp8 = (0.8f * exp); // 80% of pool is split amongst all the damagers
float exp2 = (0.2f * exp); // 20% of pool goes to the killer or his/her party
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
expDist.put(damage.getKey(), (int) (0.80f * exp * damage.getValue().get() / totalHealth));
expDist.put(damage.getKey(), (int) (Math.min((exp8 * damage.getValue().get()) / totalHealth, Integer.MAX_VALUE)));
}
Collection<MapleCharacter> chrs = map.getCharacters();
for (MapleCharacter mc : chrs) {
if (expDist.containsKey(mc.getId())) {
boolean isKiller = mc.getId() == killerId;
boolean isKiller = (mc.getId() == killerId);
int xp = expDist.get(mc.getId());
if (isKiller) {
xp += exp / 5;
xp = (int)Math.min(exp2 + xp, Integer.MAX_VALUE);
}
MapleParty p = mc.getParty();
if (p != null) {
int pID = p.getId();
int pXP = xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, pXP);
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
} else {
giveExpToCharacter(mc, xp, isKiller, 1);
if(ServerConstants.USE_UNDERLEVELED_EXP_GAIN || mc.getLevel() >= this.getLevel() - 5) {
//NO EXP WILL BE GIVEN for those who are underleveled!
giveExpToCharacter(mc, xp, isKiller, 1);
}
}
}
}

View File

@@ -43,6 +43,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.LinkedList;
import java.util.List;
import java.util.Iterator;
@@ -93,6 +94,7 @@ public class MapleMap {
private AtomicInteger spawnedMonstersOnMap = new AtomicInteger(0);
private AtomicInteger droppedItemCount = new AtomicInteger(0);
private Collection<MapleCharacter> characters = new LinkedHashSet<>();
private Map<Integer, Set<Integer>> mapParty = new LinkedHashMap<>();
private Map<Integer, MaplePortal> portals = new HashMap<>();
private Map<Integer, Integer> backgroundTypes = new HashMap<>();
private Map<String, Integer> environment = new LinkedHashMap<>();
@@ -133,6 +135,7 @@ public class MapleMap {
private short mobInterval = 5000;
private boolean allowSummons = true; // All maps should have this true at the beginning
private int lastDoorOwner = -1;
// HPQ
private int riceCakes = 0;
private int bunnyDamage = 0;
@@ -1781,10 +1784,84 @@ public class MapleMap {
}, time);
}
public MapleCharacter getAnyCharacterFromParty(int partyid) {
chrRLock.lock();
try {
Set<Integer> list = mapParty.get(partyid);
if(list == null) return null;
for(Integer cid : list) {
for (MapleCharacter c : this.characters) {
if (c.getId() == cid) {
return c;
}
}
}
return null;
} finally {
chrRLock.unlock();
}
}
private void addPartyMemberInternal(MapleCharacter chr) {
int partyid = chr.getPartyId();
if(partyid == -1) return;
Set<Integer> partyEntry = mapParty.get(partyid);
if(partyEntry == null) {
partyEntry = new LinkedHashSet<>();
partyEntry.add(chr.getId());
mapParty.put(partyid, partyEntry);
} else {
partyEntry.add(chr.getId());
}
}
private void removePartyMemberInternal(MapleCharacter chr) {
int partyid = chr.getPartyId();
if(partyid == -1) return;
Set<Integer> partyEntry = mapParty.get(partyid);
if(partyEntry != null) {
if(partyEntry.size() > 1) partyEntry.remove(chr.getId());
else mapParty.remove(partyid);
}
}
public void addPartyMember(MapleCharacter chr) {
chrWLock.lock();
try {
addPartyMemberInternal(chr);
} finally {
chrWLock.unlock();
}
}
public void removePartyMember(MapleCharacter chr) {
chrWLock.lock();
try {
removePartyMemberInternal(chr);
} finally {
chrWLock.unlock();
}
}
public void removeParty(int partyid) {
chrWLock.lock();
try {
mapParty.remove(partyid);
} finally {
chrWLock.unlock();
}
}
public void addPlayer(final MapleCharacter chr) {
chrWLock.lock();
try {
characters.add(chr);
addPartyMemberInternal(chr);
} finally {
chrWLock.unlock();
}
@@ -2047,6 +2124,7 @@ public class MapleMap {
public void removePlayer(MapleCharacter chr) {
chrWLock.lock();
try {
removePartyMemberInternal(chr);
characters.remove(chr);
} finally {
chrWLock.unlock();

View File

@@ -2623,7 +2623,8 @@ public class MaplePacketCreator {
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
mplew.writeInt(cid);
writeLongMaskD(mplew, statups);
for (int i = 0; i < statups.size(); i++) {
for (Pair<MapleDisease, Integer> statup : statups) {
mplew.writeShort(statup.getRight().shortValue());
mplew.writeShort(skill.getSkillId());
mplew.writeShort(skill.getSkillLevel());
}