Boss Daily Entry + Maker enable actions + Duey Quick Delivery
Fixed Legendary Spirit UI getting stuck when trying to apply scrolls in equipments without upgrade slots available. Revised map leasing. Players no longer lose ownership when changing maps. Players are allowed to lease one map each time. Revised expeditions warping players out as soon as the leader leaves the event or the number of players inside gets to be less than the minimum required to enter. Fixed start/complete quest commands not acting properly for some quests. Refactored quest loadouts unnecessarily reloading MapleData. Implemented support for daily boss limit entry, usable on expeditions. Revised potential exploit cases within chair, face expression, quest action, summon damage and mob damage mob handlers. Adjusted displayed date in Duey. Value displayed now should be consistent with the expected expiration time. Refactored damage for friendly mobs getting handled inside packet structure. Implemented support for Quick Delivery from Duey. Fixed Horntail specifically not dropping loots after recent updates. Refactored commands system. All commands are instanced at boot time instead of at every call. Fixed usage of Maker skill not sending MAKER_RESULT packet to players. This automatically reenables the actions button (such as create) in Maker UI. Adjusted minidungeons, now using time limits specified in their respective recipes. Reviewed the "timeLimit" property utilized by maps, which was poised to work on 2 different concepts altogether. Fixed Gaga space event, should be functional now. Added RPS minigame, resources implemented by Arnah. Fixed damage taken from mob auto-destruction not working properly.
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
package client;
|
||||
|
||||
import server.minigame.MapleRockPaperScissor;
|
||||
import java.awt.Point;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.sql.Connection;
|
||||
@@ -94,11 +95,10 @@ import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import server.maps.MapleMiniGame;
|
||||
import server.maps.MapleMiniGame.MiniGameResult;
|
||||
import server.life.MaplePlayerNPC;
|
||||
import server.maps.MaplePlayerShop;
|
||||
import server.maps.MaplePlayerShopItem;
|
||||
import server.maps.MapleSummon;
|
||||
import server.life.MaplePlayerNPC;
|
||||
import server.life.MonsterDropEntry;
|
||||
import server.maps.SavedLocation;
|
||||
import server.maps.SavedLocationType;
|
||||
import server.partyquest.AriantColiseum;
|
||||
@@ -221,7 +221,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private AtomicInteger exp = new AtomicInteger();
|
||||
private AtomicInteger gachaexp = new AtomicInteger();
|
||||
private AtomicInteger meso = new AtomicInteger();
|
||||
private AtomicInteger chair = new AtomicInteger();
|
||||
private AtomicInteger chair = new AtomicInteger(-1);
|
||||
private int merchantmeso;
|
||||
private BuddyList buddylist;
|
||||
private EventInstanceManager eventInstance = null;
|
||||
@@ -233,6 +233,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private MapleJob job = MapleJob.BEGINNER;
|
||||
private MapleMessenger messenger = null;
|
||||
private MapleMiniGame miniGame;
|
||||
private MapleRockPaperScissor rps;
|
||||
private MapleMount maplemount;
|
||||
private MapleParty party;
|
||||
private MaplePet[] pets = new MaplePet[3];
|
||||
@@ -248,6 +249,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private SkillMacro[] skillMacros = new SkillMacro[5];
|
||||
private List<Integer> lastmonthfameids;
|
||||
private List<WeakReference<MapleMap>> lastVisitedMaps = new LinkedList<>();
|
||||
private WeakReference<MapleMap> ownedMap = new WeakReference<>(null);
|
||||
private final Map<Short, MapleQuestStatus> quests;
|
||||
private Set<MapleMonster> controlled = new LinkedHashSet<>();
|
||||
private Map<Integer, String> entered = new LinkedHashMap<>();
|
||||
@@ -826,6 +828,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
return maxbasedamage;
|
||||
}
|
||||
|
||||
public int calculateMaxBaseMagicDamage() {
|
||||
int maxbasedamage = getTotalMagic();
|
||||
int totalint = getTotalInt();
|
||||
|
||||
if (totalint > 2000) {
|
||||
maxbasedamage -= 2000;
|
||||
maxbasedamage += (int) ((0.09033024267 * totalint) + 3823.8038);
|
||||
} else {
|
||||
maxbasedamage -= totalint;
|
||||
|
||||
if (totalint > 1700) {
|
||||
maxbasedamage += (int) (0.1996049769 * Math.pow(totalint, 1.300631341));
|
||||
} else {
|
||||
maxbasedamage += (int) (0.1996049769 * Math.pow(totalint, 1.290631341));
|
||||
}
|
||||
}
|
||||
|
||||
return (maxbasedamage * 107) / 100;
|
||||
}
|
||||
|
||||
public void setCombo(short count) {
|
||||
if (count < combocounter) {
|
||||
@@ -1664,6 +1686,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
petLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOwnedMap(MapleMap map) {
|
||||
ownedMap = new WeakReference<>(map);
|
||||
}
|
||||
|
||||
public MapleMap getOwnedMap() {
|
||||
return ownedMap.get();
|
||||
}
|
||||
|
||||
public void notifyMapTransferToPartner(int mapid) {
|
||||
if(partnerId > 0) {
|
||||
@@ -2435,7 +2465,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
private void startChairTask() {
|
||||
if (chair.get() == 0) {
|
||||
if (chair.get() < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2644,8 +2674,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
chrLock.unlock();
|
||||
}
|
||||
|
||||
if (disease == MapleDisease.SEDUCE && chair.get() != 0) {
|
||||
sitChair(0);
|
||||
if (disease == MapleDisease.SEDUCE && chair.get() < 0) {
|
||||
sitChair(-1);
|
||||
}
|
||||
|
||||
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
|
||||
@@ -5080,7 +5110,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public int getTotalMagic() {
|
||||
return localmagic;
|
||||
}
|
||||
|
||||
|
||||
public int getTotalWatk() {
|
||||
return localwatk;
|
||||
}
|
||||
@@ -5339,6 +5369,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
return playerShop;
|
||||
}
|
||||
|
||||
public MapleRockPaperScissor getRPS() { // thanks inhyuk for suggesting RPS addition
|
||||
return rps;
|
||||
}
|
||||
|
||||
public void setGMLevel(int level) {
|
||||
this.gmLevel = Math.min(level, 6);
|
||||
this.gmLevel = Math.max(level, 0);
|
||||
@@ -5356,6 +5390,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
closeTrade();
|
||||
closePlayerShop();
|
||||
closeMiniGame(true);
|
||||
closeRPS();
|
||||
closeHiredMerchant(false);
|
||||
closePlayerMessenger();
|
||||
|
||||
@@ -5512,23 +5547,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
public final byte getQuestStatus(final int quest) {
|
||||
synchronized (quests) {
|
||||
for (final MapleQuestStatus q : quests.values()) {
|
||||
if (q.getQuest().getId() == quest) {
|
||||
return (byte) q.getStatus().getId();
|
||||
}
|
||||
MapleQuestStatus mqs = quests.get((short) quest);
|
||||
if (mqs != null) {
|
||||
return (byte) mqs.getStatus().getId();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public final MapleQuestStatus getMapleQuestStatus(final int quest) {
|
||||
synchronized (quests) {
|
||||
for (final MapleQuestStatus q : quests.values()) {
|
||||
if (q.getQuest().getId() == quest) {
|
||||
return q;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
MapleQuestStatus mqs = quests.get((short) quest);
|
||||
return mqs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6085,15 +6116,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public void leaveMap() {
|
||||
releaseControlledMonsters();
|
||||
visibleMapObjects.clear();
|
||||
setChair(0);
|
||||
setChair(-1);
|
||||
if (hpDecreaseTask != null) {
|
||||
hpDecreaseTask.cancel(false);
|
||||
}
|
||||
|
||||
if (map.unclaimOwnership(this)) {
|
||||
map.dropMessage(5, "This lawn is now free real estate.");
|
||||
}
|
||||
|
||||
AriantColiseum arena = this.getAriantColiseum();
|
||||
if (arena != null) {
|
||||
arena.leaveArena(this);
|
||||
@@ -7411,12 +7438,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
private void unsitChairInternal() {
|
||||
int chairid = chair.get();
|
||||
if (chairid != 0) {
|
||||
if (chairid >= 0) {
|
||||
if (ItemConstants.isFishingChair(chairid)) {
|
||||
this.getWorldServer().unregisterFisherPlayer(this);
|
||||
}
|
||||
|
||||
setChair(0);
|
||||
setChair(-1);
|
||||
if (unregisterChairBuff()) {
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignChairSkillEffect(this.getId()), false);
|
||||
}
|
||||
@@ -7430,22 +7457,24 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public void sitChair(int itemId) {
|
||||
if (client.tryacquireClient()) {
|
||||
try {
|
||||
if (itemId >= 1000000) { // sit on item chair
|
||||
if (chair.get() == 0) {
|
||||
setChair(itemId);
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), itemId), false);
|
||||
}
|
||||
announce(MaplePacketCreator.enableActions());
|
||||
} else if (itemId != 0) { // sit on map chair
|
||||
if (chair.get() == 0) {
|
||||
setChair(itemId);
|
||||
if (registerChairBuff()) {
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.giveForeignChairSkillEffect(this.getId()), false);
|
||||
if (this.isLoggedinWorld()) {
|
||||
if (itemId >= 1000000) { // sit on item chair
|
||||
if (chair.get() < 0) {
|
||||
setChair(itemId);
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), itemId), false);
|
||||
}
|
||||
announce(MaplePacketCreator.cancelChair(itemId));
|
||||
announce(MaplePacketCreator.enableActions());
|
||||
} else if (itemId >= 0) { // sit on map chair
|
||||
if (chair.get() < 0) {
|
||||
setChair(itemId);
|
||||
if (registerChairBuff()) {
|
||||
getMap().broadcastMessage(this, MaplePacketCreator.giveForeignChairSkillEffect(this.getId()), false);
|
||||
}
|
||||
announce(MaplePacketCreator.cancelChair(itemId));
|
||||
}
|
||||
} else { // stand up
|
||||
unsitChairInternal();
|
||||
}
|
||||
} else { // stand up
|
||||
unsitChairInternal();
|
||||
}
|
||||
} finally {
|
||||
client.releaseClient();
|
||||
@@ -8955,6 +8984,18 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setRPS(MapleRockPaperScissor rps) {
|
||||
this.rps = rps;
|
||||
}
|
||||
|
||||
public void closeRPS() {
|
||||
MapleRockPaperScissor rps = this.rps;
|
||||
if (rps != null) {
|
||||
rps.dispose(client);
|
||||
setRPS(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void changeName(String name) {
|
||||
FredrickProcessor.removeFredrickReminders(this.getId());
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleClient;
|
||||
|
||||
public abstract class Command {
|
||||
|
||||
protected int rank;
|
||||
protected String description;
|
||||
|
||||
public abstract void execute(MapleClient client, String[] params);
|
||||
@@ -38,6 +39,14 @@ public abstract class Command {
|
||||
protected void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getRank() {
|
||||
return rank;
|
||||
}
|
||||
|
||||
public void setRank(int rank) {
|
||||
this.rank = rank;
|
||||
}
|
||||
|
||||
protected String joinStringFrom(String arr[], int start) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
@@ -62,7 +62,7 @@ public class CommandsExecutor {
|
||||
return heading == USER_HEADING;
|
||||
}
|
||||
|
||||
private HashMap<String, RegisteredCommand> registeredCommands = new HashMap<>();
|
||||
private HashMap<String, Command> registeredCommands = new HashMap<>();
|
||||
private Pair<List<String>, List<String>> levelCommandsCursor;
|
||||
private List<Pair<List<String>, List<String>>> commandsNameDesc = new ArrayList<>();
|
||||
|
||||
@@ -94,7 +94,7 @@ 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.");
|
||||
client.getPlayer().yellowMessage("You do not have permission to use commands while in jail.");
|
||||
return;
|
||||
}
|
||||
final String splitRegex = "[ ]";
|
||||
@@ -107,13 +107,13 @@ public class CommandsExecutor {
|
||||
final String commandName = splitedMessage[0].toLowerCase();
|
||||
final String[] lowercaseParams = splitedMessage[1].toLowerCase().split(splitRegex);
|
||||
|
||||
final RegisteredCommand command = registeredCommands.get(commandName);
|
||||
final Command command = registeredCommands.get(commandName);
|
||||
if (command == null){
|
||||
client.getPlayer().yellowMessage("Command '" + commandName + "' is not available. See @commands for a list of available commands.");
|
||||
return;
|
||||
}
|
||||
if (client.getPlayer().gmLevel() < command.getRank()){
|
||||
client.getPlayer().yellowMessage("You not have permission to use this command.");
|
||||
client.getPlayer().yellowMessage("You do not have permission to use this command.");
|
||||
return;
|
||||
}
|
||||
String[] params;
|
||||
@@ -122,16 +122,9 @@ public class CommandsExecutor {
|
||||
} else {
|
||||
params = new String[]{};
|
||||
}
|
||||
try {
|
||||
Command commandInstance = command.getCommandClass().newInstance();
|
||||
commandInstance.execute(client, params);
|
||||
writeLog(client, message);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
command.execute(client, params);
|
||||
writeLog(client, message);
|
||||
}
|
||||
|
||||
private void writeLog(MapleClient client, String command){
|
||||
@@ -172,11 +165,19 @@ public class CommandsExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
RegisteredCommand registeredCommand = new RegisteredCommand(commandClass, rank);
|
||||
|
||||
String commandName = syntax.toLowerCase();
|
||||
addCommandInfo(commandName, commandClass);
|
||||
registeredCommands.put(commandName, registeredCommand);
|
||||
|
||||
try {
|
||||
Command commandInstance = commandClass.newInstance(); // thanks Halcyon for noticing commands getting reinstanced every call
|
||||
commandInstance.setRank(rank);
|
||||
|
||||
registeredCommands.put(commandName, commandInstance);
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void registerLv0Commands(){
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
@Author: Arthur L - Refactored command content into modules
|
||||
*/
|
||||
package client.command;
|
||||
|
||||
class RegisteredCommand {
|
||||
|
||||
private final Class<? extends Command> commandClass;
|
||||
private final int rank;
|
||||
|
||||
RegisteredCommand(Class<? extends Command> commandClass, int rank){
|
||||
this.commandClass = commandClass;
|
||||
this.rank = rank;
|
||||
}
|
||||
|
||||
public Class<? extends Command> getCommandClass() {
|
||||
return commandClass;
|
||||
}
|
||||
|
||||
public int getRank() {
|
||||
return rank;
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@ import client.command.Command;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import constants.ServerConstants;
|
||||
import server.maps.MapleMap;
|
||||
|
||||
public class MapOwnerClaimCommand extends Command {
|
||||
{
|
||||
@@ -41,12 +42,20 @@ public class MapOwnerClaimCommand extends Command {
|
||||
|
||||
if (ServerConstants.USE_MAP_OWNERSHIP_SYSTEM) {
|
||||
if (chr.getEventInstance() == null) {
|
||||
if (chr.getMap().unclaimOwnership(chr)) {
|
||||
chr.dropMessage(5, "This lawn is now free real estate.");
|
||||
} else if (chr.getMap().claimOwnership(chr)) {
|
||||
MapleMap ownedMap = chr.getOwnedMap(); // thanks Conrad for suggesting not unlease a map as soon as player exits it
|
||||
if (ownedMap != null) {
|
||||
ownedMap.unclaimOwnership(chr);
|
||||
|
||||
if (chr.getMap() == ownedMap) {
|
||||
chr.dropMessage(5, "This lawn is now free real estate.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (chr.getMap().claimOwnership(chr)) {
|
||||
chr.dropMessage(5, "You have leased this lawn for a while, until you leave here or after 1 minute of inactivity.");
|
||||
} else {
|
||||
chr.dropMessage(5, "This lawn has already been leased by another player.");
|
||||
chr.dropMessage(5, "This lawn has already been leased by a player.");
|
||||
}
|
||||
} else {
|
||||
chr.dropMessage(5, "This lawn cannot be leased.");
|
||||
|
||||
@@ -105,7 +105,7 @@ public class GotoCommand extends Command {
|
||||
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);
|
||||
gotomaps = GameConstants.GOTO_TOWNS;
|
||||
}
|
||||
|
||||
if (gotomaps.containsKey(params[0])) {
|
||||
|
||||
@@ -55,7 +55,7 @@ public class IdCommand extends Command {
|
||||
}
|
||||
sb.append(String.format("Results found: #r%d#k | Returned: #b%d#k/100 | Refine search query to improve time.", resultList.size(), count) + "\r\n");
|
||||
|
||||
player.getClient().getAbstractPlayerInteraction().npcTalk(9010000, sb.toString());
|
||||
player.getAbstractPlayerInteraction().npcTalk(9010000, sb.toString());
|
||||
} else {
|
||||
player.yellowMessage(String.format("Id not found for item: %s, of type: %s.", queryItem, params[0]));
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ package client.command.commands.gm3;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import server.quest.MapleQuest;
|
||||
|
||||
public class QuestCompleteCommand extends Command {
|
||||
{
|
||||
@@ -45,14 +44,8 @@ public class QuestCompleteCommand extends Command {
|
||||
int questId = Integer.parseInt(params[0]);
|
||||
|
||||
if (player.getQuestStatus(questId) == 1) {
|
||||
MapleQuest quest = MapleQuest.getInstance(questId);
|
||||
if (quest != null) {
|
||||
int npcid = quest.getNpcRequirement(true);
|
||||
quest.forceComplete(player, npcid);
|
||||
player.dropMessage(5, "QUEST " + questId + " completed.");
|
||||
} else { // should not occur
|
||||
player.dropMessage(5, "QUESTID " + questId + " is invalid.");
|
||||
}
|
||||
c.getAbstractPlayerInteraction().forceCompleteQuest(questId);
|
||||
player.dropMessage(5, "QUEST " + questId + " completed.");
|
||||
} else {
|
||||
player.dropMessage(5, "QUESTID " + questId + " not started or already completed.");
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ package client.command.commands.gm3;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import server.quest.MapleQuest;
|
||||
|
||||
public class QuestStartCommand extends Command {
|
||||
{
|
||||
@@ -45,14 +44,8 @@ public class QuestStartCommand extends Command {
|
||||
int questid = Integer.parseInt(params[0]);
|
||||
|
||||
if (player.getQuestStatus(questid) == 0) {
|
||||
MapleQuest quest = MapleQuest.getInstance(questid);
|
||||
if (quest != null) {
|
||||
int npcid = quest.getNpcRequirement(false);
|
||||
quest.forceStart(player, npcid);
|
||||
player.dropMessage(5, "QUEST " + questid + " started.");
|
||||
} else {
|
||||
player.dropMessage(5, "QUESTID " + questid + " is invalid.");
|
||||
}
|
||||
c.getAbstractPlayerInteraction().forceStartQuest(questid);
|
||||
player.dropMessage(5, "QUEST " + questid + " started.");
|
||||
} else {
|
||||
player.dropMessage(5, "QUESTID " + questid + " already started/completed.");
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import server.life.SpawnPoint;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import server.maps.MapleReactor;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -112,10 +112,14 @@ public class DueyProcessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getCurrentDate() {
|
||||
private static String getCurrentDate(boolean quick) {
|
||||
String date = "";
|
||||
Calendar cal = Calendar.getInstance();
|
||||
int day = cal.get(Calendar.DATE) - 1; // instant duey ?
|
||||
if (!quick) {
|
||||
cal.add(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
int day = cal.get(Calendar.DATE);
|
||||
int month = cal.get(Calendar.MONTH) + 1; // its an array of months.
|
||||
int year = cal.get(Calendar.YEAR);
|
||||
date += day <= 9 ? "0" + day + "-" : "" + day + "-";
|
||||
@@ -132,7 +136,7 @@ public class DueyProcessor {
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
ps = con.prepareStatement("SELECT Mesos FROM dueypackages WHERE ReceiverId = ? and Checked = 1");
|
||||
ps = con.prepareStatement("SELECT SenderName, Type FROM dueypackages WHERE ReceiverId = ? AND Checked = 1 ORDER BY Type DESC");
|
||||
ps.setInt(1, player.getId());
|
||||
rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
@@ -143,11 +147,11 @@ public class DueyProcessor {
|
||||
pss.executeUpdate();
|
||||
pss.close();
|
||||
con2.close();
|
||||
|
||||
c.announce(MaplePacketCreator.sendDueyParcelReceived(rs.getString("SenderName"), rs.getInt("Type") == 1));
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.sendDueyNotification(false));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
@@ -241,7 +245,7 @@ public class DueyProcessor {
|
||||
return packages;
|
||||
}
|
||||
|
||||
private static int createPackage(int mesos, String message, String sender, int toCid) {
|
||||
private static int createPackage(int mesos, String message, String sender, int toCid, boolean quick) {
|
||||
try {
|
||||
Connection con = null;
|
||||
PreparedStatement ps = null;
|
||||
@@ -249,16 +253,17 @@ public class DueyProcessor {
|
||||
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
ps = con.prepareStatement("INSERT INTO `dueypackages` (ReceiverId, SenderName, Mesos, TimeStamp, Message, Checked) VALUES (?, ?, ?, ?, ?, 1)", Statement.RETURN_GENERATED_KEYS);
|
||||
ps = con.prepareStatement("INSERT INTO `dueypackages` (ReceiverId, SenderName, Mesos, TimeStamp, Message, Type, 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(4, getCurrentDate(quick));
|
||||
ps.setString(5, message);
|
||||
ps.setInt(6, quick ? 1 : 0);
|
||||
|
||||
int updateRows = ps.executeUpdate();
|
||||
if (updateRows < 1) {
|
||||
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Error trying to create package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
|
||||
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Error trying to create package [mesos: " + mesos + ", " + sender + ", quick: " + quick + ", to CharacterId: " + toCid + "]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -267,7 +272,7 @@ public class DueyProcessor {
|
||||
if (rs.next()) {
|
||||
packageId = rs.getInt(1);
|
||||
} else {
|
||||
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Failed inserting package [mesos: " + mesos + ", " + sender + ", to CharacterId: " + toCid + "]");
|
||||
FilePrinter.printError(FilePrinter.INSERT_CHAR, "Failed inserting package [mesos: " + mesos + ", " + sender + ", quick: " + quick + ", to CharacterId: " + toCid + "]");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -348,10 +353,18 @@ public class DueyProcessor {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void dueySendItem(MapleClient c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient) {
|
||||
public static void dueySendItem(MapleClient c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient, boolean quick) {
|
||||
if (c.tryacquireClient()) {
|
||||
try {
|
||||
final int fee = 5000 + MapleTrade.getFee(sendMesos);
|
||||
int fee = MapleTrade.getFee(sendMesos);
|
||||
if (!quick) {
|
||||
fee += 5000;
|
||||
} else if (!c.getPlayer().haveItem(5330000)) {
|
||||
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with Quick Delivery on duey.");
|
||||
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use duey with Quick Delivery, mesos " + sendMesos + " and amount " + amount);
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
long finalcost = (long) sendMesos + fee;
|
||||
if (finalcost < 0 || finalcost > Integer.MAX_VALUE || (amount < 1 && sendMesos == 0)) {
|
||||
@@ -385,7 +398,11 @@ public class DueyProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
int packageId = createPackage(sendMesos, sendMessage, c.getPlayer().getName(), recipientCid);
|
||||
if (quick) {
|
||||
MapleInventoryManipulator.removeById(c, MapleInventoryType.CASH, 5330000, (short) 1, false, false);
|
||||
}
|
||||
|
||||
int packageId = createPackage(sendMesos, sendMessage, c.getPlayer().getName(), recipientCid, quick);
|
||||
if (packageId == -1) {
|
||||
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_ENABLE_ACTIONS.getCode()));
|
||||
return;
|
||||
@@ -490,10 +507,17 @@ public class DueyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
public static void dueySendTalk(MapleClient c) {
|
||||
public static void dueySendTalk(MapleClient c, boolean quickDelivery) {
|
||||
if (c.tryacquireClient()) {
|
||||
try {
|
||||
c.announce(MaplePacketCreator.sendDuey((byte) 8, loadPackages(c.getPlayer())));
|
||||
long timeNow = System.currentTimeMillis();
|
||||
if(timeNow - c.getPlayer().getNpcCooldown() < ServerConstants.BLOCK_NPC_RACE_CONDT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
c.getPlayer().setNpcCooldown(timeNow);
|
||||
|
||||
c.announce(MaplePacketCreator.sendDuey(quickDelivery ? 0x1A : 0x8, loadPackages(c.getPlayer())));
|
||||
} finally {
|
||||
c.releaseClient();
|
||||
}
|
||||
@@ -501,7 +525,7 @@ public class DueyProcessor {
|
||||
}
|
||||
|
||||
public static void dueyCreatePackage(Item item, int mesos, String sender, int recipientCid) {
|
||||
int packageId = createPackage(mesos, "", sender, recipientCid);
|
||||
int packageId = createPackage(mesos, "", sender, recipientCid, false);
|
||||
if (packageId != -1) {
|
||||
insertPackageItem(packageId, item);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import server.MakerItemFactory;
|
||||
import server.MakerItemFactory.MakerItemCreateEntry;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -44,6 +45,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MakerProcessor {
|
||||
|
||||
private static MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
public static void makerAction(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
@@ -54,7 +56,7 @@ public class MakerProcessor {
|
||||
int toDisassemble = -1, pos = -1;
|
||||
boolean makerSucceeded = true;
|
||||
|
||||
MakerItemFactory.MakerItemCreateEntry recipe;
|
||||
MakerItemCreateEntry recipe;
|
||||
Map<Integer, Short> reagentids = new LinkedHashMap<>();
|
||||
int stimulantid = -1;
|
||||
|
||||
@@ -62,29 +64,31 @@ public class MakerProcessor {
|
||||
int fromLeftover = toCreate;
|
||||
toCreate = ii.getMakerCrystalFromLeftover(toCreate);
|
||||
if(toCreate == -1) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal conversion."));
|
||||
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(fromLeftover) + " is unavailable for Monster Crystal conversion."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
recipe = MakerItemFactory.generateLeftoverCrystalEntry(fromLeftover);
|
||||
|
||||
recipe = MakerItemFactory.generateLeftoverCrystalEntry(fromLeftover, toCreate);
|
||||
} else if(type == 4) { // disassembling
|
||||
slea.readInt(); // 1... probably inventory type
|
||||
pos = slea.readInt();
|
||||
|
||||
Item it = c.getPlayer().getInventory(MapleInventoryType.EQUIP).getItem((short) pos);
|
||||
if(it != null && it.getItemId() == toCreate) {
|
||||
Pair<Integer, Integer> p;
|
||||
|
||||
if((p = generateDisassemblyInfo(toCreate)) != null) {
|
||||
recipe = MakerItemFactory.generateDisassemblyCrystalEntry(p.getLeft(), p.getRight());
|
||||
toDisassemble = toCreate;
|
||||
toCreate = ii.getMakerCrystalFromEquip(toCreate);
|
||||
toDisassemble = toCreate;
|
||||
|
||||
Pair<Integer, List<Pair<Integer, Integer>>> p = generateDisassemblyInfo(toDisassemble);
|
||||
if(p != null) {
|
||||
recipe = MakerItemFactory.generateDisassemblyCrystalEntry(toDisassemble, p.getLeft(), p.getRight());
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal disassembly."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "An unknown error occurred when trying to apply that item for disassembly."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -132,6 +136,7 @@ public class MakerProcessor {
|
||||
if(!reagentids.isEmpty()) {
|
||||
if(!removeOddMakerReagents(toCreate, reagentids)) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You can only use WATK and MATK Strengthening Gems on weapon items."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -146,65 +151,80 @@ public class MakerProcessor {
|
||||
case -1:// non-available for Maker itemid has been tried to forge
|
||||
FilePrinter.printError(FilePrinter.EXPLOITS, "Player " + c.getPlayer().getName() + " tried to craft itemid " + toCreate + " using the Maker skill.");
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "The requested item could not be crafted on this operation."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
case 1: // no items
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have all required items in your inventory to make " + recipe.getRewardAmount() + " " + ii.getName(toCreate) + "."));
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have all required items in your inventory to make " + ii.getName(toCreate) + "."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
case 2: // no meso
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough mesos (" + GameConstants.numberWithCommas(recipe.getCost()) + ") to complete this operation."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
case 3: // no req level
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough level to complete this operation."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
case 4: // no req skill level
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough Maker level to complete this operation."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
case 5: // inventory full
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Your inventory is full."));
|
||||
c.announce(MaplePacketCreator.makerEnableActions());
|
||||
break;
|
||||
|
||||
default:
|
||||
if (MapleInventoryManipulator.checkSpace(c, toCreate, (short) recipe.getRewardAmount(), "")) {
|
||||
if(toDisassemble != -1) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIP, (short) pos, (short) 1, false);
|
||||
} else {
|
||||
for (Pair<Integer, Integer> p : recipe.getReqItems()) {
|
||||
c.getAbstractPlayerInteraction().gainItem(p.getLeft(), (short) -p.getRight());
|
||||
c.getAbstractPlayerInteraction().gainItem(p.getLeft(), (short) -p.getRight(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if(toDisassemble != -1) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.EQUIP, (short) pos, (short) 1, false);
|
||||
c.announce(MaplePacketCreator.getShowItemGain(toDisassemble, (short) -1, true));
|
||||
}
|
||||
|
||||
int cost = recipe.getCost();
|
||||
if(stimulantid == -1 && reagentids.isEmpty()) {
|
||||
if(cost > 0) c.getPlayer().gainMeso(-cost);
|
||||
|
||||
int cost = recipe.getCost();
|
||||
if(stimulantid == -1 && reagentids.isEmpty()) {
|
||||
if(cost > 0) c.getPlayer().gainMeso(-cost, false);
|
||||
|
||||
for (Pair<Integer, Integer> p : recipe.getGainItems()) {
|
||||
c.getPlayer().setCS(true);
|
||||
c.getAbstractPlayerInteraction().gainItem(toCreate, (short) recipe.getRewardAmount());
|
||||
c.getAbstractPlayerInteraction().gainItem(p.getLeft(), p.getRight().shortValue(), false);
|
||||
c.getPlayer().setCS(false);
|
||||
} else {
|
||||
if(stimulantid != -1) c.getAbstractPlayerInteraction().gainItem(stimulantid, (short) -1);
|
||||
if(!reagentids.isEmpty()) {
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
c.getAbstractPlayerInteraction().gainItem(r.getKey(), (short) (-1 * r.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
if(cost > 0) c.getPlayer().gainMeso(-cost);
|
||||
makerSucceeded = addBoostedMakerItem(c, toCreate, stimulantid, reagentids);
|
||||
}
|
||||
|
||||
if(makerSucceeded) c.announce(MaplePacketCreator.serverNotice(1, "You have successfully created " + recipe.getRewardAmount() + " " + ii.getName(toCreate) + "."));
|
||||
else c.getPlayer().dropMessage(5, "The Maker skill lights up, but the skill winds up as if nothing happened.");
|
||||
|
||||
c.announce(MaplePacketCreator.showMakerEffect(makerSucceeded));
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignMakerEffect(c.getPlayer().getId(), makerSucceeded), false);
|
||||
|
||||
if(toCreate == 4260003 && type == 3 && c.getPlayer().getQuestStatus(6033) == 1) {
|
||||
c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Your inventory is full."));
|
||||
toCreate = recipe.getGainItems().get(0).getLeft();
|
||||
|
||||
if(stimulantid != -1) c.getAbstractPlayerInteraction().gainItem(stimulantid, (short) -1, false);
|
||||
if(!reagentids.isEmpty()) {
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
c.getAbstractPlayerInteraction().gainItem(r.getKey(), (short) (-1 * r.getValue()), false);
|
||||
}
|
||||
}
|
||||
|
||||
if(cost > 0) c.getPlayer().gainMeso(-cost, false);
|
||||
makerSucceeded = addBoostedMakerItem(c, toCreate, stimulantid, reagentids);
|
||||
}
|
||||
|
||||
// thanks inhyuk for noticing missing MAKER_RESULT packets
|
||||
if (type == 3) {
|
||||
c.announce(MaplePacketCreator.makerResultCrystal(recipe.getGainItems().get(0).getLeft(), recipe.getReqItems().get(0).getLeft()));
|
||||
} else if (type == 4) {
|
||||
c.announce(MaplePacketCreator.makerResultDesynth(recipe.getReqItems().get(0).getLeft(), recipe.getCost(), recipe.getGainItems()));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.makerResult(makerSucceeded, recipe.getGainItems().get(0).getLeft(), recipe.getGainItems().get(0).getRight(), recipe.getCost(), recipe.getReqItems(), stimulantid, new LinkedList<>(reagentids.keySet())));
|
||||
}
|
||||
|
||||
c.announce(MaplePacketCreator.showMakerEffect(makerSucceeded));
|
||||
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showForeignMakerEffect(c.getPlayer().getId(), makerSucceeded), false);
|
||||
|
||||
if(toCreate == 4260003 && type == 3 && c.getPlayer().getQuestStatus(6033) == 1) {
|
||||
c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -271,12 +291,12 @@ public class MakerProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static Pair<Integer, Integer> generateDisassemblyInfo(int itemId) {
|
||||
private static Pair<Integer, List<Pair<Integer, Integer>>> generateDisassemblyInfo(int itemId) {
|
||||
int recvFee = ii.getMakerDisassembledFee(itemId);
|
||||
if(recvFee > -1) {
|
||||
int recvQty = ii.getMakerDisassembledQuantity(itemId);
|
||||
if(recvQty > 0) {
|
||||
return new Pair<>(recvFee, recvQty);
|
||||
List<Pair<Integer, Integer>> gains = ii.getMakerDisassembledItems(itemId);
|
||||
if(!gains.isEmpty()) {
|
||||
return new Pair<>(recvFee, gains);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +307,7 @@ public class MakerProcessor {
|
||||
return chr.getSkillLevel((chr.getJob().getId() / 1000) * 10000000 + 1007);
|
||||
}
|
||||
|
||||
private static short getCreateStatus(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
|
||||
private static short getCreateStatus(MapleClient c, MakerItemCreateEntry recipe) {
|
||||
if(recipe == null) {
|
||||
return -1;
|
||||
}
|
||||
@@ -308,10 +328,29 @@ public class MakerProcessor {
|
||||
return 4;
|
||||
}
|
||||
|
||||
List<Integer> addItemids = new LinkedList<>();
|
||||
List<Integer> addQuantity = new LinkedList<>();
|
||||
List<Integer> rmvItemids = new LinkedList<>();
|
||||
List<Integer> rmvQuantity = new LinkedList<>();
|
||||
|
||||
for (Pair<Integer, Integer> p : recipe.getReqItems()) {
|
||||
rmvItemids.add(p.getLeft());
|
||||
rmvQuantity.add(p.getRight());
|
||||
}
|
||||
|
||||
for (Pair<Integer, Integer> p : recipe.getGainItems()) {
|
||||
addItemids.add(p.getLeft());
|
||||
addQuantity.add(p.getRight());
|
||||
}
|
||||
|
||||
if (!c.getAbstractPlayerInteraction().canHoldAllAfterRemoving(addItemids, addQuantity, rmvItemids, rmvQuantity)) {
|
||||
return 5;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean hasItems(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
|
||||
private static boolean hasItems(MapleClient c, MakerItemCreateEntry recipe) {
|
||||
for (Pair<Integer, Integer> p : recipe.getReqItems()) {
|
||||
int itemId = p.getLeft();
|
||||
if (c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).countById(itemId) < p.getRight()) {
|
||||
@@ -397,7 +436,6 @@ public class MakerProcessor {
|
||||
}
|
||||
|
||||
MapleInventoryManipulator.addFromDrop(c, item, false, -1);
|
||||
c.announce(MaplePacketCreator.getShowItemGain(itemid, (short) 1, true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user