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

@@ -116,6 +116,7 @@ import client.inventory.MaplePet;
import client.inventory.MapleWeaponType;
import client.inventory.ModifyInventory;
import client.inventory.PetDataFactory;
import client.newyear.NewYearCardRecord;
import constants.ExpTable;
import constants.GameConstants;
import constants.ItemConstants;
@@ -238,6 +239,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private MonsterBook monsterbook;
private MapleRing marriageRing;
private CashShop cashshop;
private Set<NewYearCardRecord> newyears = new LinkedHashSet<>();
private SavedLocation savedLocations[];
private SkillMacro[] skillMacros = new SkillMacro[5];
private List<Integer> lastmonthfameids;
@@ -830,7 +832,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
announce(MaplePacketCreator.getGMEffect(0x10, (byte) 0));
List<MapleBuffStat> dsstat = Collections.singletonList(MapleBuffStat.DARKSIGHT);
getMap().broadcastGMMessage(this, MaplePacketCreator.cancelForeignBuff(id, dsstat), false);
getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapobject(this), false);
getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapObject(this), false);
for(MapleSummon ms: this.getSummonsValues()) {
getMap().broadcastNONGMMessage(this, MaplePacketCreator.spawnSummon(ms, false), false);
@@ -843,7 +845,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (!login) {
getMap().broadcastMessage(this, MaplePacketCreator.removePlayerFromMap(getId()), false);
}
getMap().broadcastGMMessage(this, MaplePacketCreator.spawnPlayerMapobject(this), false);
getMap().broadcastGMMessage(this, MaplePacketCreator.spawnPlayerMapObject(this), false);
List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<MapleBuffStat, Integer>(MapleBuffStat.DARKSIGHT, 0));
getMap().broadcastGMMessage(this, MaplePacketCreator.giveForeignBuff(id, dsstat), false);
for (MapleMonster mon : this.getControlledMonsters()) {
@@ -1074,7 +1076,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
guildUpdate();
getMap().broadcastMessage(this, MaplePacketCreator.removePlayerFromMap(this.getId()), false);
getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapobject(this), false);
getMap().broadcastMessage(this, MaplePacketCreator.spawnPlayerMapObject(this), false);
getMap().broadcastMessage(this, MaplePacketCreator.showForeignEffect(getId(), 8), false);
if (GameConstants.hasSPTable(newJob) && newJob.getId() != 2001) {
@@ -5338,6 +5340,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
NewYearCardRecord.loadPlayerNewYearCards(ret);
PreparedStatement ps2, ps3;
ResultSet rs2, rs3;
@@ -7571,7 +7575,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
@Override
public void sendSpawnData(MapleClient client) {
if (!this.isHidden() || client.getPlayer().gmLevel() > 1) {
client.announce(MaplePacketCreator.spawnPlayerMapobject(this));
client.announce(MaplePacketCreator.spawnPlayerMapObject(this));
}
if (this.isHidden()) {
@@ -7600,6 +7604,40 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public CashShop getCashShop() {
return cashshop;
}
public Set<NewYearCardRecord> getNewYearRecords() {
return newyears;
}
public Set<NewYearCardRecord> getReceivedNewYearRecords() {
Set<NewYearCardRecord> received = new LinkedHashSet<>();
for(NewYearCardRecord nyc : newyears) {
if(nyc.isReceiverCardReceived()) {
received.add(nyc);
}
}
return received;
}
public NewYearCardRecord getNewYearRecord(int cardid) {
for(NewYearCardRecord nyc : newyears) {
if(nyc.getId() == cardid) {
return nyc;
}
}
return null;
}
public void addNewYearRecord(NewYearCardRecord newyear) {
newyears.add(newyear);
}
public void removeNewYearRecord(NewYearCardRecord newyear) {
newyears.remove(newyear);
}
public void portalDelay(long delay) {
this.portaldelay = System.currentTimeMillis() + delay;

View File

@@ -0,0 +1,377 @@
/*
* 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 client.newyear;
import client.MapleCharacter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ScheduledFuture;
import net.server.Server;
import server.TimerManager;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
/**
*
* @author Ronan (credits to Eric for showing the New Year opcodes and handler layout)
*/
public class NewYearCardRecord {
private int id;
private int senderId;
private String senderName;
private boolean senderDiscardCard;
private int receiverId;
private String receiverName;
private boolean receiverDiscardCard;
private boolean receiverReceivedCard;
private String stringContent;
private long dateSent = 0;
private long dateReceived = 0;
private ScheduledFuture<?> sendTask = null;
public NewYearCardRecord(int senderid, String sender, int receiverid, String receiver, String message) {
this.id = -1;
this.senderId = senderid;
this.senderName = sender;
this.senderDiscardCard = false;
this.receiverId = receiverid;
this.receiverName = receiver;
this.receiverDiscardCard = false;
this.receiverReceivedCard = false;
this.stringContent = message;
this.dateSent = System.currentTimeMillis();
this.dateReceived = 0;
}
private void setExtraNewYearCardRecord(int id, boolean senderDiscardCard, boolean receiverDiscardCard, boolean receiverReceivedCard, long dateSent, long dateReceived) {
this.id = id;
this.senderDiscardCard = senderDiscardCard;
this.receiverDiscardCard = receiverDiscardCard;
this.receiverReceivedCard = receiverReceivedCard;
this.dateSent = dateSent;
this.dateReceived = dateReceived;
}
public void setId(int cardid) {
this.id = cardid;
}
public int getId() {
return this.id;
}
public int getSenderId() {
return senderId;
}
public String getSenderName() {
return senderName;
}
public boolean isSenderCardDiscarded() {
return senderDiscardCard;
}
public int getReceiverId() {
return receiverId;
}
public String getReceiverName() {
return receiverName;
}
public boolean isReceiverCardDiscarded() {
return receiverDiscardCard;
}
public boolean isReceiverCardReceived() {
return receiverReceivedCard;
}
public String getMessage() {
return stringContent;
}
public long getDateSent() {
return dateSent;
}
public long getDateReceived() {
return dateReceived;
}
public static void saveNewYearCard(NewYearCardRecord newyear) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO newyear VALUES (DEFAULT, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) {
ps.setInt(1, newyear.senderId);
ps.setString(2, newyear.senderName);
ps.setInt(3, newyear.receiverId);
ps.setString(4, newyear.receiverName);
ps.setString(5, newyear.stringContent);
ps.setBoolean(6, newyear.senderDiscardCard);
ps.setBoolean(7, newyear.receiverDiscardCard);
ps.setBoolean(8, newyear.receiverReceivedCard);
ps.setLong(9, newyear.dateSent);
ps.setLong(10, newyear.dateReceived);
ps.executeUpdate();
try (ResultSet rs = ps.getGeneratedKeys()) {
rs.next();
newyear.id = rs.getInt(1);
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
public static void updateNewYearCard(NewYearCardRecord newyear) {
newyear.receiverReceivedCard = true;
newyear.dateReceived = System.currentTimeMillis();
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE newyear SET received=1, timereceived=? WHERE id=?")) {
ps.setLong(1, newyear.dateReceived);
ps.setInt(2, newyear.id);
ps.executeUpdate();
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
public static NewYearCardRecord loadNewYearCard(int cardid) {
NewYearCardRecord nyc = Server.getInstance().getNewYearCard(cardid);
if(nyc != null) return nyc;
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE id = ?")) {
ps.setInt(1, cardid);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
NewYearCardRecord newyear = new NewYearCardRecord(rs.getInt("senderid"), rs.getString("sendername"), rs.getInt("receiverid"), rs.getString("receivername"), rs.getString("message"));
newyear.setExtraNewYearCardRecord(rs.getInt("id"), rs.getBoolean("senderdiscard"), rs.getBoolean("receiverdiscard"), rs.getBoolean("received"), rs.getLong("timesent"), rs.getLong("timereceived"));
Server.getInstance().setNewYearCard(newyear);
return newyear;
}
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
return null;
}
public static void loadPlayerNewYearCards(MapleCharacter chr) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE senderid = ? OR receiverid = ?")) {
ps.setInt(1, chr.getId());
ps.setInt(2, chr.getId());
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
NewYearCardRecord newyear = new NewYearCardRecord(rs.getInt("senderid"), rs.getString("sendername"), rs.getInt("receiverid"), rs.getString("receivername"), rs.getString("message"));
newyear.setExtraNewYearCardRecord(rs.getInt("id"), rs.getBoolean("senderdiscard"), rs.getBoolean("receiverdiscard"), rs.getBoolean("received"), rs.getLong("timesent"), rs.getLong("timereceived"));
chr.addNewYearRecord(newyear);
}
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
public static void printNewYearRecords(MapleCharacter chr) {
chr.dropMessage(5, "New Years: " + chr.getNewYearRecords().size());
for(NewYearCardRecord nyc : chr.getNewYearRecords()) {
chr.dropMessage(5, "-------------------------------");
chr.dropMessage(5, "Id: " + nyc.id);
chr.dropMessage(5, "Sender id: " + nyc.senderId);
chr.dropMessage(5, "Sender name: " + nyc.senderName);
chr.dropMessage(5, "Sender discard: " + nyc.senderDiscardCard);
chr.dropMessage(5, "Receiver id: " + nyc.receiverId);
chr.dropMessage(5, "Receiver name: " + nyc.receiverName);
chr.dropMessage(5, "Receiver discard: " + nyc.receiverDiscardCard);
chr.dropMessage(5, "Received: " + nyc.receiverReceivedCard);
chr.dropMessage(5, "Message: " + nyc.stringContent);
chr.dropMessage(5, "Date sent: " + nyc.dateSent);
chr.dropMessage(5, "Date recv: " + nyc.dateReceived);
}
}
private static int getCharacterWorld(int receiverid) {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT world FROM characters WHERE id = ?")) {
ps.setInt(1, receiverid);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
return rs.getInt("world");
}
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
return -1;
}
public void startNewYearCardTask() {
if(sendTask != null) return;
sendTask = TimerManager.getInstance().register(new Runnable() {
@Override
public void run() {
int world = getCharacterWorld(receiverId);
if(world == -1) {
sendTask.cancel(false);
sendTask = null;
return;
}
MapleCharacter target = Server.getInstance().getWorld(world).getPlayerStorage().getCharacterById(receiverId);
if(target != null && target.isLoggedin() && !target.isAwayFromWorld()) {
target.announce(MaplePacketCreator.onNewYearCardRes(target, NewYearCardRecord.this, 0xC, 0));
}
}
}, 1000 * 60 * 60); //1 Hour
}
public void stopNewYearCardTask() {
if(sendTask != null) {
sendTask.cancel(false);
sendTask = null;
}
}
private static void deleteNewYearCard(int id) {
Server.getInstance().removeNewYearCard(id);
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("DELETE FROM newyear WHERE id = ?")) {
ps.setInt(1, id);
ps.executeUpdate();
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
public static void removeAllNewYearCard(boolean send, MapleCharacter chr) {
int cid = chr.getId();
/* not truly needed since it's going to be hard removed from the DB
String actor = (send ? "sender" : "receiver");
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("UPDATE newyear SET " + actor + "id = 1, received = 0 WHERE " + actor + "id = ?")) {
ps.setInt(1, cid);
ps.executeUpdate();
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
*/
Set<NewYearCardRecord> set = new HashSet<>(chr.getNewYearRecords());
for(NewYearCardRecord nyc : set) {
if(send) {
if(nyc.senderId == cid) {
nyc.senderDiscardCard = true;
nyc.receiverReceivedCard = false;
chr.removeNewYearRecord(nyc);
deleteNewYearCard(nyc.id);
chr.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(chr, nyc, 0xE, 0));
MapleCharacter other = chr.getClient().getWorldServer().getPlayerStorage().getCharacterById(nyc.getReceiverId());
if(other != null && other.isLoggedin() && !other.isAwayFromWorld()) {
other.removeNewYearRecord(nyc);
other.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(other, nyc, 0xE, 0));
other.dropMessage(6, "[NEW YEAR] " + chr.getName() + " threw away the New Year card.");
}
}
} else {
if(nyc.receiverId == cid) {
nyc.receiverDiscardCard = true;
nyc.receiverReceivedCard = false;
chr.removeNewYearRecord(nyc);
deleteNewYearCard(nyc.id);
chr.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(chr, nyc, 0xE, 0));
MapleCharacter other = chr.getClient().getWorldServer().getPlayerStorage().getCharacterById(nyc.getSenderId());
if(other != null && other.isLoggedin() && !other.isAwayFromWorld()) {
other.removeNewYearRecord(nyc);
other.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(other, nyc, 0xE, 0));
other.dropMessage(6, "[NEW YEAR] " + chr.getName() + " threw away the New Year card.");
}
}
}
}
}
public static void startPendingNewYearCardRequests() {
try (Connection con = DatabaseConnection.getConnection()) {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM newyear WHERE timereceived = 0 AND senderdiscard = 0")) {
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
NewYearCardRecord newyear = new NewYearCardRecord(rs.getInt("senderid"), rs.getString("sendername"), rs.getInt("receiverid"), rs.getString("receivername"), rs.getString("message"));
newyear.setExtraNewYearCardRecord(rs.getInt("id"), rs.getBoolean("senderdiscard"), rs.getBoolean("receiverdiscard"), rs.getBoolean("received"), rs.getLong("timesent"), rs.getLong("timereceived"));
Server.getInstance().setNewYearCard(newyear);
newyear.startNewYearCardTask();
}
}
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
}