Stat pool & Skills on change field Patch + Elemental Charge broadcast
Patched account storages not getting cached properly at login time. Reviewed item acquisition at the Cash Shop happening before point transaction. EXP toggle flag now also works on equipment gains. Factored several skills (Energy Charge, Wind Walk, Dash) not updating properly other players when changing maps. Refactored stat pool system, which wasn't working properly on limit scenarios. Fixed "untradeable at wear"equipments losing flags upon equipping. Reviewed Inventory Sort, now sorting projectiles at descending order on damage. Implemented support for visibility of effects on weapons imbued with Charge skill (e.g. Paladin's Holy Charge) for other players.
This commit is contained in:
@@ -2305,4 +2305,27 @@ Corrigido buff Final Attack de Cygnus sendo reaplicado a todo acerto de skill.
|
||||
24 - 25 Novembro 2019,
|
||||
Corrigido caso não sendo checado devidamente com Maker.
|
||||
Corrigido contagem de projéteis nos stats de skill usando tipo de dados de tamanho insuficiente.
|
||||
Refatorado acesso a membros relativos a Dojo em canais de forma a buscar melhorar efetividade dos ingressos e liberações de lobby.
|
||||
Refatorado acesso a membros relativos a Dojo em canais de forma a buscar melhorar efetividade dos ingressos e liberações de lobby.
|
||||
Revisado exceção inutilizável na classe geradora de áreas do jogo.
|
||||
|
||||
27 Novembro 2019,
|
||||
Revisado carregamento de storage da DB ocorrendo a cada login realizado.
|
||||
Revisado aquisição de itens no CS ocorrendo antes de utilizar os pontos disponíveis.
|
||||
|
||||
28 Novembro 2019,
|
||||
Revisado interação de flag de permissão de ganho de EXP em equipamentos.
|
||||
|
||||
29 - 30 Novembro 2019,
|
||||
Fatorado diversas habilidades (Energy Charge, Wind Walk, Dash) não transcorrendo como esperado na visão de outros jogadores ao trocar de mapas.
|
||||
|
||||
02 - 03 Dezembro 2019,
|
||||
Revisado uso de locks compartilhados em MapleClient.
|
||||
Refatorado criação de conjunto durante checagem de slots, que seria de fato efetivo em cenários muito raros (melhor deixar inserção de itens limitados dar fail-fast nas réplicas).
|
||||
Refatorado sistema de pool de stats, que estava atuando erroneamente em casos-limite.
|
||||
Corrigido Item Guard inconsistentemente levando a NPE ao utilizar o mesmo.
|
||||
Corrigido itens perdendo flags ao equipar aqueles tidos como "untradeable após equipar".
|
||||
Revisado Inventory Sort, agora ordenando projéteis por bônus de dano.
|
||||
|
||||
06 Dezembro 2019,
|
||||
Implementado pacote para visão de buffs de efeito imbuído em armas para outros jogadores.
|
||||
Corrigido casos de exceção devido a portais nulos na função que troca jogador de mapas interferindo com próximas trocas de mapa (jogador fica preso até relogar).
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
Copyleft (L) 2016 - 2019 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
@@ -61,8 +61,9 @@ function writeFeatureTab_Skills() {
|
||||
addFeature("Maker skill features developed - pckts thanks Arnah.");
|
||||
addFeature("Chair Mastery - map chair boosts HP/MP rec.");
|
||||
addFeature("Mu Lung Dojo skills functional.");
|
||||
addFeature("Monster Magnet skill no longer crashes players.");
|
||||
addFeature("Monster Magnet skill on bosses no longer crash.");
|
||||
addFeature("HP/MP consumption from skills triggers pet autopot.");
|
||||
addFeature("Elemental weapon imbue visibility for other players.");
|
||||
}
|
||||
|
||||
function writeFeatureTab_Quests() {
|
||||
|
||||
@@ -277,17 +277,22 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
this.clientmaxmp = Math.min(30000, mp_);
|
||||
}
|
||||
|
||||
private static long calcStatPoolNode(long v, int displacement) {
|
||||
if (v > Short.MAX_VALUE) {
|
||||
v = Short.MAX_VALUE;
|
||||
} else if (v < Short.MIN_VALUE) {
|
||||
v = Short.MIN_VALUE;
|
||||
}
|
||||
|
||||
return ((v & 0x0FFFF) << displacement);
|
||||
private static long clampStat(int v, int min, int max) {
|
||||
return (v < min) ? min : ((v > max) ? max : v);
|
||||
}
|
||||
|
||||
private static long calcStatPoolLong(int v1, int v2, int v3, int v4) {
|
||||
private static long calcStatPoolNode(Integer v, int displacement) {
|
||||
long r;
|
||||
if (v == null) {
|
||||
r = -32768;
|
||||
} else {
|
||||
r = clampStat(v, -32767, 32767);
|
||||
}
|
||||
|
||||
return ((r & 0x0FFFF) << displacement);
|
||||
}
|
||||
|
||||
private static long calcStatPoolLong(Integer v1, Integer v2, Integer v3, Integer v4) {
|
||||
long ret = 0;
|
||||
|
||||
ret |= calcStatPoolNode(v1, 48);
|
||||
@@ -419,40 +424,48 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
}
|
||||
|
||||
protected void changeHpMp(int newhp, int newmp, boolean silent) {
|
||||
changeHpMpPool(newhp, newmp, Short.MIN_VALUE, Short.MIN_VALUE, silent);
|
||||
changeHpMpPool(newhp, newmp, null, null, silent);
|
||||
}
|
||||
|
||||
private void changeHpMpPool(int hp, int mp, int maxhp, int maxmp, boolean silent) {
|
||||
private void changeHpMpPool(Integer hp, Integer mp, Integer maxhp, Integer maxmp, boolean silent) {
|
||||
long hpMpPool = calcStatPoolLong(hp, mp, maxhp, maxmp);
|
||||
changeStatPool(hpMpPool, null, null, -1, silent);
|
||||
}
|
||||
|
||||
public void updateHp(int hp) {
|
||||
updateHpMaxHp(hp, Short.MIN_VALUE);
|
||||
updateHpMaxHp(hp, null);
|
||||
}
|
||||
|
||||
public void updateMaxHp(int maxhp) {
|
||||
updateHpMaxHp(Short.MIN_VALUE, maxhp);
|
||||
updateHpMaxHp(null, maxhp);
|
||||
}
|
||||
|
||||
public void updateHpMaxHp(int hp, int maxhp) {
|
||||
changeHpMpPool(hp, Short.MIN_VALUE, maxhp, Short.MIN_VALUE, false);
|
||||
updateHpMaxHp(Integer.valueOf(hp), Integer.valueOf(maxhp));
|
||||
}
|
||||
|
||||
private void updateHpMaxHp(Integer hp, Integer maxhp) {
|
||||
changeHpMpPool(hp, null, maxhp, null, false);
|
||||
}
|
||||
|
||||
public void updateMp(int mp) {
|
||||
updateMpMaxMp(mp, Short.MIN_VALUE);
|
||||
updateMpMaxMp(mp, null);
|
||||
}
|
||||
|
||||
public void updateMaxMp(int maxmp) {
|
||||
updateMpMaxMp(Short.MIN_VALUE, maxmp);
|
||||
updateMpMaxMp(null, maxmp);
|
||||
}
|
||||
|
||||
public void updateMpMaxMp(int mp, int maxmp) {
|
||||
changeHpMpPool(Short.MIN_VALUE, mp, Short.MIN_VALUE, maxmp, false);
|
||||
updateMpMaxMp(Integer.valueOf(mp), Integer.valueOf(maxmp));
|
||||
}
|
||||
|
||||
private void updateMpMaxMp(Integer mp, Integer maxmp) {
|
||||
changeHpMpPool(null, mp, null, maxmp, false);
|
||||
}
|
||||
|
||||
public void updateMaxHpMaxMp(int maxhp, int maxmp) {
|
||||
changeHpMpPool(Short.MIN_VALUE, Short.MIN_VALUE, maxhp, maxmp, false);
|
||||
changeHpMpPool(null, null, maxhp, maxmp, false);
|
||||
}
|
||||
|
||||
protected void enforceMaxHpMp() {
|
||||
@@ -521,7 +534,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
effLock.lock();
|
||||
statWlock.lock();
|
||||
try {
|
||||
changeHpMpPool(Short.MIN_VALUE, Short.MIN_VALUE, maxhp + hpdelta, maxmp + mpdelta, silent);
|
||||
changeHpMpPool(null, null, maxhp + hpdelta, maxmp + mpdelta, silent);
|
||||
} finally {
|
||||
statWlock.unlock();
|
||||
effLock.unlock();
|
||||
@@ -567,19 +580,19 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
}
|
||||
|
||||
public boolean assignStr(int x) {
|
||||
return assignStrDexIntLuk(x, Short.MIN_VALUE, Short.MIN_VALUE, Short.MIN_VALUE);
|
||||
return assignStrDexIntLuk(x, null, null, null);
|
||||
}
|
||||
|
||||
public boolean assignDex(int x) {
|
||||
return assignStrDexIntLuk(Short.MIN_VALUE, x, Short.MIN_VALUE, Short.MIN_VALUE);
|
||||
return assignStrDexIntLuk(null, x, null, null);
|
||||
}
|
||||
|
||||
public boolean assignInt(int x) {
|
||||
return assignStrDexIntLuk(Short.MIN_VALUE, Short.MIN_VALUE, x, Short.MIN_VALUE);
|
||||
return assignStrDexIntLuk(null, null, x, null);
|
||||
}
|
||||
|
||||
public boolean assignLuk(int x) {
|
||||
return assignStrDexIntLuk(Short.MIN_VALUE, Short.MIN_VALUE, Short.MIN_VALUE, x);
|
||||
return assignStrDexIntLuk(null, null, null, x);
|
||||
}
|
||||
|
||||
public boolean assignHP(int deltaHP, int deltaAp) {
|
||||
@@ -590,7 +603,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
return false;
|
||||
}
|
||||
|
||||
long hpMpPool = calcStatPoolLong(Short.MIN_VALUE, Short.MIN_VALUE, maxhp + deltaHP, maxmp);
|
||||
long hpMpPool = calcStatPoolLong(null, null, maxhp + deltaHP, maxmp);
|
||||
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
|
||||
|
||||
changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false);
|
||||
@@ -610,7 +623,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
return false;
|
||||
}
|
||||
|
||||
long hpMpPool = calcStatPoolLong(Short.MIN_VALUE, Short.MIN_VALUE, maxhp, maxmp + deltaMP);
|
||||
long hpMpPool = calcStatPoolLong(null, null, maxhp, maxmp + deltaMP);
|
||||
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
|
||||
|
||||
changeStatPool(hpMpPool, strDexIntLuk, null, remainingAp - deltaAp, false);
|
||||
@@ -622,11 +635,15 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
}
|
||||
}
|
||||
|
||||
private static int apAssigned(int x) {
|
||||
return x != Short.MIN_VALUE ? x : 0;
|
||||
private static int apAssigned(Integer x) {
|
||||
return x != null ? x : 0;
|
||||
}
|
||||
|
||||
public boolean assignStrDexIntLuk(int deltaStr, int deltaDex, int deltaInt, int deltaLuk) {
|
||||
return assignStrDexIntLuk(Integer.valueOf(deltaStr), Integer.valueOf(deltaDex), Integer.valueOf(deltaInt), Integer.valueOf(deltaLuk));
|
||||
}
|
||||
|
||||
private boolean assignStrDexIntLuk(Integer deltaStr, Integer deltaDex, Integer deltaInt, Integer deltaLuk) {
|
||||
effLock.lock();
|
||||
statWlock.lock();
|
||||
try {
|
||||
@@ -636,19 +653,19 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
}
|
||||
|
||||
int newStr = str + deltaStr, newDex = dex + deltaDex, newInt = int_ + deltaInt, newLuk = luk + deltaLuk;
|
||||
if (newStr < 4 && deltaStr != Short.MIN_VALUE || newStr > YamlConfig.config.server.MAX_AP) {
|
||||
if (newStr < 4 && deltaStr != null || newStr > YamlConfig.config.server.MAX_AP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newDex < 4 && deltaDex != Short.MIN_VALUE || newDex > YamlConfig.config.server.MAX_AP) {
|
||||
if (newDex < 4 && deltaDex != null || newDex > YamlConfig.config.server.MAX_AP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newInt < 4 && deltaInt != Short.MIN_VALUE || newInt > YamlConfig.config.server.MAX_AP) {
|
||||
if (newInt < 4 && deltaInt != null || newInt > YamlConfig.config.server.MAX_AP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newLuk < 4 && deltaLuk != Short.MIN_VALUE || newLuk > YamlConfig.config.server.MAX_AP) {
|
||||
if (newLuk < 4 && deltaLuk != null || newLuk > YamlConfig.config.server.MAX_AP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -691,12 +708,12 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
|
||||
changeStrDexIntLuk(str, dex, int_, luk, remainingAp, false);
|
||||
}
|
||||
|
||||
private void changeStrDexIntLuk(int str, int dex, int int_, int luk, int remainingAp, boolean silent) {
|
||||
private void changeStrDexIntLuk(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, boolean silent) {
|
||||
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
|
||||
changeStatPool(null, strDexIntLuk, null, remainingAp, silent);
|
||||
}
|
||||
|
||||
private void changeStrDexIntLukSp(int str, int dex, int int_, int luk, int remainingAp, int remainingSp, int skillbook, boolean silent) {
|
||||
private void changeStrDexIntLukSp(Integer str, Integer dex, Integer int_, Integer luk, int remainingAp, int remainingSp, int skillbook, boolean silent) {
|
||||
long strDexIntLuk = calcStatPoolLong(str, dex, int_, luk);
|
||||
long sp = calcStatPoolLong(0, 0, remainingSp, skillbook);
|
||||
changeStatPool(null, strDexIntLuk, sp, remainingAp, silent);
|
||||
|
||||
@@ -1472,11 +1472,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
changeMap(to, to.getPortal(portal));
|
||||
}
|
||||
|
||||
public void changeMap(final MapleMap target, final MaplePortal pto) {
|
||||
public void changeMap(final MapleMap target, MaplePortal pto) {
|
||||
canWarpCounter++;
|
||||
|
||||
eventChangedMap(target.getId()); // player can be dropped from an event here, hence the new warping target.
|
||||
MapleMap to = getWarpMap(target.getId());
|
||||
if (pto == null) {
|
||||
pto = to.getPortal(0);
|
||||
}
|
||||
changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this));
|
||||
canWarpMap = false;
|
||||
|
||||
@@ -1504,7 +1507,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
eventAfterChangedMap(this.getMapId());
|
||||
}
|
||||
|
||||
public void forceChangeMap(final MapleMap target, final MaplePortal pto) {
|
||||
public void forceChangeMap(final MapleMap target, MaplePortal pto) {
|
||||
// will actually enter the map given as parameter, regardless of being an eventmap or whatnot
|
||||
|
||||
canWarpCounter++;
|
||||
@@ -1525,6 +1528,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
MapleMap to = target; // warps directly to the target intead of the target's map id, this allows GMs to patrol players inside instances.
|
||||
if (pto == null) {
|
||||
pto = to.getPortal(0);
|
||||
}
|
||||
changeMapInternal(to, pto.getPosition(), MaplePacketCreator.getWarpToMap(to, pto.getId(), this));
|
||||
canWarpMap = false;
|
||||
|
||||
@@ -6102,7 +6108,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<>(MapleBuffStat.ENERGY_CHARGE, energybar));
|
||||
setBuffedValue(MapleBuffStat.ENERGY_CHARGE, energybar);
|
||||
client.announce(MaplePacketCreator.giveBuff(energybar, 0, stat));
|
||||
getMap().broadcastMessage(chr, MaplePacketCreator.giveForeignBuff(energybar, stat));
|
||||
getMap().broadcastMessage(chr, MaplePacketCreator.cancelForeignFirstDebuff(id, ((long) 1) << 50));
|
||||
}
|
||||
}, ceffect.getDuration());
|
||||
}
|
||||
@@ -9403,25 +9409,41 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public byte getSlots(int type) {
|
||||
return type == MapleInventoryType.CASH.getType() ? 96 : inventory[type].getSlotLimit();
|
||||
}
|
||||
|
||||
|
||||
public boolean canGainSlots(int type, int slots) {
|
||||
slots += inventory[type].getSlotLimit();
|
||||
return slots <= 96;
|
||||
}
|
||||
|
||||
public boolean gainSlots(int type, int slots) {
|
||||
return gainSlots(type, slots, true);
|
||||
}
|
||||
|
||||
public boolean gainSlots(int type, int slots, boolean update) {
|
||||
slots += inventory[type].getSlotLimit();
|
||||
if (slots <= 96) {
|
||||
inventory[type].setSlotLimit(slots);
|
||||
|
||||
boolean ret = gainSlotsInternal(type, slots, update);
|
||||
if (ret) {
|
||||
this.saveCharToDB();
|
||||
if (update) {
|
||||
client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean gainSlotsInternal(int type, int slots, boolean update) {
|
||||
inventory[type].lockInventory();
|
||||
try {
|
||||
if (canGainSlots(type, slots)) {
|
||||
slots += inventory[type].getSlotLimit();
|
||||
inventory[type].setSlotLimit(slots);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
inventory[type].unlockInventory();
|
||||
}
|
||||
}
|
||||
|
||||
public int sellAllItemsFromName(byte invTypeId, String name) {
|
||||
@@ -10487,18 +10509,20 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void increaseEquipExp(int expGain) {
|
||||
if(expGain < 0) {
|
||||
expGain = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
for (Item item : getUpgradeableEquipList()) {
|
||||
Equip nEquip = (Equip) item;
|
||||
String itemName = ii.getName(nEquip.getItemId());
|
||||
if (itemName == null) {
|
||||
continue;
|
||||
if (allowExpGain) { // thanks Vcoc for suggesting equip EXP gain conditionally
|
||||
if(expGain < 0) {
|
||||
expGain = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
for (Item item : getUpgradeableEquipList()) {
|
||||
Equip nEquip = (Equip) item;
|
||||
String itemName = ii.getName(nEquip.getItemId());
|
||||
if (itemName == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nEquip.gainItemExp(client, expGain);
|
||||
}
|
||||
|
||||
nEquip.gainItemExp(client, expGain);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -118,8 +118,7 @@ public class MapleClient {
|
||||
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
|
||||
private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
|
||||
private final Lock announcerLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ANNOUNCER, true);
|
||||
private static final int lockCount = 200;
|
||||
private static final Lock loginLocks[] = new Lock[lockCount]; // thanks Masterrulax & try2hack for pointing out a bottleneck issue here
|
||||
// thanks Masterrulax & try2hack for pointing out a bottleneck issue with shared locks, shavit for noticing an opportunity for improvement
|
||||
private Calendar tempBanCalendar;
|
||||
private int votePoints;
|
||||
private int voteTime = -1;
|
||||
@@ -129,12 +128,6 @@ public class MapleClient {
|
||||
private long lastPacket = System.currentTimeMillis();
|
||||
private int lang = 0;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < lockCount; i++) {
|
||||
loginLocks[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLastPacket() {
|
||||
lastPacket = System.currentTimeMillis();
|
||||
}
|
||||
@@ -453,8 +446,7 @@ public class MapleClient {
|
||||
}
|
||||
|
||||
public int finishLogin() {
|
||||
Lock loginLock = loginLocks[this.getAccID() % lockCount];
|
||||
loginLock.lock();
|
||||
encoderLock.lock();
|
||||
try {
|
||||
if (getLoginState() > LOGIN_NOTLOGGEDIN) { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
|
||||
loggedIn = false;
|
||||
@@ -462,7 +454,7 @@ public class MapleClient {
|
||||
}
|
||||
updateLoginState(MapleClient.LOGIN_LOGGEDIN);
|
||||
} finally {
|
||||
loginLock.unlock();
|
||||
encoderLock.unlock();
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1379,8 +1371,12 @@ public class MapleClient {
|
||||
characterSlots = slots;
|
||||
}
|
||||
|
||||
public boolean canGainCharacterSlot() {
|
||||
return characterSlots < 15;
|
||||
}
|
||||
|
||||
public synchronized boolean gainCharacterSlot() {
|
||||
if (characterSlots < 15) {
|
||||
if (canGainCharacterSlot()) {
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
@@ -41,5 +41,5 @@ public class DisposeCommand extends Command {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
c.removeClickedNPC();
|
||||
c.getPlayer().message("You've been disposed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,10 +453,10 @@ public class MapleInventory implements Iterable<Item> {
|
||||
private static boolean checkItemRestricted(List<Pair<Item, MapleInventoryType>> items) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
Set<Integer> itemids = new HashSet<>();
|
||||
// thanks Shavit for noticing set creation that would be only effective in rare situations
|
||||
for (Pair<Item, MapleInventoryType> p : items) {
|
||||
int itemid = p.getLeft().getItemId();
|
||||
if (ii.isPickupRestricted(itemid) && (p.getLeft().getQuantity() > 1 || !itemids.add(itemid))) {
|
||||
if (ii.isPickupRestricted(itemid) && p.getLeft().getQuantity() > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +523,10 @@ public class MapleInventoryManipulator {
|
||||
}
|
||||
boolean itemChanged = false;
|
||||
if (ii.isUntradeableOnEquip(source.getItemId())) {
|
||||
source.setFlag((byte) ItemConstants.UNTRADEABLE);
|
||||
short flag = source.getFlag(); // thanks BHB for noticing flags missing after equipping these
|
||||
flag |= ItemConstants.UNTRADEABLE;
|
||||
source.setFlag(flag);
|
||||
|
||||
itemChanged = true;
|
||||
}
|
||||
if (dst == -6) { // unequip the overall
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
*/
|
||||
package constants.inventory;
|
||||
|
||||
import constants.net.ServerConstants;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import config.YamlConfig;
|
||||
|
||||
|
||||
@@ -894,33 +894,8 @@ public class Server {
|
||||
//MaplePet.clearMissingPetsFromDb(); // thanks Optimist for noticing this taking too long to run
|
||||
MapleCashidGenerator.loadExistentCashIdsFromDb();
|
||||
|
||||
IoBuffer.setUseDirectBuffer(false);
|
||||
IoBuffer.setAllocator(new SimpleBufferAllocator());
|
||||
acceptor = new NioSocketAcceptor();
|
||||
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
|
||||
|
||||
ThreadManager.getInstance().start();
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.start();
|
||||
tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw...
|
||||
disconnectIdlesOnLoginTask();
|
||||
|
||||
long timeLeft = getTimeLeftForNextHour();
|
||||
tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
|
||||
tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
|
||||
tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
|
||||
tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
|
||||
tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
|
||||
tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
|
||||
tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
|
||||
tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
|
||||
|
||||
timeLeft = getTimeLeftForNextDay();
|
||||
MapleExpeditionBossLog.resetBossLogTable();
|
||||
tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft);
|
||||
initializeTimelyTasks(); // aggregated method for timely tasks thanks to lxconan
|
||||
|
||||
long timeToTake = System.currentTimeMillis();
|
||||
SkillFactory.loadAllSkills();
|
||||
@@ -965,6 +940,10 @@ public class Server {
|
||||
|
||||
System.out.println();
|
||||
|
||||
IoBuffer.setUseDirectBuffer(false); // join IO operations performed by lxconan
|
||||
IoBuffer.setAllocator(new SimpleBufferAllocator());
|
||||
acceptor = new NioSocketAcceptor();
|
||||
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
|
||||
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
|
||||
acceptor.setHandler(new MapleServerHandler());
|
||||
try {
|
||||
@@ -986,6 +965,30 @@ public class Server {
|
||||
ch.reloadEventScriptManager();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeTimelyTasks() {
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.start();
|
||||
tMan.register(tMan.purge(), YamlConfig.config.server.PURGING_INTERVAL);//Purging ftw...
|
||||
disconnectIdlesOnLoginTask();
|
||||
|
||||
long timeLeft = getTimeLeftForNextHour();
|
||||
tMan.register(new CharacterDiseaseTask(), YamlConfig.config.server.UPDATE_INTERVAL, YamlConfig.config.server.UPDATE_INTERVAL);
|
||||
tMan.register(new ReleaseLockTask(), 2 * 60 * 1000, 2 * 60 * 1000);
|
||||
tMan.register(new CouponTask(), YamlConfig.config.server.COUPON_INTERVAL, timeLeft);
|
||||
tMan.register(new RankingCommandTask(), 5 * 60 * 1000, 5 * 60 * 1000);
|
||||
tMan.register(new RankingLoginTask(), YamlConfig.config.server.RANKING_INTERVAL, timeLeft);
|
||||
tMan.register(new LoginCoordinatorTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new EventRecallCoordinatorTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new LoginStorageTask(), 2 * 60 * 1000, 2 * 60 * 1000);
|
||||
tMan.register(new DueyFredrickTask(), 60 * 60 * 1000, timeLeft);
|
||||
tMan.register(new InvitationTask(), 30 * 1000, 30 * 1000);
|
||||
tMan.register(new RespawnTask(), YamlConfig.config.server.RESPAWN_INTERVAL, YamlConfig.config.server.RESPAWN_INTERVAL);
|
||||
|
||||
timeLeft = getTimeLeftForNextDay();
|
||||
MapleExpeditionBossLog.resetBossLogTable();
|
||||
tMan.register(new BossLogTask(), 24 * 60 * 60 * 1000, timeLeft);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.setProperty("wzpath", "wz");
|
||||
@@ -1755,7 +1758,7 @@ public class Server {
|
||||
for (Integer worldid : accWorlds) {
|
||||
if (worldid < worldList.size()) {
|
||||
World wserv = worldList.get(worldid);
|
||||
wserv.registerAccountStorage(accountId);
|
||||
wserv.loadAccountStorage(accountId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
24
src/net/server/audit/locks/empty/AbstractEmptyLock.java
Normal file
24
src/net/server/audit/locks/empty/AbstractEmptyLock.java
Normal file
@@ -0,0 +1,24 @@
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public abstract class AbstractEmptyLock {
|
||||
|
||||
protected static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); // DRY-code opportunity performed by jtumidanski
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -19,11 +19,6 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.net.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReadLock;
|
||||
import tools.FilePrinter;
|
||||
@@ -32,27 +27,13 @@ import tools.FilePrinter;
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReadLock implements MonitoredReadLock {
|
||||
public class EmptyReadLock extends AbstractEmptyLock implements MonitoredReadLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReadLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
|
||||
@@ -19,11 +19,6 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.net.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredReentrantLock;
|
||||
import tools.FilePrinter;
|
||||
@@ -32,27 +27,13 @@ import tools.FilePrinter;
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyReentrantLock implements MonitoredReentrantLock {
|
||||
public class EmptyReentrantLock extends AbstractEmptyLock implements MonitoredReentrantLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyReentrantLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
|
||||
@@ -19,11 +19,6 @@
|
||||
*/
|
||||
package net.server.audit.locks.empty;
|
||||
|
||||
import constants.net.ServerConstants;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.MonitoredWriteLock;
|
||||
import tools.FilePrinter;
|
||||
@@ -32,27 +27,13 @@ import tools.FilePrinter;
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class EmptyWriteLock implements MonitoredWriteLock {
|
||||
public class EmptyWriteLock extends AbstractEmptyLock implements MonitoredWriteLock {
|
||||
private final MonitoredLockType id;
|
||||
|
||||
public EmptyWriteLock(MonitoredLockType type) {
|
||||
this.id = type;
|
||||
}
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
for(int i = 0; i < list.length; i++) {
|
||||
s += (" " + list[i].toString() + "\r\n");
|
||||
}
|
||||
s += "----------------------------\r\n\r\n";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lock() {
|
||||
FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace()));
|
||||
|
||||
@@ -86,16 +86,18 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
Item item = cItem.toItem();
|
||||
cs.gainCash(useNX, cItem, chr.getWorld()); // thanks Rohenn for noticing cash operations after item acquisition
|
||||
cs.addToInventory(item);
|
||||
c.announce(MaplePacketCreator.showBoughtCashItem(item, c.getAccID()));
|
||||
} else { // Package
|
||||
cs.gainCash(useNX, cItem, chr.getWorld());
|
||||
|
||||
List<Item> cashPackage = CashItemFactory.getPackage(cItem.getItemId());
|
||||
for (Item item : cashPackage) {
|
||||
cs.addToInventory(item);
|
||||
}
|
||||
c.announce(MaplePacketCreator.showBoughtCashPackage(cashPackage, c.getAccID()));
|
||||
}
|
||||
cs.gainCash(useNX, cItem, chr.getWorld());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else if (action == 0x04) {//TODO check for gender
|
||||
int birthday = slea.readInt();
|
||||
@@ -116,9 +118,9 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA8));
|
||||
return;
|
||||
}
|
||||
cs.gainCash(4, cItem, chr.getWorld());
|
||||
cs.gift(Integer.parseInt(recipient.get("id")), chr.getName(), message, cItem.getSN());
|
||||
c.announce(MaplePacketCreator.showGiftSucceed(recipient.get("name"), cItem));
|
||||
cs.gainCash(4, cItem, chr.getWorld());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
try {
|
||||
chr.sendNote(recipient.get("name"), chr.getName() + " has sent you a gift! Go check out the Cash Shop.", (byte) 0); //fame or not
|
||||
@@ -147,10 +149,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
if (chr.gainSlots(type, 4, false)) {
|
||||
int qty = 4;
|
||||
if (!chr.canGainSlots(type, qty)) {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
cs.gainCash(cash, -4000);
|
||||
if (chr.gainSlots(type, qty, false)) {
|
||||
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
|
||||
cs.gainCash(cash, -4000);
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
|
||||
}
|
||||
} else {
|
||||
CashItem cItem = CashItemFactory.getItem(slea.readInt());
|
||||
@@ -159,10 +168,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
if (chr.gainSlots(type, 8, false)) {
|
||||
int qty = 8;
|
||||
if (!chr.canGainSlots(type, qty)) {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
if (chr.gainSlots(type, qty, false)) {
|
||||
c.announce(MaplePacketCreator.showBoughtInventorySlots(type, chr.getSlots(type)));
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots of type " + type + " for player " + MapleCharacter.makeMapleReadable(chr.getName()));
|
||||
}
|
||||
}
|
||||
} else if (action == 0x07) { // Increase Storage Slots
|
||||
@@ -174,13 +190,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
if (chr.getStorage().gainSlots(4)) {
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 4 slots to their account storage.");
|
||||
int qty = 4;
|
||||
if (!chr.getStorage().canGainSlots(qty)) {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
cs.gainCash(cash, -4000);
|
||||
if (chr.getStorage().gainSlots(qty)) {
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
|
||||
chr.setUsedStorage();
|
||||
|
||||
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
|
||||
cs.gainCash(cash, -4000);
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
|
||||
}
|
||||
} else {
|
||||
CashItem cItem = CashItemFactory.getItem(slea.readInt());
|
||||
@@ -189,13 +212,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
if (chr.getStorage().gainSlots(8)) { // thanks ABaldParrot & Thora for detecting storage issues here
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought 8 slots to their account storage.");
|
||||
int qty = 8;
|
||||
if (!chr.getStorage().canGainSlots(qty)) {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
if (chr.getStorage().gainSlots(qty)) { // thanks ABaldParrot & Thora for detecting storage issues here
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " bought " + qty + " slots to their account storage.");
|
||||
chr.setUsedStorage();
|
||||
|
||||
c.announce(MaplePacketCreator.showBoughtStorageSlots(chr.getStorage().getSlots()));
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add " + qty + " slots to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
|
||||
}
|
||||
}
|
||||
} else if (action == 0x08) { // Increase Character Slots
|
||||
@@ -207,13 +237,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!c.canGainCharacterSlot()) {
|
||||
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
if (c.gainCharacterSlot()) {
|
||||
c.announce(MaplePacketCreator.showBoughtCharacterSlot(c.getCharacterSlots()));
|
||||
cs.gainCash(cash, cItem, chr.getWorld());
|
||||
c.announce(MaplePacketCreator.showCash(chr));
|
||||
} else {
|
||||
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
|
||||
FilePrinter.printError(FilePrinter.CASHITEM_BOUGHT, "Could not add a character slot to " + MapleCharacter.makeMapleReadable(chr.getName()) + "'s account.");
|
||||
c.enableCSActions();
|
||||
return;
|
||||
}
|
||||
@@ -287,8 +321,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
eqp.setRingId(rings.getLeft());
|
||||
cs.addToInventory(eqp);
|
||||
c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
|
||||
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
|
||||
cs.gainCash(toCharge, itemRing, chr.getWorld());
|
||||
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
|
||||
chr.addCrushRing(MapleRing.loadFromDb(rings.getLeft()));
|
||||
try {
|
||||
chr.sendNote(partner.getName(), text, (byte) 1);
|
||||
@@ -353,8 +387,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
eqp.setRingId(rings.getLeft());
|
||||
cs.addToInventory(eqp);
|
||||
c.announce(MaplePacketCreator.showBoughtCashRing(eqp, partner.getName(), c.getAccID()));
|
||||
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
|
||||
cs.gainCash(payment, -itemRing.getPrice());
|
||||
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
|
||||
chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft()));
|
||||
try {
|
||||
chr.sendNote(partner.getName(), text, (byte) 1);
|
||||
@@ -391,8 +425,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
if(chr.registerNameChange(newName)) { //success
|
||||
Item item = cItem.toItem();
|
||||
c.announce(MaplePacketCreator.showNameChangeSuccess(item, c.getAccID()));
|
||||
cs.addToInventory(item);
|
||||
cs.gainCash(4, cItem, chr.getWorld());
|
||||
cs.addToInventory(item);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
|
||||
}
|
||||
@@ -421,8 +455,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
|
||||
} else if(chr.registerWorldTransfer(newWorldSelection)) {
|
||||
Item item = cItem.toItem();
|
||||
c.announce(MaplePacketCreator.showWorldTransferSuccess(item, c.getAccID()));
|
||||
cs.addToInventory(item);
|
||||
cs.gainCash(4, cItem, chr.getWorld());
|
||||
cs.addToInventory(item);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.showCashShopMessage((byte)0));
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import client.inventory.Equip;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.ModifyInventory;
|
||||
import constants.net.ServerConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import net.server.Server;
|
||||
|
||||
@@ -73,7 +72,11 @@ class PairedQuicksort {
|
||||
} while (i <= j);
|
||||
}
|
||||
|
||||
private void PartitionByItemIdReverse(int Esq, int Dir, ArrayList<Item> A) {
|
||||
private int getWatkForProjectile(Item item) {
|
||||
return ii.getWatkForProjectile(item.getItemId());
|
||||
}
|
||||
|
||||
private void PartitionByProjectileAtk(int Esq, int Dir, ArrayList<Item> A) {
|
||||
Item x, w;
|
||||
|
||||
i = Esq;
|
||||
@@ -81,8 +84,9 @@ class PairedQuicksort {
|
||||
|
||||
x = A.get((i + j) / 2);
|
||||
do {
|
||||
while (x.getItemId() < A.get(i).getItemId()) i++;
|
||||
while (x.getItemId() > A.get(j).getItemId()) j--;
|
||||
int watk = getWatkForProjectile(x);
|
||||
while (watk < getWatkForProjectile(A.get(i))) i++;
|
||||
while (watk > getWatkForProjectile(A.get(j))) j--;
|
||||
|
||||
if (i <= j) {
|
||||
w = A.get(i);
|
||||
@@ -228,7 +232,7 @@ class PairedQuicksort {
|
||||
|
||||
public void reverseSortSublist(ArrayList<Item> A, int[] range) {
|
||||
if (range != null) {
|
||||
PartitionByItemIdReverse(range[0], range[1], A);
|
||||
PartitionByProjectileAtk(range[0], range[1], A);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
eq.setExpiration(currentServerTime() + (period * 60 * 60 * 24 * 1000));
|
||||
}
|
||||
|
||||
remove(c, position, itemId);
|
||||
// double-remove found thanks to BHB
|
||||
} else if (itemId == 5060002) { // Incubator
|
||||
byte inventory2 = (byte) slea.readInt();
|
||||
short slot2 = (short) slea.readInt();
|
||||
|
||||
@@ -467,7 +467,13 @@ public class World {
|
||||
}
|
||||
}
|
||||
|
||||
public void registerAccountStorage(Integer accountId) {
|
||||
public void loadAccountStorage(Integer accountId) {
|
||||
if (getAccountStorage(accountId) == null) {
|
||||
registerAccountStorage(accountId);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerAccountStorage(Integer accountId) {
|
||||
MapleStorage storage = MapleStorage.loadOrCreateFromDB(accountId, this.id);
|
||||
accountCharsLock.lock();
|
||||
try {
|
||||
@@ -572,7 +578,7 @@ public class World {
|
||||
|
||||
if(cserv != null) {
|
||||
if(!cserv.removePlayer(chr)) {
|
||||
// oy the player is not where it should be, find this mf
|
||||
// oy the player is not where they should be, find this mf
|
||||
|
||||
for(Channel ch : getChannels()) {
|
||||
if(ch.removePlayer(chr)) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import config.YamlConfig;
|
||||
@@ -640,7 +639,7 @@ public class MapleStatEffect {
|
||||
break;
|
||||
case WindArcher.WIND_WALK:
|
||||
statups.add(new Pair<>(MapleBuffStat.WIND_WALK, Integer.valueOf(x)));
|
||||
break;
|
||||
//break; thanks Vcoc for noticing WW not showing for other players when changing maps
|
||||
case Rogue.DARK_SIGHT:
|
||||
case NightWalker.DARK_SIGHT:
|
||||
statups.add(new Pair<>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x)));
|
||||
@@ -1343,6 +1342,8 @@ public class MapleStatEffect {
|
||||
if (isDash()) {
|
||||
buff = MaplePacketCreator.givePirateBuff(statups, sourceid, seconds);
|
||||
mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups);
|
||||
} else if (isWkCharge()) {
|
||||
mbuff = MaplePacketCreator.giveForeignWKChargeEffect(applyto.getId(), sourceid, localstatups);
|
||||
} else if (isInfusion()) {
|
||||
buff = MaplePacketCreator.givePirateBuff(localstatups, sourceid, seconds);
|
||||
mbuff = MaplePacketCreator.giveForeignPirateBuff(applyto.getId(), sourceid, seconds, localstatups);
|
||||
@@ -1746,6 +1747,20 @@ public class MapleStatEffect {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isWkCharge() {
|
||||
if (!skill) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Pair<MapleBuffStat, Integer> p : statups) {
|
||||
if (p.getLeft().equals(MapleBuffStat.WK_CHARGE)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isDash() {
|
||||
return skill && (sourceid == Pirate.DASH || sourceid == ThunderBreaker.DASH || sourceid == Beginner.SPACE_DASH || sourceid == Noblesse.SPACE_DASH);
|
||||
|
||||
@@ -114,12 +114,16 @@ public class MapleStorage {
|
||||
return slots;
|
||||
}
|
||||
|
||||
public boolean canGainSlots(int slots) {
|
||||
slots += this.slots;
|
||||
return slots <= 48;
|
||||
}
|
||||
|
||||
public boolean gainSlots(int slots) {
|
||||
lock.lock();
|
||||
try {
|
||||
slots += this.slots;
|
||||
|
||||
if (slots <= 48) {
|
||||
if (canGainSlots(slots)) {
|
||||
slots += this.slots;
|
||||
this.slots = (byte) slots;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -310,19 +310,9 @@ public class MapleMapFactory {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
map.setMapName(loadPlaceName(mapid));
|
||||
map.setStreetName(loadStreetName(mapid));
|
||||
} catch (Exception e) {
|
||||
if (mapid / 1000 != 1020) { // explorer job introduction scenes
|
||||
e.printStackTrace();
|
||||
System.err.println("Not found mapid " + mapid);
|
||||
}
|
||||
|
||||
map.setMapName("");
|
||||
map.setStreetName("");
|
||||
}
|
||||
|
||||
map.setMapName(loadPlaceName(mapid));
|
||||
map.setStreetName(loadStreetName(mapid));
|
||||
|
||||
map.setClock(mapData.getChildByPath("clock") != null);
|
||||
map.setEverlast(MapleDataTool.getIntConvert("everlast", infoData, 0) != 0); // thanks davidlafriniere for noticing value 0 accounting as true
|
||||
map.setTown(MapleDataTool.getIntConvert("town", infoData, 0) != 0);
|
||||
@@ -435,7 +425,7 @@ public class MapleMapFactory {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String loadPlaceName(int mapid) throws Exception {
|
||||
public static String loadPlaceName(int mapid) {
|
||||
try {
|
||||
return MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(mapid)), "");
|
||||
} catch (Exception e) {
|
||||
@@ -443,7 +433,7 @@ public class MapleMapFactory {
|
||||
}
|
||||
}
|
||||
|
||||
public static String loadStreetName(int mapid) throws Exception {
|
||||
public static String loadStreetName(int mapid) {
|
||||
try {
|
||||
return MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(mapid)), "");
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1890,7 +1890,7 @@ public class MaplePacketCreator {
|
||||
}
|
||||
long buffmask = 0;
|
||||
Integer buffvalue = null;
|
||||
if (chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && !chr.isHidden()) {
|
||||
if ((chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null || chr.getBuffedValue(MapleBuffStat.WIND_WALK) != null) && !chr.isHidden()) {
|
||||
buffmask |= MapleBuffStat.DARKSIGHT.getValue();
|
||||
}
|
||||
if (chr.getBuffedValue(MapleBuffStat.COMBO) != null) {
|
||||
@@ -1906,10 +1906,6 @@ public class MaplePacketCreator {
|
||||
if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) {
|
||||
buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.MORPH).intValue());
|
||||
}
|
||||
if (chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE) != null) {
|
||||
buffmask |= MapleBuffStat.ENERGY_CHARGE.getValue();
|
||||
buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.ENERGY_CHARGE).intValue());
|
||||
}//AREN'T THESE
|
||||
mplew.writeInt((int) ((buffmask >> 32) & 0xffffffffL));
|
||||
if (buffvalue != null) {
|
||||
if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { //TEST
|
||||
@@ -1919,16 +1915,24 @@ public class MaplePacketCreator {
|
||||
}
|
||||
}
|
||||
mplew.writeInt((int) (buffmask & 0xffffffffL));
|
||||
int CHAR_MAGIC_SPAWN = Randomizer.nextInt();
|
||||
mplew.skip(6);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
|
||||
// Energy Charge
|
||||
mplew.writeInt(chr.getEnergyBar() == 15000 ? 1 : 0);
|
||||
mplew.writeShort(0);
|
||||
mplew.skip(4);
|
||||
|
||||
boolean dashBuff = chr.getBuffedValue(MapleBuffStat.DASH) != null;
|
||||
// Dash Speed
|
||||
mplew.writeInt(dashBuff ? 1 << 24 : 0);
|
||||
mplew.skip(11);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);//v74
|
||||
mplew.skip(11);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.writeShort(0);
|
||||
// Dash Jump
|
||||
mplew.skip(9);
|
||||
mplew.writeInt(dashBuff ? 1 << 24 : 0);
|
||||
mplew.writeShort(0);
|
||||
mplew.write(0);
|
||||
|
||||
// Monster Riding
|
||||
Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING);
|
||||
if (bv != null) {
|
||||
MapleMount mount = chr.getMount();
|
||||
@@ -1942,17 +1946,23 @@ public class MaplePacketCreator {
|
||||
mplew.writeLong(0);
|
||||
}
|
||||
|
||||
int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); // skill references found thanks to Rien dev team
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
// Speed Infusion
|
||||
mplew.skip(8);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.write(0);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.writeShort(0);
|
||||
// Homing Beacon
|
||||
mplew.skip(9);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.writeInt(0);
|
||||
// Zombify
|
||||
mplew.skip(9);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.writeShort(0);
|
||||
mplew.writeInt(0); // actually not 0, why is it 0 then?
|
||||
mplew.skip(10);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.skip(13);
|
||||
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
||||
mplew.writeShort(0);
|
||||
mplew.write(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3067,6 +3077,15 @@ public class MaplePacketCreator {
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] cancelForeignFirstDebuff(int cid, long mask) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
||||
mplew.writeInt(cid);
|
||||
mplew.writeLong(mask);
|
||||
mplew.writeLong(0);
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] cancelForeignDebuff(int cid, long mask) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
||||
@@ -3198,6 +3217,20 @@ public class MaplePacketCreator {
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
// packet found thanks to Ronan
|
||||
public static byte[] giveForeignWKChargeEffect(int cid, int buffid, List<Pair<MapleBuffStat, Integer>> statups) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
||||
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
||||
mplew.writeInt(cid);
|
||||
writeLongMask(mplew, statups);
|
||||
mplew.writeInt(buffid);
|
||||
mplew.writeShort(600);
|
||||
mplew.writeShort(1000);//Delay
|
||||
mplew.write(1);
|
||||
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] cancelForeignChairSkillEffect(int cid) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
||||
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
</imgdir>
|
||||
<imgdir name="2010007">
|
||||
<string name="name" value="Roger's Apple"/>
|
||||
<string name="desc" value="A ripe, red apple.\nRecovers HP 30.nn#cTo eat Roger's Apple, simply double-click on it in your use inventory#."/>
|
||||
<string name="desc" value="A ripe, red apple.\nRecovers HP 30.\n\n#cTo eat Roger's Apple, simply double-click on it in your use inventory#."/>
|
||||
</imgdir>
|
||||
<imgdir name="2010009">
|
||||
<string name="name" value="Green Apple"/>
|
||||
@@ -1445,31 +1445,31 @@
|
||||
</imgdir>
|
||||
<imgdir name="2030001">
|
||||
<string name="name" value="Return Scroll to Lith Harbor"/>
|
||||
<string name="desc" value="Returns you to Lith Harbor. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to Lith Harbor. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030002">
|
||||
<string name="name" value="Return Scroll to Ellinia"/>
|
||||
<string name="desc" value="Returns you to Ellinia. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to Ellinia. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030003">
|
||||
<string name="name" value="Return Scroll to Perion"/>
|
||||
<string name="desc" value="Returns you to Perion. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to Perion. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030004">
|
||||
<string name="name" value="Return Scroll to Henesys"/>
|
||||
<string name="desc" value="Returns you to Henesys, the peaceful town. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to Henesys, the peaceful town. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030005">
|
||||
<string name="name" value="Return Scroll to Kerning City"/>
|
||||
<string name="desc" value="Returns you to the dark Kerning City. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to the dark Kerning City. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030006">
|
||||
<string name="name" value="Return Scroll to Sleepywood"/>
|
||||
<string name="desc" value="Returns you to Sleepywood, a quiet and dark forest-town. It disappears once it's used."/>
|
||||
<string name="desc" value="Returns you to Sleepywood, a quiet and dark forest-town. It disappears once it's used."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030007">
|
||||
<string name="name" value="Return Scroll to Dead Mine"/>
|
||||
<string name="desc" value="Returns you to the dead mine at the higher ground of El Nath. It disappears once it's used.\nCan only be used in Orbis and El Nath."/>
|
||||
<string name="desc" value="Returns you to the dead mine at the higher ground of El Nath. It disappears once it's used.\nCan only be used in Orbis and El Nath."/>
|
||||
</imgdir>
|
||||
<imgdir name="2030008">
|
||||
<string name="name" value="Coffee Milk"/>
|
||||
@@ -3689,7 +3689,7 @@
|
||||
</imgdir>
|
||||
<imgdir name="2060004">
|
||||
<string name="name" value="Diamond Arrow for Bow"/>
|
||||
<string name="desc" value="A case full of arrows. Can only be used with a bow.nAttack+4."/>
|
||||
<string name="desc" value="A case full of arrows. Can only be used with a bow.\nAttack+4."/>
|
||||
</imgdir>
|
||||
<imgdir name="2060005">
|
||||
<string name="name" value="Snowball"/>
|
||||
@@ -8305,7 +8305,7 @@
|
||||
</imgdir>
|
||||
<imgdir name="2049203">
|
||||
<string name="name" value="Dark Scroll for Accessory for DEX 30%"/>
|
||||
<string name="desc" value="Improves DEX on accessories (pendants, belts, rings).\nSuccess rate:30%, DEX+3\.nIf failed, the item will be destroyed at a 50% rate."/>
|
||||
<string name="desc" value="Improves DEX on accessories (pendants, belts, rings).\nSuccess rate:30%, DEX+3.\nIf failed, the item will be destroyed at a 50% rate."/>
|
||||
</imgdir>
|
||||
<imgdir name="2049204">
|
||||
<string name="name" value="Dark Scroll for Accessory for INT 70%"/>
|
||||
|
||||
Reference in New Issue
Block a user