Merge branch 'master' into credits_update

This commit is contained in:
ronancpl
2019-06-15 15:56:15 -03:00
146 changed files with 7810 additions and 2802 deletions
+71 -73
View File
@@ -84,13 +84,12 @@ import server.events.gm.MapleFitness;
import server.events.gm.MapleOla;
import server.life.MapleMonster;
import server.life.MobSkill;
import server.loot.MapleLootManager;
import server.maps.MapleHiredMerchant;
import server.maps.MapleDoor;
import server.maps.MapleDragon;
import server.maps.MapleMap;
import server.maps.MapleMapEffect;
import server.maps.MapleMapFactory;
import server.maps.MapleMapManager;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.maps.MapleMiniGame;
@@ -206,7 +205,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private transient int localstr, localdex, localluk, localint_, localmagic, localwatk;
private transient int equipmaxhp, equipmaxmp, equipstr, equipdex, equipluk, equipint_, equipmagic, equipwatk, localchairhp, localchairmp;
private int localchairrate;
private boolean hidden, equipchanged = true, canDoor = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false, canRecvPartySearchInvite = true;
private boolean hidden, equipchanged = true, berserk, hasMerchant, hasSandboxItem = false, whiteChat = false, canRecvPartySearchInvite = true;
private boolean equippedMesoMagnet = false, equippedItemPouch = false, equippedPetItemIgnore = false;
private int linkedLevel = 0;
private String linkedName = null;
@@ -961,7 +960,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public boolean canDoor() {
return canDoor;
MapleDoor door = getPlayerDoor();
return door == null || (door.isActive() && door.getElapsedDeployTime() > 5000);
}
public void setHasSandboxItem() {
@@ -2297,6 +2297,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
deleteQuestProgressWhereCharacterId(con, cid);
FredrickProcessor.removeFredrickLog(cid); // thanks maple006 for pointing out the player's Fredrick items are not being deleted at character deletion
try (PreparedStatement ps = con.prepareStatement("SELECT id FROM mts_cart WHERE cid = ?")) {
ps.setInt(1, cid);
@@ -2521,19 +2522,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}, healInterval, healInterval);
}
public void disableDoorSpawn() {
canDoor = false;
Runnable r = new Runnable() {
@Override
public void run() {
canDoor = true;
}
};
client.getChannelServer().registerOverallAction(mapid, r, 5000);
}
public void disbandGuild() {
if (guildid < 1 || guildRank != 1) {
return;
@@ -3500,7 +3488,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
for(Entry<Integer, Map<MapleBuffStat, MapleBuffStatValueHolder>> bpl: buffEffects.entrySet()) {
MapleBuffStatValueHolder mbsvhi = bpl.getValue().get(mbs);
if(mbsvhi != null) {
if(!mbsvhi.effect.isActive(mapid)) {
if(!mbsvhi.effect.isActive(this)) {
continue;
}
@@ -3725,17 +3713,57 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
public void updateActiveEffects() {
chrLock.lock();
private static MapleStatEffect getEffectFromBuffSource(Map<MapleBuffStat, MapleBuffStatValueHolder> buffSource) {
try {
effects.clear();
updateEffects(buffEffectsCount.keySet());
return buffSource.entrySet().iterator().next().getValue().effect;
} catch (Exception e) {
return null;
}
}
private boolean isUpdatingEffect(Set<MapleStatEffect> activeEffects, MapleStatEffect mse) {
if (mse == null) return false;
// thanks xinyifly for noticing "Speed Infusion" crashing game when updating buffs during map transition
boolean active = mse.isActive(this);
if (active) {
return !activeEffects.contains(mse);
} else {
return activeEffects.contains(mse);
}
}
public void updateActiveEffects() {
effLock.lock(); // thanks davidlafriniere, maple006, RedHat for pointing a deadlock occurring here
try {
Set<MapleBuffStat> updatedBuffs = new LinkedHashSet<>();
Set<MapleStatEffect> activeEffects = new LinkedHashSet<>();
for (MapleBuffStatValueHolder mse : effects.values()) {
activeEffects.add(mse.effect);
}
for (Map<MapleBuffStat, MapleBuffStatValueHolder> buff : buffEffects.values()) {
MapleStatEffect mse = getEffectFromBuffSource(buff);
if (isUpdatingEffect(activeEffects, mse)) {
for (Pair<MapleBuffStat, Integer> p : mse.getStatups()) {
updatedBuffs.add(p.getLeft());
}
}
}
for (MapleBuffStat mbs : updatedBuffs) {
effects.remove(mbs);
}
updateEffects(updatedBuffs);
} finally {
chrLock.unlock();
effLock.unlock();
}
}
private void updateEffects(Set<MapleBuffStat> removedStats) {
effLock.lock();
chrLock.lock();
try {
Set<MapleBuffStat> retrievedStats = new LinkedHashSet<>();
@@ -3754,6 +3782,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
propagateBuffEffectUpdates(new LinkedHashMap<Integer, Pair<MapleStatEffect, Long>>(), retrievedStats, removedStats);
} finally {
chrLock.unlock();
effLock.unlock();
}
}
@@ -3783,29 +3812,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
if (effect.isMagicDoor()) {
MapleDoor destroyDoor = removePartyDoor(false);
if (destroyDoor != null) {
destroyDoor.getTarget().removeMapObject(destroyDoor.getAreaDoor());
destroyDoor.getTown().removeMapObject(destroyDoor.getTownDoor());
for (MapleCharacter chr : destroyDoor.getTarget().getCharacters()) {
destroyDoor.getAreaDoor().sendDestroyData(chr.getClient());
}
Collection<MapleCharacter> townChars = destroyDoor.getTown().getCharacters();
for (MapleCharacter chr : townChars) {
destroyDoor.getTownDoor().sendDestroyData(chr.getClient());
}
if (destroyDoor.getTownPortal().getId() == 0x80) {
for (MapleCharacter chr : townChars) {
MapleDoor door = chr.getMainTownDoor();
if (door != null) {
destroyDoor.getTownDoor().sendSpawnData(chr.getClient());
}
}
}
}
MapleDoor.attemptRemoveDoor(this);
} else if (effect.isMapChair()) {
stopChairTask();
}
@@ -4202,6 +4209,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
case COUPON_DRP1:
case COUPON_DRP2:
case COUPON_DRP3:
case MESO_UP_BY_ITEM:
case ITEM_UP_BY_ITEM:
case RESPECT_PIMMUNE:
case RESPECT_MIMMUNE:
case DEFENSE_ATT:
case DEFENSE_STATE:
case WATK:
case WDEF:
case MATK:
@@ -4347,7 +4360,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
appliedStatups.put(ps.getLeft(), new MapleBuffStatValueHolder(effect, starttime, ps.getRight()));
}
boolean active = effect.isActive(mapid);
boolean active = effect.isActive(this);
if(ServerConstants.USE_BUFF_MOST_SIGNIFICANT) {
toDeploy = new LinkedHashMap<>();
Map<Integer, Pair<MapleStatEffect, Long>> retrievedEffects = new LinkedHashMap<>();
@@ -4559,7 +4572,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
silentPartyUpdateInternal(chrParty);
}
private MapleDoor removePartyDoor(boolean partyUpdate) {
public MapleDoor removePartyDoor(boolean partyUpdate) {
MapleDoor ret = null;
MapleParty chrParty;
@@ -5322,20 +5335,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
return false;
}
public List<MonsterDropEntry> retrieveRelevantDrops(int monsterId) {
List<MapleCharacter> pchars = new LinkedList<>();
for (MapleCharacter chr : getPartyMembers()) {
if (chr.isLoggedinWorld()) {
pchars.add(chr);
}
}
if (pchars.isEmpty()) {
pchars.add(this);
}
return MapleLootManager.retrieveRelevantDrops(monsterId, pchars);
}
public MaplePlayerShop getPlayerShop() {
return playerShop;
}
@@ -5356,7 +5355,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
closeNpcShop();
closeTrade();
closePlayerShop();
closeMiniGame();
closeMiniGame(true);
closeHiredMerchant(false);
closePlayerMessenger();
@@ -5398,18 +5397,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
this.setPlayerShop(null);
}
public void closeMiniGame() {
public void closeMiniGame(boolean forceClose) {
MapleMiniGame game = this.getMiniGame();
if (game == null) {
return;
}
this.setMiniGame(null);
if (game.isOwner(this)) {
this.getMap().broadcastMessage(MaplePacketCreator.removeMinigameBox(this));
game.broadcastToVisitor(MaplePacketCreator.getMiniGameClose(3));
game.closeRoom(forceClose);
} else {
game.removeVisitor(this);
game.removeVisitor(forceClose, this);
}
}
@@ -6542,9 +6539,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
public void updateCouponRates() {
MapleInventory cashInv = this.getInventory(MapleInventoryType.CASH);
if (cashInv == null) return;
if (cpnLock.tryLock()) {
MapleInventory cashInv = this.getInventory(MapleInventoryType.CASH);
effLock.lock();
chrLock.lock();
cashInv.lockInventory();
@@ -6979,11 +6977,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.commitExcludedItems();
if (channelserver) {
MapleMapFactory mapFactory = client.getChannelServer().getMapFactory();
ret.map = mapFactory.getMap(ret.mapid);
MapleMapManager mapManager = client.getChannelServer().getMapFactory();
ret.map = mapManager.getMap(ret.mapid);
if (ret.map == null) {
ret.map = mapFactory.getMap(100000000);
ret.map = mapManager.getMap(100000000);
}
MaplePortal portal = ret.map.getPortal(ret.initialSpawnPoint);
if (portal == null) {
+10 -4
View File
@@ -109,11 +109,11 @@ public class MapleClient {
private Map<String, ScriptEngine> engines = new HashMap<>();
private byte characterSlots = 3;
private byte loginattempt = 0;
private String pin = null;
private String pin = "";
private int pinattempt = 0;
private String pic = null;
private String hwid = null;
private String pic = "";
private int picattempt = 0;
private String hwid = null;
private byte csattempt = 0;
private byte gender = -1;
private boolean disconnecting = false;
@@ -480,6 +480,10 @@ public class MapleClient {
}
public boolean checkPin(String other) {
if (!(ServerConstants.ENABLE_PIN && !canBypassPin())) {
return true;
}
pinattempt++;
if (pinattempt > 5) {
MapleSessionCoordinator.getInstance().closeSession(session, false);
@@ -521,7 +525,7 @@ public class MapleClient {
if (picattempt > 5) {
MapleSessionCoordinator.getInstance().closeSession(session, false);
}
if (pic.equals(other)) {
if (pic.equals(other)) { // thanks ryantpayton (HeavenClient) for noticing null pics being checked here
picattempt = 0;
MapleLoginBypassCoordinator.getInstance().registerLoginBypassEntry(getNibbleHWID(), accId, true);
return true;
@@ -1485,6 +1489,8 @@ public class MapleClient {
player.getMap().removePlayer(player);
player.clearBanishPlayerData();
player.getClient().getChannelServer().removePlayer(player);
player.saveCharToDB();
player.getClient().updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
player.setSessionTransitionState();
+1 -1
View File
@@ -85,7 +85,7 @@ public enum AutobanFactory {
public void alert(MapleCharacter chr, String reason) {
if(ServerConstants.USE_AUTOBAN == true) {
if (chr != null && MapleLogger.ignored.contains(chr.getName())){
if (chr != null && MapleLogger.ignored.contains(chr.getId())){
return;
}
Server.getInstance().broadcastGMMessage((chr != null ? chr.getWorld() : 0), MaplePacketCreator.sendYellowTip((chr != null ? MapleCharacter.makeMapleReadable(chr.getName()) : "") + " caused " + this.name() + " " + reason));
+3 -3
View File
@@ -119,9 +119,9 @@ public class AutobanManager {
FilePrinter.print(FilePrinter.EXPLOITS, "Player " + chr + " was caught spamming TYPE " + type + " and has been disconnected.");
}
return;
} else {
this.timestamp[type] = time;
this.timestampcounter[type] = 0;
}
this.timestamp[type] = time;
this.timestampcounter[type] = 0;
}
}
+5
View File
@@ -93,6 +93,10 @@ public class CommandsExecutor {
}
private void handleInternal(MapleClient client, String message){
if (client.getPlayer().getMapId() == 300000012) {
client.getPlayer().yellowMessage("You not have permission to use this command while in jail.");
return;
}
final String splitRegex = "[ ]";
String[] splitedMessage = message.substring(1).split(splitRegex, 2);
if (splitedMessage.length < 2) {
@@ -259,6 +263,7 @@ public class CommandsExecutor {
addCommand("job", 2, JobCommand.class);
addCommand("unbug", 2, UnBugCommand.class);
addCommand("id", 2, IdCommand.class);
addCommand("gachalist", GachaListCommand.class);
commandsNameDesc.add(levelCommandsCursor);
}
@@ -33,7 +33,7 @@ import net.server.Server;
import server.MaplePortal;
import server.maps.FieldLimit;
import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleMapManager;
import server.maps.MapleMiniDungeonInfo;
import java.util.Comparator;
@@ -47,18 +47,18 @@ public class GotoCommand extends Command {
{
setDescription("");
MapleMapFactory mapFactory = Server.getInstance().getWorlds().get(0).getChannels().get(0).getMapFactory();
MapleMapManager mapManager = Server.getInstance().getWorlds().get(0).getChannels().get(0).getMapFactory();
List<Entry<String, Integer>> towns = new ArrayList<>(GameConstants.GOTO_TOWNS.entrySet());
sortGotoEntries(towns);
for (Map.Entry<String, Integer> e : towns) {
GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (mapFactory.getMap(e.getValue()).getMapName()) + "#k\r\n");
GOTO_TOWNS_INFO += ("'" + e.getKey() + "' - #b" + (mapManager.getMap(e.getValue()).getMapName()) + "#k\r\n");
}
List<Entry<String, Integer>> areas = new ArrayList<>(GameConstants.GOTO_AREAS.entrySet());
sortGotoEntries(areas);
for (Map.Entry<String, Integer> e : areas) {
GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (mapFactory.getMap(e.getValue()).getMapName()) + "#k\r\n");
GOTO_AREAS_INFO += ("'" + e.getKey() + "' - #b" + (mapManager.getMap(e.getValue()).getMapName()) + "#k\r\n");
}
}
@@ -103,6 +103,7 @@ public class GotoCommand extends Command {
HashMap<String, Integer> gotomaps;
if (player.isGM()) {
gotomaps = new HashMap<>(GameConstants.GOTO_AREAS); // distinct map registry for GM/users suggested thanks to Vcoc
gotomaps.putAll(GameConstants.GOTO_TOWNS); // thanks Halcyon for pointing out duplicates on listed entries functionality
} else {
gotomaps = new HashMap<>(GameConstants.GOTO_TOWNS);
}
@@ -0,0 +1,38 @@
/*
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
Copyleft (L) 2016 - 2018 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
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package client.command.commands.gm2;
import client.MapleClient;
import client.command.Command;
/**
*
* @author Ronan
*/
public class GachaListCommand extends Command {
{
setDescription("");
}
@Override
public void execute(MapleClient c, String[] params) {
c.getAbstractPlayerInteraction().openNpc(10000, "gachaponInfo");
}
}
@@ -47,11 +47,11 @@ public class IgnoreCommand extends Command {
player.message("Player '" + params[0] + "' could not be found on this world.");
return;
}
boolean monitored_ = MapleLogger.ignored.contains(victim.getName());
boolean monitored_ = MapleLogger.ignored.contains(victim.getId());
if (monitored_) {
MapleLogger.ignored.remove(victim.getName());
MapleLogger.ignored.remove(victim.getId());
} else {
MapleLogger.ignored.add(victim.getName());
MapleLogger.ignored.add(victim.getId());
}
player.yellowMessage(victim.getName() + " is " + (!monitored_ ? "now being ignored." : "no longer being ignored."));
String message_ = player.getName() + (!monitored_ ? " has started ignoring " : " has stopped ignoring ") + victim.getName() + ".";
@@ -36,8 +36,8 @@ public class IgnoredCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
MapleCharacter player = c.getPlayer();
for (String ign : MapleLogger.ignored) {
player.yellowMessage(ign + " is being ignored.");
for (Integer cid : MapleLogger.ignored) {
player.yellowMessage(MapleCharacter.getNameById(cid) + " is being ignored.");
}
}
}
@@ -47,14 +47,14 @@ public class MonitorCommand extends Command {
player.message("Player '" + params[0] + "' could not be found on this world.");
return;
}
boolean monitored = MapleLogger.monitored.contains(victim.getName());
boolean monitored = MapleLogger.monitored.contains(victim.getId());
if (monitored) {
MapleLogger.monitored.remove(victim.getName());
MapleLogger.monitored.remove(victim.getId());
} else {
MapleLogger.monitored.add(victim.getName());
MapleLogger.monitored.add(victim.getId());
}
player.yellowMessage(victim.getName() + " is " + (!monitored ? "now being monitored." : "no longer being monitored."));
String message = player.getName() + (!monitored ? " has started monitoring " : " has stopped monitoring ") + victim.getName() + ".";
player.yellowMessage(victim.getId() + " is " + (!monitored ? "now being monitored." : "no longer being monitored."));
String message = player.getName() + (!monitored ? " has started monitoring " : " has stopped monitoring ") + victim.getId() + ".";
Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.serverNotice(5, message));
}
@@ -36,8 +36,8 @@ public class MonitorsCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
MapleCharacter player = c.getPlayer();
for (String ign : MapleLogger.monitored) {
player.yellowMessage(ign + " is being monitored.");
for (Integer cid : MapleLogger.monitored) {
player.yellowMessage(MapleCharacter.getNameById(cid) + " is being monitored.");
}
}
}
+11 -6
View File
@@ -46,13 +46,16 @@ public enum ItemFactory {
CASH_ARAN(5, true),
MERCHANT(6, false),
CASH_OVERALL(7, true),
MARRIAGE_GIFTS(8, false);
MARRIAGE_GIFTS(8, false),
DUEY(9, false);
private final int value;
private final boolean account;
private static final Lock locks[] = new Lock[200]; // thanks Masterrulax for pointing out a bottleneck issue here
private static final int lockCount = 400;
private static final Lock locks[] = new Lock[lockCount]; // thanks Masterrulax for pointing out a bottleneck issue here
static {
for (int i = 0; i < 200; i++) {
for (int i = 0; i < lockCount; i++) {
locks[i] = MonitoredReentrantLockFactory.createLock(MonitoredLockType.ITEM, true);
}
}
@@ -75,7 +78,9 @@ public enum ItemFactory {
saveItems(items, null, id, con);
}
public synchronized void saveItems(List<Pair<Item, MapleInventoryType>> items, List<Short> bundlesList, int id, Connection con) throws SQLException {
public void saveItems(List<Pair<Item, MapleInventoryType>> items, List<Short> bundlesList, int id, Connection con) throws SQLException {
// thanks Arufonsu, MedicOP, BHB for pointing a "synchronized" bottleneck here
if(value != 6) saveItemsCommon(items, id, con);
else saveItemsMerchant(items, bundlesList, id, con);
}
@@ -199,7 +204,7 @@ public enum ItemFactory {
PreparedStatement pse = null;
ResultSet rs = null;
Lock lock = locks[id % 200];
Lock lock = locks[id % lockCount];
lock.lock();
try {
StringBuilder query = new StringBuilder();
@@ -365,7 +370,7 @@ public enum ItemFactory {
PreparedStatement pse = null;
ResultSet rs = null;
Lock lock = locks[id % 200];
Lock lock = locks[id % lockCount];
lock.lock();
try {
ps = con.prepareStatement("DELETE FROM `inventorymerchant` WHERE `characterid` = ?");
+47 -27
View File
@@ -463,31 +463,41 @@ public class MapleInventory implements Iterable<Item> {
public static boolean checkSpots(MapleCharacter chr, List<Pair<Item, MapleInventoryType>> items, List<Integer> typesSlotsUsed, boolean useProofInv) {
// assumption: no "UNDEFINED" or "EQUIPPED" items shall be tested here, all counts are >= 0.
Map<Integer, Short> rcvItems = new LinkedHashMap<>();
Map<Integer, List<Integer>> rcvItems = new LinkedHashMap<>();
Map<Integer, Byte> rcvTypes = new LinkedHashMap<>();
for (Pair<Item, MapleInventoryType> item : items) {
Integer itemId = item.left.getItemId();
Short qty = rcvItems.get(itemId);
List<Integer> qty = rcvItems.get(itemId);
if(qty == null) {
rcvItems.put(itemId, item.left.getQuantity());
List<Integer> itemQtyList = new LinkedList<>();
itemQtyList.add((int) item.left.getQuantity());
rcvItems.put(itemId, itemQtyList);
rcvTypes.put(itemId, item.right.getType());
} else {
rcvItems.put(itemId, (short)(qty + item.left.getQuantity()));
if (!ItemConstants.isRechargeable(itemId)) {
qty.set(0, qty.get(0) + item.left.getQuantity());
} else {
qty.add((int) item.left.getQuantity());
}
}
}
MapleClient c = chr.getClient();
for(Entry<Integer, Short> it: rcvItems.entrySet()) {
for(Entry<Integer, List<Integer>> it: rcvItems.entrySet()) {
int itemType = rcvTypes.get(it.getKey()) - 1;
int usedSlots = typesSlotsUsed.get(itemType);
int result = MapleInventoryManipulator.checkSpaceProgressively(c, it.getKey(), it.getValue(), "", usedSlots, useProofInv);
boolean hasSpace = ((result % 2) != 0);
if(!hasSpace) return false;
typesSlotsUsed.set(itemType, (result >> 1));
for (Integer itValue : it.getValue()) {
int usedSlots = typesSlotsUsed.get(itemType);
int result = MapleInventoryManipulator.checkSpaceProgressively(c, it.getKey(), itValue, "", usedSlots, useProofInv);
boolean hasSpace = ((result % 2) != 0);
if(!hasSpace) return false;
typesSlotsUsed.set(itemType, (result >> 1));
}
}
return true;
@@ -525,38 +535,48 @@ public class MapleInventory implements Iterable<Item> {
public static boolean checkSpotsAndOwnership(MapleCharacter chr, List<Pair<Item, MapleInventoryType>> items, List<Integer> typesSlotsUsed, boolean useProofInv) {
//assumption: no "UNDEFINED" or "EQUIPPED" items shall be tested here, all counts are >= 0 and item list to be checked is a legal one.
Map<Long, Short> rcvItems = new LinkedHashMap<>();
Map<Long, List<Integer>> rcvItems = new LinkedHashMap<>();
Map<Long, Byte> rcvTypes = new LinkedHashMap<>();
Map<Long, String> rcvOwners = new LinkedHashMap<>();
for (Pair<Item, MapleInventoryType> item : items) {
Long itemHash = hashKey(item.left.getItemId(), item.left.getOwner());
Short qty = rcvItems.get(itemHash);
List<Integer> qty = rcvItems.get(itemHash);
if(qty == null) {
rcvItems.put(itemHash, item.left.getQuantity());
List<Integer> itemQtyList = new LinkedList<>();
itemQtyList.add((int) item.left.getQuantity());
rcvItems.put(itemHash, itemQtyList);
rcvTypes.put(itemHash, item.right.getType());
rcvOwners.put(itemHash, item.left.getOwner());
} else {
rcvItems.put(itemHash, (short)(qty + item.left.getQuantity()));
// thanks BHB88 for pointing out an issue with rechargeable items being stacked on inventory check
if (!ItemConstants.isRechargeable(item.left.getItemId())) {
qty.set(0, qty.get(0) + item.left.getQuantity());
} else {
qty.add((int) item.left.getQuantity());
}
}
}
MapleClient c = chr.getClient();
for(Entry<Long, Short> it: rcvItems.entrySet()) {
for(Entry<Long, List<Integer>> it: rcvItems.entrySet()) {
int itemType = rcvTypes.get(it.getKey()) - 1;
int usedSlots = typesSlotsUsed.get(itemType);
int itemId = (int) (it.getKey() >> 32L);
Long itemId = it.getKey() >> 32L;
//System.out.print("inserting " + itemId.intValue() + " with type " + itemType + " qty " + it.getValue() + " owner '" + rcvOwners.get(it.getKey()) + "' current usedSlots:");
//for(Integer i : typesSlotsUsed) System.out.print(" " + i);
int result = MapleInventoryManipulator.checkSpaceProgressively(c, itemId.intValue(), it.getValue(), rcvOwners.get(it.getKey()), usedSlots, useProofInv);
boolean hasSpace = ((result % 2) != 0);
//System.out.print(" -> hasSpace: " + hasSpace + " RESULT : " + result + "\n");
if(!hasSpace) return false;
typesSlotsUsed.set(itemType, (result >> 1));
for (Integer itValue : it.getValue()) {
int usedSlots = typesSlotsUsed.get(itemType);
//System.out.print("inserting " + itemId.intValue() + " with type " + itemType + " qty " + it.getValue() + " owner '" + rcvOwners.get(it.getKey()) + "' current usedSlots:");
//for(Integer i : typesSlotsUsed) System.out.print(" " + i);
int result = MapleInventoryManipulator.checkSpaceProgressively(c, itemId, itValue, rcvOwners.get(it.getKey()), usedSlots, useProofInv);
boolean hasSpace = ((result % 2) != 0);
//System.out.print(" -> hasSpace: " + hasSpace + " RESULT : " + result + "\n");
if(!hasSpace) return false;
typesSlotsUsed.set(itemType, (result >> 1));
}
}
return true;
@@ -316,7 +316,11 @@ public class MapleInventoryManipulator {
if (!type.equals(MapleInventoryType.EQUIP)) {
short slotMax = ii.getSlotMax(c, itemid);
List<Item> existing = inv.listById(itemid);
if (!ItemConstants.isRechargeable(itemid)) {
final int numSlotsNeeded;
if (ItemConstants.isRechargeable(itemid)) {
numSlotsNeeded = 1;
} else {
if (existing.size() > 0) // first update all existing slots to slotMax
{
for (Item eItem : existing) {
@@ -330,15 +334,14 @@ public class MapleInventoryManipulator {
}
}
}
if (slotMax > 0) {
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
} else {
numSlotsNeeded = 1;
}
}
final int numSlotsNeeded;
if (slotMax > 0) {
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
} else if (ItemConstants.isRechargeable(itemid)) {
numSlotsNeeded = 1;
} else {
numSlotsNeeded = 1;
}
return !inv.isFull(numSlotsNeeded - 1);
} else {
return !inv.isFull();
@@ -367,7 +370,11 @@ public class MapleInventoryManipulator {
if (!type.equals(MapleInventoryType.EQUIP)) {
short slotMax = ii.getSlotMax(c, itemid);
if (!ItemConstants.isRechargeable(itemid)) {
final int numSlotsNeeded;
if (ItemConstants.isRechargeable(itemid)) {
numSlotsNeeded = 1;
} else {
List<Item> existing = inv.listById(itemid);
if (existing.size() > 0) // first update all existing slots to slotMax
@@ -383,14 +390,12 @@ public class MapleInventoryManipulator {
}
}
}
}
final int numSlotsNeeded;
if (slotMax > 0) {
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
} else if (ItemConstants.isRechargeable(itemid)) {
numSlotsNeeded = 1;
} else {
numSlotsNeeded = 1;
if (slotMax > 0) {
numSlotsNeeded = (int) (Math.ceil(((double) quantity) / slotMax));
} else {
numSlotsNeeded = 1;
}
}
returnValue = ((numSlotsNeeded + usedSlots) << 1);
@@ -708,7 +713,7 @@ public class MapleInventoryManipulator {
source.setQuantity((short) (source.getQuantity() - quantity));
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(1, source))));
if(ItemConstants.isNewYearCardEtc(itemId)) {
if (ItemConstants.isNewYearCardEtc(itemId)) {
if(itemId == 4300000) {
NewYearCardRecord.removeAllNewYearCard(true, chr);
c.getAbstractPlayerInteraction().removeAll(4300000);
@@ -718,13 +723,9 @@ public class MapleInventoryManipulator {
}
} else if (ItemConstants.isWeddingRing(source.getItemId())) {
map.disappearingItemDrop(chr, chr, target, dropPos);
} else if (map.getEverlast()) {
if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
map.disappearingItemDrop(chr, chr, target, dropPos);
} else {
map.spawnItemDrop(chr, chr, target, dropPos, true, true);
}
} else if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
}
if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
map.disappearingItemDrop(chr, chr, target, dropPos);
} else {
map.spawnItemDrop(chr, chr, target, dropPos, true, true);
@@ -745,24 +746,20 @@ public class MapleInventoryManipulator {
c.announce(MaplePacketCreator.modifyInventory(true, Collections.singletonList(new ModifyInventory(3, source))));
if (src < 0) {
chr.equipChanged();
} else if(ItemConstants.isNewYearCardEtc(itemId)) {
if(itemId == 4300000) {
} else if (ItemConstants.isNewYearCardEtc(itemId)) {
if (itemId == 4300000) {
NewYearCardRecord.removeAllNewYearCard(true, chr);
c.getAbstractPlayerInteraction().removeAll(4300000);
} else {
NewYearCardRecord.removeAllNewYearCard(false, chr);
c.getAbstractPlayerInteraction().removeAll(4301000);
}
} else if (ItemConstants.isWeddingRing(source.getItemId())) {
map.disappearingItemDrop(chr, chr, source, dropPos);
}
if (map.getEverlast()) {
if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
map.disappearingItemDrop(chr, chr, source, dropPos);
} else {
map.spawnItemDrop(chr, chr, source, dropPos, true, true);
}
} else if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
map.disappearingItemDrop(chr, chr, source, dropPos);
if (ii.isDropRestricted(itemId) || ii.isCash(itemId) || isDroppedItemRestricted(source)) {
map.disappearingItemDrop(chr, chr, source, dropPos);
} else {
map.spawnItemDrop(chr, chr, source, dropPos, true, true);
}
+234 -223
View File
@@ -26,26 +26,31 @@ package client.processor;
import client.MapleCharacter;
import client.MapleClient;
import client.autoban.AutobanFactory;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.ItemFactory;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.manipulator.MapleInventoryManipulator;
import client.inventory.manipulator.MapleKarmaManipulator;
import constants.ItemConstants;
import constants.ServerConstants;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import net.server.channel.Channel;
import server.DueyPackages;
import server.DueyPackage;
import server.MapleItemInformationProvider;
import server.MapleTrade;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
/**
*
@@ -86,21 +91,17 @@ public class DueyProcessor {
}
}
private static int getAccIdFromCNAME(String name, boolean accountid) {
private static Pair<Integer, Integer> getAccountCharacterIdFromCNAME(String name) {
try {
PreparedStatement ps;
String text = "SELECT id,accountid FROM characters WHERE name = ?";
Connection con = DatabaseConnection.getConnection();
ps = con.prepareStatement(text);
PreparedStatement ps = con.prepareStatement("SELECT id,accountid FROM characters WHERE name = ?");
ps.setString(1, name);
int id_;
Pair<Integer, Integer> id_ = null;
try (ResultSet rs = ps.executeQuery()) {
if (!rs.next()) {
rs.close();
ps.close();
return -1;
if (rs.next()) {
id_ = new Pair<>(rs.getInt("accountid"), rs.getInt("id"));
}
id_ = accountid ? rs.getInt("accountid") : rs.getInt("id");
}
ps.close();
con.close();
@@ -108,7 +109,7 @@ public class DueyProcessor {
} catch (SQLException e) {
e.printStackTrace();
}
return -1;
return null;
}
private static String getCurrentDate() {
@@ -123,67 +124,6 @@ public class DueyProcessor {
return date;
}
private static void removeItemFromDB(int packageid) {
Connection con = null;
try {
con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM dueypackages WHERE PackageId = ?");
ps.setInt(1, packageid);
ps.executeUpdate();
ps.close();
ps = con.prepareStatement("DELETE FROM dueyitems WHERE PackageId = ?");
ps.setInt(1, packageid);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static DueyPackages getItemByPID(ResultSet rs) {
try {
DueyPackages dueypack;
if (rs.getInt("type") == 1) {
Equip eq = new Equip(rs.getInt("itemid"), (byte) 0, -1);
eq.setUpgradeSlots((byte) rs.getInt("upgradeslots"));
eq.setLevel((byte) rs.getInt("level"));
eq.setItemLevel((byte) rs.getInt("itemlevel"));
eq.setItemExp(rs.getInt("itemexp"));
eq.setStr((short) rs.getInt("str"));
eq.setDex((short) rs.getInt("dex"));
eq.setInt((short) rs.getInt("int"));
eq.setLuk((short) rs.getInt("luk"));
eq.setHp((short) rs.getInt("hp"));
eq.setMp((short) rs.getInt("mp"));
eq.setWatk((short) rs.getInt("watk"));
eq.setMatk((short) rs.getInt("matk"));
eq.setWdef((short) rs.getInt("wdef"));
eq.setMdef((short) rs.getInt("mdef"));
eq.setAcc((short) rs.getInt("acc"));
eq.setAvoid((short) rs.getInt("avoid"));
eq.setHands((short) rs.getInt("hands"));
eq.setSpeed((short) rs.getInt("speed"));
eq.setJump((short) rs.getInt("jump"));
eq.setFlag((byte) rs.getInt("flag"));
eq.setOwner(rs.getString("owner"));
dueypack = new DueyPackages(rs.getInt("PackageId"), eq);
} else if (rs.getInt("type") == 2) {
Item newItem = new Item(rs.getInt("itemid"), (short) 0, (short) rs.getInt("quantity"));
newItem.setFlag((byte) rs.getInt("flag"));
newItem.setOwner(rs.getString("owner"));
dueypack = new DueyPackages(rs.getInt("PackageId"), newItem);
} else {
dueypack = new DueyPackages(rs.getInt("PackageId"));
}
return dueypack;
} catch (SQLException se) {
se.printStackTrace();
return null;
}
}
private static void showDueyNotification(MapleClient c, MapleCharacter player) {
Connection con = null;
@@ -230,70 +170,21 @@ public class DueyProcessor {
}
}
}
private static void addMesoToDB(int mesos, String sName, int recipientID) {
addItemToDB(null, 1, mesos, sName, recipientID);
}
public static void addItemToDB(Item item, int quantity, int mesos, String sName, int recipientID) {
Connection con = null;
private static void deletePackageFromInventoryDB(Connection con, int packageId) throws SQLException {
ItemFactory.DUEY.saveItems(new LinkedList<Pair<Item, MapleInventoryType>>(), packageId, con);
}
private static void removePackageFromDB(int packageId) {
try {
con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("INSERT INTO dueypackages (ReceiverId, SenderName, Mesos, TimeStamp, Checked, Type) VALUES (?, ?, ?, ?, ?, ?)")) {
ps.setInt(1, recipientID);
ps.setString(2, sName);
ps.setInt(3, mesos);
ps.setString(4, getCurrentDate());
ps.setInt(5, 1);
if (item == null) {
ps.setInt(6, 3);
ps.executeUpdate();
} else {
ps.setInt(6, item.getItemType());
ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys()) {
rs.next();
PreparedStatement ps2;
if (item.getInventoryType().equals(MapleInventoryType.EQUIP)) {
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, upgradeslots, level, itemlevel, itemexp, str, dex, `int`, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, flag, owner) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
Equip eq = (Equip) item;
ps2.setInt(2, eq.getItemId());
ps2.setInt(3, 1);
ps2.setInt(4, eq.getUpgradeSlots());
ps2.setInt(5, eq.getLevel());
ps2.setInt(6, eq.getItemLevel());
ps2.setInt(7, eq.getItemExp());
ps2.setInt(8, eq.getStr());
ps2.setInt(9, eq.getDex());
ps2.setInt(10, eq.getInt());
ps2.setInt(11, eq.getLuk());
ps2.setInt(12, eq.getHp());
ps2.setInt(13, eq.getMp());
ps2.setInt(14, eq.getWatk());
ps2.setInt(15, eq.getMatk());
ps2.setInt(16, eq.getWdef());
ps2.setInt(17, eq.getMdef());
ps2.setInt(18, eq.getAcc());
ps2.setInt(19, eq.getAvoid());
ps2.setInt(20, eq.getHands());
ps2.setInt(21, eq.getSpeed());
ps2.setInt(22, eq.getJump());
ps2.setInt(23, eq.getFlag());
ps2.setString(24, eq.getOwner());
} else {
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, flag, owner) VALUES (?, ?, ?, ?, ?)");
ps2.setInt(2, item.getItemId());
ps2.setInt(3, quantity);
ps2.setInt(4, item.getFlag());
ps2.setString(5, item.getOwner());
}
ps2.setInt(1, rs.getInt(1));
ps2.executeUpdate();
ps2.close();
}
}
}
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM dueypackages WHERE PackageId = ?");
ps.setInt(1, packageId);
ps.executeUpdate();
ps.close();
deletePackageFromInventoryDB(con, packageId);
con.close();
} catch (SQLException e) {
@@ -301,49 +192,181 @@ public class DueyProcessor {
}
}
private static List<DueyPackages> loadItems(MapleCharacter chr) {
List<DueyPackages> packages = new LinkedList<>();
Connection con = null;
private static DueyPackage getPackageFromDB(ResultSet rs) {
try {
con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages dp LEFT JOIN dueyitems di ON dp.PackageId=di.PackageId WHERE ReceiverId = ?")) {
int packageId = rs.getInt("PackageId");
List<Pair<Item, MapleInventoryType>> dueyItems = ItemFactory.DUEY.loadItems(packageId, false);
DueyPackage dueypack;
if (!dueyItems.isEmpty()) { // in a duey package there's only one item
dueypack = new DueyPackage(packageId, dueyItems.get(0).getLeft());
} else {
dueypack = new DueyPackage(packageId);
}
dueypack.setSender(rs.getString("SenderName"));
dueypack.setMesos(rs.getInt("Mesos"));
dueypack.setSentTime(rs.getString("TimeStamp"));
dueypack.setMessage(rs.getString("Message"));
return dueypack;
} catch (SQLException sqle) {
sqle.printStackTrace();
return null;
}
}
private static List<DueyPackage> loadPackages(MapleCharacter chr) {
List<DueyPackage> packages = new LinkedList<>();
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages dp WHERE ReceiverId = ?")) {
ps.setInt(1, chr.getId());
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
DueyPackages dueypack = getItemByPID(rs);
dueypack.setSender(rs.getString("SenderName"));
dueypack.setMesos(rs.getInt("Mesos"));
dueypack.setSentTime(rs.getString("TimeStamp"));
DueyPackage dueypack = getPackageFromDB(rs);
if (dueypack == null) continue;
packages.add(dueypack);
}
}
}
con.close();
return packages;
} catch (SQLException e) {
e.printStackTrace();
return null;
}
return packages;
}
private static int createPackage(int mesos, String message, String sender, int toCid) {
try {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("INSERT INTO `dueypackages` (ReceiverId, SenderName, Mesos, TimeStamp, Message, Checked) VALUES (?, ?, ?, ?, ?, 1)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, toCid);
ps.setString(2, sender);
ps.setInt(3, mesos);
ps.setString(4, getCurrentDate());
ps.setString(5, message);
int updateRows = ps.executeUpdate();
if (updateRows < 1) {
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Error trying to create package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
return -1;
}
int packageId;
rs = ps.getGeneratedKeys();
if (rs.next()) {
packageId = rs.getInt(1);
} else {
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Failed inserting package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
return -1;
}
return packageId;
} finally {
if (rs != null && !rs.isClosed()) {
rs.close();
}
if (ps != null && !ps.isClosed()) {
ps.close();
}
if (con != null && !con.isClosed()) {
con.close();
}
}
} catch (SQLException sqle) {
sqle.printStackTrace();
}
return -1;
}
private static boolean insertPackageItem(int packageId, Item item) {
try {
Pair<Item, MapleInventoryType> dueyItem = new Pair<>(item, MapleInventoryType.getByType(item.getItemType()));
Connection con = DatabaseConnection.getConnection();
ItemFactory.DUEY.saveItems(Collections.singletonList(dueyItem), packageId, con);
con.close();
return true;
} catch (SQLException sqle) {
sqle.printStackTrace();
return false;
}
}
public static void dueySendItem(MapleClient c, byte inventId, short itemPos, short amount, int mesos, String recipient) {
private static int addPackageItemFromInventory(int packageId, MapleClient c, byte invTypeId, short itemPos, short amount) {
if (invTypeId > 0) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
MapleInventoryType invType = MapleInventoryType.getByType(invTypeId);
MapleInventory inv = c.getPlayer().getInventory(invType);
Item item;
inv.lockInventory();
try {
item = inv.getItem(itemPos);
if (item != null && item.getQuantity() >= amount) {
if (item.isUntradeable() || ii.isUnmerchable(item.getItemId())) {
return -1;
}
if (ItemConstants.isRechargeable(item.getItemId())) {
MapleInventoryManipulator.removeFromSlot(c, invType, itemPos, item.getQuantity(), true);
} else {
MapleInventoryManipulator.removeFromSlot(c, invType, itemPos, amount, true, false);
}
item = item.copy();
} else {
return -2;
}
} finally {
inv.unlockInventory();
}
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
item.setQuantity(amount);
if (!insertPackageItem(packageId, item)) {
return 1;
}
}
return 0;
}
public static void dueySendItem(MapleClient c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient) {
if (c.tryacquireClient()) {
try {
final int fee = 5000;
final long sendMesos = (long) mesos + fee;
if (mesos < 0 || sendMesos > Integer.MAX_VALUE || (amount < 1 && mesos == 0)) {
final int fee = 5000 + MapleTrade.getFee(sendMesos);
long finalcost = (long) sendMesos + fee;
if (finalcost < 0 || finalcost > Integer.MAX_VALUE || (amount < 1 && sendMesos == 0)) {
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with duey.");
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use duey with mesos " + mesos + " and amount " + amount);
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use duey with mesos " + sendMesos + " and amount " + amount);
c.disconnect(true, false);
return;
}
int finalcost = mesos + fee;
Pair<Integer, Integer> accIdCid;
if (c.getPlayer().getMeso() >= finalcost) {
int accid = getAccIdFromCNAME(recipient, true);
if (accid != -1) {
if (accid == c.getAccID()) {
accIdCid = getAccountCharacterIdFromCNAME(recipient);
int recipientAccId = accIdCid.getLeft();
if (recipientAccId != -1) {
if (recipientAccId == c.getAccID()) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SAMEACC_ERROR.getCode()));
return;
}
@@ -355,7 +378,29 @@ public class DueyProcessor {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NOT_ENOUGH_MESOS.getCode()));
return;
}
int recipientCid = accIdCid.getRight();
if (recipientCid == -1) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NAME_DOES_NOT_EXIST.getCode()));
return;
}
int packageId = createPackage(sendMesos, sendMessage, c.getPlayer().getName(), recipientCid);
if (packageId == -1) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_ENABLE_ACTIONS.getCode()));
return;
}
c.getPlayer().gainMeso((int) -finalcost, false);
int res = addPackageItemFromInventory(packageId, c, invTypeId, itemPos, amount);
if (res == 0) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
} else if (res > 0) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_ENABLE_ACTIONS.getCode()));
} else {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
}
MapleClient rClient = null;
int channel = c.getWorldServer().find(recipient);
if (channel > -1) {
@@ -367,40 +412,7 @@ public class DueyProcessor {
}
}
}
if (inventId > 0) {
MapleInventoryType inv = MapleInventoryType.getByType(inventId);
Item item = c.getPlayer().getInventory(inv).getItem(itemPos);
if (item != null && c.getPlayer().getItemQuantity(item.getItemId(), false) >= amount) {
if (item.isUntradeable()) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
return;
}
c.getPlayer().gainMeso(-finalcost, false);
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
if (ItemConstants.isRechargeable(item.getItemId())) {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, item.getQuantity(), true);
} else {
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false);
}
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
addItemToDB(item, amount, mesos - MapleTrade.getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
} else {
if (item != null) {
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
}
return;
}
} else {
c.getPlayer().gainMeso(-finalcost, false);
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
addMesoToDB(mesos - MapleTrade.getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
}
if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) {
showDueyNotification(rClient, rClient.getPlayer());
}
@@ -410,55 +422,50 @@ public class DueyProcessor {
}
}
public static void dueyRemovePackage(MapleClient c, int packageid) {
public static void dueyRemovePackage(MapleClient c, int packageid, boolean playerRemove) {
if (c.tryacquireClient()) {
try {
removeItemFromDB(packageid);
c.announce(MaplePacketCreator.removeItemFromDuey(true, packageid));
removePackageFromDB(packageid);
c.announce(MaplePacketCreator.removeItemFromDuey(playerRemove, packageid));
} finally {
c.releaseClient();
}
}
}
public static void dueyClaimPackage(MapleClient c, int packageid) {
public static void dueyClaimPackage(MapleClient c, int packageId) {
if (c.tryacquireClient()) {
try {
List<DueyPackages> packages = new LinkedList<>();
DueyPackages dp = null;
Connection con = null;
try {
con = DatabaseConnection.getConnection();
DueyPackages dueypack;
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages LEFT JOIN dueyitems USING (PackageId) WHERE PackageId = ?")) {
ps.setInt(1, packageid);
DueyPackage dp = null;
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages dp WHERE PackageId = ?")) {
ps.setInt(1, packageId);
try (ResultSet rs = ps.executeQuery()) {
dueypack = null;
if (rs.next()) {
dueypack = getItemByPID(rs);
dueypack.setSender(rs.getString("SenderName"));
dueypack.setMesos(rs.getInt("Mesos"));
dueypack.setSentTime(rs.getString("TimeStamp"));
packages.add(dueypack);
dp = getPackageFromDB(rs);
}
}
}
dp = dueypack;
con.close();
if(dp == null) {
c.announce(MaplePacketCreator.sendDueyMSG(Actions.TOCLIENT_RECV_UNKNOWN_ERROR.getCode()));
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to receive package from duey with id " + packageid);
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to receive package from duey with id " + packageId);
return;
}
if (dp.getItem() != null) {
Item dpItem = dp.getItem();
if (dpItem != null) {
if (!c.getPlayer().canHoldMeso(dp.getMesos())) {
c.announce(MaplePacketCreator.sendDueyMSG(Actions.TOCLIENT_RECV_UNKNOWN_ERROR.getCode()));
return;
}
if (!MapleInventoryManipulator.checkSpace(c, dp.getItem().getItemId(), dp.getItem().getQuantity(), dp.getItem().getOwner())) {
int itemid = dp.getItem().getItemId();
if (!MapleInventoryManipulator.checkSpace(c, dpItem.getItemId(), dpItem.getQuantity(), dpItem.getOwner())) {
int itemid = dpItem.getItemId();
if(MapleItemInformationProvider.getInstance().isPickupRestricted(itemid) && c.getPlayer().getInventory(ItemConstants.getInventoryType(itemid)).findById(itemid) != null) {
c.announce(MaplePacketCreator.sendDueyMSG(Actions.TOCLIENT_RECV_RECEIVER_WITH_UNIQUE.getCode()));
} else {
@@ -467,16 +474,13 @@ public class DueyProcessor {
return;
} else {
MapleInventoryManipulator.addFromDrop(c, dp.getItem(), false);
MapleInventoryManipulator.addFromDrop(c, dpItem, false);
}
}
c.getPlayer().gainMeso(dp.getMesos(), false);
removeItemFromDB(packageid);
c.announce(MaplePacketCreator.removeItemFromDuey(false, packageid));
con.close();
dueyRemovePackage(c, packageId, false);
} catch (SQLException e) {
e.printStackTrace();
}
@@ -489,10 +493,17 @@ public class DueyProcessor {
public static void dueySendTalk(MapleClient c) {
if (c.tryacquireClient()) {
try {
c.announce(MaplePacketCreator.sendDuey((byte) 8, loadItems(c.getPlayer())));
c.announce(MaplePacketCreator.sendDuey((byte) 8, loadPackages(c.getPlayer())));
} finally {
c.releaseClient();
}
}
}
public static void dueyCreatePackage(Item item, int mesos, String sender, int recipientCid) {
int packageId = createPackage(mesos, "", sender, recipientCid);
if (packageId != -1) {
insertPackageItem(packageId, item);
}
}
}
+1 -1
View File
@@ -100,7 +100,7 @@ public class FredrickProcessor {
return msg;
}
private static void removeFredrickLog(int cid) {
public static void removeFredrickLog(int cid) {
try {
Connection con = DatabaseConnection.getConnection();
removeFredrickLog(con, cid);
@@ -139,6 +139,8 @@ public class StorageProcessor {
c.announce(MaplePacketCreator.enableActions());
return;
}
item = item.copy(); // thanks Robin Schulz & BHB88 for noticing a inventory glitch when storing items
} finally {
inv.unlockInventory();
}
-2
View File
@@ -92,8 +92,6 @@ public class GameConstants {
// used by the "goto" command for only-GMs
public static final HashMap<String, Integer> GOTO_AREAS = new HashMap<String, Integer>() {{
putAll(GOTO_TOWNS);
put("gmmap", 180000000);
put("excavation", 990000000);
put("mushmom", 100000005);
+8 -4
View File
@@ -37,7 +37,7 @@ public class ServerConstants {
public static final boolean AUTOMATIC_REGISTER = true; //Automatically register players when they login with a nonexistent username.
public static final boolean BCRYPT_MIGRATION = true; //Performs a migration from old SHA-1 and SHA-512 password to bcrypt.
public static final boolean COLLECTIVE_CHARSLOT = false; //Available character slots are contabilized globally rather than per world server.
public static final boolean DETERRED_MULTICLIENT = false; //Enables multi-client and suspicious remote IP detection on the login system.
public static final boolean DETERRED_MULTICLIENT = false; //Enables detection of multi-client and suspicious remote IP on the login system.
//Besides blocking logging in with several client sessions on the same machine, this also blocks suspicious login attempts for players that tries to login on an account using several diferent remote addresses.
@@ -98,6 +98,7 @@ public class ServerConstants {
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = false; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
public static final boolean USE_ENFORCE_MERCHANT_SAVE = true; //Forces automatic DB save on merchant owners, at every item movement on shop.
public static final boolean USE_ENFORCE_MDOOR_POSITION = false; //Forces mystic door to be spawned near spawnpoints.
public static final boolean USE_SPAWN_CLEAN_MDOOR = false; //Makes mystic doors to be spawned without deploy animation. This clears disconnecting issues that may happen when trying to cancel doors a couple seconds after deployment.
public static final boolean USE_SPAWN_LOOT_ON_ANIMATION = false;//Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly).
public static final boolean USE_SPAWN_RELEVANT_LOOT = true; //Forces to only spawn loots that are collectable by the player or any of their party members.
public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop.
@@ -149,15 +150,18 @@ public class ServerConstants {
public static final int TRAVEL_RATE = 10; //Means of transportation rides/departs using 1/N of the default time.
public static final double EQUIP_EXP_RATE = 1.0; //Rate for equipment exp gain, grows linearly. Set 1.0 for default (about 100~200 same-level range mobs killed to pass equip from level 1 to 2).
public static final float PARTY_BONUS_EXP_RATE = 1.0f; //Rate for the party exp bonus reward.
public static final double PQ_BONUS_EXP_RATE = 0.5; //Rate for the PQ exp reward.
public static final byte EXP_SPLIT_LEVEL_INTERVAL = 5; //Non-contributing players must be within N level between the mob to receive EXP.
public static final byte EXP_SPLIT_LEECH_INTERVAL = 5; //Non-contributing players must be within N level between any contributing party member to receive EXP.
public static final float EXP_SPLIT_MVP_MOD = 0.2f;
public static final float EXP_SPLIT_COMMON_MOD = 0.8f;
public static final float PARTY_BONUS_EXP_RATE = 1.0f; //Rate for the party exp bonus reward.
//Miscellaneous Configuration
public static String TIMEZONE = "GMT-3";
public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 20; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled. For bosses, this attribute is doubled.
public static final byte MIN_RANGELEVEL_TO_EXP_LEECH = 40; //Characters are unable to leech EXP from party member kills whose level difference are past this limit.
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
+2 -1
View File
@@ -263,7 +263,8 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());
registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
registerHandler(RecvOpcode.USE_ITEMUI, new UseItemCanvasHandler());
registerHandler(RecvOpcode.OPEN_ITEMUI, new RaiseUIStateHandler());
registerHandler(RecvOpcode.USE_ITEMUI, new RaiseIncExpHandler());
}
}
}
+1 -4
View File
@@ -495,15 +495,12 @@ public class Server {
return true;
}
private void resetServerWorlds() {
private void resetServerWorlds() { // thanks maple006 for noticing proprietary lists assigned to null
wldWLock.lock();
try {
worlds.clear();
worlds = null;
channels.clear();
channels = null;
worldRecommendedList.clear();
worldRecommendedList = null;
} finally {
wldWLock.unlock();
}
+4 -1
View File
@@ -239,7 +239,10 @@ public class ThreadTracker {
}
else {
AtomicInteger c = lockCount.get(lockOid);
c.decrementAndGet();
if (c != null) { // thanks BHB for detecting an NPE here
c.decrementAndGet();
}
lockUpdate.put(lockOid, 0);
List<MonitoredLockType> list = threadTracker.get(tid);
@@ -26,6 +26,7 @@ package net.server.audit.locks;
public enum MonitoredLockType {
UNDEFINED,
INTERVAL,
CHARACTER_CHR,
CHARACTER_CPN,
CHARACTER_EFF,
@@ -96,7 +97,7 @@ public enum MonitoredLockType {
VISITOR_MERCH,
MAP_CHRS,
MAP_OBJS,
MAP_FACTORY,
MAP_MANAGER,
MAP_ITEM,
MAP_LOOT,
MAP_BOUNDS,
+7 -27
View File
@@ -26,7 +26,6 @@ import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Collections;
import java.util.HashSet;
@@ -64,7 +63,6 @@ import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketSessionConfig;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import provider.MapleDataProviderFactory;
import scripting.event.EventScriptManager;
import server.TimerManager;
import server.events.gm.MapleEvent;
@@ -72,7 +70,7 @@ import server.expeditions.MapleExpedition;
import server.expeditions.MapleExpeditionType;
import server.maps.MapleHiredMerchant;
import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleMapManager;
import server.maps.MapleMiniDungeon;
import tools.MaplePacketCreator;
import tools.Pair;
@@ -88,7 +86,7 @@ public final class Channel {
private int world, channel;
private IoAcceptor acceptor;
private String ip, serverMessage;
private MapleMapFactory mapFactory;
private MapleMapManager mapManager;
private EventScriptManager eventSM;
private MobStatusScheduler mobStatusSchedulers[] = new MobStatusScheduler[ServerConstants.CHANNEL_LOCKS];
private MobAnimationScheduler mobAnimationSchedulers[] = new MobAnimationScheduler[ServerConstants.CHANNEL_LOCKS];
@@ -108,8 +106,6 @@ public final class Channel {
private int usedDojo = 0;
private Set<Integer> usedMC = new HashSet<>();
private ScheduledFuture<?> respawnTask;
private int[] dojoStage;
private long[] dojoFinishTime;
private ScheduledFuture<?>[] dojoTask;
@@ -142,7 +138,7 @@ public final class Channel {
this.channel = channel;
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
this.mapFactory = new MapleMapFactory(null, MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz")), MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz")), world, channel);
this.mapManager = new MapleMapManager(null, world, channel);
try {
eventSM = new EventScriptManager(this, getEvents());
port = 7575 + this.channel - 1;
@@ -151,7 +147,6 @@ public final class Channel {
IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
respawnTask = TimerManager.getInstance().register(new respawnMaps(), ServerConstants.RESPAWN_INTERVAL);
acceptor.setHandler(new MapleServerHandler(world, channel));
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
@@ -204,13 +199,8 @@ public final class Channel {
disconnectAwayPlayers();
players.disconnectAll();
if(respawnTask != null) {
respawnTask.cancel(false);
respawnTask = null;
}
mapFactory.dispose();
mapFactory = null;
mapManager.dispose();
mapManager = null;
eventSM.cancel();
eventSM = null;
@@ -315,8 +305,8 @@ public final class Channel {
}
}
public MapleMapFactory getMapFactory() {
return mapFactory;
public MapleMapManager getMapFactory() {
return mapManager;
}
public int getWorld() {
@@ -417,16 +407,6 @@ public final class Channel {
}
}
public class respawnMaps implements Runnable {
@Override
public void run() {
for (MapleMap map : mapFactory.getMaps().values()) {
map.respawn();
}
}
}
public Map<Integer, MapleHiredMerchant> getHiredMerchants() {
merchRlock.lock();
try {
@@ -45,12 +45,12 @@ public final class DueyHandler extends AbstractMaplePacketHandler {
short amount = slea.readShort();
int mesos = slea.readInt();
String recipient = slea.readMapleAsciiString();
DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, recipient);
String message = slea.readByte() != 0 ? slea.readMapleAsciiString() : "";
DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, message, recipient);
} else if (operation == DueyProcessor.Actions.TOSERVER_REMOVE_PACKAGE.getCode()) {
int packageid = slea.readInt();
DueyProcessor.dueyRemovePackage(c, packageid);
DueyProcessor.dueyRemovePackage(c, packageid, true);
} else if (operation == DueyProcessor.Actions.TOSERVER_CLAIM_PACKAGE.getCode()) {
int packageid = slea.readInt();
@@ -94,7 +94,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
ANSWER_TIE(0x33),
GIVE_UP(0x34),
EXIT_AFTER_GAME(0x38),
CANCEL_EXIT(0x39),
CANCEL_EXIT_AFTER_GAME(0x39),
READY(0x3A),
UN_READY(0x3B),
EXPEL(0x3C),
@@ -344,7 +344,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
MapleTrade.cancelTrade(chr, MapleTrade.TradeResult.PARTNER_CANCEL);
} else {
chr.closePlayerShop();
chr.closeMiniGame();
chr.closeMiniGame(false);
chr.closeHiredMerchant(true);
}
} else if (mode == Action.OPEN_STORE.getCode() || mode == Action.OPEN_CASH.getCode()) {
@@ -495,13 +495,14 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
return;
}
if(ServerConstants.USE_ENFORCE_UNMERCHABLE_CASH && ii.isCash(item.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Cash items are not allowed to be traded."));
return;
}
if (ServerConstants.USE_ENFORCE_UNMERCHABLE_PET && ItemConstants.isPet(item.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be traded."));
if (ii.isUnmerchable(item.getItemId())) {
if (ItemConstants.isPet(item.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be traded."));
} else {
c.announce(MaplePacketCreator.serverNotice(1, "Cash items are not allowed to be traded."));
}
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -567,6 +568,15 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
if (ivItem == null || ivItem.isUntradeable()) {
c.announce(MaplePacketCreator.serverNotice(1, "Could not perform shop operation with that item."));
c.announce(MaplePacketCreator.enableActions());
return;
} else if (MapleItemInformationProvider.getInstance().isUnmerchable(ivItem.getItemId())) {
if (ItemConstants.isPet(ivItem.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be sold on the Player Store."));
} else {
c.announce(MaplePacketCreator.serverNotice(1, "Cash items are not allowed to be sold on the Player Store."));
}
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -588,17 +598,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
FilePrinter.printError(FilePrinter.EXPLOITS + chr.getName() + ".txt", chr.getName() + " might of possibly packet edited Hired Merchants\nperBundle: " + perBundle + "\nperBundle * bundles (This multiplied cannot be greater than 2000): " + perBundle * bundles + "\nbundles: " + bundles + "\nprice: " + price);
return;
}
if(ServerConstants.USE_ENFORCE_UNMERCHABLE_CASH && MapleItemInformationProvider.getInstance().isCash(ivItem.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Cash items are not allowed to be sold on the Player Store."));
return;
}
if (ServerConstants.USE_ENFORCE_UNMERCHABLE_PET && ItemConstants.isPet(ivItem.getItemId())) {
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be sold on the Player Store."));
return;
}
Item sellItem = ivItem.copy();
if(!ItemConstants.isRechargeable(ivItem.getItemId())) {
sellItem.setQuantity(perBundle);
@@ -608,8 +608,6 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
MaplePlayerShop shop = chr.getPlayerShop();
MapleHiredMerchant merchant = chr.getHiredMerchant();
if (shop != null && shop.isOwner(chr)) {
System.out.println(shopItem.getItem().getPet() + " " + shopItem.getItem().getPetId());
System.out.println(ivItem.getPet() + " " + ivItem.getPetId());
if (shop.isOpen() || !shop.addItem(shopItem)) { // thanks Vcoc for pointing an exploit with unlimited shop slots
c.announce(MaplePacketCreator.serverNotice(1, "You can't sell it anymore."));
return;
@@ -770,10 +768,20 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
MapleCharacter visitor = miniGame.getVisitor();
if(visitor != null) {
visitor.closeMiniGame();
visitor.announce(MaplePacketCreator.getMiniGameClose(5));
visitor.closeMiniGame(false);
visitor.announce(MaplePacketCreator.getMiniGameClose(true, 5));
}
}
} else if (mode == Action.EXIT_AFTER_GAME.getCode()) {
MapleMiniGame miniGame = chr.getMiniGame();
if(miniGame != null) {
miniGame.setQuitAfterGame(chr, true);
}
} else if (mode == Action.CANCEL_EXIT_AFTER_GAME.getCode()) {
MapleMiniGame miniGame = chr.getMiniGame();
if(miniGame != null) {
miniGame.setQuitAfterGame(chr, false);
}
}
} finally {
c.releaseClient();
@@ -0,0 +1,59 @@
package net.server.channel.handlers;
import java.util.Map;
import client.MapleClient;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.MapleItemInformationProvider.QuestConsItem;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Xari
* @author Ronan - added concurrency protection and quest progress limit
*/
public class RaiseIncExpHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte inventorytype = slea.readByte();//nItemIT
short slot = slea.readShort();//nSlotPosition
int itemid = slea.readInt();//nItemID
if (c.tryacquireClient()) {
try {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
QuestConsItem consItem = ii.getQuestConsumablesInfo(itemid);
if (consItem == null) {
return;
}
int questid = consItem.questid;
Map<Integer, Integer> consumables = consItem.items;
int consId;
MapleInventory inv = c.getPlayer().getInventory(MapleInventoryType.getByType(inventorytype));
inv.lockInventory();
try {
consId = inv.getItem(slot).getItemId();
if (!consumables.containsKey(consId) || !c.getPlayer().haveItem(consId)) {
return;
}
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.getByType(inventorytype), (short) slot, (short) 1, false, true);
} finally {
inv.unlockInventory();
}
int nextValue = Math.min(consumables.get(consId) + Integer.parseInt(c.getPlayer().getQuestInfo(questid)), consItem.exp * consItem.grade);
c.getPlayer().updateQuestInfo(questid, "" + nextValue);
} finally {
c.releaseClient();
}
}
}
}
@@ -0,0 +1,37 @@
package net.server.channel.handlers;
import client.MapleClient;
import client.MapleQuestStatus;
import net.AbstractMaplePacketHandler;
import server.quest.MapleQuest;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Xari
*/
public class RaiseUIStateHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
int questid = slea.readShort();
if (c.tryacquireClient()) {
try {
MapleQuest quest = MapleQuest.getInstance(questid);
MapleQuestStatus mqs = c.getPlayer().getQuest(quest);
if (mqs.getStatus() == MapleQuestStatus.Status.NOT_STARTED) {
quest.forceStart(c.getPlayer(), 22000);
c.getPlayer().updateQuestInfo(quest.getId(), "0");
} else if (mqs.getStatus() == MapleQuestStatus.Status.STARTED) {
c.announce(MaplePacketCreator.updateQuest(mqs, false));
} else {
//c.announce(MaplePacketCreator.updateQuestInfo(mqs.getQuestID(), 22000, "0"));
}
} finally {
c.releaseClient();
}
}
}
}
@@ -422,8 +422,8 @@ public final class RingActionHandler extends AbstractMaplePacketHandler {
Item weddingTicket = new Item(newItemId, (short) 0, (short) 1);
weddingTicket.setExpiration(expiration);
DueyProcessor.addItemToDB(weddingTicket, 1, 0, groom, guest);
DueyProcessor.dueyCreatePackage(weddingTicket, 0, groom, guest);
}
} else {
c.getPlayer().dropMessage(5, "Wedding is already under way. You cannot invite any more guests for the event.");
@@ -26,6 +26,7 @@ import client.MapleClient;
import client.Skill;
import client.SkillFactory;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import java.util.Map;
import net.AbstractMaplePacketHandler;
@@ -41,38 +42,57 @@ public final class SkillBookHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.enableActions());
return;
}
slea.readInt();
short slot = (short) slea.readShort();
int itemId = slea.readInt();
boolean canuse;
boolean success = false;
int skill = 0;
int maxlevel = 0;
MapleCharacter player = c.getPlayer();
Item toUse = c.getPlayer().getInventory(MapleInventoryType.USE).getItem(slot);
if (toUse != null && toUse.getQuantity() == 1) {
if (toUse.getItemId() != itemId) {
return;
}
Map<String, Integer> skilldata = MapleItemInformationProvider.getInstance().getSkillStats(toUse.getItemId(), c.getPlayer().getJob().getId());
boolean canuse;
boolean success = false;
int skill = 0;
int maxlevel = 0;
if (skilldata == null) {
return;
}
Skill skill2 = SkillFactory.getSkill(skilldata.get("skillid"));
if (skilldata.get("skillid") == 0) {
canuse = false;
} else if ((player.getSkillLevel(skill2) >= skilldata.get("reqSkillLevel") || skilldata.get("reqSkillLevel") == 0) && player.getMasterLevel(skill2) < skilldata.get("masterLevel")) {
canuse = true;
if (MapleItemInformationProvider.rollSuccessChance(skilldata.get("success"))) {
success = true;
player.changeSkillLevel(skill2, player.getSkillLevel(skill2), Math.max(skilldata.get("masterLevel"), player.getMasterLevel(skill2)), -1);
} else {
success = false;
//player.dropMessage("The skill book lights up, but the skill winds up as if nothing happened.");
if (c.tryacquireClient()) {
try {
MapleInventory inv = c.getPlayer().getInventory(MapleInventoryType.USE);
Item toUse = inv.getItem(slot);
if (toUse == null || toUse.getItemId() != itemId) {
return;
}
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false);
} else {
canuse = false;
Map<String, Integer> skilldata = MapleItemInformationProvider.getInstance().getSkillStats(toUse.getItemId(), c.getPlayer().getJob().getId());
if (skilldata == null) {
return;
}
Skill skill2 = SkillFactory.getSkill(skilldata.get("skillid"));
if (skilldata.get("skillid") == 0) {
canuse = false;
} else if ((player.getSkillLevel(skill2) >= skilldata.get("reqSkillLevel") || skilldata.get("reqSkillLevel") == 0) && player.getMasterLevel(skill2) < skilldata.get("masterLevel")) {
inv.lockInventory();
try {
Item used = inv.getItem(slot);
if (used != toUse || toUse.getQuantity() < 1) { // thanks ClouD for noticing skillbooks not being usable when stacked
return;
}
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, slot, (short) 1, false);
} finally {
inv.unlockInventory();
}
canuse = true;
if (MapleItemInformationProvider.rollSuccessChance(skilldata.get("success"))) {
success = true;
player.changeSkillLevel(skill2, player.getSkillLevel(skill2), Math.max(skilldata.get("masterLevel"), player.getMasterLevel(skill2)), -1);
} else {
success = false;
//player.dropMessage("The skill book lights up, but the skill winds up as if nothing happened.");
}
} else {
canuse = false;
}
} finally {
c.releaseClient();
}
// thanks Vcoc for noting skill book result not showing for all in area
@@ -101,6 +101,7 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
monster.aggroClearDamages();
monster.aggroMonsterDamage(chr, 1);
// thanks onechord for pointing out Magnet disconnecting the caster (issue would actually happen upon failing to catch mob)
monster.aggroSwitchController(chr, true);
}
}
@@ -133,12 +134,20 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
} else {
skill.getEffect(skillLevel).applyEchoOfHero(chr);
}
} else if(chr.canDoor()) {
//update door lists
chr.cancelMagicDoor();
skill.getEffect(skillLevel).applyTo(chr, pos);
} else {
chr.message("Please wait 5 seconds before casting Mystic Door again.");
if (c.tryacquireClient()) {
try {
if (chr.canDoor()) {
chr.cancelMagicDoor();
skill.getEffect(skillLevel).applyTo(chr, pos);
} else {
chr.message("Please wait 5 seconds before casting Mystic Door again.");
}
} finally {
c.releaseClient();
}
}
c.announce(MaplePacketCreator.enableActions());
}
} else {
@@ -36,6 +36,7 @@ import client.inventory.ModifyInventory;
import client.inventory.manipulator.MapleInventoryManipulator;
import client.inventory.manipulator.MapleKarmaManipulator;
import client.processor.AssignAPProcessor;
import client.processor.DueyProcessor;
import constants.GameConstants;
import constants.ItemConstants;
import constants.ServerConstants;
@@ -47,7 +48,6 @@ import java.util.List;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import scripting.npc.NPCScriptManager;
import server.MapleItemInformationProvider;
import server.MapleShop;
import server.MapleShopFactory;
@@ -130,7 +130,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
if (victim != null) {
MapleMap targetMap = victim.getMap();
if (!FieldLimit.CANNOTVIPROCK.check(targetMap.getFieldLimit()) && (targetMap.getForcedReturnId() == 999999999 || targetMap.getId() < 100000000)) {
if (victim.gmLevel() <= player.gmLevel()) {
if (!victim.isGM() || victim.gmLevel() <= player.gmLevel()) { // thanks Yoboes for noticing non-GM's being unreachable through rocks
player.forceChangeMap(targetMap, targetMap.findClosestPlayerSpawnpoint(victim.getPosition()));
success = true;
} else {
@@ -294,7 +294,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
if (item == null) //hack
{
return;
} else if (item.isUntradeable()) {
} else if (item.isUntradeable() || ii.isUnmerchable(item.getItemId())) {
player.dropMessage(1, "You cannot trade this item.");
c.announce(MaplePacketCreator.enableActions());
return;
@@ -398,7 +398,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
ii.getItemEffect(itemId).applyTo(player);
remove(c, position, itemId);
} else if (itemType == 533) {
NPCScriptManager.getInstance().start(c, 9010009, null);
DueyProcessor.dueySendTalk(c);
} else if (itemType == 537) {
if (GameConstants.isFreeMarketRoom(player.getMapId())) {
player.dropMessage(5, "You cannot use the chalkboard here.");
@@ -409,7 +409,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
player.setChalkboard(slea.readMapleAsciiString());
player.getMap().broadcastMessage(MaplePacketCreator.useChalkboard(player, false));
player.getClient().announce(MaplePacketCreator.enableActions());
remove(c, position, itemId);
//remove(c, position, itemId); thanks Conrad for noticing chalkboards shouldn't be depleted upon use
} else if (itemType == 539) {
List<String> strLines = new LinkedList<>();
for (int i = 0; i < 4; i++) {
@@ -1,14 +0,0 @@
package net.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.MaplePacketCreator;
public final class UseItemCanvasHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.announce(MaplePacketCreator.enableActions());
}
}
@@ -237,7 +237,9 @@ public class MapleMonsterAggroCoordinator {
}
if (mobAggro.isEmpty()) { // all aggro on this mob expired
am.getLeft().aggroResetAggro();
if (!am.getLeft().isBoss()) {
am.getLeft().aggroResetAggro();
}
}
}
@@ -64,6 +64,10 @@ public class MaplePartySearchCoordinator {
private Map<Integer, MapleCharacter> searchLeaders = new HashMap<>();
private Map<Integer, LeaderSearchMetadata> searchSettings = new HashMap<>();
private Map<MapleCharacter, LeaderSearchMetadata> timeoutLeaders = new HashMap<>();
private int updateCount = 0;
private static Map<Integer, Set<Integer>> mapNeighbors = fetchNeighbouringMaps();
private static Map<Integer, MapleJob> jobTable = instantiateJobTable();
@@ -245,11 +249,21 @@ public class MaplePartySearchCoordinator {
addQueueLeader(leader);
}
private void registerPartyLeader(MapleCharacter leader, LeaderSearchMetadata settings) {
if (searchLeaders.containsKey(leader.getId())) return;
searchSettings.put(leader.getId(), settings);
searchLeaders.put(leader.getId(), leader);
addQueueLeader(leader);
}
public void unregisterPartyLeader(MapleCharacter leader) {
MapleCharacter toRemove = searchLeaders.remove(leader.getId());
if (toRemove != null) {
removeQueueLeader(toRemove);
searchSettings.remove(leader.getId());
} else {
unregisterLongTermPartyLeader(leader);
}
}
@@ -307,6 +321,41 @@ public class MaplePartySearchCoordinator {
return new Pair<>(queuedLeaders, nextLeaders);
}
private void registerLongTermPartyLeaders(List<Pair<MapleCharacter, LeaderSearchMetadata>> recycledLeaders) {
leaderQueueRLock.lock();
try {
for (Pair<MapleCharacter, LeaderSearchMetadata> p : recycledLeaders) {
timeoutLeaders.put(p.getLeft(), p.getRight());
}
} finally {
leaderQueueRLock.unlock();
}
}
private void unregisterLongTermPartyLeader(MapleCharacter leader) {
leaderQueueRLock.lock();
try {
timeoutLeaders.remove(leader);
} finally {
leaderQueueRLock.unlock();
}
}
private void reinstateLongTermPartyLeaders() {
Map<MapleCharacter, LeaderSearchMetadata> timeoutLeadersCopy;
leaderQueueWLock.lock();
try {
timeoutLeadersCopy = new HashMap<>(timeoutLeaders);
timeoutLeaders.clear();
} finally {
leaderQueueWLock.unlock();
}
for (Entry<MapleCharacter, LeaderSearchMetadata> e : timeoutLeadersCopy.entrySet()) {
registerPartyLeader(e.getKey(), e.getValue());
}
}
public void runPartySearch() {
Pair<List<MapleCharacter>, List<MapleCharacter>> queuedLeaders = fetchQueuedLeaders();
@@ -356,10 +405,28 @@ public class MaplePartySearchCoordinator {
}
}
List<Pair<MapleCharacter, LeaderSearchMetadata>> recycledLeaders = new LinkedList<>();
for (MapleCharacter leader : expiredLeaders) {
if (leader.isLoggedinWorld()) leader.dropMessage(5, "Your Party Search token session expired, please stop your Party Search and retry again later.");
searchLeaders.remove(leader.getId());
searchSettings.remove(leader.getId());
LeaderSearchMetadata settings = searchSettings.remove(leader.getId());
if (leader.isLoggedinWorld()) {
if (settings != null) {
recycledLeaders.add(new Pair<>(leader, settings));
if (ServerConstants.USE_DEBUG && leader.isGM()) leader.dropMessage(5, "Your Party Search token session is now on waiting queue for up to 7 minutes, to get it working right away please stop your Party Search and retry again later.");
} else {
leader.dropMessage(5, "Your Party Search token session expired, please stop your Party Search and retry again later.");
}
}
}
if (!recycledLeaders.isEmpty()) {
registerLongTermPartyLeaders(recycledLeaders);
}
updateCount++;
if (updateCount % 77 == 0) {
reinstateLongTermPartyLeaders();
}
}
@@ -34,8 +34,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import java.awt.geom.Line2D;
import tools.IntervalBuilder;
/**
*
@@ -44,84 +43,7 @@ import java.awt.geom.Line2D;
public class PartySearchStorage {
private List<PartySearchCharacter> storage = new ArrayList<>(20);
private PartySearchEmptyIntervals emptyManager = new PartySearchEmptyIntervals();
private class PartySearchEmptyIntervals {
private List<Line2D> emptyLimits = new ArrayList<>();
private void refitEmptyIntervals(int st, int en, int minLevel, int maxLevel) {
List<Line2D> checkLimits = new ArrayList<>(emptyLimits.subList(st, en));
float newLimitX1, newLimitX2;
if (!checkLimits.isEmpty()) {
Line2D firstLimit = checkLimits.get(0);
Line2D lastLimit = checkLimits.get(checkLimits.size() - 1);
newLimitX1 = (float) ((minLevel < firstLimit.getX1()) ? minLevel : firstLimit.getX1());
newLimitX2 = (float) ((maxLevel > lastLimit.getX2()) ? maxLevel : lastLimit.getX2());
for (Line2D limit : checkLimits) {
emptyLimits.remove(st);
}
} else {
newLimitX1 = minLevel;
newLimitX2 = maxLevel;
}
emptyLimits.add(st, new Line2D.Float((float) newLimitX1, 0, (float) newLimitX2, 0));
}
private int bsearchInterval(int level) {
int st = 0, en = emptyLimits.size() - 1;
int mid, idx;
while (en >= st) {
idx = (st + en) / 2;
mid = (int) emptyLimits.get(idx).getX1();
if (mid == level) {
return idx;
} else if (mid < level) {
st = idx + 1;
} else {
en = idx - 1;
}
}
return en;
}
public void addEmptyInterval(int fromLevel, int toLevel) {
synchronized (emptyLimits) { // adding intervals occurs on a same-thread process, so this is actually not performance grinding
int st = bsearchInterval(fromLevel);
if (st < 0) {
st = 0;
} else if (emptyLimits.get(st).getX2() < fromLevel) {
st += 1;
}
int en = bsearchInterval(toLevel);
if (en < st) en = st - 1;
refitEmptyIntervals(st, en + 1, fromLevel, toLevel);
}
}
public boolean isInEmptyInterval(int minLevel, int maxLevel) {
synchronized (emptyLimits) {
int idx = bsearchInterval(minLevel);
return idx >= 0 && maxLevel <= emptyLimits.get(idx).getX2();
}
}
public void clearEmptyInterval() {
synchronized (emptyLimits) {
emptyLimits.clear();
}
}
}
private IntervalBuilder emptyIntervals = new IntervalBuilder();
private final ReentrantReadWriteLock psLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_PARTY_SEARCH_STORAGE, true);
private final ReadLock psRLock = psLock.readLock();
@@ -183,7 +105,7 @@ public class PartySearchStorage {
psWLock.unlock();
}
emptyManager.clearEmptyInterval();
emptyIntervals.clear();
}
private static int bsearchStorage(List<PartySearchCharacter> storage, int level) {
@@ -207,7 +129,7 @@ public class PartySearchStorage {
}
public MapleCharacter callPlayer(int callerCid, int callerMapid, int minLevel, int maxLevel) {
if (emptyManager.isInEmptyInterval(minLevel, maxLevel)) {
if (emptyIntervals.inInterval(minLevel, maxLevel)) {
return null;
}
@@ -230,7 +152,7 @@ public class PartySearchStorage {
}
}
emptyManager.addEmptyInterval(minLevel, maxLevel);
emptyIntervals.addInterval(minLevel, maxLevel);
return null;
}
@@ -37,7 +37,7 @@ public final class AfterLoginHandler extends AbstractMaplePacketHandler {
c3 = slea.readByte();
}
if (c2 == 1 && c3 == 1) {
if (c.getPin() == null) {
if (c.getPin() == null || c.getPin().equals("")) {
c.announce(MaplePacketCreator.registerPin());
} else {
c.announce(MaplePacketCreator.requestPin());
@@ -457,6 +457,64 @@ public class AbstractPlayerInteraction {
getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false));
}
public boolean forceStartQuest(int id) {
return forceStartQuest(id, 9010000);
}
public boolean forceStartQuest(int id, int npc) {
return startQuest(id, npc);
}
public boolean forceCompleteQuest(int id) {
return forceCompleteQuest(id, 9010000);
}
public boolean forceCompleteQuest(int id, int npc) {
return completeQuest(id, npc);
}
public boolean startQuest(short id) {
return startQuest((int) id);
}
public boolean completeQuest(short id) {
return completeQuest((int) id);
}
public boolean startQuest(int id) {
return startQuest(id, 9010000);
}
public boolean completeQuest(int id) {
return completeQuest(id, 9010000);
}
public boolean startQuest(short id, int npcId) {
return startQuest((int) id, npcId);
}
public boolean completeQuest(short id, int npcId) {
return completeQuest((int) id, npcId);
}
public boolean startQuest(int id, int npcId) {
try {
return MapleQuest.getInstance(id).forceStart(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
return false;
}
}
public boolean completeQuest(int id, int npcId) {
try {
return MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
return false;
}
}
public Item evolvePet(byte slot, int afterId) {
MaplePet evolved = null;
MaplePet target;
+9 -12
View File
@@ -21,7 +21,6 @@
*/
package scripting.event;
import java.io.File;
import tools.Pair;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -40,14 +39,13 @@ import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import provider.MapleDataProviderFactory;
import server.MaplePortal;
import server.TimerManager;
import server.MapleStatEffect;
import server.expeditions.MapleExpedition;
import server.life.MapleMonster;
import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleMapManager;
import server.maps.MapleReactor;
import client.MapleCharacter;
import client.SkillFactory;
@@ -82,7 +80,7 @@ public class EventInstanceManager {
private Map<MapleCharacter, Integer> killCount = new HashMap<>();
private EventManager em;
private EventScriptScheduler ess;
private MapleMapFactory mapFactory;
private MapleMapManager mapManager;
private String name;
private Properties props = new Properties();
private Map<String, Object> objectProps = new HashMap<>();
@@ -125,8 +123,7 @@ public class EventInstanceManager {
this.em = em;
this.name = name;
this.ess = new EventScriptScheduler();
mapFactory = new MapleMapFactory(this, MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz")), MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz")), (byte) 0, (byte) 1);//Fk this
mapFactory.setChannel(em.getChannelServer().getId());
this.mapManager = new MapleMapManager(this, em.getWorldServer().getId(), em.getChannelServer().getId());
}
public void setName(String name) {
@@ -647,10 +644,10 @@ public class EventInstanceManager {
TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
mapFactory.dispose(); // issues from instantly disposing some event objects found thanks to MedicOP
mapManager.dispose(); // issues from instantly disposing some event objects found thanks to MedicOP
wL.lock();
try {
mapFactory = null;
mapManager = null;
em = null;
} finally {
wL.unlock();
@@ -675,8 +672,8 @@ public class EventInstanceManager {
sL = sL.dispose();
}
public MapleMapFactory getMapFactory() {
return mapFactory;
public MapleMapManager getMapFactory() {
return mapManager;
}
public void schedule(final String methodName, long delay) {
@@ -706,10 +703,10 @@ public class EventInstanceManager {
}
public MapleMap getMapInstance(int mapId) {
MapleMap map = mapFactory.getMap(mapId);
MapleMap map = mapManager.getMap(mapId);
map.setEventInstance(this);
if (!mapFactory.isMapLoaded(mapId)) {
if (!mapManager.isMapLoaded(mapId)) {
sL.lock();
try {
if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) {
+46 -65
View File
@@ -41,10 +41,9 @@ import server.gachapon.MapleGachapon;
import server.gachapon.MapleGachapon.MapleGachaponItem;
import server.life.MaplePlayerNPC;
import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleMapManager;
import server.partyquest.Pyramid;
import server.partyquest.Pyramid.PyramidMode;
import server.quest.MapleQuest;
import tools.LogHelper;
import tools.MaplePacketCreator;
import client.MapleCharacter;
@@ -63,9 +62,11 @@ import constants.LanguageConstants;
import net.server.PlayerStorage;
import net.server.channel.Channel;
import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType;
import server.MapleMarriage;
import server.MapleSkillbookInformationProvider;
import server.MapleSkillbookInformationProvider.SkillBookEntry;
import server.TimerManager;
import server.life.MapleLifeFactory;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import server.expeditions.MapleExpedition;
@@ -77,10 +78,11 @@ import tools.packets.Wedding;
import java.awt.Point;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import server.MapleMarriage;
/**
*
@@ -95,6 +97,18 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
private boolean itemScript;
private List<MaplePartyCharacter> otherParty;
private static Map<Integer, String> npcDefaultTalks = new HashMap<>();
private static String getDefaultTalk(int npcid) {
String talk = npcDefaultTalks.get(npcid);
if (talk == null) {
talk = MapleLifeFactory.getNPCDefaultTalk(npcid);
npcDefaultTalks.put(npcid, talk);
}
return talk;
}
public NPCConversationManager(MapleClient c, int npc, String scriptName) {
this(c, npc, -1, scriptName, false);
}
@@ -154,6 +168,10 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
public void sendOk(String text) {
getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 0, text, "00 00", (byte) 0));
}
public void sendDefault() {
sendOk(getDefaultTalk(npc));
}
public void sendYesNo(String text) {
getClient().announce(MaplePacketCreator.getNPCTalk(npc, (byte) 1, text, "", (byte) 0));
@@ -196,7 +214,12 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
}
public void sendStyle(String text, int styles[]) {
getClient().announce(MaplePacketCreator.getNPCTalkStyle(npc, text, styles));
if (styles.length > 0) {
getClient().announce(MaplePacketCreator.getNPCTalkStyle(npc, text, styles));
} else { // thanks Conrad for noticing empty styles crashing players
sendOk("Sorry, there are no options of cosmetics available for you here at the moment.");
dispose();
}
}
public void sendGetNumber(String text, int def, int min, int max) {
@@ -236,76 +259,34 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
return getPlayer().getJob();
}
public void startQuest(short id) {
try {
MapleQuest.getInstance(id).forceStart(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
public void completeQuest(short id) {
try {
MapleQuest.getInstance(id).forceComplete(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
@Override
public boolean forceStartQuest(int id) {
return MapleQuest.getInstance(id).forceStart(getPlayer(), npc);
return forceStartQuest(id, npc);
}
@Override
public boolean forceCompleteQuest(int id) {
return MapleQuest.getInstance(id).forceComplete(getPlayer(), npc);
return forceCompleteQuest(id, npc);
}
public void startQuest(int id) {
try {
MapleQuest.getInstance(id).forceStart(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
public void completeQuest(int id) {
try {
MapleQuest.getInstance(id).forceComplete(getPlayer(), npc);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
}
public void startQuest(short id, int npcId) {
try {
MapleQuest.getInstance(id).forceStart(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
@Override
public boolean startQuest(short id) {
return startQuest((int) id);
}
public void startQuest(int id, int npcId) {
try {
MapleQuest.getInstance(id).forceStart(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
@Override
public boolean completeQuest(short id) {
return completeQuest((int) id);
}
public void completeQuest(short id, int npcId) {
try {
MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
@Override
public boolean startQuest(int id) {
return startQuest(id, npc);
}
public void completeQuest(int id, int npcId) {
try {
MapleQuest.getInstance(id).forceComplete(getPlayer(), npcId);
} catch (NullPointerException ex) {
ex.printStackTrace();
}
@Override
public boolean completeQuest(int id) {
return completeQuest(id, npc);
}
public int getMeso() {
@@ -538,7 +519,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
PyramidMode mod = PyramidMode.valueOf(mode);
MapleParty partyz = getPlayer().getParty();
MapleMapFactory mf = c.getChannelServer().getMapFactory();
MapleMapManager mapManager = c.getChannelServer().getMapFactory();
MapleMap map = null;
int mapid = 926010100;
@@ -548,7 +529,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
mapid += (mod.getMode() * 1000);
for (byte b = 0; b < 5; b++) {//They cannot warp to the next map before the timer ends (:
map = mf.getMap(mapid + b);
map = mapManager.getMap(mapid + b);
if (map.getCharacters().size() > 0) {
continue;
} else {
+2 -9
View File
@@ -92,14 +92,8 @@ public class NPCScriptManager extends AbstractScriptManager {
cms.put(c, cm);
Invocable iv = null;
iv = getInvocable("npc/" + filename + ".js", c);
NPCScriptManager npcsm = NPCScriptManager.getInstance();
if (iv == null || NPCScriptManager.getInstance() == null) {
c.getPlayer().dropMessage(1, npc + "");
cm.dispose();
return;
}
if (iv == null || npcsm == null) {
if (iv == null) {
c.getPlayer().dropMessage(1, npc + "");
cm.dispose();
return;
@@ -147,7 +141,7 @@ public class NPCScriptManager extends AbstractScriptManager {
iv = getInvocable("npc/" + npc + ".js", c);
cm.resetItemScript();
}
if (iv == null || NPCScriptManager.getInstance() == null) {
if (iv == null) {
dispose(c);
return false;
}
@@ -166,7 +160,6 @@ public class NPCScriptManager extends AbstractScriptManager {
} else {
c.announce(MaplePacketCreator.enableActions());
}
return true;
} catch (final UndeclaredThrowableException | ScriptException ute) {
FilePrinter.printError(FilePrinter.NPC + npc + ".txt", ute);
@@ -82,22 +82,6 @@ public class PortalPlayerInteraction extends AbstractPlayerInteraction {
return getPlayer().getLevel() >= 30;
}
public boolean forceStartQuest(int id) {
return forceStartQuest(id, 9010000);
}
public boolean forceStartQuest(int id, int npc) {
return MapleQuest.getInstance(id).forceStart(getPlayer(), npc);
}
public boolean forceCompleteQuest(int id) {
return forceCompleteQuest(id, 9010000);
}
public boolean forceCompleteQuest(int id, int npc) {
return MapleQuest.getInstance(id).forceComplete(getPlayer(), npc);
}
public void blockPortal() {
c.getPlayer().blockPortal(getPortal().getScriptName());
}
@@ -24,21 +24,22 @@ package server;
import client.inventory.Item;
import java.util.Calendar;
public class DueyPackages {
public class DueyPackage {
private String sender = null;
private Item item = null;
private int mesos = 0;
private String message = "";
private int day;
private int month;
private int year;
private int packageId = 0;
public DueyPackages(int pId, Item item) {
public DueyPackage(int pId, Item item) {
this.item = item;
packageId = pId;
}
public DueyPackages(int pId) { // Meso only package.
public DueyPackage(int pId) { // Meso only package.
this.packageId = pId;
}
@@ -61,6 +62,14 @@ public class DueyPackages {
public void setMesos(int set) {
mesos = set;
}
public String getMessage() {
return message;
}
public void setMessage(String m) {
message = m;
}
public int getPackageId() {
return packageId;
+57 -9
View File
@@ -136,6 +136,7 @@ public class MapleItemInformationProvider {
protected Map<Integer, Map<String, Integer>> skillUpgradeCache = new HashMap<>();
protected Map<Integer, MapleData> skillUpgradeInfoCache = new HashMap<>();
protected Map<Integer, Pair<Integer, Set<Integer>>> cashPetFoodCache = new HashMap<>();
protected Map<Integer, QuestConsItem> questItemConsCache = new HashMap<>();
private MapleItemInformationProvider() {
loadCardIdData();
@@ -1381,12 +1382,6 @@ public class MapleItemInformationProvider {
return partyquestItem;
}
public int getQuestIdFromItem(int itemId) {
MapleData data = getItemData(itemId);
int questItem = MapleDataTool.getIntConvert("info/quest", data, 0);
return questItem;
}
private void loadCardIdData() {
PreparedStatement ps = null;
ResultSet rs = null;
@@ -1440,9 +1435,10 @@ public class MapleItemInformationProvider {
if ((itemId / 10000) != 243) {
return null;
}
ScriptedItem script = new ScriptedItem(MapleDataTool.getInt("spec/npc", getItemData(itemId), 0),
MapleDataTool.getString("spec/script", getItemData(itemId), ""),
MapleDataTool.getInt("spec/runOnPickup", getItemData(itemId), 0) == 1);
MapleData itemInfo = getItemData(itemId);
ScriptedItem script = new ScriptedItem(MapleDataTool.getInt("spec/npc", itemInfo, 0),
MapleDataTool.getString("spec/script", itemInfo, ""),
MapleDataTool.getInt("spec/runOnPickup", itemInfo, 0) == 1);
scriptedItemCache.put(itemId, script);
return scriptedItemCache.get(itemId);
}
@@ -1594,6 +1590,18 @@ public class MapleItemInformationProvider {
eq.getWatk() > 0 || eq.getMatk() > 0 || eq.getWdef() > 0 || eq.getMdef() > 0 || eq.getAcc() > 0 ||
eq.getAvoid() > 0 || eq.getSpeed() > 0 || eq.getJump() > 0 || eq.getHp() > 0 || eq.getMp() > 0);
}
public boolean isUnmerchable(int itemId) {
if(ServerConstants.USE_ENFORCE_UNMERCHABLE_CASH && isCash(itemId)) {
return true;
}
if (ServerConstants.USE_ENFORCE_UNMERCHABLE_PET && ItemConstants.isPet(itemId)) {
return true;
}
return false;
}
public Collection<Item> canWearEquipment(MapleCharacter chr, Collection<Item> items) {
MapleInventory inv = chr.getInventory(MapleInventoryType.EQUIPPED);
@@ -2125,6 +2133,35 @@ public class MapleItemInformationProvider {
return skillbook;
}
public final QuestConsItem getQuestConsumablesInfo(final int itemId) {
if (questItemConsCache.containsKey(itemId)) {
return questItemConsCache.get(itemId);
}
MapleData data = getItemData(itemId);
MapleData infoData = data.getChildByPath("info");
MapleData ciData = infoData.getChildByPath("consumeItem");
QuestConsItem qcItem = null;
if (ciData != null) {
qcItem = new QuestConsItem();
qcItem.exp = MapleDataTool.getInt("exp", infoData);
qcItem.grade = MapleDataTool.getInt("grade", infoData);
qcItem.questid = MapleDataTool.getInt("questId", infoData);
qcItem.items = new HashMap<>(2);
Map<Integer, Integer> cItems = qcItem.items;
for (MapleData ciItem : ciData.getChildren()) {
int itemid = MapleDataTool.getInt("0", ciItem);
int qty = MapleDataTool.getInt("1", ciItem);
cItems.put(itemid, qty);
}
}
questItemConsCache.put(itemId, qcItem);
return qcItem;
}
public class ScriptedItem {
@@ -2157,4 +2194,15 @@ public class MapleItemInformationProvider {
public short prob, quantity;
public String effect, worldmsg;
}
public static final class QuestConsItem {
public int questid, exp, grade;
public Map<Integer, Integer> items;
public Integer getItemRequirement(int itemid) {
return items.get(itemid);
}
}
}
+38 -19
View File
@@ -150,12 +150,14 @@ public class MapleStatEffect {
private static class CardItemupStats {
protected int itemCode, prob;
protected boolean party;
private List<Pair<Integer, Integer>> areas;
private CardItemupStats(int code, int prob, List<Pair<Integer, Integer>> areas) {
private CardItemupStats(int code, int prob, List<Pair<Integer, Integer>> areas, boolean inParty) {
this.itemCode = code;
this.prob = prob;
this.areas = areas;
this.party = inParty;
}
private boolean isInArea(int mapid) {
@@ -173,8 +175,22 @@ public class MapleStatEffect {
}
}
public boolean isActive(int mapid) {
return cardStats == null || cardStats.isInArea(mapid);
private boolean isEffectActive(int mapid, boolean partyHunting) {
if (cardStats == null) return true;
if (!cardStats.isInArea(mapid)) {
return false;
}
if (cardStats.party && !partyHunting) {
return false;
}
return true;
}
public boolean isActive(MapleCharacter applyto) {
return isEffectActive(applyto.getMapId(), applyto.getPartyMembersOnSameMap().size() > 1);
}
public int getCardRate(int mapid, int itemid) {
@@ -354,16 +370,27 @@ public class MapleStatEffect {
} else if (isMonsterCard(sourceid)) {
int prob = 0, itemupCode = Integer.MAX_VALUE;
List<Pair<Integer, Integer>> areas = null;
boolean inParty = false;
MapleData con = source.getChildByPath("con");
if (con != null) {
areas = new ArrayList<>(3);
for (MapleData conData : con.getChildren()) {
int startMap = MapleDataTool.getInt("sMap", conData, 0);
int endMap = MapleDataTool.getInt("eMap", conData, 0);
int type = MapleDataTool.getInt("type", conData, -1);
if (type == 0) {
int startMap = MapleDataTool.getInt("sMap", conData, 0);
int endMap = MapleDataTool.getInt("eMap", conData, 0);
areas.add(new Pair<>(startMap, endMap));
areas.add(new Pair<>(startMap, endMap));
} else if (type == 2) {
inParty = true;
}
}
if (areas.isEmpty()) {
areas = null;
}
}
@@ -409,7 +436,7 @@ public class MapleStatEffect {
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.MAP_PROTECTION, thaw > 0 ? 1 : 2);
}
ret.cardStats = new CardItemupStats(itemupCode, prob, areas);
ret.cardStats = new CardItemupStats(itemupCode, prob, areas, inParty);
} else if (isExpIncrease(sourceid)) {
addBuffStatPairToListIfNotZero(statups, MapleBuffStat.EXP_INCREASE, MapleDataTool.getInt("expinc", source, 0));
}
@@ -1045,8 +1072,6 @@ public class MapleStatEffect {
door.getTarget().spawnDoor(door.getAreaDoor());
door.getTown().spawnDoor(door.getTownDoor());
applyto.disableDoorSpawn();
} else {
MapleInventoryManipulator.addFromDrop(applyto.getClient(), new Item(4006000, (short) 0, (short) 1), false);
@@ -1182,15 +1207,9 @@ public class MapleStatEffect {
}
private Rectangle calculateBoundingBox(Point posFrom, boolean facingLeft) {
Point mylt;
Point myrb;
if (facingLeft) {
mylt = new Point(lt.x + posFrom.x, lt.y + posFrom.y);
myrb = new Point(rb.x + posFrom.x, rb.y + posFrom.y);
} else {
myrb = new Point(-lt.x + posFrom.x, rb.y + posFrom.y);
mylt = new Point(-rb.x + posFrom.x, lt.y + posFrom.y);
}
int multiplier = facingLeft ? 1 : -1;
Point mylt = new Point(lt.x * multiplier + posFrom.x, lt.y + posFrom.y);
Point myrb = new Point(rb.x * multiplier + posFrom.x, rb.y + posFrom.y);
Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
return bounds;
}
@@ -1315,7 +1334,7 @@ public class MapleStatEffect {
if (localstatups.size() > 0) {
byte[] buff = null;
byte[] mbuff = null;
if (getSummonMovementType() == null && this.isActive(applyto.getMapId())) {
if (getSummonMovementType() == null && this.isActive(applyto)) {
buff = MaplePacketCreator.giveBuff((skill ? sourceid : -sourceid), localDuration, localstatups);
}
if (isDash()) {
+65
View File
@@ -0,0 +1,65 @@
package server.gachapon;
/**
*
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class ElNath extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
/* Scroll */
2041012, 2048003, 2043800, 2043301, 2040301, 2043101, 2043201, 2043001, 2044301, 2043801, 2044201, 2043701, 2044502,
2041011, 2041014, 2044602, 2043302, 2043202, 2043002, 2048005, 2044402, 2044302, 2043802, 2044102, 2044202, 2043702,
2044812,
/* Useable drop */
2000004, 2000005,
/* Common equipment */
1402010, 1032003, 1442013, 1432009, 1302022, 1302029, 1322021, 1302026, 1442017, 1322023, 1102011, 1032008, 1322026,
1442016, 1312000, 1032007, 1322025, 1322027, 1032020, 1442015, 1432017, 1302027, 1302049, 1372006, 1032022, 1032021,
1372004, 1332020, 1322007, 1032006, 1302028, 1322003, 1302007, 1092030, 1302021, 1322024, 1322012, 1032005, 1322022,
1032013, 1302025, 1302013, 1032017, 1032002, 1032001, 1302017, 1432018, 1442012, 1302000, 1032000, 1102013, 1442022,
1372005, 1442021, 1032009, 1302016,
/* Warrior equipment */
1442003, 1312007, 1402008, 1312008, 1412008, 1442009, 1302004, 1312006, 1442016, 1402012, 1302003, 1312005, 1432002,
1432001, 1302008, 1040030, 1402015, 1322015, 1432006, 1322002, 1302010, 1322017, 1402003, 1402006, 1322000, 1422001,
1442001, 1422004, 1412004, 1322009, 1322011, 1442000, 1412005, 1402002, 1432004, 1442010, 1422008, 1442007, 1422009,
1322019, 1412003, 1412007, 1302009, 1412000, 1322014, 1402001, 1402007, 1432005,
/* Magician equipment */
1382001, 1372007, 1382010, 1382007, 1372000, 1372003, 1382011, 1382006, 1382000,
/* Bowman equipment */
1452004, 1452000, 1452010, 1452015, 1452014, 1462012, 1462010, 1452017, 1462000, 1452008, 1452006, 1462006, 1452007,
1452002, 1402001,
/* Thief equipment */
1472006, 1472010, 1332022, 1332011, 1472015, 1472016, 1472023, 1472028, 1472022, 1472011, 1472026, 1332024, 1332009,
1472017, 1472013, 1472029, 1472021, 1332015, 1332031, 1332023, 1332004, 1472000, 1332019, 1472027, 1332018, 1472007,
1332012, 1332016, 1472024, 1332017, 1332003, 1472012, 1472014, 1472005, 1472018, 1472001,
/* Pirate equipment */
1072294, 1492009
};
}
@Override
public int[] getUncommonItems() {
return new int [] {2022439, 2040804, 2040805, 2340000};
}
@Override
public int[] getRareItems() {
return new int [] {2043803, 1102085};
}
}
+42 -80
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate equipment
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class Ellinia extends GachaponItems {
@@ -10,95 +13,54 @@ public class Ellinia extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int[] {
//warriorEquips = {
1082025, 1060028, 1051011, 1060016, 1051001,
1422001, 1002025, 1082000, 1302002, 1412012,
//magicianEquips = {
1002013, 1002016, 1002017, 1002034, 1002035,
1002036, 1002037, 1002038, 1002064, 1002065,
1002072, 1002073, 1002074, 1002075, 1002102,
1002103, 1002104, 1002105, 1002106, 1002141,
1002142, 1002143, 1002144, 1002145, 1002151,
1002152, 1002153, 1002154, 1002155, 1002215,
1002216, 1002217, 1002218, 1002242, 1002243,
1002244, 1002245, 1002246, 1002252, 1002253,
1002254, 1002271, 1002272, 1002273, 1002274,
1002363, 1002364, 1002365, 1002366, 1002398,
1002399, 1002400, 1002401, 1002579, 1002773,
1040004, 1040017, 1040018,
1040019, 1040020, 1041015, 1041016, 1041017,
1041018, 1041025, 1041026, 1041029, 1041030,
1041031, 1041041, 1041042, 1041043, 1041051,
1041052, 1041053, 1050001, 1050002, 1050003,
1050008, 1050009, 1050010, 1050023, 1050024,
1050025, 1050026, 1050027, 1050028, 1050029,
1050030, 1050031, 1050035, 1050036, 1050037,
1050038, 1050039, 1050045, 1050046, 1050047,
1050048, 1050049, 1050053, 1050054, 1050055,
1050056, 1050067, 1050068, 1050069, 1050070,
1050072, 1050073, 1050074, 1050092, 1050093,
1050094, 1050095, 1050102, 1050103, 1050104,
1050105, 1051003, 1051004, 1051005, 1051023,
1051024, 1051025, 1051026, 1051027, 1051030,
1051031, 1051032, 1051033, 1051034, 1051044,
1051045, 1051046, 1051047, 1051052, 1051053,
1051054, 1051055, 1051056, 1051057, 1051058,
1051094, 1051095, 1051096, 1051097, 1051101,
1051102, 1051103, 1051104, 1052076,
1060012, 1060013, 1060014, 1060015,
1061010, 1061011, 1061012, 1061013, 1061021,
1061022, 1061027, 1061028, 1061034, 1061035,
1061036, 1061047, 1061048, 1061049, 1072006,
1072019, 1072020, 1072021, 1072023, 1072024,
1072044, 1072045, 1072072, 1072073, 1072074,
1072075, 1072076, 1072077, 1072078, 1072089,
1072090, 1072091, 1072114, 1072115, 1072116,
1072117, 1072136, 1072137, 1072138, 1072139,
1072140, 1072141, 1072142, 1072143, 1072157,
1072158, 1072159, 1072160, 1072169, 1072177,
1072178, 1072179, 1072206, 1072207, 1072208,
1072209, 1072223, 1072224, 1072225, 1072226,
1072268, 1082019, 1082020,
1082021, 1082022, 1082026, 1082027, 1082028,
1082051, 1082052, 1082053, 1082054, 1082055,
1082056, 1082062, 1082063, 1082064, 1082080,
1082081, 1082082, 1082086, 1082087, 1082088,
1082098, 1082099, 1082100, 1082121, 1082122,
1082123, 1082131, 1082132, 1082133, 1082134,
1082151, 1082152, 1082153, 1082154, 1082164,
1092021, 1092029, 1092057,
1372000, 1372001, 1372002, 1372003, 1372004,
1372007, 1372008, 1372009, 1372010, 1372011,
1372012, 1372014, 1372015, 1372016, 1372032,
1382000, 1382001, 1382002, 1382003, 1382004,
1382005, 1382006, 1382007, 1382008, 1382010,
1382011, 1382014, 1382015, 1382016, 1382017,
1382018, 1382019, 1382035, 1382036, 1382037,
1382041, 1382053, 1382054, 1382055, 1382056,
1382060,
//bowmanEquips = {
1040003, 1462005, 1002157, 1002119, 1062002,
1062004, 1041083, 1061082, 1082017, 1041061,
//thiefEquips = {
1002174, 1040063, 1072108, 1082044, 1061071,
1060052, 1072029, 1472002, 1082031, 1060023,
//pirateEquips = {
/* Scroll */
2043302, 2040002, 2043102, 2043002, 2044402, 2044302, 2043802, 2044002, 2041017, 2044902,
/* Useable drop */
2000004, 2000005, 2022025, 2022026,
/* Common equipment */
1402010, 1442013, 1432009, 1002060, 1002063, 1322023, 1002042, 1050018, 1082147, 1002026, 1002392, 1062024, 1442016, 1322025,
1322027, 1302027, 1372006, 1302019, 1092022, 1302021, 1041004, 1002395, 1322024, 1082148, 1002012, 1322012, 1032028, 1102012,
1322022, 1051017, 1302013, 1082146, 1442014, 1302017, 1102013, 1102003, 1002041, 1002097, 1302016, 1082145,
/* Warrior equipment */
1412006, 1040029, 1040086, 1050005, 1060028, 1002059, 1060008, 1061088, 1402012, 1302003, 1432002, 1312011, 1302008, 1040030,
1002004, 1402015, 1322028, 1322015, 1432006, 1442006, 1322000, 1002085, 1002056, 1092013, 1002058, 1002050, 1060011, 1322009,
1322011, 1442000, 1051011, 1061016, 1060018, 1041024, 1061020, 1302005, 1402002, 1002030, 1092004, 1041023, 1422008, 1060009,
1051000, 1002021, 1442005, 1412003, 1412007, 1422007, 1302009, 1402000, 1402001, 1402007, 1432005,
/* Magician equipment */
1382001, 1002037, 1060014, 1040018, 1061027, 1050002, 1002152, 1051027, 1050035, 1050056, 1051047, 1051030, 1002274, 1050074,
1002218, 1002254, 1082088, 1382007, 1002013, 1082087, 1372008, 1382008, 1372002, 1372003, 1382011, 1382004, 1050047, 1040019,
1041041, 1061034, 1041051, 1051045, 1051024, 1082081, 1041030, 1040018, 1002073, 1382003, 1082086, 1382014, 1050055, 1050025,
1002155, 1060015,
/* Bowman equipment */
1452004, 1462003, 1060070, 1002118, 1061058, 1040003, 1002160, 1002121, 1040068, 1061063, 1040080, 1462004, 1041008, 1061006,
1061009, 1040022, 1002168, 1040067, 1060056, 1041054, 1041067, 1060063, 1002213, 1002119, 1462005, 1452001, 1462000, 1040025,
1002166, 1002161, 1040069, 1051039, 1452006, 1462006, 1452007, 1402001, 1041062,
/* Thief equipment */
1472010, 1472006, 1332011, 1472031, 1041048, 1472019, 1041095, 1040095, 1002128, 1061077, 1060025, 1041040, 1061033, 1472028,
1472022, 1472011, 1040096, 1062002, 1002129, 1472026, 1332009, 1060043, 1002249, 1472021, 1040084, 1332015, 1002173, 1002148,
1332004, 1332018, 1472009, 1061069, 1002176, 1041044, 1061037, 1060032, 1472020, 1040060, 1472018, 1332013, 1332002, 1402001,
/* Pirate equipment */
1002625, 1002616, 1482005, 1052098, 1482003,
1482001, 1492004, 1002622, 1492005, 1082195
};
};
}
@Override
public int[] getUncommonItems() {
return new int [] { 1372035, 1372036, 1372037, 1372038, 1372039,
1372040, 1372041, 1372042, 1382045, 1382046,
1382047, 1382048, 1382049, 1382050, 1382051,
1382052 };
return new int [] {1082149, 1002391, 1002419};
}
@Override
public int[] getRareItems() {
return new int [] {1382059, 1382057, 1072362, 1002791, 1052161, 1082240};
return new int [] {};
}
}
+19 -32
View File
@@ -3,6 +3,7 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Ronan - added ores, reworked global loots
*/
public class Global extends GachaponItems {
@@ -10,50 +11,36 @@ public class Global extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int[] {
/* Gloves */ 1082002, 1082147, 1082148, 1082146, 1082145, 1082150,
/* Capes */ 1102040, 1102043, 1102087, 1102079, 1102080, 1102081, 1102082, 1102083, 1102053, 1102054,
1102055, 1102056, 1102176, 1102177, 1102178, 1102179, 1102000, 1102001, 1102002, 1102003,
1102004, 1102011, 1102012, 1102013, 1102014, 1102015, 1102016, 1102017, 1102018, 1102021,
1102022, 1102023, 1102024, 1102026, 1102027, 1102028,
/* Tube Eqp */ 1322026, 1322025, 1322024, 1322022, 1322021,
/* Umbrellas */ 1302026, 1302027, 1302028, 1302017,
/* Snowboards */ 1442017, 1442016, 1442014, 1442012,
/* Skis */ 1432017, 1432016, 1432015,
/* Beginner Eqp */ 1442018, 1422011,
/* Potions */ 2000004, 2000005, 2001002, 2001001, 2020012, 2020013, 2020014, 2020015, 2022182, 2022245,
2022284, 2022285, 2022439,
/* Other Scrolls */ 2049000, 2049001, 2049002, 2041058, 2040727,
/* 10% Scrolls */ 2041002, 2040402, 2040702, 2040805, 2040026, 2040031, 2040318, 2040323, 2040328, 2040419,
2040422, 2040427, 2040534, 2040619, 2040622, 2040627, 2040825, 2040925, 2040928, 2040933,
2040016,
/* 60% Scrolls */ 2040001, 2040321, 2040425, 2040625, 2040931, 2048013, 2040025, 2040326, 2040532, 2040824,
2048010, 2040029, 2040418, 2040618, 2040924, 2048011, 2040317, 2040421, 2040621, 2040927,
2048012,
/* 100% Scrolls */ 2040923, 2040027, 2040417, 2040617, 2040000, 2040202, 2040400, 2040512, 2040700, 2040803,
2041000, 2041012, 2048000, 2040926, 2040316, 2040420, 2040620, 2040003, 2040207, 2040414,
2040515, 2040703, 2040818, 2041003, 2041015, 2048003, 2040929, 2040319, 2040423, 2040623,
2040102, 2040300, 2040500, 2040600, 2040706, 2040900, 2041006, 2041018, 2040024, 2040324,
2040530, 2040823, 2040107, 2040312, 2040503, 2040614, 2040800, 2040918, 2041009, 2041021
/* Potions */
2000004, 2000005, 2001002, 2001001, 2020012, 2020013, 2020014, 2020015,
/* Ores */
4004000, 4004001, 4004002, 4004003, 4004004,
4006000, 4006001,
4010000, 4010001, 4010002, 4010003, 4010004, 4010005, 4010006, 4010007,
4020000, 4020001, 4020002, 4020003, 4020004, 4020005, 4020006, 4020007, 4020008
};
}
@Override
public int[] getUncommonItems() {
return new int[] {
/* Capes */ 1102180,
/* Potions */ 2022179, 2022273, 2022282, 2022283,
/* Scrolls */ 2049003,
/* Skis */ 1432018
/* Potions */
2022179, 2022273, 2022282, 2022283, 2022285, 2022245, 2022182,
/* Scrolls */
2049003
};
}
@Override
public int[] getRareItems() {
return new int[] {
/* Gloves */ 1082149,
/* Capes */ 1102041, 1102042, 1102084, 1102085,
/* Scrolls */ 2049100, 2340000,
/* Chairs */ 3010046, 3010047
/* Scrolls */
2049100, 2340000,
/* Chairs */
3010063, 3010064
};
}
+39 -18
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class Henesys extends GachaponItems {
@@ -10,31 +13,49 @@ public class Henesys extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
/* Common Eqps */ 1432009, 1302022, 1322027, 1062000, 1002033, 1092022, 1302021, 1322009, 1002012, 1322012,
/* Warrior Eqps */ 1312007, 1002093, 1051016, 1040030, 1060009, 1060000, 1082025, 1402002, 1092000, 1072041,
/* Mage Equips */ 1051023, 1002035, 1061028, 1040019, 1002152, 1002155, 1041018, 1050031, 1002102, 1082028,
/* Bowman Equips */ 1002010, 1002057, 1002112, 1002113, 1002114, 1002115, 1002116, 1002117, 1002118, 1002119,
1002120, 1002121, 1002135, 1002136, 1002137, 1002138, 1002139, 1002156, 1002157, 1002158,
1002159, 1002160, 1002161, 1002162, 1002163, 1002164, 1002165, 1002166, 1002167, 1002168,
1002169, 1002170, 1002211, 1002212, 1002213, 1002214, 1002267, 1002268, 1002269, 1002270,
1002275, 1002276, 1002277, 1002278, 1002286, 1002287, 1002288, 1002289, 1002402, 1002403,
1002404, 1002405, 1002406, 1002407, 1002408, 1002580, 1002749
};
/* Scroll */
2040001, 2041002, 2040702, 2043802, 2040402, 2043702, 2044813,
/* Useable Drops */
2000004, 2000005, 2020012, 2030007,
/* Common equipment */
1432009, 1302022, 1322021, 1302026, 1442017, 1082147, 1102043, 1322026, 1442016, 1402012, 1322025, 1322027, 1302027,
1312012, 1062000, 1332020, 1302028, 1372002, 1002033, 1092022, 1302021, 1322009, 1322024, 1082148, 1002012, 1322012,
1322022, 1002020, 1302013, 1082146, 1442014, 1002096, 1302017, 1442012,
/* Warrior equipment */
1092011, 1092014, 1302003, 1432001, 1312011, 1002088, 1041020, 1322015, 1442004, 1422008, 1302056, 1432000, 1442005,
/* Magician equipment */
1382001, 1041053, 1041029, 1050053, 1051032, 1050073, 1061036, 1002253, 1002034, 1051025, 1050067, 1051052, 1002072,
1002144, 1051054, 1050069, 1372007, 1050056, 1050074, 1002254, 1002274, 1002218, 1051055, 1382010, 1002246, 1050039,
1382007, 1372000, 1002013, 1050072, 1002036, 1002244, 1372008, 1382008, 1382011, 1092021, 1051034, 1050047, 1040019,
1041031, 1051033, 1002153, 1002252, 1051024, 1051053, 1050068, 1382003, 1382006, 1050055, 1051031, 1050025, 1002155,
1002245, 1372001,
/* Bowman equipment */
1452004, 1452023, 1060057, 1432001, 1040071, 1002137, 1462009, 1452017, 1040025, 1041027, 1452005, 1452007, 1061057,
/* Thief equipment */
1472006, 1472019, 1060084, 1472028, 1472004, 1002179, 1082074, 1472029, 1040100, 1332015, 1432001, 1040097, 1060071,
1472007, 1472002, 1051009, 1041044, 1041003, 1332016, 1472020, 1332003,
/* Pirate equipment */
1002622, 1082204, 1082213, 1082198, 1002631, 1052122, 1482012, 1052131, 1482007, 1482004, 1072318, 1492007
};
}
@Override
public int[] getUncommonItems() {
return new int[] {
/* 110 Equips */ 1002547
};
return new int[] {2040805, 1102041, 1102042, 1442018};
}
@Override
public int[] getRareItems() {
return new int[] {
/* Reverse Eqps */ 1002792,
1462052, 1462053, 1462054, 1462055,
};
return new int[] {};
}
}
+37 -99
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate equipment
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class KerningCity extends GachaponItems {
@@ -10,112 +13,47 @@ public class KerningCity extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
//warriorEquips = {
1002023, 1082001, 1041084, 1060017, 1422008,
1402018, 1060019, 1072047, 1040009, 1060060,
//magicianEquips = {
1050029, 1072045, 1050028, 1372001, 1051024,
1061049, 1072091, 1041030, 1041042, 1002036,
//bowmanEquips = {
1072103, 1072034, 1072069, 1062004, 1082050,
1040003, 1061064, 1040074, 1061051, 1040079,
//thiefEquips = {
1002107, 1002108, 1002109, 1002110, 1002111,
1002122, 1002123, 1002124, 1002125, 1002126,
1002127, 1002128, 1002129, 1002130, 1002131,
1002146, 1002147, 1002148, 1002149, 1002150,
1002171, 1002172, 1002173, 1002174, 1002175,
1002176, 1002177, 1002178, 1002179, 1002180,
1002181, 1002182, 1002183, 1002184, 1002185,
1002207, 1002208, 1002209, 1002210, 1002247,
1002248, 1002249, 1002281, 1002282, 1002283,
1002284, 1002285, 1002323, 1002324, 1002325,
1002326, 1002327, 1002328, 1002329, 1002330,
1002380, 1002381, 1002382, 1002383, 1002550,
1002577, 1002656, 1002750,
1040031, 1040032, 1040033, 1040034, 1040035,
1040042, 1040043, 1040044, 1040048, 1040049,
1040050, 1040057, 1040058, 1040059, 1040060,
1040061, 1040062, 1040063, 1040082, 1040083,
1040084, 1040094, 1040095, 1040096, 1040097,
1040098, 1040099, 1040100, 1040105, 1040106,
1040107, 1040108, 1040109, 1040110, 1040115,
1040116, 1040117, 1040118, 1041003, 1041036,
1041037, 1041038, 1041039, 1041040, 1041044,
1041045, 1041047, 1041048, 1041049, 1041050,
1041057, 1041058, 1041059, 1041060, 1041074,
1041075, 1041076, 1041077, 1041078, 1041079,
1041080, 1041094, 1041095, 1041096, 1041100,
1041101, 1041102, 1041103, 1041105, 1041106,
1041107, 1041115, 1041116, 1041117, 1041118,
1050096, 1050097, 1050098, 1050099, 1051006,
1051007, 1051008, 1051009, 1051090, 1051091,
1051092, 1051093, 1052072, 1052163,
1060021, 1060022, 1060023, 1060024, 1060025,
1060031, 1060032, 1060033, 1060037, 1060038,
1060039, 1060043, 1060044, 1060045, 1060046,
1060050, 1060051, 1060052, 1060071, 1060072,
1060073, 1060083, 1060084, 1060085, 1060086,
1060087, 1060088, 1060089, 1060093, 1060094,
1060095, 1060097, 1060098, 1060099, 1060104,
1060105, 1060106, 1060107, 1061003, 1061029,
1061030, 1061031, 1061032, 1061033, 1061037,
1061038, 1061040, 1061041, 1061042, 1061043,
1061044, 1061045, 1061046, 1061053, 1061054,
1061055, 1061056, 1061069, 1061070, 1061071,
1061076, 1061077, 1061078, 1061079, 1061093,
1061094, 1061095, 1061099, 1061100, 1061101,
1061102, 1061104, 1061105, 1061106, 1061114,
1061115, 1061116, 1061117, 1072022, 1072028,
1072029, 1072030, 1072031, 1072032, 1072033,
1072035, 1072036, 1072065, 1072066, 1072070,
1072071, 1072084, 1072085, 1072086, 1072087,
1072104, 1072105, 1072106, 1072107, 1072108,
1072109, 1072110, 1072128, 1072129, 1072130,
1072131, 1072150, 1072151, 1072152, 1072161,
1072162, 1072163, 1072171, 1072172, 1072173,
1072174, 1072192, 1072193, 1072194, 1072195,
1072213, 1072214, 1072215, 1072216, 1072272,
1072346, 1082029, 1082030,
1082031, 1082032, 1082033, 1082034, 1082037,
1082038, 1082039, 1082042, 1082043, 1082044,
1082045, 1082046, 1082047, 1082065, 1082066,
1082067, 1082074, 1082075, 1082076, 1082092,
1082093, 1082094, 1082095, 1082096, 1082097,
1082118, 1082119, 1082120, 1082135, 1082136,
1082137, 1082138, 1082142, 1082143, 1082144,
1082167, 1082242, 1092018, 1092019,
1092020, 1302001,
1312002, 1332000, 1332001, 1332002, 1332003,
1332004, 1332011, 1332012, 1332013, 1332014,
1332015, 1332018, 1332023, 1332024, 1332027,
1332031, 1332050, 1332052, 1332054,
1332067, 1332068, 1332069, 1332070, 1332071,
1332072, 1332077,
1472000, 1472001, 1472002,
1472003, 1472004, 1472005, 1472006, 1472007,
1472008, 1472009, 1472010, 1472011, 1472012,
1472013, 1472014, 1472015, 1472016, 1472017,
1472018, 1472019, 1472020, 1472021, 1472022,
1472023, 1472024, 1472025, 1472026, 1472027,
1472028, 1472029, 1472031, 1472033, 1472051,
1472052,
1472069, 1472072, 1472074,
1472075,
///pirateEquips = {
1082192, 1072288, 1492003, 1052113, 1052104,
1492002, 1052095, 1492001, 1002613, 1492004,
};
/* Scroll */
2041016, 2043302, 2040902, 2044804, 2044906,
/* Useable drop */
2000004, 2000005, 2022025, 2022027,
/* Common equipment */
1442013, 1432009, 1322021, 1050018, 1002392, 1002394, 1442004, 1372002, 1002418, 1002033, 1092008,
1082148, 1062001, 1302017, 1032023, 1102013, 1102040, 1002041, 1002097,
/* Warrior equipment */
1332026, 1051010, 1432001, 1422005, 1332019, 1302010, 1002056, 1060011, 1322011, 1432004, 1002028,
1051000, 1442007, 1302002,
/* Magician equipment */
1002037, 1002034, 1082020, 1050039, 1372000, 1002215, 1051034, 1040019, 1061034, 1382003, 1382006,
1050025,
/* Bowman equipment */
1002118, 1061081, 1452011, 1462012, 1452006, 1452007,
/* Thief equipment */
1472010, 1472029, 1041048, 1041095, 1060031, 1061033, 1041049, 1472011, 1040096, 1472033, 1332026,
1051006, 1082074, 1472025, 1061106, 1040084, 1332015, 1472000, 1332019, 1002183, 1002209, 1092020,
1332029, 1092019, 1061099, 1060106, 1040032, 1040059, 1332003, 1040060, 1060046, 1472005, 1332027,
/* Pirate equipment */
1082192, 1072288, 1492003, 1052113, 1052104,
1492002, 1052095, 1492001, 1002613, 1492004
};
}
@Override
public int[] getUncommonItems() {
return new int[] {1472053, 1332064, 1092050, 1472054};
return new int[] {2040805, 1082149, 1102041};
}
@Override
public int[] getRareItems() {
return new int[] {1472073, 1092049, 1002793, 1332079, 1072364, 1472062, 1332078, 1332080};
return new int[] {};
}
}
+56
View File
@@ -0,0 +1,56 @@
package server.gachapon;
/**
*
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class Ludibrium extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
/* Scroll */
2048000, 2040601, 2041019, 2041007, 2041016, 2041022, 2041001, 2041010, 2041013, 2041004, 2044701, 2043301, 2040301, 2048004, 2048001, 2040901, 2040701, 2040704, 2040707, 2040602, 2041020, 2041008, 2041017, 2041023, 2041002, 2041011, 2041014, 2041005, 2044702, 2043302, 2040302, 2040002, 2044402, 2048005, 2048002, 2040702, 2040705, 2040708, 2044302, 2043802, 2040402, 2043702, 2044811,
/* Useable drop */
2000004, 2000005, 4006000, 4006001,
/* Common equipment */
1032003, 1432009, 1302022, 1302029, 1102014, 1102018, 1312014, 1302026, 1102015, 1032011, 1312013, 1032008, 1032019, 1032007, 1332030, 1032020, 1032004, 1302027, 1032022, 1312012, 1032021, 1032006, 1302028, 1322003, 1032016, 1032015, 1302024, 1092008, 1032018, 1302021, 1032014, 1332021, 1322012, 1032005, 1032013, 1102012, 1302025, 1302013, 1032002, 1032001, 1032012, 1302017, 1032010, 1402014, 1102017, 1102013, 1442021, 1032009,
/* Beginner equipment */
1332021, 1422011,
/* Warrior equipment */
1402017, 1422005, 1002023, 1332016, 1432005,
/* Magician equipment */
1002037, 1002034, 1002064, 1002038, 1002013, 1002036, 1382011, 1002035, 1002065, 1382014, 1372001,
/* Bowman equipment */
1452026, 1002162, 1002164, 1462018, 1002165, 1452014, 1002163, 1452012, 1002161, 1452009, 1462007,
/* Thief Equipment */
1332022, 1002175, 1002172, 1002174, 1040096, 1472033, 1002173, 1332054, 1472054, 1002171, 1332016,
/* Pirate equipment */
1002646
};
}
@Override
public int[] getUncommonItems() {
return new int [] {2040805, 1002419, 1442018};
}
@Override
public int[] getRareItems() {
return new int [] {};
}
}
+45 -3
View File
@@ -21,6 +21,7 @@
*/
package server.gachapon;
import server.MapleItemInformationProvider;
import tools.Randomizer;
/**
@@ -46,9 +47,11 @@ public class MapleGachapon {
MUSHROOM_SHRINE(9100105, 90, 8, 2, new MushroomShrine()),
SHOWA_SPA_MALE(9100106, 90, 8, 2, new ShowaSpaMale()),
SHOWA_SPA_FEMALE(9100107, 90, 8, 2, new ShowaSpaFemale()),
LUDIBRIUM(9100108, 90, 8, 2, new Ludibrium()),
NEW_LEAF_CITY(9100109, 90, 8, 2, new NewLeafCity()),
EL_NATH(9100110, 90, 8, 2, new ElNath()),
NAUTILUS_HARBOR(9100117, 90, 8, 2, new NautilusHarbor());
private static final Gachapon[] values = Gachapon.values();
private GachaponItems gachapon;
@@ -71,8 +74,9 @@ public class MapleGachapon {
return 2; //Rare
} else if (chance > common) {
return 1; //Uncommon
}
return 0; //Common
} else {
return 0; //Common
}
}
public int [] getItems(int tier){
@@ -94,6 +98,44 @@ public class MapleGachapon {
}
return null;
}
public static String[] getLootInfo() {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
String[] strList = new String[values.length + 1];
String menuStr = "";
int j = 0;
for (Gachapon gacha : values) {
menuStr += "#L" + j + "#" + gacha.name() + "#l\r\n";
j++;
String str = "";
for (int i = 0; i < 3; i++) {
int[] gachaItems = gacha.getItems(i);
if (gachaItems.length > 0) {
str += (" #rTier " + i + "#k:\r\n");
for (int itemid : gachaItems) {
String itemName = ii.getName(itemid);
if (itemName == null) {
itemName = "MISSING NAME #" + itemid;
}
str += (" " + itemName + "\r\n");
}
str += "\r\n";
}
}
str += "\r\n";
strList[j] = str;
}
strList[0] = menuStr;
return strList;
}
}
public MapleGachaponItem process(int npcId) {
+37 -19
View File
@@ -2,39 +2,57 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class MushroomShrine extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int []{
1382011, 1332024, 1302022, 1302021, 1462006, 1402009, 1402010, 1322012, 1312013, 1472008,
1432008, 1050100, 1051098,
};
return new int [] {
/* Scroll */
2040305, 2040306, 2040308, 2044604, 2041039, 2041037, 2041035, 2041034, 2041041, 2040608, 2040605, 2040604, 2040611,
2040610, 2040813, 2040808, 2043004, 2040017, 2040015, 2040011, 2040013, 2040405, 2040406, 2040410, 2040511, 2040509,
2040508, 2040519, 2040521, 2040108, 2040904, 2040908, 2043104, 2044104, 2043005, 2043004, 2043006, 2044004, 2044205,
2043304, 2040607, 2040715, 2040713, 2044305, 2044904,
/* Common equipment */
1102040, 1002392, 1432009, 1002393, 1002394, 1082147, 1082148, 1032028, 1002585, 1002586, 1432013, 1022047, 1322027,
1012056, 1432018,
/* Beginner equipment */
1072264, 1072262, 1072263,
/* Warrior equipment */
1060074, 1322002, 1002340, 1442004, 1402037, 1422008, 1050022,
/* Mage equipment */
1382037, 1060014, 1051026, 1050056, 1050029, 1051030, 1382036, 1372032, 1041015, 1382015, 1372008, 1382008,
/* Bowman equipment */
1452018, 1041068, 1462007,
/* Thief equipment */
1060052, 1472013, 1002180, 1002170, 1060073, 1060099,
/* Pirate equipment */
1492004, 1492012, 1482009, 1072303, 1002637, 1052107, 1082189, 1052116, 1072309
};
}
@Override
public int[] getUncommonItems() {
//All Scrolls
return new int [] {
2043015, 2043017, 2043019, 2044000, 2044001, 2044002, 2044004, 2044005, 2044010, 2044012,
2044014, 2043200, 2043201, 2043202, 2043204, 2043205, 2043210, 2043212, 2043214, 2044200,
2044201, 2044202, 2044204, 2044205, 2044210, 2044212, 2044214, 2044300, 2044301, 2044302,
2044304, 2044305, 2044310, 2044312, 2044314, 2044400, 2044401, 2044402, 2044404, 2044405,
2044410, 2044412, 2044414,
2043800, 2043801, 2043802, 2043804, 2043805, 2043700, 2043701, 2043702, 2043704, 2043705,
2044605, 2044604, 2044602, 2044601, 2044600, 2044505, 2044504, 2044502, 2044501, 2044500,
2044700, 2044701, 2044702, 2044704, 2044705, 2043300, 2043301, 2043302, 2043304, 2043305,
2044800, 2044801, 2044802, 2044803, 2044804, 2044805, 2044807, 2044809, 2044900, 2044901,
2044902, 2044903, 2044904,
};
return new int [] {2040811, 2040810, 2040815, 1102041, 1102042, 1082149};
}
@Override
public int[] getRareItems() {
return new int [] {};
return new int [] {1102084, 3010019};
}
}
+44 -27
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate items
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class NautilusHarbor extends GachaponItems {
@@ -10,40 +13,54 @@ public class NautilusHarbor extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int[] {
/* Warrior Equips*/ 1060017, 1302008, 1002055, 1041064, 1072127, 1072047, 1072002, 1040028, 1072041, 1092000,
/* Mage Equips */ 1050010, 1072006, 1061022, 1051003, 1072074, 1050008, 1082053, 1051026, 1382015, 1002013,
/* Bowman Equips */ 1082048, 1041056, 1002157, 1462048, 1041054, 1061061, 1002161, 1002162, 1002158, 1002120,
/* Thief Equips */ 1040061, 1072031, 1051009, 1072036, 1002182, 1060073, 1472013, 1472009, 1002184, 1061055,
/* Pirate Equips */ 1002610, 1002616, 1002622, 1002628, 1002634, 1002640, 1002646, 1052095, 1052101, 1052107,
1052113, 1052119, 1052125, 1052131, 1072285, 1072291, 1072297, 1072303, 1072309, 1072315,
1082180, 1082186, 1082192, 1082198, 1082204, 1082210, 1482001, 1482003, 1482005, 1482007,
1482009, 1482011, 1492000, 1492002, 1492004, 1492006, 1492008, 1492010, 1492012, 1002613,
1002619, 1002625, 1002631, 1002637, 1002643, 1052098, 1052104, 1052110, 1052116, 1052122,
1052128, 1072288, 1072294, 1072300, 1072306, 1072312, 1072318, 1072338, 1082183, 1082189,
1082195, 1082201, 1082207, 1082213, 1482000, 1482002, 1482004, 1482006, 1482008, 1482010,
1482012, 1492001, 1492003, 1492005, 1492007, 1492009, 1492011,
/*KnucklerScrolls*/ 2044800, 2044801, 2044802, 2044803, 2044804, 2044805, 2044806, 2044807, 2044808, 2044809,
/* Gun Scrolls */ 2044900, 2044901, 2044902, 2044903, 2044904,
/* Bullets */ 2330005, 2330004
};
/* Scroll */
2040605, 2040626, 2040609, 2040607, 2041029, 2041027, 2041031, 2041037, 2041033, 2041039, 2041041, 2041035,
2040809, 2040813, 2040015, 2040009, 2040011, 2040013, 2040509, 2040521, 2040519, 2040507, 2040905, 2040909,
2040907, 2040713, 2040715, 2040717, 2040405, 2040409, 2040407, 2040426, 2040303, 2040307, 2040309, 2044505,
2044705, 2044605, 2043305, 2043105, 2043205, 2043005, 2043007, 2044405, 2044305, 2043805, 2044105, 2044205,
2044005, 2043705, 2044901,
/* Useable drop */
2012000, 2000004, 2020008, 2000005, 2012002, 2101004, 2101005, 2101002, 2101003, 4006000,
/* Warrior equipment */
1092014, 1402017,
/* Magician equipment */
1002037, 1002034, 1002064, 1002038, 1382037, 1372000, 1002013, 1002035, 1002065, 1382000,
/* Bowman equipment */
1452018,
/* Thief equipment */
1472010, 1002175, 1472017, 1472025,
/* Pirate equipment */
1002610, 1002616, 1002622, 1002628, 1002634, 1002640, 1002646, 1052095, 1052101, 1052107,
1052113, 1052119, 1052125, 1052131, 1072285, 1072291, 1072297, 1072303, 1072309, 1072315,
1082180, 1082186, 1082192, 1082198, 1082204, 1082210, 1482001, 1482003, 1482005, 1482007,
1482009, 1482011, 1492000, 1492002, 1492004, 1492006, 1492008, 1492010, 1492012, 1002613,
1002619, 1002625, 1002631, 1002637, 1002643, 1052098, 1052104, 1052110, 1052116, 1052122,
1052128, 1072288, 1072294, 1072300, 1072306, 1072312, 1072318, 1072338, 1082183, 1082189,
1082195, 1082201, 1082207, 1082213, 1482000, 1482002, 1482004, 1482006, 1482008, 1482010,
1482012, 1492001, 1492003, 1492005, 1492007, 1492009, 1492011,
/* Knuckler Scrolls */
2044800, 2044801, 2044802, 2044803, 2044804, 2044805, 2044806, 2044807, 2044808, 2044809,
/* Gun Scrolls */
2044900, 2044901, 2044902, 2044903, 2044904
};
}
@Override
public int[] getUncommonItems() {
return new int[] {
/* Pirate Equips */ 1072321, 1082216, 1482013, 1002649, 1052134, 1492013,
/* Mastery Books */ 2290097, 2290098, 2290099, 2290100, 2290101, 2290102, 2290103, 2290104, 2290105, 2290106,
2290107, 2290108, 2290110, 2290111, 2290111, 2290113, 2290114, 2290115, 2290116, 2290117,
2290118, 2290119, 2290120, 2290121, 2290122, 2290123, 2290124
};
return new int[] {2040811, 2040815, 2101001};
}
@Override
public int[] getRareItems() {
return new int[] {
/* Pirate Equips */ 1082243, 1482024, 1002794, 1052164, 1072365,
1482034, 1492025
};
return new int[] {};
}
}
+33 -44
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate equipment
* @author Ronan - parsed MapleSEA loots, thanks Vcoc for noticing somewhat unbalanced loots in NLC
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class NewLeafCity extends GachaponItems {
@@ -10,57 +13,43 @@ public class NewLeafCity extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int[] {
/* Warrior Equips*/ 1002338, 1002339, 1002340, 1002377, 1002378, 1002379, 1002528, 1002529, 1002530, 1002531,
1002532, 1040111, 1040112, 1040113, 1040120, 1040121, 1040122, 1041119, 1041120, 1041121,
1041122, 1041123, 1041124, 1050080, 1050081, 1050082, 1050083, 1051077, 1051078, 1051079,
1051080, 1060100, 1060101, 1060102, 1060109, 1060110, 1060111, 1061118, 1061119, 1061120,
1061121, 1061122, 1061123, 1072196, 1072197, 1072198, 1072210, 1072211, 1072212, 1072220,
1072221, 1072222, 1082114, 1082115, 1082116, 1082117, 1082128, 1082129, 1082130, 1082139,
1082140, 1082141, 1092023, 1092024, 1092025, 1092026, 1092027, 1092028, 1092036, 1092037,
1092038, 1092061, 1302018, 1302023, 1302056, 1312011, 1312015, 1312030, 1322020, 1322028,
1322029, 1322045, 1402004, 1402005, 1402015, 1402016, 1402035,
1412009, 1412010, 1412021, 1412040, 1422012, 1422013, 1422027, 1432010,
1432011, 1432030, 1432056, 1442019, 1442020, 1442044,
/* Mage Equips */ 1002271, 1002272, 1002273, 1002274, 1002363, 1002364, 1002365, 1002366, 1002398, 1002399,
1002400, 1002401, 1050072, 1050073, 1050074, 1050092, 1050093, 1050094, 1050095, 1050102,
1050103, 1050104, 1050105, 1051056, 1051057, 1051058, 1051094, 1051095, 1051096, 1051097,
1051101, 1051102, 1051103, 1051104, 1072177, 1072178, 1072179, 1072206, 1072207, 1072208,
1072209, 1072223, 1072224, 1072225, 1072226, 1082121, 1082122, 1082123, 1082131, 1082132,
1082133, 1082134, 1082151, 1082152, 1082153, 1082154, 1372009, 1372010, 1372016, 1382008,
1382010, 1382016, 1382035, 1382056, 1382060,
/* Bowman Equips */ 1002275, 1002276, 1002277, 1002275, 1002278, 1002402, 1002403, 1002404, 1002405, 1002406,
1002407, 1002408, 1050075, 1050076, 1050077, 1050078, 1050088, 1050089, 1050090, 1050091,
1050106, 1050107, 1050108, 1002275, 1051066, 1051067, 1051068, 1051069, 1051082, 1051083,
1051084, 1051085, 1051105, 1051106, 1051107, 1072182, 1072183, 1072184, 1072185, 1072203,
1072204, 1072205, 1072227, 1072228, 1072229, 1082109, 1082110, 1082111, 1082112, 1082125,
1082126, 1082127, 1082158, 1082159, 1082160, 1452012, 1452013, 1452014, 1452015, 1452017,
1452019, 1452020, 1452021, 1452025, 1452026, 1452060, 1462010, 1452017, 1462011, 1462012,
1462013, 1462015, 1462016, 1462017, 1462018, 1462021, 1462022, 1462049,
/* Thief Equips */ 1002323, 1002324, 1002325, 1002326, 1002327, 1002328, 1002329, 1002330, 1002380, 1002381,
1002382, 1002383, 1040108, 1040109, 1040110, 1040115, 1040117, 1040118, 1041105, 1041106,
1041107, 1041115, 1041116, 1041117, 1041118, 1050096, 1050097, 1050098, 1050099, 1051090,
1051091, 1051092, 1051093, 1060097, 1060098, 1060099, 1060104, 1060105, 1060106, 1060107,
1061104, 1061105, 1061106, 1061114, 1061115, 1061116, 1061117, 1072172, 1072173, 1072174,
1072192, 1072193, 1072194, 1072195, 1072213, 1072214, 1072215, 1072216, 1082118, 1082119,
1082120, 1082135, 1082136, 1082137, 1082138, 1082143, 1082144, 1092050, 1332023, 1332027,
1332052, 1332069, 1332072, 1472031, 1472033, 1472053,
/* Pirate Equips */ 1002640, 1002643, 1002646, 1052125, 1052128, 1052131, 1072312, 1072315, 1072318, 1082207,
1082210, 1082213, 1482010, 1482011, 1002640, 1482012, 1492010, 1492011, 1492012
};
/* Scroll */
2040406, 2040408, 2040404, 2040411, 2040409, 2044405, 2040610, 2040607, 2040812, 2041039, 2041040, 2041034,
2041030, 2041037, 2043105, 2043304, 2040103, 2040605, 2040611, 2043004, 2043204, 2044204, 2044005, 2040521,
2040510, 2043304, 2040908, 2040904, 2040907, 2040809, 2040812, 2040014, 2040714, 2040712, 2044004, 2043705,
2044505, 2040519, 2040204, 2040104, 2040109, 2044704, 2040906, 2044304, 2043007, 2040307, 2040304, 2040309,
2040208, 2040209, 2044803,
/* Common equipment */
1102040, 1102086, 1082145, 1032027, 1082146, 1002395, 1002083, 1002392, 1002587, 1022047,
/* Warrior equipment */
1312002, 1432013, 1060030, 1422008, 1050022, 1050011, 1402013, 1402017, 1302012,
/* Mage equipment */
1002074, 1050029, 1040093, 1050056, 1050039, 1382008,
/* Bowman equipment */
1002159, 1061051, 1040023,
/* Thief equipment */
1061054, 1061106, 1002249, 1040084, 1060052, 1472054,
/* Pirate equipment */
1002640, 1002643, 1002646, 1052125, 1052128, 1052131, 1072312, 1072315, 1072318, 1082207, 1082210, 1082213,
1482010, 1482011, 1002640, 1482012, 1492010, 1492011, 1492012
};
}
@Override
public int[] getUncommonItems() {
return new int[] {
2022179
};
return new int[] {2022284, 2040811, 2040815, 2040811, 1102041, 1102042, 1082149};
}
@Override
public int[] getRareItems() {
return new int[] {
2049100
};
return new int[] {};
}
}
+35 -115
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate equipment
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class Perion extends GachaponItems {
@@ -10,128 +13,45 @@ public class Perion extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
//warriorEquips = {
1002002, 1002003, 1002004, 1002005, 1002007,
1002009, 1002011, 1002021, 1002022, 1002023,
1002024, 1002025, 1002027, 1002028, 1002029,
1002030, 1002039, 1002040, 1002043, 1002044,
1002045, 1002046, 1002047, 1002048, 1002049,
1002050, 1002051, 1002052, 1002055, 1002056,
1002058, 1002059, 1002084, 1002085, 1002086,
1002087, 1002088, 1002091, 1002092, 1002093,
1002094, 1002095, 1002098, 1002099, 1002100,
1002101, 1002338, 1002339, 1002340, 1002377,
1002378, 1002379, 1002528, 1002529, 1002530,
1002531, 1002532, 1002551, 1002578,
1002790, 1040000, 1040009, 1040012, 1040015,
1040016, 1040021, 1040026, 1040028, 1040029,
1040030, 1040037, 1040038, 1040039, 1040040,
1040041, 1040085, 1040086, 1040087, 1040088,
1040089, 1040090, 1040091, 1040092, 1040093,
1040102, 1040103, 1040104, 1040111, 1040112,
1040113, 1040120, 1040121, 1040122, 1041014,
1041019, 1041020, 1041021, 1041022, 1041023,
1041024, 1041064, 1041084, 1041085, 1041086,
1041087, 1041088, 1041089, 1041091, 1041092,
1041093, 1041097, 1041098, 1041099, 1041119,
1041120, 1041121, 1041122, 1041123, 1041124,
1050000, 1050005, 1050006, 1050007, 1050011,
1050021, 1050022, 1050080, 1050081, 1050082,
1050083, 1051000, 1051001, 1051010, 1051011,
1051012, 1051013, 1051014, 1051015, 1051016,
1051077, 1051078, 1051079, 1051080, 1052075,
1052160, 1060000, 1060008, 1060009,
1060010, 1060011, 1060016, 1060017, 1060018,
1060019, 1060020, 1060027, 1060028, 1060029,
1060030, 1060060, 1060074, 1060075, 1060076,
1060077, 1060078, 1060079, 1060080, 1060081,
1060082, 1060090, 1060091, 1060092, 1060100,
1060101, 1060102, 1060109, 1060110, 1060111,
1061014, 1061015, 1061016, 1061017, 1061018,
1061019, 1061020, 1061023, 1061083, 1061084,
1061085, 1061086, 1061087, 1061088, 1061090,
1061091, 1061092, 1061096, 1061097, 1061098,
1061118, 1061119, 1061120, 1061121, 1061122,
1061123, 1072000, 1072002, 1072003, 1072007,
1072009, 1072011, 1072039, 1072040, 1072041,
1072046, 1072047, 1072050, 1072051, 1072052,
1072053, 1072112, 1072113, 1072126, 1072127,
1072132, 1072133, 1072134, 1072135, 1072147,
1072148, 1072149, 1072154, 1072155, 1072156,
1072168, 1072196, 1072197, 1072198, 1072210,
1072211, 1072212, 1072220, 1072221, 1072222,
1072273, 1082000, 1082001,
1082003, 1082004, 1082005, 1082006, 1082007,
1082008, 1082009, 1082010, 1082011, 1082023,
1082024, 1082025, 1082035, 1082036, 1082059,
1082060, 1082061, 1082103, 1082104, 1082105,
1082114, 1082115, 1082116, 1082117, 1082128,
1082129, 1082130, 1082139, 1082140, 1082141,
1082168, 1082218, 1082239, 1092000,
1092001, 1092002, 1092004, 1092005, 1092006,
1092007, 1092009, 1092010, 1092011, 1092012,
1092013, 1092014, 1092015, 1092016, 1092017,
1092023, 1092024, 1092025, 1092026, 1092027,
1092028, 1092036, 1092037, 1092038,
1092060, 1092061, 1302002, 1302004, 1302005,
1302008, 1302009, 1302010, 1302011, 1302012,
1302015, 1302018, 1302019, 1302023, 1302037,
1302056, 1302059, 1302068, 1302079,
1312001, 1312003, 1312005,
1312006, 1312007, 1312008, 1312009, 1312010,
1312011, 1312015, 1312016, 1312030, 1312031,
1322014, 1322015,
1322016, 1322017, 1322018, 1322019, 1322020,
1322028, 1322029, 1322045, 1322052, 1322059,
1322062, 1402000,
1402002, 1402003, 1402004, 1402005, 1402006,
1402007, 1402008, 1402011, 1402012, 1402015,
1402016, 1402017, 1402018, 1402035, 1402036,
1412000, 1412002,
1412003, 1412004, 1412005, 1412006, 1412007,
1412008, 1412009, 1412010, 1412012, 1412021,
1412026, 1412032, 1412040,
1422001, 1422002, 1422003, 1422005,
1422007, 1422008, 1422009, 1422010, 1422012,
1422013, 1422027, 1422028, 1422030, 1422031,
1422038, 1422044, 1432002, 1432003,
1432004, 1432005, 1432006, 1432007, 1432010,
1432011, 1432030, 1432038, 1432045,
1432048, 1432056, 1442001, 1442002,
1442003, 1442005, 1442006, 1442007, 1442008,
1442009, 1442010, 1442019, 1442020, 1442044,
1442045, 1442060, 1442067,
//magicianEquips = {
1002075, 1050035, 1002151, 1051023, 1072089,
1072115, 1072076, 1040018, 1382017, 1072072,
//bowmanEquips = {
1040011, 1041061, 1040076, 1040003, 1072059,
1082017, 1002114, 1041066, 1060057, 1040007,
//thiefEquips = {
1072032, 1472011, 1082037, 1040059, 1040084,
1040043, 1072085, 1040031, 1332031, 1082075,
//pirateEquips = {
1482001, 1492002, 1052113, 1002616, 1072294,
1492004, 1482006, 1082192, 1082189, 1082195,
};
/* Scrolls */
2044907, 2044802,
/* Useable drop */
2000004, 2000005,
/* Common equipment */
1402010, 1302022, 1002060, 1322021, 1082147, 1002006, 1002026, 1002392, 1322025, 1322027, 1102000, 1082150,
1332020, 1322007, 1302021, 1002395, 1082148, 1322012, 1302017, 1322010, 1032000, 1102013, 1002097,
/* Warrior equipment */
1322020, 1312007, 1312008, 1302004, 1312006, 1082036, 1082117, 1061088, 1302008, 1422005, 1002048, 1061087,
1302018, 1322017, 1422001, 1040103, 1060077, 1002022, 1002050, 1442000, 1432030, 1402037, 1092002, 1041092,
1050006, 1432004, 1061019, 1432000, 1060009, 1051000, 1002021, 1322014, 1432005,
/* Magician equipment */
1051032, 1040018, 1051027, 1372007, 1050049, 1002036, 1382012, 1002217, 1051033, 1382006, 1050048,
/* Bowman equipment */
1061061, 1060062, 1040075, 1462013, 1041065, 1452006,
/* Thief equipment */
1040095, 1060084, 1002182, 1041049, 1002247, 1332024, 1332009, 1060024, 1332015, 1041060, 1061032, 1041074,
1041003, 1332016, 1472020, 1332003, 1041059,
/* Pirate equipment */
1482001, 1492002, 1052113, 1002616, 1072294, 1492004, 1482006, 1082192, 1082189, 1082195
};
}
@Override
public int[] getUncommonItems() {
//All Scrolls
return new int [] {
2043000, 2043001, 2043002, 2043004, 2043005, 2043006, 2043007, 2043008, 2043009, 2043010,
2043015, 2043017, 2043019, 2044000, 2044001, 2044002, 2044004, 2044005, 2044010, 2044012,
2044014, 2043200, 2043201, 2043202, 2043204, 2043205, 2043210, 2043212, 2043214, 2044200,
2044201, 2044202, 2044204, 2044205, 2044210, 2044212, 2044214, 2044300, 2044301, 2044302,
2044304, 2044305, 2044310, 2044312, 2044314, 2044400, 2044401, 2044402, 2044404, 2044405,
2044410, 2044412, 2044414,
};
return new int [] {1082149, 1002391, 1002419, 1102041};
}
@Override
public int[] getRareItems() {
return new int [] {1402037, 1402049, 1072361, 1402048, 1402049, 1402050, 1402051};
return new int [] {};
}
}
+37 -4
View File
@@ -2,24 +2,57 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots src: http://maplesecrets.blogspot.com/2011/06/gachapon-showa-towns-sauna-female-spa.html
*/
public class ShowaSpaFemale extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {};
return new int [] {
/* Scroll */
2048005, 2048002, 2043202, 2044602, 2043214, 2041307, 2041035, 2044104, 2044505, 2044305, 2043304, 2041309,
2044010, 2044803, 2044814, 2044904, 2044902, 2044901,
/* Useable drop */
2022016, 2000005, 2022025, 2022027,
/* Common equipment */
1402000, 1402013, 1002418, 1022047, 1082145, 1082147, 1082146, 1082178, 1082175,
/* Common setup */
3010073, 3010099,
/* Warrior equipment */
1422013, 1432030,
/* Magician equipment */
1372002, 1382003,
/* Bowman equipment */
1040023,
/* Thief equipment */
1332003, 1002209,
/* Pirate equipment */
1082198, 1082213, 1482007, 1492004, 1002646
};
}
@Override
public int[] getUncommonItems() {
return new int [] {};
return new int [] {2040916, 1102042};
}
@Override
public int[] getRareItems() {
return new int [] {1022082, 1022060};
return new int [] {};
}
}
+39 -4
View File
@@ -2,24 +2,59 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots src: http://maplesecrets.blogspot.com/2011/05/gachapon-showa-towns-sauna.html
*/
public class ShowaSpaMale extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {};
return new int [] {
/* Scroll */
2048005, 2048002, 2043202, 2044602, 2043214, 2041307, 2041035, 2044104, 2044505, 2044305, 2043304, 2044902,
2044901, 2044811, 2044903, 2044804,
/* Useable drop */
2022016, 2000005, 2022025, 2022027,
/* Common equipment */
1332020, 1312004, 1332032, 1322023, 1322026, 1322022, 1322012, 1302014, 1302049, 1302017, 1332007, 1432009,
1432016, 1432017, 1432009, 1402013, 1402044, 1442014, 1442017, 1442016, 1442025, 1002418, 1082178, 1082179,
1082148, 1032027, 1032032, 1102028, 1102086,
/* Common setup */
3010073, 3010111,
/* Warrior equipment */
1412005, 1402048, 1402049, 1322011, 1302003, 1302004, 1302008,
/* Magician equipment */
1372000, 1372009, 1372001, 1372011, 1382006, 1382014,
/* Bowman equipment */
1452018, 1452006, 1452008, 1452005, 1462002, 1462007, 1462003, 1002169,
/* Thief equipment */
1472023, 1332012, 1332017, 1332022, 1332006, 1332029, 1040097,
/* Pirate equipment */
1052107, 1082204, 1072318, 1002637, 1482009, 1492007
};
}
@Override
public int[] getUncommonItems() {
return new int [] {};
return new int [] {2040916, 1102042};
}
@Override
public int[] getRareItems() {
return new int [] {1022082, 1022060};
return new int [] {};
}
}
+37 -84
View File
@@ -2,7 +2,10 @@ package server.gachapon;
/**
*
* @author Alan (SharpAceX)
* @author Alan (SharpAceX) - gachapon source classes stub & pirate equipment
* @author Ronan - parsed MapleSEA loots
*
* MapleSEA-like loots thanks to AyumiLove, src: https://ayumilovemaple.wordpress.com/maplestory-gachapon-guide/
*/
public class Sleepywood extends GachaponItems {
@@ -10,97 +13,47 @@ public class Sleepywood extends GachaponItems {
@Override
public int[] getCommonItems() {
return new int [] {
//warriorEquips = {
1002022, 1002024, 1002028, 1002029, 1002030,
1002045, 1002046, 1002084, 1002085, 1002086,
1002091, 1002094, 1002095, 1002100, 1002101,
1040087, 1040088, 1040089, 1040090, 1040091,
1040092, 1040093, 1040102, 1040103, 1040104,
1041087, 1041088, 1041089, 1041091, 1041092,
1041093, 1041097, 1041098, 1041099, 1060076,
1060077, 1060078, 1060079, 1060080, 1060081,
1060082, 1060090, 1060091, 1060092, 1061086,
1061087, 1061088, 1061090, 1061091, 1061092,
1061096, 1061097, 1061098, 1072132, 1072133,
1072134, 1072135, 1072147, 1072148, 1072149,
1072154, 1072155, 1072156, 1082009, 1082010,
1082011, 1082059, 1082060, 1082061, 1082103,
1082104, 1082105, 1082218, 1092004, 1092009,
1092010, 1092011, 1092015, 1092016, 1092017,
1302010, 1302011, 1302012, 1302015, 1302019,
1302037, 1302079, 1312008, 1312009,
1312010, 1322017, 1322018, 1322019, 1322059,
1402003, 1402011, 1402012, 1402017, 1412003,
1412007, 1412008, 1412032, 1422005, 1422009,
1422010, 1432004, 1432006, 1432007, 1432045,
1442005, 1442008, 1442010, 1442060,
//magicianEquips = {
1002215, 1002216, 1002217, 1002218, 1002242,
1002243, 1002244, 1002245, 1002246, 1002252,
1002253, 1002254, 1050045, 1050046, 1050047,
1050048, 1050049, 1050053, 1050054, 1050055,
1050056, 1050067, 1050068, 1050069, 1050070,
1051030, 1051031, 1051032, 1051033, 1051034,
1051044, 1051045, 1051046, 1051047, 1051052,
1051053, 1051054, 1051055, 1072136, 1072137,
1072138, 1072139, 1072140, 1072141, 1072142,
1072143, 1072157, 1072158, 1072159, 1072160,
1082080, 1082081, 1082082, 1082086, 1082087,
1082088, 1082098, 1082099, 1082100, 1372007,
1372008, 1372011, 1372014, 1372015, 1372035,
1372036, 1372037, 1372038, 1382001, 1382006,
1382007, 1382011, 1382014, 1382041,
//bowmanEquips = {
1002211, 1002212, 1002213, 1002214, 1002267,
1002268, 1002269, 1002270, 1002286, 1002287,
1002288, 1002289, 1002749, 1050051, 1050052,
1050058, 1050059, 1050060, 1050061, 1050062,
1050063, 1050064, 1051037, 1051038, 1051039,
1051041, 1051042, 1051043, 1051062, 1051063,
1051064, 1051065, 1072122, 1072123, 1072124,
1072125, 1072144, 1072145, 1072146, 1072164,
1072165, 1072166, 1072167, 1072345, 1082083,
1082084, 1082085, 1082089, 1082090, 1082091,
1082106, 1082107, 1082108, 1452004, 1452008,
1452009, 1452010, 1452011, 1452018, 1452023,
1452052, 1462006, 1462007, 1462008, 1462009,
1462046,
//thiefEquips = {
1002207, 1002208, 1002209, 1002210, 1002247,
1002248, 1002249, 1002281, 1002282, 1002283,
1002284, 1002285, 1002656, 1002750, 1040094,
1040095, 1040096, 1040097, 1040098, 1040099,
1040100, 1040105, 1040106, 1040107, 1041077,
1041078, 1041079, 1041080, 1041094, 1041095,
1041096, 1041100, 1041101, 1041102, 1041103,
1060083, 1060084, 1060085, 1060086, 1060087,
1060088, 1060089, 1060093, 1060094, 1060095,
1061076, 1061077, 1061078, 1061079, 1061093,
1061094, 1061095, 1061099, 1061100, 1061101,
1061102, 1072128, 1072129, 1072130, 1072131,
1072150, 1072151, 1072152, 1072161, 1072162,
1072163, 1072346, 1082065, 1082066, 1082067,
1082092, 1082093, 1082094, 1082095, 1082096,
1082097, 1332003, 1332015, 1332018, 1332024,
1332054, 1332064, 1472018, 1472019, 1472020,
1472021, 1472022, 1472023, 1472024, 1472025,
1472026, 1472027, 1472028, 1472029, 1472054,
1472062,
//pirateEquips = {
1002631, 1002634, 1002637, 1052116, 1052119,
1052122, 1072303, 1072306, 1072309, 1082198,
1082201, 1082204, 1482007, 1482008, 1482009,
};
/* Scroll */
2048003, 2048000, 2040601, 2044501, 2041019, 2041016, 2041022, 2041010, 2041013, 2043301, 2040301, 2040801, 2040001,
2040004, 2043101, 2043201, 2043001, 2040504, 2040501, 2048004, 2048001, 2044401, 2040901, 2040701, 2040704, 2040707,
2044301, 2043801, 2044101, 2044201, 2044001, 2040602, 2044502, 2041020, 2041017, 2041023, 2041014, 2041005, 2044702,
2044602, 2043302, 2040302, 2040802, 2040005, 2043202, 2043002, 2040505, 2040502, 2048005, 2048002, 2044402, 2040902,
2040702, 2040705, 2040708, 2044302, 2043802, 2044202, 2044002, 2044801, 2044903, 2044814,
/* Useable drop */
2012000, 2012003, 2020007, 2000004, 2012001, 2020008, 2070006, 2020012, 2000005, 2030007, 2012002, 2002001, 2070005,
/* Common equipment */
1032003, 1432009, 1102014, 1102018, 1002392, 1322026, 1032022, 1312012, 1332020, 1092030, 1032016, 1032015, 1032014,
1322024, 1032013, 1322022, 1102016, 1032012, 1032023, 1402014, 1032000, 1102017,
/* Warrior equipment */
1402017, 1051010, 1432011, 1442006, 1322002, 1422004, 1432010, 1051011, 1060018, 1432000, 1422003, 1412003, 1422000,
/* Magician equipment */
1002034, 1002142, 1382010, 1002013, 1382008, 1382011, 1050047, 1002065,
/* Bowman equipment */
1452003, 1002165, 1040068, 1462013, 1462011, 1462012, 1061050, 1462010, 1002161,
/* Thief equipment */
1332022, 1002175, 1040042, 1472004, 1040057, 1332031, 1332023, 1332010, 1002171, 1060046,
/* Pirate equipment */
1002631, 1002634, 1002637, 1052116, 1052119, 1052122, 1072303, 1072306, 1072309, 1082198, 1082201, 1082204, 1482007,
1482008, 1482009
};
}
@Override
public int[] getUncommonItems() {
return new int [] {};
return new int [] {2040804, 2040817, 2040805, 2340000, 1082149, 1442018};
}
@Override
public int[] getRareItems() {
return new int [] {1302068, 2070007, 1022082, 1022058};
return new int [] {};
}
}
+13
View File
@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package server.life;
import java.awt.Point;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@@ -216,6 +217,14 @@ public class MapleLifeFactory {
stats.setBanishInfo(new BanishInfo(MapleDataTool.getString("banMsg", banishData), MapleDataTool.getInt("banMap/0/field", banishData, -1), MapleDataTool.getString("banMap/0/portal", banishData, "sp")));
}
int noFlip = MapleDataTool.getInt("noFlip", monsterInfoData, 0);
if (noFlip > 0) {
Point origin = MapleDataTool.getPoint("stand/0/origin", monsterData, null);
if (origin != null) {
stats.setFixedStance(origin.getX() < 1 ? 5 : 4); // fixed left/right
}
}
return new Pair<>(stats, attackInfos);
}
@@ -269,6 +278,10 @@ public class MapleLifeFactory {
public static MapleNPC getNPC(int nid) {
return new MapleNPC(nid, new MapleNPCStats(MapleDataTool.getString(nid + "/name", npcStringData, "MISSINGNO")));
}
public static String getNPCDefaultTalk(int nid) {
return MapleDataTool.getString(nid + "/d0", npcStringData, "(...)");
}
public static class BanishInfo {
+172 -153
View File
@@ -56,7 +56,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import net.server.audit.locks.MonitoredReentrantLock;
import net.server.channel.Channel;
import net.server.world.World;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
import scripting.event.EventInstanceManager;
@@ -64,6 +63,7 @@ import server.TimerManager;
import server.life.MapleLifeFactory.BanishInfo;
import server.maps.MapleMap;
import server.maps.MapleMapObjectType;
import tools.IntervalBuilder;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
@@ -72,6 +72,7 @@ import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
import net.server.coordinator.MapleMonsterAggroCoordinator;
import server.MapleStatEffect;
import server.loot.MapleLootManager;
import server.maps.MapleSummon;
public class MapleMonster extends AbstractLoadedMapleLife {
@@ -94,12 +95,11 @@ public class MapleMonster extends AbstractLoadedMapleLife {
private Map<Pair<Integer, Integer>, Integer> skillsUsed = new HashMap<>();
private Set<Integer> usedAttacks = new HashSet<>();
private Set<Integer> calledMobOids = null;
private int calledMobCount = 0;
private WeakReference<MapleMonster> callerMob = new WeakReference<>(null);
private List<Integer> stolenItems = new ArrayList<>();
private int team;
private int parentMobOid = 0;
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
private final HashMap<Integer, AtomicLong> takenDamage = new HashMap<>();
private Runnable removeAfterAction = null;
private boolean availablePuppetUpdate = true;
@@ -160,13 +160,17 @@ public class MapleMonster extends AbstractLoadedMapleLife {
this.parentMobOid = parentMobId;
}
public int countAvailableMobSummons(int limit, int skillLimit) { // limit prop for summons has another conotation, found thanks to MedicOP
public int countAvailableMobSummons(int summonsSize, int skillLimit) { // limit prop for summons has another conotation, found thanks to MedicOP
int summonsCount;
Set<Integer> calledOids = this.calledMobOids;
if(calledOids != null) {
limit -= calledOids.size();
summonsCount = calledOids.size();
} else {
summonsCount = 0;
}
return Math.min(limit, skillLimit - this.calledMobCount);
return Math.min(summonsSize, skillLimit - summonsCount);
}
public void addSummonedMob(MapleMonster mob) {
@@ -178,7 +182,6 @@ public class MapleMonster extends AbstractLoadedMapleLife {
calledOids.add(mob.getObjectId());
mob.setSummonerMob(this);
this.calledMobCount += 1;
}
private void removeSummonedMob(int mobOid) {
@@ -442,7 +445,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
dispatchMonsterDamaged(from, trueDamage);
if (!takenDamage.containsKey(from.getId())) {
takenDamage.put(from.getId(), new AtomicInteger(trueDamage));
takenDamage.put(from.getId(), new AtomicLong(trueDamage));
} else {
takenDamage.get(from.getId()).addAndGet(trueDamage);
}
@@ -475,98 +478,85 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return takenDamage.containsKey(chr.getId());
}
private void distributeExperienceToParty(int pid, float exp, int mostDamageCid, int minThresholdLevel, int killerLevel, Set<MapleCharacter> underleveled, Map<MapleCharacter, Float> partyExpReward, Set<MapleCharacter> participants) {
MapleCharacter pchar = getMap().getAnyCharacterFromParty(pid); // thanks G h o s t, Alfred, Vcoc, BHB for poiting out a bug in detecting party members after membership transactions in a party took place
List<MapleCharacter> members;
if (pchar != null) {
members = pchar.getPartyMembersOnSameMap();
} else {
members = new LinkedList<>();
private static boolean isWhiteExpGain(MapleCharacter chr, Map<Integer, Float> personalRatio, double sdevRatio) {
Float pr = personalRatio.get(chr.getId());
if (pr == null) {
return false;
}
List<MapleCharacter> expSharers = new LinkedList<>();
int expParticipantsMaxLevel = 1;
boolean hasMostDamageCid = false;
for (MapleCharacter mc : members) {
if (mc.getId() == mostDamageCid) {
hasMostDamageCid = true;
}
if (mc.getLevel() >= minThresholdLevel) { //NO EXP WILL BE GIVEN for those who are underleveled!
if (Math.abs(killerLevel - mc.getLevel()) < ServerConstants.MIN_RANGELEVEL_TO_EXP_LEECH) {
// thanks Thora for pointing out leech level limitation
if (expParticipantsMaxLevel < mc.getLevel() && participants.contains(mc)) {
expParticipantsMaxLevel = mc.getLevel();
}
expSharers.add(mc);
}
} else {
underleveled.add(mc);
}
}
int numExpSharers = expSharers.size();
// PARTY BONUS: 2p -> +5% , 3p -> +6.25% , 4p -> +7.5% , 5p -> +8.75% , 6p -> +10%
// MOST DAMAGE BONUS: 1.5x bonus
// thanks Crypter for reporting an insufficiency on party exp bonuses
final float partyModifier = numExpSharers <= 1 ? 0.0f : 0.05f + (0.0125f * (numExpSharers - 1));
final float mostDamageModifier = hasMostDamageCid ? 1.5f : 1.0f;
final float partyExp = exp * partyModifier * mostDamageModifier;
for (MapleCharacter mc : expSharers) {
float levelPenaltyModifier = (float) Math.min(1.0, Math.sqrt(((float) mc.getLevel()) / expParticipantsMaxLevel));
partyExpReward.put(mc, partyExp * levelPenaltyModifier);
}
}
private int calcThresholdLevel(boolean isPqMob) {
if(!ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE) {
return 0;
} else if (isPqMob) {
double thresholdLevel = getLevel();
thresholdLevel /= 32.55916838;
thresholdLevel = Math.log(thresholdLevel) / 0.02058204546;
return (int) Math.ceil(thresholdLevel);
} else {
return getLevel() - (!isBoss() ? ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 2 * ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN);
}
return pr >= sdevRatio;
}
private static double calcExperienceStandDevThreshold(Map<MapleCharacter, Float> personalExpReward, float exp2) {
private static double calcExperienceStandDevThreshold(List<Float> entryExpRatio, int totalEntries) {
float avgExpReward = 0.0f;
for (Float exp : personalExpReward.values()) {
for (Float exp : entryExpRatio) {
avgExpReward += exp;
}
// thanks Simon for finding an issue with solo party player gaining yellow EXP when soloing mobs
float realAvgExpReward = avgExpReward;
avgExpReward -= exp2; // clear out the 20% raw exp from last hitting
avgExpReward /= personalExpReward.size();
avgExpReward /= totalEntries;
float varExpReward = 0.0f;
for (Float exp : personalExpReward.values()) {
varExpReward += Math.pow(exp - realAvgExpReward, 2);
for (Float exp : entryExpRatio) {
varExpReward += Math.pow(exp - avgExpReward, 2);
}
varExpReward /= personalExpReward.size();
varExpReward /= entryExpRatio.size();
return avgExpReward + Math.sqrt(varExpReward);
}
private void propagateExperienceGains(Map<MapleCharacter, Float> personalExpReward, Map<MapleCharacter, Float> partyExpReward, float exp2) {
Set<MapleCharacter> expRewardPlayers = new HashSet<>(personalExpReward.keySet());
expRewardPlayers.addAll(partyExpReward.keySet());
private void distributePlayerExperience(MapleCharacter chr, float exp, float partyBonusMod, int totalPartyLevel, boolean highestPartyDamager, boolean whiteExpGain) {
float playerExp = (ServerConstants.EXP_SPLIT_COMMON_MOD * chr.getLevel()) / totalPartyLevel;
if (highestPartyDamager) playerExp += ServerConstants.EXP_SPLIT_MVP_MOD;
double sdevExp = calcExperienceStandDevThreshold(personalExpReward, exp2);
for (MapleCharacter chr : expRewardPlayers) {
Float personalExp = personalExpReward.get(chr);
Float partyExp = partyExpReward.get(chr);
playerExp *= exp;
float bonusExp = partyBonusMod * playerExp;
this.giveExpToCharacter(chr, playerExp, bonusExp, whiteExpGain);
}
private void distributePartyExperience(Map<MapleCharacter, Long> partyParticipation, float expPerDmg, Set<MapleCharacter> underleveled, Map<Integer, Float> personalRatio, double sdevRatio) {
IntervalBuilder leechInterval = new IntervalBuilder();
leechInterval.addInterval(this.getLevel() - ServerConstants.EXP_SPLIT_LEVEL_INTERVAL, this.getLevel() + ServerConstants.EXP_SPLIT_LEVEL_INTERVAL);
long maxDamage = 0, partyDamage = 0;
MapleCharacter participationMvp = null;
for (Entry<MapleCharacter, Long> e : partyParticipation.entrySet()) {
long entryDamage = e.getValue();
partyDamage += entryDamage;
this.giveExpToCharacter(chr, personalExp, partyExp, personalExp != null && personalExp >= sdevExp);
if (maxDamage < entryDamage) {
maxDamage = entryDamage;
participationMvp = e.getKey();
}
// thanks Thora for pointing out leech level limitation
int chrLevel = e.getKey().getLevel();
leechInterval.addInterval(chrLevel - ServerConstants.EXP_SPLIT_LEECH_INTERVAL, chrLevel + ServerConstants.EXP_SPLIT_LEECH_INTERVAL);
}
List<MapleCharacter> expMembers = new LinkedList<>();
int totalPartyLevel = 0;
// thanks G h o s t, Alfred, Vcoc, BHB for poiting out a bug in detecting party members after membership transactions in a party took place
for (MapleCharacter member : partyParticipation.keySet().iterator().next().getPartyMembersOnSameMap()) {
if (!leechInterval.inInterval(member.getLevel())) {
underleveled.add(member);
continue;
}
totalPartyLevel += member.getLevel();
expMembers.add(member);
}
int membersSize = expMembers.size();
float participationExp = partyDamage * expPerDmg;
// thanks Crypter for reporting an insufficiency on party exp bonuses
float partyBonusMod = (membersSize > 1) ? 0.05f * membersSize : 0.0f;
for (MapleCharacter mc : expMembers) {
distributePlayerExperience(mc, participationExp, partyBonusMod, totalPartyLevel, mc == participationMvp, isWhiteExpGain(mc, personalRatio, sdevRatio));
}
}
@@ -575,84 +565,89 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return;
}
Map<MapleCharacter, Float> personalExpReward = new HashMap<>();
Map<MapleCharacter, Float> partyExpReward = new HashMap<>();
Map<MapleParty, Map<MapleCharacter, Long>> partyExpDist = new HashMap<>();
Map<MapleCharacter, Long> soloExpDist = new HashMap<>();
Map<Integer, MapleCharacter> mapPlayers = map.getMapAllPlayers();
int totalEntries = 0; // counts "participant parties", players who no longer are available in the map is an "independent party"
for (Entry<Integer, AtomicLong> e : takenDamage.entrySet()) {
MapleCharacter chr = mapPlayers.get(e.getKey());
if (chr != null) {
long damage = e.getValue().longValue();
MapleParty p = chr.getParty();
if (p != null) {
Map<MapleCharacter, Long> partyParticipation = partyExpDist.get(p);
if (partyParticipation == null) {
partyParticipation = new HashMap<>(6);
partyExpDist.put(p, partyParticipation);
totalEntries += 1;
}
partyParticipation.put(chr, damage);
} else {
soloExpDist.put(chr, damage);
totalEntries += 1;
}
} else {
totalEntries += 1;
}
}
long totalDamage = maxHpPlusHeal.get();
int mobExp = getExp();
float expPerDmg = ((float) mobExp) / totalDamage;
Map<Integer, Float> personalRatio = new HashMap<>();
List<Float> entryExpRatio = new LinkedList<>();
for (Entry<MapleCharacter, Long> e : soloExpDist.entrySet()) {
float ratio = ((float) e.getValue()) / totalDamage;
personalRatio.put(e.getKey().getId(), ratio);
entryExpRatio.add(ratio);
}
for (Map<MapleCharacter, Long> m : partyExpDist.values()) {
float ratio = 0.0f;
for (Entry<MapleCharacter, Long> e : m.entrySet()) {
float chrRatio = ((float) e.getValue()) / totalDamage;
personalRatio.put(e.getKey().getId(), chrRatio);
ratio += chrRatio;
}
entryExpRatio.add(ratio);
}
double sdevRatio = calcExperienceStandDevThreshold(entryExpRatio, totalEntries);
// GMS-like player and party split calculations found thanks to Russt, KaidaTan, Dusk, AyumiLove. Src: https://ayumilovemaple.wordpress.com/maplestory_calculator_formula/
Set<MapleCharacter> underleveled = new HashSet<>();
for (Entry<MapleCharacter, Long> chrParticipation : soloExpDist.entrySet()) {
float exp = chrParticipation.getValue() * expPerDmg;
MapleCharacter chr = chrParticipation.getKey();
distributePlayerExperience(chr, exp, 0.0f, chr.getLevel(), true, isWhiteExpGain(chr, personalRatio, sdevRatio));
}
for (Map<MapleCharacter, Long> partyParticipation : partyExpDist.values()) {
distributePartyExperience(partyParticipation, expPerDmg, underleveled, personalRatio, sdevRatio);
}
EventInstanceManager eim = getMap().getEventInstance();
int minThresholdLevel = calcThresholdLevel(eim != null), killerLevel = Integer.MAX_VALUE;
int exp = getExp();
long totalHealth = maxHpPlusHeal.get();
Map<Integer, Float> expDist = new HashMap<>();
Map<Integer, Float> partyExp = new HashMap<>();
float exp8perHp = (0.8f * exp) / totalHealth; // 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(), exp8perHp * damage.getValue().get());
}
Set<MapleCharacter> underleveled = new HashSet<>();
Collection<MapleCharacter> mapChrs = map.getCharacters();
for (MapleCharacter mc : mapChrs) {
Float mcExp = expDist.remove(mc.getId());
if (mcExp != null) {
float xp = mcExp;
boolean isKiller = (mc.getId() == killerId);
if (isKiller) {
if (eim != null) {
eim.monsterKilled(mc, this);
}
killerLevel = mc.getLevel();
xp += exp2;
}
if(mc.getLevel() >= minThresholdLevel) {
//NO EXP WILL BE GIVEN for those who are underleveled!
personalExpReward.put(mc, xp);
MapleParty p = mc.getParty();
if (p != null) { // for party bonus exp
int pID = p.getId();
float pXP = xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, pXP);
}
} else {
underleveled.add(mc);
}
if (eim != null) {
MapleCharacter chr = mapPlayers.get(killerId);
if (chr != null) {
eim.monsterKilled(chr, this);
}
}
if(!expDist.isEmpty()) { // locate on world server the partyid of the missing characters
World wserv = map.getWorldServer();
for (Entry<Integer, Float> ed : expDist.entrySet()) {
boolean isKiller = (ed.getKey() == killerId);
float xp = ed.getValue();
if (isKiller) {
xp += exp2;
}
Integer pID = wserv.getCharacterPartyid(ed.getKey());
if (pID != null) {
float pXP = xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, pXP);
}
}
}
Set<MapleCharacter> participants = personalExpReward.keySet();
int mostDamageCid = this.getHighestDamagerId();
for (Entry<Integer, Float> party : partyExp.entrySet()) {
distributeExperienceToParty(party.getKey(), party.getValue(), mostDamageCid, minThresholdLevel, killerLevel, underleveled, partyExpReward, participants);
}
for(MapleCharacter mc : underleveled) {
mc.showUnderleveledInfo(this);
}
propagateExperienceGains(personalExpReward, partyExpReward, killerLevel != Integer.MAX_VALUE ? exp2 : 0.0f);
}
private float getStatusExpMultiplier(MapleCharacter attacker) {
@@ -718,6 +713,20 @@ public class MapleMonster extends AbstractLoadedMapleLife {
attacker.updateQuestMobCount(getId());
}
}
public List<MonsterDropEntry> retrieveRelevantDrops() {
Map<Integer, MapleCharacter> pchars = map.getMapAllPlayers();
List<MapleCharacter> lootChars = new LinkedList<>();
for (Integer cid : takenDamage.keySet()) {
MapleCharacter chr = pchars.get(cid);
if (chr != null && chr.isLoggedinWorld()) {
lootChars.add(chr);
}
}
return MapleLootManager.retrieveRelevantDrops(this.getId(), lootChars);
}
public MapleCharacter killBy(final MapleCharacter killer) {
distributeExperience(killer != null ? killer.getId() : 0);
@@ -904,9 +913,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
public int getHighestDamagerId() {
int curId = 0;
int curDmg = 0;
long curDmg = 0;
for (Entry<Integer, AtomicInteger> damage : takenDamage.entrySet()) {
for (Entry<Integer, AtomicLong> damage : takenDamage.entrySet()) {
curId = damage.getValue().get() >= curDmg ? damage.getKey() : curId;
curDmg = damage.getKey() == curId ? damage.getValue().get() : curDmg;
}
@@ -1012,6 +1021,16 @@ public class MapleMonster extends AbstractLoadedMapleLife {
return stats.isMobile();
}
@Override
public boolean isFacingLeft() {
int fixedStance = stats.getFixedStance(); // thanks DimDiDima for noticing inconsistency on some AOE mobskills
if (fixedStance != 0) {
return Math.abs(fixedStance) % 2 == 1;
}
return super.isFacingLeft();
}
public ElementalEffectiveness getElementalEffectiveness(Element e) {
statiLock.lock();
try {
+9
View File
@@ -50,6 +50,7 @@ public class MapleMonsterStats {
public BanishInfo banish = null;
public List<loseItem> loseItem = null;
public selfDestruction selfDestruction = null;
public int fixedStance = 0;
public boolean friendly;
public void setChange(boolean change) {
@@ -339,6 +340,14 @@ public class MapleMonsterStats {
this.MDDamage = MDDamage;
}
public int getFixedStance() {
return this.fixedStance;
}
public void setFixedStance(int stance) {
this.fixedStance = stance;
}
public MapleMonsterStats copy() {
MapleMonsterStats copy = new MapleMonsterStats();
try {
+6 -7
View File
@@ -197,7 +197,7 @@ public class MobSkill {
}
break;
case 131: // Mist
monster.getMap().spawnMist(new MapleMist(calculateBoundingBox(monster.getPosition(), true), monster, this), x * 100, false, false, false);
monster.getMap().spawnMist(new MapleMist(calculateBoundingBox(monster.getPosition(), monster.isFacingLeft()), monster, this), x * 100, false, false, false);
break;
case 132:
disease = MapleDisease.CONFUSE;
@@ -253,9 +253,9 @@ public class MobSkill {
List<Integer> summons = getSummons();
int summonLimit = monster.countAvailableMobSummons(summons.size(), skillLimit);
if (summonLimit >= 1) {
Collections.shuffle(summons);
boolean bossRushMap = GameConstants.isBossRush(map.getId());
Collections.shuffle(summons);
for (Integer mobId : summons.subList(0, summonLimit)) {
MapleMonster toSpawn = MapleLifeFactory.getMonster(mobId);
if (toSpawn != null) {
@@ -412,12 +412,11 @@ public class MobSkill {
int multiplier = facingLeft ? 1 : -1;
Point mylt = new Point(lt.x * multiplier + posFrom.x, lt.y + posFrom.y);
Point myrb = new Point(rb.x * multiplier + posFrom.x, rb.y + posFrom.y);
return new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
Rectangle bounds = new Rectangle(mylt.x, mylt.y, myrb.x - mylt.x, myrb.y - mylt.y);
return bounds;
}
private List<MapleMapObject> getObjectsInRange(MapleMonster monster, MapleMapObjectType objectType) {
List<MapleMapObjectType> objectTypes = new ArrayList<MapleMapObjectType>();
objectTypes.add(objectType);
return monster.getMap().getMapObjectsInBox(calculateBoundingBox(monster.getPosition(), monster.isFacingLeft()), objectTypes);
return monster.getMap().getMapObjectsInBox(calculateBoundingBox(monster.getPosition(), monster.isFacingLeft()), Collections.singletonList(objectType));
}
}
+15 -15
View File
@@ -23,7 +23,7 @@ import client.MapleCharacter;
import java.util.LinkedList;
import java.util.List;
import server.MapleItemInformationProvider;
//import server.MapleItemInformationProvider;
import server.life.MapleMonsterInformationProvider;
import server.life.MonsterDropEntry;
import server.quest.MapleQuest;
@@ -34,7 +34,7 @@ import server.quest.MapleQuest;
*/
public class MapleLootManager {
private static boolean isRelevantDrop(MonsterDropEntry dropEntry, List<MapleCharacter> partyMembers, List<MapleLootInventory> partyInv) {
private static boolean isRelevantDrop(MonsterDropEntry dropEntry, List<MapleCharacter> players, List<MapleLootInventory> playersInv) {
int qStartAmount = 0, qCompleteAmount = 0;
MapleQuest quest = MapleQuest.getInstance(dropEntry.questid);
if (quest != null) {
@@ -42,12 +42,12 @@ public class MapleLootManager {
qCompleteAmount = quest.getCompleteItemAmountNeeded(dropEntry.itemId);
}
boolean restricted = MapleItemInformationProvider.getInstance().isPickupRestricted(dropEntry.itemId);
for (int i = 0; i < partyMembers.size(); i++) {
MapleLootInventory chrInv = partyInv.get(i);
//boolean restricted = MapleItemInformationProvider.getInstance().isPickupRestricted(dropEntry.itemId);
for (int i = 0; i < players.size(); i++) {
MapleLootInventory chrInv = playersInv.get(i);
if (dropEntry.questid > 0) {
int qItemAmount, chrQuestStatus = partyMembers.get(i).getQuestStatus(dropEntry.questid);
int qItemAmount, chrQuestStatus = players.get(i).getQuestStatus(dropEntry.questid);
if (chrQuestStatus == 0) {
qItemAmount = qStartAmount;
} else if (chrQuestStatus != 1) {
@@ -63,12 +63,12 @@ public class MapleLootManager {
int qItemStatus = chrInv.hasItem(dropEntry.itemId, qItemAmount);
if (qItemStatus == 2) {
continue;
} else if (restricted && qItemStatus == 1) {
} /*else if (restricted && qItemStatus == 1) {
continue;
}
} else if (restricted && chrInv.hasItem(dropEntry.itemId, 1) > 0) {
}*/
} /*else if (restricted && chrInv.hasItem(dropEntry.itemId, 1) > 0) { // thanks Conrad, Legalize for noticing eligible loots not being available to drop for non-killer parties
continue;
}
}*/
return true;
}
@@ -76,19 +76,19 @@ public class MapleLootManager {
return false;
}
public static List<MonsterDropEntry> retrieveRelevantDrops(int monsterId, List<MapleCharacter> partyMembers) {
public static List<MonsterDropEntry> retrieveRelevantDrops(int monsterId, List<MapleCharacter> players) {
List<MonsterDropEntry> loots = MapleMonsterInformationProvider.getInstance().retrieveEffectiveDrop(monsterId);
if(loots.isEmpty()) return loots;
List<MapleLootInventory> partyInv = new LinkedList<>();
for(MapleCharacter chr : partyMembers) {
List<MapleLootInventory> playersInv = new LinkedList<>();
for(MapleCharacter chr : players) {
MapleLootInventory lootInv = new MapleLootInventory(chr);
partyInv.add(lootInv);
playersInv.add(lootInv);
}
List<MonsterDropEntry> effectiveLoot = new LinkedList<>();
for(MonsterDropEntry mde : loots) {
if(isRelevantDrop(mde, partyMembers, partyInv)) {
if(isRelevantDrop(mde, players, playersInv)) {
effectiveLoot.add(mde);
}
}
+73
View File
@@ -22,6 +22,7 @@
package server.maps;
import java.awt.Point;
import java.util.Collection;
import tools.Pair;
import server.MaplePortal;
@@ -39,6 +40,8 @@ public class MapleDoor {
private MaplePortal townPortal;
private MapleMap target;
private Pair<String, Integer> posStatus = null;
private long deployTime;
private boolean active;
private MapleDoorObject townDoor;
private MapleDoorObject areaDoor;
@@ -55,6 +58,8 @@ public class MapleDoor {
if(posStatus == null) {
this.town = this.target.getReturnMap();
this.townPortal = getTownDoorPortal(owner.getDoorSlot());
this.deployTime = System.currentTimeMillis();
this.active = true;
if(townPortal != null) {
this.areaDoor = new MapleDoorObject(ownerId, town, target, townPortal.getId(), targetPosition, townPortal.getPosition());
@@ -83,6 +88,57 @@ public class MapleDoor {
}
}
private void broadcastRemoveDoor(MapleCharacter owner) {
MapleDoorObject areaDoor = this.getAreaDoor();
MapleDoorObject townDoor = this.getTownDoor();
MapleMap target = this.getTarget();
MapleMap town = this.getTown();
Collection<MapleCharacter> targetChars = target.getCharacters();
Collection<MapleCharacter> townChars = town.getCharacters();
target.removeMapObject(areaDoor);
town.removeMapObject(townDoor);
for (MapleCharacter chr : targetChars) {
areaDoor.sendDestroyData(chr.getClient());
}
for (MapleCharacter chr : townChars) {
townDoor.sendDestroyData(chr.getClient());
}
owner.removePartyDoor(false);
if (this.getTownPortal().getId() == 0x80) {
for (MapleCharacter chr : townChars) {
MapleDoor door = chr.getMainTownDoor();
if (door != null) {
townDoor.sendSpawnData(chr.getClient());
}
}
}
}
public static void attemptRemoveDoor(final MapleCharacter owner) {
final MapleDoor destroyDoor = owner.getPlayerDoor();
if (destroyDoor != null && destroyDoor.dispose()) {
long effectTimeLeft = 3000 - destroyDoor.getElapsedDeployTime(); // portal deployment effect duration
if (effectTimeLeft > 0) {
MapleMap town = destroyDoor.getTown();
town.getChannelServer().registerOverallAction(town.getId(), new Runnable() {
@Override
public void run() {
destroyDoor.broadcastRemoveDoor(owner); // thanks BHB88 for noticing doors crashing players when instantly cancelling buff
}
}, effectTimeLeft);
} else {
destroyDoor.broadcastRemoveDoor(owner);
}
}
}
private MaplePortal getTownDoorPortal(int doorid) {
return town.getDoorPortal(doorid);
}
@@ -114,4 +170,21 @@ public class MapleDoor {
public Pair<String, Integer> getDoorStatus() {
return posStatus;
}
public long getElapsedDeployTime() {
return System.currentTimeMillis() - deployTime;
}
private boolean dispose() {
if (active) {
active = false;
return true;
} else {
return false;
}
}
public boolean isActive() {
return active;
}
}
+12 -7
View File
@@ -100,15 +100,20 @@ public class MapleDoorObject extends AbstractMapleMapObject {
@Override
public void sendSpawnData(MapleClient client) {
sendSpawnData(client, true);
}
public void sendSpawnData(MapleClient client, boolean launched) {
MapleCharacter chr = client.getPlayer();
if (from.getId() == chr.getMapId()) {
MapleParty party = chr.getParty();
if (party != null && (ownerId == chr.getId() || party.getMemberById(ownerId) != null)) {
client.announce(MaplePacketCreator.partyPortal(this.getFrom().getId(), this.getTo().getId(), this.toPosition()));
if (this.getFrom().getId() == chr.getMapId()) {
if (chr.getParty() != null && (this.getOwnerId() == chr.getId() || chr.getParty().getMemberById(this.getOwnerId()) != null)) {
chr.announce(MaplePacketCreator.partyPortal(this.getFrom().getId(), this.getTo().getId(), this.toPosition()));
}
chr.announce(MaplePacketCreator.spawnPortal(this.getFrom().getId(), this.getTo().getId(), this.toPosition()));
if (!this.inTown()) {
chr.announce(MaplePacketCreator.spawnDoor(this.getOwnerId(), this.getPosition(), launched));
}
client.announce(MaplePacketCreator.spawnPortal(this.getFrom().getId(), this.getTo().getId(), this.toPosition()));
if(!this.inTown()) client.announce(MaplePacketCreator.spawnDoor(this.getOwnerId(), this.getPosition(), true));
}
}
+1 -2
View File
@@ -238,8 +238,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
}
}
private static boolean canBuy(MapleClient c, Item newItem) {
System.out.println(newItem.getPet().getName());
private static boolean canBuy(MapleClient c, Item newItem) { // thanks xiaokelvin (Conrad) for noticing a leaked test code here
return MapleInventoryManipulator.checkSpace(c, newItem.getItemId(), newItem.getQuantity(), newItem.getOwner()) && MapleInventoryManipulator.addFromDrop(c, newItem, false);
}
+19 -15
View File
@@ -85,8 +85,6 @@ import server.life.MonsterDropEntry;
import server.life.MonsterGlobalDropEntry;
import server.life.SpawnPoint;
import scripting.event.EventInstanceManager;
import server.expeditions.MapleExpedition;
import server.expeditions.MapleExpeditionType;
import server.life.MaplePlayerNPC;
import server.life.MonsterListener;
import server.partyquest.GuardianSpawnPoint;
@@ -744,7 +742,7 @@ public class MapleMap {
final List<MonsterDropEntry> dropEntry = new ArrayList<>();
final List<MonsterDropEntry> visibleQuestEntry = new ArrayList<>();
final List<MonsterDropEntry> otherQuestEntry = new ArrayList<>();
sortDropEntries(ServerConstants.USE_SPAWN_RELEVANT_LOOT ? chr.retrieveRelevantDrops(mob.getId()) : mi.retrieveEffectiveDrop(mob.getId()), dropEntry, visibleQuestEntry, otherQuestEntry, chr);
sortDropEntries(ServerConstants.USE_SPAWN_RELEVANT_LOOT ? mob.retrieveRelevantDrops() : mi.retrieveEffectiveDrop(mob.getId()), dropEntry, visibleQuestEntry, otherQuestEntry, chr);
registerMobItemDrops(droptype, mobpos, chRate, pos, dropEntry, visibleQuestEntry, otherQuestEntry, globalEntry, chr, mob);
}
@@ -1281,6 +1279,15 @@ public class MapleMap {
return character;
}
public Map<Integer, MapleCharacter> getMapAllPlayers() {
Map<Integer, MapleCharacter> pchars = new HashMap<>();
for (MapleCharacter chr : this.getAllPlayers()) {
pchars.put(chr.getId(), chr);
}
return pchars;
}
public List<MapleCharacter> getPlayersInRange(Rectangle box, List<MapleCharacter> targets) {
List<MapleCharacter> character = new LinkedList<>();
chrRLock.lock();
@@ -2131,18 +2138,7 @@ public class MapleMap {
spawnAndAddRangedMapObject(door, new DelayedPacketCreation() {
@Override
public void sendPackets(MapleClient c) {
if (door.getFrom().getId() == c.getPlayer().getMapId()) {
if (c.getPlayer().getParty() != null && (door.getOwnerId() == c.getPlayer().getId() || c.getPlayer().getParty().getMemberById(door.getOwnerId()) != null)) {
c.announce(MaplePacketCreator.partyPortal(door.getFrom().getId(), door.getTo().getId(), door.toPosition()));
}
c.announce(MaplePacketCreator.spawnPortal(door.getFrom().getId(), door.getTo().getId(), door.toPosition()));
if (!door.inTown()) {
c.announce(MaplePacketCreator.spawnDoor(door.getOwnerId(), door.getPosition(), false));
}
}
c.announce(MaplePacketCreator.enableActions());
door.sendSpawnData(c, false);
}
}, new SpawnCondition() {
@Override
@@ -3735,6 +3731,14 @@ public class MapleMap {
}
}
public void mobMpRecovery() {
for (MapleMonster mob : this.getAllMonsters()) {
if (mob.isAlive()) {
mob.heal(0, mob.getLevel());
}
}
}
public final int getNumPlayersInArea(final int index) {
return getNumPlayersInRect(getArea(index));
}
+30 -134
View File
@@ -23,23 +23,18 @@ package server.maps;
import java.awt.Point;
import java.awt.Rectangle;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import provider.MapleData;
import provider.MapleDataProvider;
import provider.MapleDataProviderFactory;
import provider.MapleDataTool;
import server.PortalFactory;
import server.life.AbstractLoadedMapleLife;
@@ -54,40 +49,17 @@ import tools.StringUtil;
public class MapleMapFactory {
private static Map<Integer, Float> mapRecoveryRate = new HashMap<>();
private MapleDataProvider source;
private MapleData nameData;
private EventInstanceManager event;
private Map<Integer, MapleMap> maps = new HashMap<>();
private ReadLock mapsRLock;
private WriteLock mapsWLock;
private int channel, world;
public MapleMapFactory(EventInstanceManager eim, MapleDataProvider source, MapleDataProvider stringSource, int world, int channel) {
this.source = source;
this.nameData = stringSource.getData("Map.img");
this.world = world;
this.channel = channel;
this.event = eim;
ReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_FACTORY);
this.mapsRLock = rrwl.readLock();
this.mapsWLock = rrwl.writeLock();
private static Map<Integer, Float> mapRecoveryRateCache = new HashMap<>();
private static MapleData nameData;
private static MapleDataProvider mapSource;
static {
nameData = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz")).getData("Map.img");
mapSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz"));
}
public MapleMap resetMap(int mapid) {
mapsWLock.lock();
try {
maps.remove(Integer.valueOf(mapid));
} finally {
mapsWLock.unlock();
}
return getMap(mapid);
}
private void loadLifeFromWz(MapleMap map, MapleData mapData) {
private static void loadLifeFromWz(MapleMap map, MapleData mapData) {
for (MapleData life : mapData.getChildByPath("life")) {
life.getName();
String id = MapleDataTool.getString(life.getChildByPath("id"));
@@ -115,7 +87,7 @@ public class MapleMapFactory {
}
}
private void loadLifeFromDb(MapleMap map) {
private static void loadLifeFromDb(MapleMap map) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM plife WHERE map = ? and world = ?");
@@ -148,7 +120,7 @@ public class MapleMapFactory {
}
}
private void loadLifeRaw(MapleMap map, int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide, int mobTime, int team) {
private static void loadLifeRaw(MapleMap map, int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide, int mobTime, int team) {
AbstractLoadedMapleLife myLife = loadLife(id, type, cy, f, fh, rx0, rx1, x, y, hide);
if (myLife instanceof MapleMonster) {
MapleMonster monster = (MapleMonster) myLife;
@@ -166,30 +138,17 @@ public class MapleMapFactory {
}
}
private synchronized MapleMap loadMapFromWz(int mapid, Integer omapid, boolean cache) {
public static MapleMap loadMapFromWz(int mapid, int world, int channel, EventInstanceManager event) {
MapleMap map;
if (cache) {
mapsRLock.lock();
try {
map = maps.get(omapid);
} finally {
mapsRLock.unlock();
}
if (map != null) {
return map;
}
}
String mapName = getMapName(mapid);
MapleData mapData = source.getData(mapName); // source.getData issue with giving nulls in rare ocasions found thanks to MedicOP
MapleData mapData = mapSource.getData(mapName); // source.getData issue with giving nulls in rare ocasions found thanks to MedicOP
MapleData infoData = mapData.getChildByPath("info");
String link = MapleDataTool.getString(infoData.getChildByPath("link"), "");
if (!link.equals("")) { //nexon made hundreds of dojo maps so to reduce the size they added links.
mapName = getMapName(Integer.parseInt(link));
mapData = source.getData(mapName);
mapData = mapSource.getData(mapName);
}
float monsterRate = 0;
MapleData mobRate = infoData.getChildByPath("mobRate");
@@ -288,7 +247,7 @@ public class MapleMapFactory {
try {
Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM playernpcs WHERE map = ? AND world = ?")) {
ps.setInt(1, omapid);
ps.setInt(1, mapid);
ps.setInt(2, world);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
@@ -352,12 +311,12 @@ public class MapleMapFactory {
}
}
try {
map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(omapid)), ""));
map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(omapid)), ""));
map.setMapName(MapleDataTool.getString("mapName", nameData.getChildByPath(getMapStringName(mapid)), ""));
map.setStreetName(MapleDataTool.getString("streetName", nameData.getChildByPath(getMapStringName(mapid)), ""));
} catch (Exception e) {
if (omapid / 1000 != 1020) { // explorer job introducion scenes
if (mapid / 1000 != 1020) { // explorer job introduction scenes
e.printStackTrace();
System.err.println("Not found mapid " + omapid);
System.err.println("Not found mapid " + mapid);
}
map.setMapName("");
@@ -365,8 +324,8 @@ public class MapleMapFactory {
}
map.setClock(mapData.getChildByPath("clock") != null);
map.setEverlast(infoData.getChildByPath("everlast") != null);
map.setTown(infoData.getChildByPath("town") != 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);
map.setHPDec(MapleDataTool.getIntConvert("decHP", infoData, 0));
map.setHPDecProtect(MapleDataTool.getIntConvert("protectItem", infoData, 0));
map.setForcedReturnMap(MapleDataTool.getInt(infoData.getChildByPath("forcedReturn"), 999999999));
@@ -378,7 +337,7 @@ public class MapleMapFactory {
MapleData recData = infoData.getChildByPath("recovery");
if (recData != null) {
float recoveryRate = MapleDataTool.getFloat(recData);
mapRecoveryRate.put(mapid, recoveryRate);
mapRecoveryRateCache.put(mapid, recoveryRate);
}
HashMap<Integer, Integer> backTypes = new HashMap<>();
@@ -397,46 +356,10 @@ public class MapleMapFactory {
map.setBackgroundTypes(backTypes);
map.generateMapDropRangeCache();
if (cache) {
mapsWLock.lock();
try {
maps.put(omapid, map);
} finally {
mapsWLock.unlock();
}
}
return map;
}
public MapleMap getMap(int mapid) {
Integer omapid = Integer.valueOf(mapid);
MapleMap map;
mapsRLock.lock();
try {
map = maps.get(omapid);
} finally {
mapsRLock.unlock();
}
return (map != null) ? map : loadMapFromWz(mapid, omapid, true);
}
public MapleMap getDisposableMap(int mapid) {
return loadMapFromWz(mapid, mapid, false);
}
public boolean isMapLoaded(int mapId) {
mapsRLock.lock();
try {
return maps.containsKey(mapId);
} finally {
mapsRLock.unlock();
}
}
private AbstractLoadedMapleLife loadLife(int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide) {
private static AbstractLoadedMapleLife loadLife(int id, String type, int cy, int f, int fh, int rx0, int rx1, int x, int y, int hide) {
AbstractLoadedMapleLife myLife = MapleLifeFactory.getLife(id, type);
myLife.setCy(cy);
myLife.setF(f);
@@ -450,7 +373,7 @@ public class MapleMapFactory {
return myLife;
}
private MapleReactor loadReactor(MapleData reactor, String id, final byte FacingDirection) {
private static MapleReactor loadReactor(MapleData reactor, String id, final byte FacingDirection) {
MapleReactor myReactor = new MapleReactor(MapleReactorFactory.getReactor(Integer.parseInt(id)), Integer.parseInt(id));
int x = MapleDataTool.getInt(reactor.getChildByPath("x"));
int y = MapleDataTool.getInt(reactor.getChildByPath("y"));
@@ -462,7 +385,7 @@ public class MapleMapFactory {
return myReactor;
}
private String getMapName(int mapid) {
private static String getMapName(int mapid) {
String mapName = StringUtil.getLeftPaddedStr(Integer.toString(mapid), '0', 9);
StringBuilder builder = new StringBuilder("Map/Map");
int area = mapid / 100000000;
@@ -474,7 +397,7 @@ public class MapleMapFactory {
return mapName;
}
private String getMapStringName(int mapid) {
private static String getMapStringName(int mapid) {
StringBuilder builder = new StringBuilder();
if (mapid < 100000000) {
builder.append("maple");
@@ -513,35 +436,8 @@ public class MapleMapFactory {
return builder.toString();
}
public void setChannel(int channel) {
this.channel = channel;
}
public void setWorld(int world) {
this.channel = world;
}
public Map<Integer, MapleMap> getMaps() {
mapsRLock.lock();
try {
return new HashMap<>(maps);
} finally {
mapsRLock.unlock();
}
}
public void dispose() {
Collection<MapleMap> mapValues = getMaps().values();
for (MapleMap map : mapValues) {
map.dispose();
}
this.event = null;
}
public static float getMapRecoveryRate(int mapid) {
Float recRate = mapRecoveryRate.get(mapid);
Float recRate = mapRecoveryRateCache.get(mapid);
return recRate != null ? recRate : 1.0f;
}
}
+162
View File
@@ -0,0 +1,162 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2018 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
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package server.maps;
import constants.ServerConstants;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
import scripting.event.EventInstanceManager;
import server.TimerManager;
public class MapleMapManager {
private int channel, world;
private EventInstanceManager event;
private Map<Integer, MapleMap> maps = new HashMap<>();
private ScheduledFuture<?> updateTask;
private ReadLock mapsRLock;
private WriteLock mapsWLock;
public MapleMapManager(EventInstanceManager eim, int world, int channel) {
this.world = world;
this.channel = channel;
this.event = eim;
ReentrantReadWriteLock rrwl = new MonitoredReentrantReadWriteLock(MonitoredLockType.MAP_MANAGER);
this.mapsRLock = rrwl.readLock();
this.mapsWLock = rrwl.writeLock();
updateTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
updateMaps();
}
}, ServerConstants.RESPAWN_INTERVAL);
}
public MapleMap resetMap(int mapid) {
mapsWLock.lock();
try {
maps.remove(mapid);
} finally {
mapsWLock.unlock();
}
return getMap(mapid);
}
private synchronized MapleMap loadMapFromWz(int mapid, boolean cache) {
MapleMap map;
if (cache) {
mapsRLock.lock();
try {
map = maps.get(mapid);
} finally {
mapsRLock.unlock();
}
if (map != null) {
return map;
}
}
map = MapleMapFactory.loadMapFromWz(mapid, world, channel, event);
if (cache) {
mapsWLock.lock();
try {
maps.put(mapid, map);
} finally {
mapsWLock.unlock();
}
}
return map;
}
public MapleMap getMap(int mapid) {
MapleMap map;
mapsRLock.lock();
try {
map = maps.get(mapid);
} finally {
mapsRLock.unlock();
}
return (map != null) ? map : loadMapFromWz(mapid, true);
}
public MapleMap getDisposableMap(int mapid) {
return loadMapFromWz(mapid, false);
}
public boolean isMapLoaded(int mapId) {
mapsRLock.lock();
try {
return maps.containsKey(mapId);
} finally {
mapsRLock.unlock();
}
}
public Map<Integer, MapleMap> getMaps() {
mapsRLock.lock();
try {
return new HashMap<>(maps);
} finally {
mapsRLock.unlock();
}
}
private void updateMaps() {
for (MapleMap map : getMaps().values()) {
map.respawn();
map.mobMpRecovery();
}
}
public void dispose() {
if (updateTask != null) {
updateTask.cancel(false);
updateTask = null;
}
for (MapleMap map : getMaps().values()) {
map.dispose();
}
this.event = null;
}
public static float getMapRecoveryRate(int mapid) {
return MapleMapFactory.getMapRecoveryRate(mapid);
}
}
+65 -6
View File
@@ -50,6 +50,7 @@ public class MapleMiniGame extends AbstractMapleMapObject {
private int firstslot = 0;
private int visitorpoints = 0, visitorscore = 0, visitorforfeits = 0, lastvisitor = -1;
private int ownerpoints = 0, ownerscore = 0, ownerforfeits = 0;
private boolean visitorquit, ownerquit;
private long nextavailabletie = 0;
private int matchestowin = 0;
@@ -112,10 +113,33 @@ public class MapleMiniGame extends AbstractMapleMapObject {
owner.getMap().broadcastMessage(MaplePacketCreator.addMatchCardBox(owner, 2, 0));
}
}
public void removeVisitor(MapleCharacter challenger) {
if (visitor == challenger) {
public void closeRoom(boolean forceClose) {
owner.getMap().broadcastMessage(MaplePacketCreator.removeMinigameBox(owner));
if (forceClose) {
this.broadcastToOwner(MaplePacketCreator.getMiniGameClose(false, 4));
}
this.broadcastToVisitor(MaplePacketCreator.getMiniGameClose(true, 3));
if (visitor != null) {
visitor.setMiniGame(null);
visitor = null;
}
owner.setMiniGame(null);
owner = null;
}
public void removeVisitor(boolean forceClose, MapleCharacter challenger) {
if (visitor == challenger) {
if (forceClose) {
visitor.announce(MaplePacketCreator.getMiniGameClose(true, 4));
}
challenger.setMiniGame(null);
visitor = null;
this.getOwner().getClient().announce(MaplePacketCreator.getMiniGameRemoveVisitor());
if (GameType == MiniGameType.OMOK) {
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addOmokBox(owner, 1, 0));
@@ -154,13 +178,37 @@ public class MapleMiniGame extends AbstractMapleMapObject {
this.getOwner().getMap().broadcastMessage(MaplePacketCreator.addOmokBox(owner, visitor != null ? 2 : 1, inprogress));
}
private synchronized boolean minigameMatchFinish() {
if (isMatchInProgress()) {
inprogress = 0;
return true;
} else {
return false;
}
}
private void minigameMatchFinished() {
inprogress = 0;
updateMiniGameBox();
if (ownerquit) {
owner.closeMiniGame(true);
} else if (visitorquit) {
visitor.closeMiniGame(true);
}
}
public void minigameMatchStarted() {
inprogress = 1;
ownerquit = false;
visitorquit = false;
}
public void setQuitAfterGame(MapleCharacter player, boolean quit) {
if (isOwner(player)) {
ownerquit = quit;
} else {
visitorquit = quit;
}
}
public boolean isMatchInProgress() {
@@ -177,33 +225,43 @@ public class MapleMiniGame extends AbstractMapleMapObject {
public boolean isTieDenied(MapleCharacter chr) {
if (this.isOwner(chr)) {
return ((inprogress >> 1) % 2) == 1;
} else {
return ((inprogress >> 2) % 2) == 1;
} else {
return ((inprogress >> 1) % 2) == 1;
}
}
public void minigameMatchOwnerWins(boolean forfeit) {
if (!minigameMatchFinish()) return;
owner.setMiniGamePoints(visitor, 1, this.isOmok());
if (visitorforfeits < 4 || !forfeit) ownerscore += 50;
visitorscore += (15 * (forfeit ? -1 : 1));
if (forfeit) visitorforfeits++;
this.broadcast(MaplePacketCreator.getMiniGameOwnerWin(this, forfeit));
minigameMatchFinished();
}
public void minigameMatchVisitorWins(boolean forfeit) {
if (!minigameMatchFinish()) return;
owner.setMiniGamePoints(visitor, 2, this.isOmok());
if (ownerforfeits < 4 || !forfeit) visitorscore += 50;
ownerscore += (15 * (forfeit ? -1 : 1));
if (forfeit) ownerforfeits++;
this.broadcast(MaplePacketCreator.getMiniGameVisitorWin(this, forfeit));
minigameMatchFinished();
}
public void minigameMatchDraw() {
if (!minigameMatchFinish()) return;
owner.setMiniGamePoints(visitor, 3, this.isOmok());
long timeNow = Server.getInstance().getCurrentTime();
@@ -215,6 +273,7 @@ public class MapleMiniGame extends AbstractMapleMapObject {
}
this.broadcast(MaplePacketCreator.getMiniGameTie(this));
minigameMatchFinished();
}
+3 -4
View File
@@ -194,7 +194,7 @@ public class MapleReactor extends AbstractMapleMapObject {
}
private void tryForceHitReactor(final byte newState) { // weak hit state signal, if already changed reactor state before timeout then drop this
if (!this.reactorLock.tryLock()) {
if (!reactorLock.tryLock()) {
return;
}
@@ -202,7 +202,7 @@ public class MapleReactor extends AbstractMapleMapObject {
this.resetReactorActions(newState);
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, (short) 0));
} finally {
this.reactorLock.unlock();
reactorLock.unlock();
}
}
@@ -311,9 +311,8 @@ public class MapleReactor extends AbstractMapleMapObject {
}
} finally {
this.unlockReactor();
hitLock.unlock(); // non-encapsulated unlock found thanks to MiLin
}
hitLock.unlock();
}
} catch (Exception e) {
e.printStackTrace();
+132
View File
@@ -0,0 +1,132 @@
/*
This file is part of the HeavenMS MapleStory Server
Copyleft (L) 2016 - 2018 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
published by the Free Software Foundation version 3 as published by
the Free Software Foundation. You may not use, modify or distribute
this program under any other version of the GNU Affero General Public
License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package tools;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.server.audit.locks.MonitoredLockType;
import net.server.audit.locks.MonitoredReentrantReadWriteLock;
/**
*
* @author Ronan
*/
public class IntervalBuilder {
private List<Line2D> intervalLimits = new ArrayList<>();
protected ReadLock intervalRlock;
protected WriteLock intervalWlock;
public IntervalBuilder() {
ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.INTERVAL, true);
intervalRlock = locks.readLock();
intervalWlock = locks.writeLock();
}
private void refitOverlappedIntervals(int st, int en, int newFrom, int newTo) {
List<Line2D> checkLimits = new ArrayList<>(intervalLimits.subList(st, en));
float newLimitX1, newLimitX2;
if (!checkLimits.isEmpty()) {
Line2D firstLimit = checkLimits.get(0);
Line2D lastLimit = checkLimits.get(checkLimits.size() - 1);
newLimitX1 = (float) ((newFrom < firstLimit.getX1()) ? newFrom : firstLimit.getX1());
newLimitX2 = (float) ((newTo > lastLimit.getX2()) ? newTo : lastLimit.getX2());
for (Line2D limit : checkLimits) {
intervalLimits.remove(st);
}
} else {
newLimitX1 = newFrom;
newLimitX2 = newTo;
}
intervalLimits.add(st, new Line2D.Float((float) newLimitX1, 0, (float) newLimitX2, 0));
}
private int bsearchInterval(int point) {
int st = 0, en = intervalLimits.size() - 1;
int mid, idx;
while (en >= st) {
idx = (st + en) / 2;
mid = (int) intervalLimits.get(idx).getX1();
if (mid == point) {
return idx;
} else if (mid < point) {
st = idx + 1;
} else {
en = idx - 1;
}
}
return en;
}
public void addInterval(int from, int to) {
intervalWlock.lock();
try {
int st = bsearchInterval(from);
if (st < 0) {
st = 0;
} else if (intervalLimits.get(st).getX2() < from) {
st += 1;
}
int en = bsearchInterval(to);
if (en < st) en = st - 1;
refitOverlappedIntervals(st, en + 1, from, to);
} finally {
intervalWlock.unlock();
}
}
public boolean inInterval(int point) {
return inInterval(point, point);
}
public boolean inInterval(int from, int to) {
intervalRlock.lock();
try {
int idx = bsearchInterval(from);
return idx >= 0 && to <= intervalLimits.get(idx).getX2();
} finally {
intervalRlock.unlock();
}
}
public void clear() {
intervalWlock.lock();
try {
intervalLimits.clear();
} finally {
intervalWlock.unlock();
}
}
}
+9 -7
View File
@@ -20,10 +20,11 @@
*/
package tools;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.Set;
import net.opcodes.RecvOpcode;
import client.MapleCharacter;
import client.MapleClient;
/**
@@ -34,14 +35,15 @@ import client.MapleClient;
public class MapleLogger {
public static List<String> monitored = new ArrayList<>();
public static List<String> ignored = new ArrayList<>();
public static Set<Integer> monitored = new HashSet<>();
public static Set<Integer> ignored = new HashSet<>();
public static void logRecv(MapleClient c, short packetId, Object message) {
if (c.getPlayer() == null){
MapleCharacter chr = c.getPlayer();
if (chr == null){
return;
}
if (!monitored.contains(c.getPlayer().getName())){
if (!monitored.contains(chr.getId())){
return;
}
RecvOpcode op = getOpcodeFromValue(packetId);
@@ -49,7 +51,7 @@ public class MapleLogger {
return;
}
String packet = op.toString() + "\r\n" + HexTool.toString((byte[]) message);
FilePrinter.printError(FilePrinter.PACKET_LOGS + c.getAccountName() + "-" + c.getPlayer().getName() + ".txt", packet);
FilePrinter.printError(FilePrinter.PACKET_LOGS + c.getAccountName() + "-" + chr.getName() + ".txt", packet);
}
private static final boolean isRecvBlocked(RecvOpcode op){
+22 -13
View File
@@ -51,7 +51,7 @@ import net.server.world.PartyOperation;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import server.CashShop.SpecialCashItem;
import server.DueyPackages;
import server.DueyPackage;
import server.MTSItemInfo;
import server.MapleItemInformationProvider;
import server.MapleShopItem;
@@ -719,7 +719,7 @@ public class MaplePacketCreator {
mplew.writeInt(1); // 1: Remove the "Select the world you want to play in"
mplew.write(ServerConstants.ENABLE_PIN && !c.canBypassPin() ? 0 : 1); // 0 = Pin-System Enabled, 1 = Disabled
mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2); // 0 = Register PIC, 1 = Ask for PIC, 2 = Disabled
mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null || c.getPic().equals("") ? 0 : 1) : 2); // 0 = Register PIC, 1 = Ask for PIC, 2 = Disabled
return mplew.getPacket();
}
@@ -905,7 +905,7 @@ public class MaplePacketCreator {
addCharEntry(mplew, chr, false);
}
mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null ? 0 : 1) : 2);
mplew.write(ServerConstants.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null || c.getPic().equals("") ? 0 : 1) : 2);
mplew.writeInt(ServerConstants.COLLECTIVE_CHARSLOT ? chars.size() + c.getAvailableCharacterSlots() : c.getCharacterSlots());
return mplew.getPacket();
}
@@ -5252,7 +5252,7 @@ public class MaplePacketCreator {
mplew.write(1);
return mplew.getPacket();
}
private static byte[] getMiniGameResult(MapleMiniGame game, int tie, int result, int forfeit) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
@@ -5312,12 +5312,12 @@ public class MaplePacketCreator {
public static byte[] getMiniGameTie(MapleMiniGame game) {
return getMiniGameResult(game, 1, 3, 0);
}
public static byte[] getMiniGameClose(int type) {
public static byte[] getMiniGameClose(boolean visitor, int type) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
mplew.write(1);
mplew.writeBool(visitor);
mplew.write(type); /* 2 : CRASH 3 : The room has been closed 4 : You have left the room 5 : You have been expelled */
return mplew.getPacket();
}
@@ -7039,26 +7039,35 @@ public class MaplePacketCreator {
return sendDuey(operation, null);
}
public static byte[] sendDuey(byte operation, List<DueyPackages> packages) {
public static byte[] sendDuey(byte operation, List<DueyPackage> packages) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.PARCEL.getValue());
mplew.write(operation);
if (operation == 8) {
mplew.write(0);
mplew.write(packages.size());
for (DueyPackages dp : packages) {
for (DueyPackage dp : packages) {
mplew.writeInt(dp.getPackageId());
mplew.writeAsciiString(dp.getSender());
for (int i = dp.getSender().length(); i < 13; i++) {
mplew.write(0);
}
mplew.writeInt(dp.getMesos());
mplew.writeLong(getTime(dp.sentTimeInMilliseconds()));
mplew.writeLong(0); // Contains message o____o.
for (int i = 0; i < 48; i++) {
mplew.writeInt(Randomizer.nextInt(Integer.MAX_VALUE));
String msg = dp.getMessage();
if (!msg.isEmpty()) {
mplew.writeInt(1);
mplew.writeAsciiString(msg);
for (int i = msg.length(); i < 200; i++) {
mplew.write(0);
}
} else {
mplew.writeInt(0);
mplew.skip(200);
}
mplew.writeInt(0);
mplew.write(0);
if (dp.getItem() != null) {
mplew.write(1);