Event Recall + Cash Shop bestsellers + MapleSessionCoordinator rework
Implemented an event recall system. Players that went disconnected during an event instance are able to rejoin the ongoing event upon relogin. Implemented a player-activity backed best-sellers system for the Cash Shop. Patched the recently added selective loot system interfering with quest items, ever disabling drops after the player picked up one item. Implemented a server flag for everlasting buffs. Fixed some inconsistencies with Priest Dispel skill, sometimes crashing party players. Fixed change job not properly showing effects for other players. Fixed wrong fee value being taken from players that expands their guild size. Also, implemented GMS-like fee for this action. Reworked the MapleSessionCoordinator, now evaluating client's HWID as well as remote IP. This's expected to lessen account drought time for players that are constantly changing their IP. Last but not least, added world maps for Mushroom Castle, Zipangu, CBD/Malaysia and Ellin Forest regions. Original artwork content used on files depicted in this topic are rightful property of Nexon Corps., these files thoroughly trying to adhere the "Fair Use" disclaimer policy, their purpose being solely to fulfill gaming experience for the areas that were already present on v83 GMS but still lacked worldmaps. For more info regarding Fair Use, please refer to "http://www.dmlp.org/legal-guide/fair-use".
This commit is contained in:
@@ -32,6 +32,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
import net.server.Server;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
|
||||
import provider.MapleData;
|
||||
@@ -107,18 +109,18 @@ public class CashShop {
|
||||
if (ItemConstants.EXPIRING_ITEMS) {
|
||||
if(period == 1) {
|
||||
if(itemId == 5211048 || itemId == 5360042) { // 4 Hour 2X coupons, the period is 1, but we don't want them to last a day.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 4));
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + (1000 * 60 * 60 * 4));
|
||||
/*
|
||||
} else if(itemId == 5211047 || itemId == 5360014) { // 3 Hour 2X coupons, unused as of now
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 3));
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + (1000 * 60 * 60 * 3));
|
||||
*/
|
||||
} else if(itemId == 5211060) { // 2 Hour 3X coupons.
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 2));
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + (1000 * 60 * 60 * 2));
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24));
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + (1000 * 60 * 60 * 24));
|
||||
}
|
||||
} else {
|
||||
item.setExpiration(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * period));
|
||||
item.setExpiration(Server.getInstance().getCurrentTime() + (1000 * 60 * 60 * 24 * period));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,6 +355,11 @@ public class CashShop {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void gainCash(int type, CashItem buyItem, int world) {
|
||||
gainCash(type, -buyItem.getPrice());
|
||||
if(!ServerConstants.USE_ENFORCE_ITEM_SUGGESTION) Server.getInstance().getWorld(world).addCashItemBought(buyItem.getSN());
|
||||
}
|
||||
|
||||
public boolean isOpened() {
|
||||
return opened;
|
||||
|
||||
@@ -97,6 +97,8 @@ public class MapleItemInformationProvider {
|
||||
protected Map<Integer, MapleStatEffect> itemEffects = new HashMap<>();
|
||||
protected Map<Integer, Map<String, Integer>> equipStatsCache = new HashMap<>();
|
||||
protected Map<Integer, Equip> equipCache = new HashMap<>();
|
||||
protected Map<Integer, MapleData> equipLevelInfoCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> equipMaxLevelCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> wholePriceCache = new HashMap<>();
|
||||
protected Map<Integer, Double> unitPriceCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> projectileWatkCache = new HashMap<>();
|
||||
@@ -1217,7 +1219,7 @@ public class MapleItemInformationProvider {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isDropRestricted(int itemId) {
|
||||
public boolean isLootRestricted(int itemId) {
|
||||
if (dropRestrictionCache.containsKey(itemId)) {
|
||||
return dropRestrictionCache.get(itemId);
|
||||
}
|
||||
@@ -1227,16 +1229,17 @@ public class MapleItemInformationProvider {
|
||||
MapleData data = getItemData(itemId);
|
||||
bRestricted = MapleDataTool.getIntConvert("info/tradeBlock", data, 0) == 1;
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
|
||||
}
|
||||
if (!bRestricted) {
|
||||
bRestricted = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
|
||||
bRestricted = MapleDataTool.getIntConvert("info/accountSharable", data, 0) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
dropRestrictionCache.put(itemId, bRestricted);
|
||||
return bRestricted;
|
||||
}
|
||||
|
||||
public boolean isDropRestricted(int itemId) {
|
||||
return isLootRestricted(itemId) || isQuestItem(itemId);
|
||||
}
|
||||
|
||||
public boolean isPickupRestricted(int itemId) {
|
||||
if (pickupRestrictionCache.containsKey(itemId)) {
|
||||
@@ -1674,24 +1677,72 @@ public class MapleItemInformationProvider {
|
||||
return true;
|
||||
}
|
||||
|
||||
public ArrayList<Pair<Integer, String>> getItemDataByName(String name)
|
||||
{
|
||||
public ArrayList<Pair<Integer, String>> getItemDataByName(String name) {
|
||||
ArrayList<Pair<Integer, String>> ret = new ArrayList<>();
|
||||
for (Pair<Integer, String> itemPair : MapleItemInformationProvider.getInstance().getAllItems()) {
|
||||
if (itemPair.getRight().toLowerCase().contains(name.toLowerCase())) {
|
||||
ret.add(itemPair);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
for (Pair<Integer, String> itemPair : MapleItemInformationProvider.getInstance().getAllItems()) {
|
||||
if (itemPair.getRight().toLowerCase().contains(name.toLowerCase())) {
|
||||
ret.add(itemPair);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private MapleData getEquipLevelInfo(int itemId) {
|
||||
MapleData equipLevelData = equipLevelInfoCache.get(itemId);
|
||||
if (equipLevelData == null) {
|
||||
if (equipLevelInfoCache.containsKey(itemId)) return null;
|
||||
|
||||
MapleData iData = getItemData(itemId);
|
||||
if (iData != null) {
|
||||
MapleData data = iData.getChildByPath("info/level");
|
||||
if (data != null) {
|
||||
equipLevelData = data.getChildByPath("info");
|
||||
}
|
||||
}
|
||||
|
||||
equipLevelInfoCache.put(itemId, equipLevelData);
|
||||
}
|
||||
|
||||
return equipLevelData;
|
||||
}
|
||||
|
||||
public int getEquipLevel(int itemId, boolean getMaxLevel) {
|
||||
Integer eqLevel = equipMaxLevelCache.get(itemId);
|
||||
if (eqLevel == null) {
|
||||
eqLevel = 1; // greater than 1 means that it was supposed to levelup on GMS
|
||||
|
||||
MapleData data = getEquipLevelInfo(itemId);
|
||||
if (data != null) {
|
||||
if (getMaxLevel) {
|
||||
int curLevel = 1;
|
||||
|
||||
while (true) {
|
||||
MapleData data2 = data.getChildByPath(Integer.toString(curLevel));
|
||||
if (data2 == null || data2.getChildren().size() <= 1) {
|
||||
eqLevel = curLevel;
|
||||
equipMaxLevelCache.put(itemId, eqLevel);
|
||||
break;
|
||||
}
|
||||
|
||||
curLevel++;
|
||||
}
|
||||
} else {
|
||||
MapleData data2 = data.getChildByPath("1");
|
||||
if (data2 != null && data2.getChildren().size() > 1) {
|
||||
eqLevel = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return eqLevel;
|
||||
}
|
||||
|
||||
public List<Pair<String, Integer>> getItemLevelupStats(int itemId, int level) {
|
||||
List<Pair<String, Integer>> list = new LinkedList<>();
|
||||
MapleData data = getItemData(itemId);
|
||||
MapleData data1 = data.getChildByPath("info").getChildByPath("level");
|
||||
|
||||
if (data1 != null) {
|
||||
MapleData data2 = data1.getChildByPath("info").getChildByPath(Integer.toString(level));
|
||||
MapleData data = getEquipLevelInfo(itemId);
|
||||
if (data != null) {
|
||||
MapleData data2 = data.getChildByPath(Integer.toString(level));
|
||||
if (data2 != null) {
|
||||
for (MapleData da : data2.getChildren()) {
|
||||
if (Math.random() < 0.9) {
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.server.world.MaplePartyCharacter;
|
||||
import net.server.Server;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataTool;
|
||||
import server.life.MapleMonster;
|
||||
@@ -997,11 +997,15 @@ public class MapleStatEffect {
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public int getBuffLocalDuration() {
|
||||
return !ServerConstants.USE_BUFF_EVERLASTING ? duration : Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void silentApplyBuff(MapleCharacter chr, long localStartTime) {
|
||||
int localDuration = duration;
|
||||
int localDuration = getBuffLocalDuration();
|
||||
localDuration = alchemistModifyVal(chr, localDuration, false);
|
||||
//CancelEffectAction cancelAction = new CancelEffectAction(chr, this, starttime);
|
||||
//ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - System.currentTimeMillis()));
|
||||
//ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + localDuration) - Server.getInstance().getCurrentTime()));
|
||||
|
||||
chr.registerEffect(this, localStartTime, localStartTime + localDuration, true);
|
||||
SummonMovementType summonMovementType = getSummonMovementType();
|
||||
@@ -1021,17 +1025,17 @@ public class MapleStatEffect {
|
||||
final List<Pair<MapleBuffStat, Integer>> stat = Collections.singletonList(new Pair<>(MapleBuffStat.ARAN_COMBO, combo));
|
||||
applyto.announce(MaplePacketCreator.giveBuff(sourceid, 99999, stat));
|
||||
|
||||
final long starttime = System.currentTimeMillis();
|
||||
final long starttime = Server.getInstance().getCurrentTime();
|
||||
// final CancelEffectAction cancelAction = new CancelEffectAction(applyto, this, starttime);
|
||||
// final ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + 99999) - System.currentTimeMillis()));
|
||||
// final ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, ((starttime + 99999) - Server.getInstance().getCurrentTime()));
|
||||
applyto.registerEffect(this, starttime, Long.MAX_VALUE, false);
|
||||
}
|
||||
|
||||
public void updateBuffEffect(MapleCharacter target, List<Pair<MapleBuffStat, Integer>> activeStats, long starttime) {
|
||||
int localDuration = duration;
|
||||
int localDuration = getBuffLocalDuration();
|
||||
localDuration = alchemistModifyVal(target, localDuration, false);
|
||||
|
||||
long leftDuration = (starttime + localDuration) - System.currentTimeMillis();
|
||||
long leftDuration = (starttime + localDuration) - Server.getInstance().getCurrentTime();
|
||||
if(leftDuration > 0) {
|
||||
target.announce(MaplePacketCreator.giveBuff((skill ? sourceid : -sourceid), (int)leftDuration, activeStats));
|
||||
}
|
||||
@@ -1043,7 +1047,7 @@ public class MapleStatEffect {
|
||||
}
|
||||
|
||||
List<Pair<MapleBuffStat, Integer>> localstatups = statups;
|
||||
int localDuration = duration;
|
||||
int localDuration = getBuffLocalDuration();
|
||||
int localsourceid = sourceid;
|
||||
int seconds = localDuration / 1000;
|
||||
MapleMount givemount = null;
|
||||
@@ -1155,7 +1159,7 @@ public class MapleStatEffect {
|
||||
}
|
||||
}
|
||||
|
||||
long starttime = System.currentTimeMillis();
|
||||
long starttime = Server.getInstance().getCurrentTime();
|
||||
//CancelEffectAction cancelAction = new CancelEffectAction(applyto, this, starttime);
|
||||
//ScheduledFuture<?> schedule = TimerManager.getInstance().schedule(cancelAction, localDuration);
|
||||
applyto.registerEffect(this, starttime, starttime + localDuration, false);
|
||||
|
||||
@@ -32,7 +32,6 @@ import client.status.MonsterStatus;
|
||||
import constants.GameConstants;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import server.TimerManager;
|
||||
import tools.Randomizer;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
|
||||
@@ -48,9 +48,9 @@ public class MapleLootInventory {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasItem(int itemid, int quantity) {
|
||||
public int hasItem(int itemid, int quantity) {
|
||||
Integer itemQty = items.get(itemid);
|
||||
return itemQty != null && itemQty >= quantity;
|
||||
return itemQty == null ? 0 : itemQty >= quantity ? 2 : itemQty > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,25 +34,30 @@ import server.quest.MapleQuest;
|
||||
*/
|
||||
public class MapleLootManager {
|
||||
|
||||
private static boolean needQuestItem(MonsterDropEntry dropEntry, MapleQuest quest, MapleCharacter chr, MapleLootInventory chrInv) {
|
||||
if (chr.getQuestStatus(dropEntry.questid) != 1) return false;
|
||||
return !chrInv.hasItem(dropEntry.itemId, quest.getItemAmountNeeded(dropEntry.itemId));
|
||||
}
|
||||
|
||||
private static boolean isRelevantDrop(MonsterDropEntry dropEntry, List<MapleCharacter> partyMembers, List<MapleLootInventory> partyInv) {
|
||||
MapleQuest quest = MapleQuest.getInstance(dropEntry.questid);
|
||||
boolean restricted = MapleItemInformationProvider.getInstance().isDropRestricted(dropEntry.itemId);
|
||||
int qItemAmount = quest != null ? quest.getItemAmountNeeded(dropEntry.itemId) : 0;
|
||||
|
||||
boolean restricted = MapleItemInformationProvider.getInstance().isLootRestricted(dropEntry.itemId);
|
||||
for (int i = 0; i < partyMembers.size(); i++) {
|
||||
MapleLootInventory chrInv = partyInv.get(i);
|
||||
|
||||
if(restricted && chrInv.hasItem(dropEntry.itemId, 1)) {
|
||||
if (dropEntry.questid > 0) {
|
||||
if (partyMembers.get(i).getQuestStatus(dropEntry.questid) != 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int qItemStatus = chrInv.hasItem(dropEntry.itemId, qItemAmount);
|
||||
if (qItemStatus == 2) {
|
||||
continue;
|
||||
} else if (restricted && qItemStatus == 1) {
|
||||
continue;
|
||||
}
|
||||
} else if (restricted && chrInv.hasItem(dropEntry.itemId, 1) > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(dropEntry.questid <= 0 || needQuestItem(dropEntry, quest, partyMembers.get(i), chrInv)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -242,7 +242,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
if (c.getPlayer().getMeso() >= price) {
|
||||
if (canBuy(c, newItem)) {
|
||||
c.getPlayer().gainMeso(-price, false);
|
||||
if(ServerConstants.USE_ANNOUNCE_SHOPITEMSOLD) announceItemSold(newItem, price); // idea thanks to vcoc
|
||||
if(ServerConstants.USE_ANNOUNCE_SHOPITEMSOLD) announceItemSold(newItem, price); // idea thanks to Vcoc
|
||||
|
||||
synchronized (sold) {
|
||||
sold.add(new SoldItem(c.getPlayer().getName(), pItem.getItem().getItemId(), newItem.getQuantity(), price));
|
||||
|
||||
@@ -1144,11 +1144,11 @@ public class MapleMap {
|
||||
return character;
|
||||
}
|
||||
|
||||
public List<MapleCharacter> getPlayersInRange(Rectangle box, List<MapleCharacter> chrList) {
|
||||
public List<MapleCharacter> getPlayersInRange(Rectangle box, List<MapleCharacter> targets) {
|
||||
List<MapleCharacter> character = new LinkedList<>();
|
||||
chrRLock.lock();
|
||||
try {
|
||||
for (MapleCharacter chr : chrList) {
|
||||
for (MapleCharacter chr : targets) {
|
||||
if (characters.contains(chr)) {
|
||||
if (box.contains(chr.getPosition())) {
|
||||
character.add(chr);
|
||||
|
||||
@@ -227,7 +227,7 @@ public class MapleQuest {
|
||||
if(!repeatable) return false;
|
||||
|
||||
IntervalRequirement ir = (IntervalRequirement) startReqs.get(MapleQuestRequirementType.INTERVAL);
|
||||
return ir.getInterval() < ServerConstants.FAME_GAIN_MIN_HOUR_INTERVAL * 60 * 60 * 1000;
|
||||
return ir.getInterval() < ServerConstants.QUEST_POINT_REPEATABLE_INTERVAL * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
public boolean canStartWithoutRequirements(MapleCharacter c) {
|
||||
@@ -369,12 +369,11 @@ public class MapleQuest {
|
||||
|
||||
public int getItemAmountNeeded(int itemid) {
|
||||
MapleQuestRequirement req = completeReqs.get(MapleQuestRequirementType.ITEM);
|
||||
if(req == null)
|
||||
return 0;
|
||||
if(req == null)
|
||||
return 0;
|
||||
|
||||
ItemRequirement ireq = (ItemRequirement) req;
|
||||
|
||||
return ireq.getItemAmountNeeded(itemid);
|
||||
ItemRequirement ireq = (ItemRequirement) req;
|
||||
return ireq.getItemAmountNeeded(itemid);
|
||||
}
|
||||
|
||||
public int getMobAmountNeeded(int mid) {
|
||||
|
||||
@@ -50,8 +50,6 @@ public class FameAction extends MapleQuestAction {
|
||||
|
||||
@Override
|
||||
public void run(MapleCharacter chr, Integer extSelection) {
|
||||
chr.addFame(fame);
|
||||
chr.updateSingleStat(MapleStat.FAME, chr.getFame());
|
||||
chr.announce(MaplePacketCreator.getShowFameGain(fame));
|
||||
chr.gainFame(fame);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user