GMS-like Wedding + Scissors of Karma + Maple Life + Buyback
Properly developed the Marriage feature in the source. Added TRAVEL_RATE server flag, a modifier for the travel frequency rate. Corrected stance for players in 3rd party view when entering a map to work similarly as GMS. Fixed mobs spamming skills incoherently. Added code support for old GMS-like PQ NPCs, where party leaders just need to click once to start a new PQ. Implemented podium system for the Hall of Fame PlayerNPCs. Improved character load-out system, now using way less queries to the DB in the process. Fixed birthday field for accounts not being read correctly. Further implemented the incomplete yet-existing Scissors of Karma mechanic. Fixed Duey not propagating item flags when packaging an item. Added a custom buyback system. Refactored the character creation system, now offering support for Maple Life. Fixed some issues with the PlayerNPC positioning system. Added server flag allowing AP assignment for novices (beginners under level 11). Fixed Strategy Time (GPQ) announcement being sent twice to guilds in certain cases. Tweaked mount EXP system now awarding it accordingly with the amount of tiredness healed. Removed the randomness aspect of closeness gain when feeding the pet, now acting accordingly with amount of fullness gained. Fixed an exploit with Arwen script. Fixed travel-back from Florina forcefully sending players to Lith Harbor in certain situations. Thoroughly reviewed job skill questlines for Explorers and Aran. Localhost edit: removed MTS block in certain maps (useful for the buyback system). Localhost edit: removed party blocks for novices. Localhost edit: removed AP assigning block for novices. Localhost edit: removed speed cap. Localhost edit: removed Maker block popping up when inputting ATK gems on non-weapons.
This commit is contained in:
104
src/client/processor/BuybackProcessor.java
Normal file
104
src/client/processor/BuybackProcessor.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
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 client.processor;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleStat;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import server.maps.MapleMap;
|
||||
import server.movement.AbsoluteLifeMovement;
|
||||
import server.movement.LifeMovementFragment;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author RonanLana
|
||||
*/
|
||||
public class BuybackProcessor {
|
||||
|
||||
public static void processBuyback(MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
boolean buyback;
|
||||
|
||||
c.lockClient();
|
||||
try {
|
||||
buyback = !chr.isAlive() && chr.couldBuyback();
|
||||
} finally {
|
||||
c.unlockClient();
|
||||
}
|
||||
|
||||
if(buyback) {
|
||||
String jobString;
|
||||
switch(chr.getJobStyle()) {
|
||||
case WARRIOR:
|
||||
jobString = "warrior";
|
||||
break;
|
||||
|
||||
case MAGICIAN:
|
||||
jobString = "magician";
|
||||
break;
|
||||
|
||||
case BOWMAN:
|
||||
jobString = "bowman";
|
||||
break;
|
||||
|
||||
case THIEF:
|
||||
jobString = "thief";
|
||||
break;
|
||||
|
||||
case BRAWLER:
|
||||
case GUNSLINGER:
|
||||
jobString = "pirate";
|
||||
break;
|
||||
|
||||
default:
|
||||
jobString = "beginner";
|
||||
}
|
||||
|
||||
chr.setStance(0);
|
||||
|
||||
chr.setHp(chr.getMaxHp());
|
||||
chr.setMp(chr.getMaxMp());
|
||||
|
||||
List<Pair<MapleStat, Integer>> hpmpupdate = new ArrayList<>(2);
|
||||
hpmpupdate.add(new Pair<>(MapleStat.HP, Integer.valueOf(chr.getHp())));
|
||||
hpmpupdate.add(new Pair<>(MapleStat.MP, Integer.valueOf(chr.getMp())));
|
||||
c.announce(MaplePacketCreator.updatePlayerStats(hpmpupdate, true, chr));
|
||||
|
||||
AbsoluteLifeMovement alm = new AbsoluteLifeMovement(0, chr.getPosition(), 0, 0);
|
||||
alm.setPixelsPerSecond(new Point(0, 0));
|
||||
List<LifeMovementFragment> moveUpdate = Collections.singletonList((LifeMovementFragment) alm);
|
||||
|
||||
MapleMap map = chr.getMap();
|
||||
map.broadcastMessage(chr, MaplePacketCreator.movePlayer(c.getPlayer().getId(), moveUpdate), false);
|
||||
|
||||
map.broadcastMessage(MaplePacketCreator.playSound("Buyback/" + jobString));
|
||||
map.broadcastMessage(MaplePacketCreator.earnTitleMessage(chr.getName() + " just bought back into the game!"));
|
||||
|
||||
chr.announce(MaplePacketCreator.showBuybackEffect());
|
||||
map.broadcastMessage(chr, MaplePacketCreator.showForeignBuybackEffect(chr.getId()), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import client.autoban.AutobanFactory;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import constants.ItemConstants;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
@@ -39,7 +41,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import net.server.channel.Channel;
|
||||
import server.DueyPackages;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.FilePrinter;
|
||||
@@ -163,10 +164,12 @@ public class DueyProcessor {
|
||||
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 {
|
||||
@@ -186,13 +189,13 @@ public class DueyProcessor {
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
ps = con.prepareStatement("SELECT Mesos FROM dueypackages WHERE RecieverId = ? and Checked = 1");
|
||||
ps = con.prepareStatement("SELECT Mesos FROM dueypackages WHERE ReceiverId = ? and Checked = 1");
|
||||
ps.setInt(1, player.getId());
|
||||
rs = ps.executeQuery();
|
||||
if (rs.next()) {
|
||||
try {
|
||||
Connection con2 = DatabaseConnection.getConnection();
|
||||
pss = con2.prepareStatement("UPDATE dueypackages SET Checked = 0 where RecieverId = ?");
|
||||
pss = con2.prepareStatement("UPDATE dueypackages SET Checked = 0 where ReceiverId = ?");
|
||||
pss.setInt(1, player.getId());
|
||||
pss.executeUpdate();
|
||||
pss.close();
|
||||
@@ -225,31 +228,33 @@ public class DueyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private static int getFee(int meso) {
|
||||
int fee = 0;
|
||||
if (meso >= 10000000) {
|
||||
fee = meso / 25;
|
||||
private static int getFee(long meso) {
|
||||
long fee = 0;
|
||||
if (meso >= 100000000) {
|
||||
fee = (meso * 6) / 100;
|
||||
} else if (meso >= 25000000) {
|
||||
fee = (meso * 5) / 100;
|
||||
} else if (meso >= 10000000) {
|
||||
fee = (meso * 4) / 100;
|
||||
} else if (meso >= 5000000) {
|
||||
fee = meso * 3 / 100;
|
||||
fee = (meso * 3) / 100;
|
||||
} else if (meso >= 1000000) {
|
||||
fee = meso / 50;
|
||||
fee = (meso * 18) / 1000;
|
||||
} else if (meso >= 100000) {
|
||||
fee = meso / 100;
|
||||
} else if (meso >= 50000) {
|
||||
fee = meso / 200;
|
||||
fee = (meso * 8) / 1000;
|
||||
}
|
||||
return fee;
|
||||
return (int) fee;
|
||||
}
|
||||
|
||||
private static void addMesoToDB(int mesos, String sName, int recipientID) {
|
||||
addItemToDB(null, 1, mesos, sName, recipientID);
|
||||
}
|
||||
|
||||
private static void addItemToDB(Item item, int quantity, int mesos, String sName, int recipientID) {
|
||||
public static void addItemToDB(Item item, int quantity, int mesos, String sName, int recipientID) {
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("INSERT INTO dueypackages (RecieverId, SenderName, Mesos, TimeStamp, Checked, Type) VALUES (?, ?, ?, ?, ?, ?)")) {
|
||||
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);
|
||||
@@ -266,7 +271,7 @@ public class DueyProcessor {
|
||||
rs.next();
|
||||
PreparedStatement ps2;
|
||||
if (item.getInventoryType().equals(MapleInventoryType.EQUIP)) {
|
||||
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, upgradeslots, level, str, dex, `int`, luk, hp, mp, watk, matk, wdef, mdef, acc, avoid, hands, speed, jump, owner) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, upgradeslots, level, 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);
|
||||
@@ -287,12 +292,14 @@ public class DueyProcessor {
|
||||
ps2.setInt(18, eq.getHands());
|
||||
ps2.setInt(19, eq.getSpeed());
|
||||
ps2.setInt(20, eq.getJump());
|
||||
ps2.setString(21, eq.getOwner());
|
||||
ps2.setInt(21, eq.getFlag());
|
||||
ps2.setString(22, eq.getOwner());
|
||||
} else {
|
||||
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, owner) VALUES (?, ?, ?, ?)");
|
||||
ps2 = con.prepareStatement("INSERT INTO dueyitems (PackageId, itemid, quantity, flag, owner) VALUES (?, ?, ?, ?, ?)");
|
||||
ps2.setInt(2, item.getItemId());
|
||||
ps2.setInt(3, quantity);
|
||||
ps2.setString(4, item.getOwner());
|
||||
ps2.setInt(4, item.getFlag());
|
||||
ps2.setString(5, item.getOwner());
|
||||
}
|
||||
ps2.setInt(1, rs.getInt(1));
|
||||
ps2.executeUpdate();
|
||||
@@ -312,7 +319,7 @@ public class DueyProcessor {
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages dp LEFT JOIN dueyitems di ON dp.PackageId=di.PackageId WHERE RecieverId = ?")) {
|
||||
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM dueypackages dp LEFT JOIN dueyitems di ON dp.PackageId=di.PackageId WHERE ReceiverId = ?")) {
|
||||
ps.setInt(1, chr.getId());
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
while (rs.next()) {
|
||||
@@ -337,13 +344,14 @@ public class DueyProcessor {
|
||||
c.lockClient();
|
||||
try {
|
||||
final int fee = 5000;
|
||||
if (mesos < 0 || ((long) mesos + fee + getFee(mesos)) > Integer.MAX_VALUE || (amount < 1 && mesos == 0)) {
|
||||
final long sendMesos = (long) mesos + fee;
|
||||
if (mesos < 0 || sendMesos > Integer.MAX_VALUE || (amount < 1 && mesos == 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 + "\r\n");
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
int finalcost = mesos + fee + getFee(mesos);
|
||||
int finalcost = mesos + fee;
|
||||
boolean send = false;
|
||||
if (c.getPlayer().getMeso() >= finalcost) {
|
||||
int accid = getAccIdFromCNAME(recipient, true);
|
||||
@@ -382,7 +390,8 @@ public class DueyProcessor {
|
||||
MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false);
|
||||
}
|
||||
|
||||
addItemToDB(item, amount, mesos, c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
|
||||
addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
|
||||
} else {
|
||||
if (item != null) {
|
||||
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode()));
|
||||
@@ -393,7 +402,7 @@ public class DueyProcessor {
|
||||
c.getPlayer().gainMeso(-finalcost, false);
|
||||
c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode()));
|
||||
|
||||
addMesoToDB(mesos, c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
|
||||
addMesoToDB(mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false));
|
||||
}
|
||||
|
||||
if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) {
|
||||
@@ -460,14 +469,16 @@ public class DueyProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
long gainmesos = 0;
|
||||
long totalmesos = (long) dp.getMesos() + (long) c.getPlayer().getMeso();
|
||||
long gainmesos;
|
||||
long totalmesos = (long) dp.getMesos() + c.getPlayer().getMeso();
|
||||
|
||||
if (totalmesos < 0 || dp.getMesos() < 0) gainmesos = 0;
|
||||
else {
|
||||
if (totalmesos < 0 || dp.getMesos() < 0) {
|
||||
gainmesos = 0;
|
||||
} else {
|
||||
totalmesos = Math.min(totalmesos, Integer.MAX_VALUE);
|
||||
gainmesos = totalmesos - c.getPlayer().getMeso();
|
||||
}
|
||||
|
||||
c.getPlayer().gainMeso((int)gainmesos, false);
|
||||
|
||||
removeItemFromDB(packageid);
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import server.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.maps.MapleHiredMerchant;
|
||||
import tools.DatabaseConnection;
|
||||
|
||||
476
src/client/processor/MakerProcessor.java
Normal file
476
src/client/processor/MakerProcessor.java
Normal file
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
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 client.processor;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.inventory.Equip;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import constants.EquipType;
|
||||
import constants.GameConstants;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import server.MakerItemFactory;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Ronan
|
||||
*/
|
||||
public class MakerProcessor {
|
||||
private static MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
public static void makerAction(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
c.lockClient();
|
||||
try {
|
||||
int type = slea.readInt();
|
||||
int toCreate = slea.readInt();
|
||||
int toDisassemble = -1, pos = -1;
|
||||
boolean makerSucceeded = true;
|
||||
|
||||
MakerItemFactory.MakerItemCreateEntry recipe;
|
||||
Map<Integer, Short> reagentids = new LinkedHashMap<>();
|
||||
int stimulantid = -1;
|
||||
|
||||
if(type == 3) { // building monster crystal
|
||||
int fromLeftover = toCreate;
|
||||
toCreate = ii.getMakerCrystalFromLeftover(toCreate);
|
||||
if(toCreate == -1) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal conversion."));
|
||||
return;
|
||||
}
|
||||
|
||||
recipe = MakerItemFactory.generateLeftoverCrystalEntry(fromLeftover);
|
||||
} 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);
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, ii.getName(toCreate) + " is unavailable for Monster Crystal disassembly."));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "An unknown error occurred when trying to apply that item for disassembly."));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if(ItemConstants.isEquipment(toCreate)) { // only equips uses stimulant and reagents
|
||||
if(slea.readByte() != 0) { // stimulant
|
||||
stimulantid = getMakerStimulant(toCreate);
|
||||
if(!c.getAbstractPlayerInteraction().haveItem(stimulantid)) {
|
||||
stimulantid = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int reagents = Math.min(slea.readInt(), getMakerReagentSlots(toCreate));
|
||||
for(int i = 0; i < reagents; i++) { // crystals
|
||||
int reagentid = slea.readInt();
|
||||
if(ItemConstants.isMakerReagent(reagentid)) {
|
||||
Short rs = reagentids.get(reagentid);
|
||||
if(rs == null) {
|
||||
reagentids.put(reagentid, (short) 1);
|
||||
} else {
|
||||
reagentids.put(reagentid, (short) (rs + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Pair<Integer, Short>> toUpdate = new LinkedList<>();
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
int qty = c.getAbstractPlayerInteraction().getItemQuantity(r.getKey());
|
||||
|
||||
if(qty < r.getValue()) {
|
||||
toUpdate.add(new Pair<>(r.getKey(), (short) qty));
|
||||
}
|
||||
}
|
||||
|
||||
// remove those not present on player inventory
|
||||
if(!toUpdate.isEmpty()) {
|
||||
for(Pair<Integer, Short> rp : toUpdate) {
|
||||
if(rp.getRight() > 0) {
|
||||
reagentids.put(rp.getLeft(), rp.getRight());
|
||||
} else {
|
||||
reagentids.remove(rp.getLeft());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!reagentids.isEmpty()) {
|
||||
if(!removeOddMakerReagents(toCreate, reagentids)) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You can only use WATK and MATK Strengthening Gems on weapon items."));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recipe = MakerItemFactory.getItemCreateEntry(toCreate, stimulantid, reagentids);
|
||||
}
|
||||
|
||||
short createStatus = getCreateStatus(c, recipe);
|
||||
|
||||
switch(createStatus) {
|
||||
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."));
|
||||
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) + "."));
|
||||
break;
|
||||
|
||||
case 2: // no meso
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough mesos (" + GameConstants.numberWithCommas(recipe.getCost()) + ") to complete this operation."));
|
||||
break;
|
||||
|
||||
case 3: // no req level
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough level to complete this operation."));
|
||||
break;
|
||||
|
||||
case 4: // no req skill level
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough Maker level to complete this operation."));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (MapleInventoryManipulator.checkSpace(c, toCreate, (short) recipe.getRewardAmount(), "")) {
|
||||
for (Pair<Integer, Integer> p : recipe.getReqItems()) {
|
||||
c.getAbstractPlayerInteraction().gainItem(p.getLeft(), (short) -p.getRight());
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
c.getPlayer().setCS(true);
|
||||
c.getAbstractPlayerInteraction().gainItem(toCreate, (short) recipe.getRewardAmount());
|
||||
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 && c.getPlayer().getQuestStatus(6033) == 1) {
|
||||
c.getAbstractPlayerInteraction().setQuestProgress(6033, 1);
|
||||
}
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Your inventory is full."));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.unlockClient();
|
||||
}
|
||||
}
|
||||
|
||||
// checks and prevents hackers from PE'ing Maker operations with invalid operations
|
||||
private static boolean removeOddMakerReagents(int toCreate, Map<Integer, Short> reagentids) {
|
||||
Map<Integer, Integer> reagentType = new LinkedHashMap<>();
|
||||
List<Integer> toRemove = new LinkedList<>();
|
||||
|
||||
boolean isWeapon = ItemConstants.isWeapon(toCreate) || ServerConstants.USE_MAKER_PERMISSIVE_ATKUP;
|
||||
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
int curRid = r.getKey();
|
||||
int type = r.getKey() / 100;
|
||||
|
||||
if(type < 42502 && !isWeapon) { // only weapons should gain w.att/m.att from these.
|
||||
return false; //toRemove.add(curRid);
|
||||
} else {
|
||||
Integer tableRid = reagentType.get(type);
|
||||
|
||||
if(tableRid != null) {
|
||||
if(tableRid < curRid) {
|
||||
toRemove.add(tableRid);
|
||||
reagentType.put(type, curRid);
|
||||
} else {
|
||||
toRemove.add(curRid);
|
||||
}
|
||||
} else {
|
||||
reagentType.put(type, curRid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// removing less effective gems of repeated type
|
||||
for(Integer i : toRemove) {
|
||||
reagentids.remove(i);
|
||||
}
|
||||
|
||||
// only quantity 1 of each gem will be accepted by the Maker skill
|
||||
for(Integer i : reagentids.keySet()) {
|
||||
reagentids.put(i, (short) 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int getMakerReagentSlots(int itemId) {
|
||||
try {
|
||||
int eqpLevel = ii.getEquipStats(itemId).get("reqLevel");
|
||||
|
||||
if(eqpLevel < 78) {
|
||||
return 1;
|
||||
} else if(eqpLevel >= 78 && eqpLevel < 108) {
|
||||
return 2;
|
||||
} else {
|
||||
return 3;
|
||||
}
|
||||
} catch(NullPointerException npe) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMakerStimulant(int itemId) {
|
||||
EquipType et = EquipType.getEquipTypeById(itemId);
|
||||
|
||||
switch(et) {
|
||||
case GLOVES:
|
||||
return 4130000;
|
||||
|
||||
case SHOES:
|
||||
return 4130001;
|
||||
|
||||
case SWORD:
|
||||
return 4130002;
|
||||
|
||||
case AXE:
|
||||
return 4130003;
|
||||
|
||||
case MACE:
|
||||
return 4130004;
|
||||
|
||||
case SWORD_2H:
|
||||
return 4130005;
|
||||
|
||||
case AXE_2H:
|
||||
return 4130006;
|
||||
|
||||
case MACE_2H:
|
||||
return 4130007;
|
||||
|
||||
case SPEAR:
|
||||
return 4130008;
|
||||
|
||||
case POLEARM:
|
||||
return 4130009;
|
||||
|
||||
case WAND:
|
||||
return 4130010;
|
||||
|
||||
case STAFF:
|
||||
return 4130011;
|
||||
|
||||
case BOW:
|
||||
return 4130012;
|
||||
|
||||
case CROSSBOW:
|
||||
return 4130013;
|
||||
|
||||
case DAGGER:
|
||||
return 4130014;
|
||||
|
||||
case CLAW:
|
||||
return 4130015;
|
||||
|
||||
case KNUCKLER:
|
||||
return 4130016;
|
||||
|
||||
case PISTOL:
|
||||
return 4130017;
|
||||
|
||||
case CAP:
|
||||
return 4130018;
|
||||
|
||||
case COAT:
|
||||
return 4130019;
|
||||
|
||||
case PANTS:
|
||||
return 4130020;
|
||||
|
||||
case LONGCOAT:
|
||||
return 4130021;
|
||||
|
||||
case SHIELD:
|
||||
return 4130022;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static 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);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static short getCreateStatus(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
|
||||
if(recipe == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!hasItems(c, recipe)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(c.getPlayer().getMeso() < recipe.getCost()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if(c.getPlayer().getLevel() < recipe.getReqLevel()) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if(c.getPlayer().getSkillLevel((c.getPlayer().getJob().getId() / 1000) * 10000000 + 1007) < recipe.getReqSkillLevel()) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean hasItems(MapleClient c, MakerItemFactory.MakerItemCreateEntry recipe) {
|
||||
for (Pair<Integer, Integer> p : recipe.getReqItems()) {
|
||||
int itemId = p.getLeft();
|
||||
if (c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).countById(itemId) < p.getRight()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean addBoostedMakerItem(MapleClient c, int itemid, int stimulantid, Map<Integer, Short> reagentids) {
|
||||
if(stimulantid != -1 && !ii.rollSuccessChance(90.0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Item item = ii.getEquipById(itemid);
|
||||
if(item == null) return false;
|
||||
|
||||
Equip eqp = (Equip)item;
|
||||
if(ItemConstants.isAccessory(item.getItemId()) && eqp.getUpgradeSlots() <= 0) eqp.setUpgradeSlots(3);
|
||||
|
||||
if(ServerConstants.USE_ENHANCED_CRAFTING == true) {
|
||||
if(!(c.getPlayer().isGM() && ServerConstants.USE_PERFECT_GM_SCROLL)) {
|
||||
eqp.setUpgradeSlots((byte)(eqp.getUpgradeSlots() + 1));
|
||||
}
|
||||
item = MapleItemInformationProvider.getInstance().scrollEquipWithId(eqp, 2049100, true, 2049100, c.getPlayer().isGM());
|
||||
}
|
||||
|
||||
if(!reagentids.isEmpty()) {
|
||||
Map<String, Integer> stats = new LinkedHashMap<>();
|
||||
List<Short> randOption = new LinkedList<>();
|
||||
List<Short> randStat = new LinkedList<>();
|
||||
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
Pair<String, Integer> reagentBuff = ii.getMakerReagentStatUpgrade(r.getKey());
|
||||
|
||||
if(reagentBuff != null) {
|
||||
String s = reagentBuff.getLeft();
|
||||
|
||||
if(s.substring(0, 4).contains("rand")) {
|
||||
if(s.substring(4).equals("Stat")) {
|
||||
randStat.add((short) (reagentBuff.getRight() * r.getValue()));
|
||||
} else {
|
||||
randOption.add((short) (reagentBuff.getRight() * r.getValue()));
|
||||
}
|
||||
} else {
|
||||
String stat = s.substring(3);
|
||||
|
||||
if(!stat.equals("ReqLevel")) { // improve req level... really?
|
||||
switch (stat) {
|
||||
case "MaxHP":
|
||||
stat = "MHP";
|
||||
break;
|
||||
|
||||
case "MaxMP":
|
||||
stat = "MMP";
|
||||
break;
|
||||
}
|
||||
|
||||
Integer d = stats.get(stat);
|
||||
if(d == null) {
|
||||
stats.put(stat, reagentBuff.getRight() * r.getValue());
|
||||
} else {
|
||||
stats.put(stat, d + (reagentBuff.getRight() * r.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ii.improveEquipStats(eqp, stats);
|
||||
|
||||
for(Short sh : randStat) {
|
||||
ii.scrollOptionEquipWithChaos(eqp, sh, false);
|
||||
}
|
||||
|
||||
for(Short sh : randOption) {
|
||||
ii.scrollOptionEquipWithChaos(eqp, sh, true);
|
||||
}
|
||||
}
|
||||
|
||||
if(stimulantid != -1) {
|
||||
eqp = ii.randomizeUpgradeStats(eqp);
|
||||
}
|
||||
|
||||
MapleInventoryManipulator.addFromDrop(c, item, false, -1);
|
||||
c.announce(MaplePacketCreator.getShowItemGain(itemid, (short) 1, true));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
173
src/client/processor/StorageProcessor.java
Normal file
173
src/client/processor/StorageProcessor.java
Normal file
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
|
||||
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.processor;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleStorage;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Matze
|
||||
*/
|
||||
public class StorageProcessor {
|
||||
|
||||
public static void storageAction(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
MapleStorage storage = chr.getStorage();
|
||||
byte mode = slea.readByte();
|
||||
|
||||
if (chr.getLevel() < 15){
|
||||
chr.dropMessage(1, "You may only use the storage once you have reached level 15.");
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
c.lockClient();
|
||||
try {
|
||||
if (mode == 4) { // take out
|
||||
byte type = slea.readByte();
|
||||
byte slot = slea.readByte();
|
||||
if (slot < 0 || slot > storage.getSlots()) { // removal starts at zero
|
||||
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with storage.");
|
||||
FilePrinter.print(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to work with storage slot " + slot + "\r\n");
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
slot = storage.getSlot(MapleInventoryType.getByType(type), slot);
|
||||
Item item = storage.getItem(slot);
|
||||
if (item != null) {
|
||||
if (MapleItemInformationProvider.getInstance().isPickupRestricted(item.getItemId()) && chr.haveItemWithId(item.getItemId(), true)) {
|
||||
c.announce(MaplePacketCreator.getStorageError((byte) 0x0C));
|
||||
return;
|
||||
}
|
||||
if (chr.getMap().getId() == 910000000) {
|
||||
if (chr.getMeso() < 1000) {
|
||||
c.announce(MaplePacketCreator.getStorageError((byte) 0x0B));
|
||||
return;
|
||||
} else {
|
||||
chr.gainMeso(-1000, false);
|
||||
}
|
||||
}
|
||||
if (MapleInventoryManipulator.checkSpace(c, item.getItemId(), item.getQuantity(), item.getOwner())) {
|
||||
item = storage.takeOut(slot);//actually the same but idc
|
||||
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " took out " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")\r\n");
|
||||
chr.setUsedStorage();
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
|
||||
MapleInventoryManipulator.addFromDrop(c, item, false);
|
||||
storage.sendTakenOut(c, item.getInventoryType());
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.getStorageError((byte) 0x0A));
|
||||
}
|
||||
}
|
||||
} else if (mode == 5) { // store
|
||||
short slot = slea.readShort();
|
||||
int itemId = slea.readInt();
|
||||
short quantity = slea.readShort();
|
||||
MapleInventoryType slotType = ItemConstants.getInventoryType(itemId);
|
||||
MapleInventory Inv = chr.getInventory(slotType);
|
||||
if (slot < 1 || slot > Inv.getSlotLimit()) { //player inv starts at one
|
||||
AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with storage.");
|
||||
FilePrinter.print(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to store item at slot " + slot + "\r\n");
|
||||
c.disconnect(true, false);
|
||||
return;
|
||||
}
|
||||
if (quantity < 1 || chr.getItemQuantity(itemId, false) < quantity) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
if (storage.isFull()) {
|
||||
c.announce(MaplePacketCreator.getStorageError((byte) 0x11));
|
||||
return;
|
||||
}
|
||||
short meso = (short) (chr.getMap().getId() == 910000000 ? -500 : -100);
|
||||
if (chr.getMeso() < meso) {
|
||||
c.announce(MaplePacketCreator.getStorageError((byte) 0x0B));
|
||||
} else {
|
||||
MapleInventoryType invType = ItemConstants.getInventoryType(itemId);
|
||||
Item item = chr.getInventory(invType).getItem(slot).copy();
|
||||
if (item.getItemId() == itemId && (item.getQuantity() >= quantity || ItemConstants.isRechargeable(itemId))) {
|
||||
if (ItemConstants.isRechargeable(itemId)) {
|
||||
quantity = item.getQuantity();
|
||||
}
|
||||
chr.gainMeso(meso, false, true, false);
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
|
||||
MapleInventoryManipulator.removeFromSlot(c, invType, slot, quantity, false);
|
||||
item.setQuantity(quantity);
|
||||
storage.store(item);
|
||||
storage.sendStored(c, ItemConstants.getInventoryType(itemId));
|
||||
String itemName = MapleItemInformationProvider.getInstance().getName(item.getItemId());
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getAccountName() + ".txt", c.getPlayer().getName() + " stored " + item.getQuantity() + " " + itemName + " (" + item.getItemId() + ")\r\n");
|
||||
chr.setUsedStorage();
|
||||
}
|
||||
}
|
||||
} else if (mode == 6) { // arrange items
|
||||
if(ServerConstants.USE_STORAGE_ITEM_SORT) storage.arrangeItems(c);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
} else if (mode == 7) { // meso
|
||||
int meso = slea.readInt();
|
||||
int storageMesos = storage.getMeso();
|
||||
int playerMesos = chr.getMeso();
|
||||
if ((meso > 0 && storageMesos >= meso) || (meso < 0 && playerMesos >= -meso)) {
|
||||
if (meso < 0 && (storageMesos - meso) < 0) {
|
||||
meso = -2147483648 + storageMesos;
|
||||
if (meso < playerMesos) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
} else if (meso > 0 && (playerMesos + meso) < 0) {
|
||||
meso = 2147483647 - playerMesos;
|
||||
if (meso > storageMesos) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
}
|
||||
storage.setMeso(storageMesos - meso);
|
||||
chr.gainMeso(meso, false, true, false);
|
||||
FilePrinter.print(FilePrinter.STORAGE + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + (meso > 0 ? " took out " : " stored ") + Math.abs(meso) + " mesos\r\n");
|
||||
chr.setUsedStorage();
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
storage.sendMeso(c);
|
||||
} else if (mode == 8) {// close
|
||||
storage.close();
|
||||
}
|
||||
} finally {
|
||||
c.unlockClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user