New Year cards + Info on PlayerShops/HiredMerchants

New Year is coming soon! Figured out implementation for the New Year cards. Opcodes and packet structures are thanks to Eric.
New Year effect crashes/dc's the player in some cases.
Added informative notes to shop owners when transactioning an item/bundle.
This commit is contained in:
ronancpl
2017-12-19 16:40:45 -02:00
parent c1126213cc
commit 012f965f6a
19 changed files with 799 additions and 56 deletions

View File

@@ -226,6 +226,7 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.ALLIANCE_OPERATION, new AllianceOperationHandler());
registerHandler(RecvOpcode.USE_SOLOMON_ITEM, new UseSolomonHandler());
registerHandler(RecvOpcode.USE_GACHA_EXP, new UseGachaExpHandler());
registerHandler(RecvOpcode.NEW_YEAR_CARD_REQUEST, new NewYearCardHandler());
registerHandler(RecvOpcode.USE_ITEM_REWARD, new ItemRewardHandler());
registerHandler(RecvOpcode.USE_REMOTE, new RemoteGachaponHandler());
registerHandler(RecvOpcode.ACCEPT_FAMILY, new AcceptFamilyHandler());

View File

@@ -146,6 +146,7 @@ public enum RecvOpcode {
ENTER_MTS(0x9C),
USE_SOLOMON_ITEM(0x9D),
USE_GACHA_EXP(0x9E),
NEW_YEAR_CARD_REQUEST(0x9F),
CLICK_GUIDE(0xA2),
ARAN_COMBO_COUNTER(0xA3),
MOVE_PET(0xA7),

View File

@@ -68,6 +68,7 @@ import tools.Pair;
import client.MapleClient;
import client.MapleCharacter;
import client.SkillFactory;
import client.newyear.NewYearCardRecord;
import constants.ItemConstants;
import constants.ServerConstants;
import java.util.Calendar;
@@ -91,6 +92,7 @@ public class Server implements Runnable {
private final Lock srvLock = new MonitoredReentrantLock(MonitoredLockType.SERVER);
private final PlayerBuffStorage buffStorage = new PlayerBuffStorage();
private final Map<Integer, MapleAlliance> alliances = new HashMap<>(100);
private final Map<Integer, NewYearCardRecord> newyears = new HashMap<>();
private boolean online = false;
public static long uptime = System.currentTimeMillis();
@@ -109,6 +111,18 @@ public class Server implements Runnable {
public List<Pair<Integer, String>> worldRecommendedList() {
return worldRecommendedList;
}
public void setNewYearCard(NewYearCardRecord nyc) {
newyears.put(nyc.getId(), nyc);
}
public NewYearCardRecord getNewYearCard(int cardid) {
return newyears.get(cardid);
}
public NewYearCardRecord removeNewYearCard(int cardid) {
return newyears.remove(cardid);
}
/*
public void removeChannel(int worldid, int channel) { //lol don't!
@@ -306,6 +320,8 @@ public class Server implements Runnable {
MapleQuest.loadAllQuest();
System.out.println("Quest loaded in " + ((System.currentTimeMillis() - timeToTake) / 1000.0) + " seconds\r\n");
NewYearCardRecord.startPendingNewYearCardRequests();
if(ServerConstants.USE_THREAD_TRACKER) ThreadTracker.getInstance().registerThreadTrackerTask();
try {

View File

@@ -48,7 +48,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler {
private void respawnPlayer(MapleCharacter mc) {
mc.getMap().broadcastMessage(mc, MaplePacketCreator.removePlayerFromMap(mc.getId()), false);
mc.getMap().broadcastMessage(mc, MaplePacketCreator.spawnPlayerMapobject(mc), false);
mc.getMap().broadcastMessage(mc, MaplePacketCreator.spawnPlayerMapObject(mc), false);
}
private class Invited {

View File

@@ -0,0 +1,153 @@
/*
* This file is part of the HeavenMS (MapleSolaxiaV2) Maple Story Server
*
* Copyright (C) 2017 RonanLana
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package net.server.channel.handlers;
import constants.ItemConstants;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Item;
import client.newyear.NewYearCardRecord;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import net.AbstractMaplePacketHandler;
import net.server.Server;
import server.MapleItemInformationProvider;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Ronan - header layout courtesy of Eric
*/
public final class NewYearCardHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
final MapleCharacter player = c.getPlayer();
byte reqMode = slea.readByte(); //[00] -> NewYearReq (0 = Send)
if(reqMode == 0) { // card has been sent
if(player.haveItem(2160101)) { // new year's card
short slot = slea.readShort(); //[00 2C] -> nPOS (Item Slot Pos)
int itemid = slea.readInt(); //[00 20 F5 E5] -> nItemID (item id)
int status = getValidNewYearCardStatus(itemid, player, slot);
if(status == 0) {
if(player.canHold(4300000, 1)) {
String receiver = slea.readMapleAsciiString(); //[04 00 54 65 73 74] -> sReceiverName (person to send to)
int receiverid = getReceiverId(receiver, c.getWorld());
if(receiverid != -1) {
if(receiverid != c.getPlayer().getId()) {
String message = slea.readMapleAsciiString(); //[06 00 4C 65 74 74 65 72] -> sContent (message)
NewYearCardRecord newyear = new NewYearCardRecord(player.getId(), player.getName(), receiverid, receiver, message);
NewYearCardRecord.saveNewYearCard(newyear);
player.addNewYearRecord(newyear);
player.getClient().getAbstractPlayerInteraction().gainItem(2160101, (short)-1);
player.getClient().getAbstractPlayerInteraction().gainItem(4300000, (short) 1);
Server.getInstance().setNewYearCard(newyear);
newyear.startNewYearCardTask();
player.announce(MaplePacketCreator.onNewYearCardRes(player, newyear, 4, 0)); // successfully sent
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0xF)); // cannot send to yourself
}
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0x13)); // cannot find such character
}
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0x10)); // inventory full
}
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, status)); // item and inventory errors
}
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0x11)); // have no card to send
}
} else { //receiver accepted the card
int cardid = slea.readInt();
NewYearCardRecord newyear = NewYearCardRecord.loadNewYearCard(cardid);
if(newyear != null && newyear.getReceiverId() == player.getId() && !newyear.isReceiverCardReceived()) {
if(!newyear.isSenderCardDiscarded()) {
if(player.canHold(4301000, 1)) {
newyear.stopNewYearCardTask();
NewYearCardRecord.updateNewYearCard(newyear);
player.getClient().getAbstractPlayerInteraction().gainItem(4301000, (short)1);
if(!newyear.getMessage().isEmpty()) player.dropMessage(6, "[NEW YEAR] " + newyear.getSenderName() + ": " + newyear.getMessage());
player.addNewYearRecord(newyear);
player.announce(MaplePacketCreator.onNewYearCardRes(player, newyear, 6, 0)); // successfully rcvd
player.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(player, newyear, 0xD, 0));
MapleCharacter sender = c.getWorldServer().getPlayerStorage().getCharacterById(newyear.getSenderId());
if(sender != null && sender.isLoggedin() && !sender.isAwayFromWorld()) {
sender.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(sender, newyear, 0xD, 0));
sender.dropMessage(6, "[NEW YEAR] Your addressee successfully received the New Year card.");
}
} else {
player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0x10)); // inventory full
}
} else {
player.dropMessage(6, "[NEW YEAR] The sender of the New Year card already dropped it. Nothing to receive.");
}
} else {
if(newyear == null) {
player.dropMessage(6, "[NEW YEAR] The sender of the New Year card already dropped it. Nothing to receive.");
}
}
}
}
private static int getReceiverId(String receiver, int world) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT id, world FROM characters WHERE name LIKE ?")) {
ps.setString(1, receiver);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
if(rs.getInt("world") == world) {
return rs.getInt("id");
}
}
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
return -1;
}
private static int getValidNewYearCardStatus(int itemid, MapleCharacter player, short slot) {
if(!ItemConstants.isNewYearCardUse(itemid)) return 0x14;
Item it = player.getInventory(MapleItemInformationProvider.getInstance().getInventoryType(itemid)).getItem(slot);
return (it != null && it.getItemId() == itemid) ? 0 : 0x12;
}
}

View File

@@ -336,7 +336,7 @@ public class World {
}
if (bDifferentGuild) {
mc.getMap().broadcastMessage(mc, MaplePacketCreator.removePlayerFromMap(cid), false);
mc.getMap().broadcastMessage(mc, MaplePacketCreator.spawnPlayerMapobject(mc), false);
mc.getMap().broadcastMessage(mc, MaplePacketCreator.spawnPlayerMapObject(mc), false);
}
}