Overall wedding implementation

Implementation of the wedding feature.
This commit is contained in:
ronancpl
2018-04-10 21:50:29 -03:00
parent 6da5edd837
commit ede8ad8551
59 changed files with 5280 additions and 1245 deletions
+98 -15
View File
@@ -106,6 +106,7 @@ import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.Randomizer;
import tools.packets.Wedding;
import client.autoban.AutobanManager;
import client.inventory.Equip;
import client.inventory.Item;
@@ -237,7 +238,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private MapleStorage storage = null;
private MapleTrade trade = null;
private MonsterBook monsterbook;
private MapleRing marriageRing;
private CashShop cashshop;
private Set<NewYearCardRecord> newyears = new LinkedHashSet<>();
private SavedLocation savedLocations[];
@@ -279,8 +279,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private Lock prtLock = new MonitoredReentrantLock(MonitoredLockType.PRT);
private Map<Integer, Set<Integer>> excluded = new LinkedHashMap<>();
private Set<Integer> excludedItems = new LinkedHashSet<>();
private List<MapleRing> crushRings = new ArrayList<>();
private List<MapleRing> friendshipRings = new ArrayList<>();
private static String[] ariantroomleader = new String[3];
private static int[] ariantroomslot = new int[3];
private long portaldelay = 0, lastcombo = 0;
@@ -295,8 +293,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private List<Integer> viptrockmaps = new ArrayList<>();
private Map<String, MapleEvents> events = new LinkedHashMap<>();
private PartyQuest partyQuest = null;
private boolean loggedIn = false;
private MapleDragon dragon = null;
private MapleRing marriageRing;
private int marriageItemid = -1;
private int partnerId = -1;
private List<MapleRing> crushRings = new ArrayList<>();
private List<MapleRing> friendshipRings = new ArrayList<>();
private boolean loggedIn = false;
private boolean useCS; //chaos scroll upon crafting item.
private long npcCd;
private long petLootCd;
@@ -498,12 +501,39 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return ring;
}
}
if (getMarriageRing().getRingId() == id) {
return getMarriageRing();
if(marriageRing != null) {
if (marriageRing.getRingId() == id) {
return marriageRing;
}
}
return null;
}
public int getMarriageItemId() {
return marriageItemid;
}
public void setMarriageItemId(int itemid) {
marriageItemid = itemid;
}
public int getPartnerId() {
return partnerId;
}
public void setPartnerId(int partnerid) {
partnerId = partnerid;
}
public int getRelationshipId() {
return client.getWorldServer().getRelationshipId(id);
}
public boolean isMarried() {
return marriageRing != null && partnerId > 0;
}
public int addDojoPointsByMap(int mapid) {
int pts = 0;
@@ -542,6 +572,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public void addFriendshipRing(MapleRing r) {
friendshipRings.add(r);
}
public void addMarriageRing(MapleRing r) {
marriageRing = r;
}
public void addHP(int delta) {
setHp(hp + delta);
@@ -1286,6 +1320,15 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return false;
}
public void notifyMapTransferToPartner(int mapid) {
if(partnerId > 0) {
final MapleCharacter partner = client.getWorldServer().getPlayerStorage().getCharacterById(partnerId);
if(partner != null && !partner.isAwayFromWorld()) {
partner.announce(Wedding.OnNotifyWeddingPartnerTransfer(id, mapid));
}
}
}
private void changeMapInternal(final MapleMap to, final Point pos, final byte[] warpPacket) {
if(!canWarpMap) return;
@@ -1321,6 +1364,8 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
FilePrinter.printError(FilePrinter.MAPLE_MAP, "Character " + this.getName() + " got stuck when moving to map " + map.getId() + ".");
}
notifyMapTransferToPartner(map.getId());
//alas, new map has been specified when a warping was being processed...
if(newWarpMap != -1) {
canWarpMap = true;
@@ -3913,7 +3958,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
public MapleRing getMarriageRing() {
return marriageRing;
return partnerId > 0 ? marriageRing : null;
}
public int getMarried() {
@@ -5275,6 +5320,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
}
public void addPlayerRing(MapleRing ring) {
int ringItemId = ring.getItemId();
if (ItemConstants.isWeddingRing(ringItemId)) {
this.addMarriageRing(ring);
} else if (ring.getItemId() > 1112012) {
this.addFriendshipRing(ring);
} else {
this.addCrushRing(ring);
}
}
public static MapleCharacter loadCharFromDB(int charid, MapleClient client, boolean channelserver) throws SQLException {
try {
MapleCharacter ret = new MapleCharacter();
@@ -5374,15 +5430,23 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (item.getRight().equals(MapleInventoryType.EQUIPPED)) {
ring.equip();
}
if (ring.getItemId() > 1112012) {
ret.addFriendshipRing(ring);
} else {
ret.addCrushRing(ring);
}
ret.addPlayerRing(ring);
}
}
}
World wserv = Server.getInstance().getWorld(ret.world);
ret.partnerId = rs.getInt("partnerId");
ret.marriageItemid = rs.getInt("marriageItemId");
if(ret.marriageItemid > 0 && ret.partnerId <= 0) {
ret.marriageItemid = -1;
} else if(ret.partnerId > 0 && wserv.getRelationshipId(ret.id) <= 0) {
ret.marriageItemid = -1;
ret.partnerId = -1;
}
NewYearCardRecord.loadPlayerNewYearCards(ret);
PreparedStatement ps2, ps3;
@@ -6335,7 +6399,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
con.setAutoCommit(false);
PreparedStatement ps;
ps = con.prepareStatement("UPDATE characters SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, exp = ?, gachaexp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, meso = ?, hpMpUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, mountlevel = ?, mountexp = ?, mounttiredness= ?, equipslots = ?, useslots = ?, setupslots = ?, etcslots = ?, monsterbookcover = ?, vanquisherStage = ?, dojoPoints = ?, lastDojoStage = ?, finishedDojoTutorial = ?, vanquisherKills = ?, matchcardwins = ?, matchcardlosses = ?, matchcardties = ?, omokwins = ?, omoklosses = ?, omokties = ?, dataString = ?, fquest = ?, jailexpire = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
ps = con.prepareStatement("UPDATE characters SET level = ?, fame = ?, str = ?, dex = ?, luk = ?, `int` = ?, exp = ?, gachaexp = ?, hp = ?, mp = ?, maxhp = ?, maxmp = ?, sp = ?, ap = ?, gm = ?, skincolor = ?, gender = ?, job = ?, hair = ?, face = ?, map = ?, meso = ?, hpMpUsed = ?, spawnpoint = ?, party = ?, buddyCapacity = ?, messengerid = ?, messengerposition = ?, mountlevel = ?, mountexp = ?, mounttiredness= ?, equipslots = ?, useslots = ?, setupslots = ?, etcslots = ?, monsterbookcover = ?, vanquisherStage = ?, dojoPoints = ?, lastDojoStage = ?, finishedDojoTutorial = ?, vanquisherKills = ?, matchcardwins = ?, matchcardlosses = ?, matchcardties = ?, omokwins = ?, omoklosses = ?, omokties = ?, dataString = ?, fquest = ?, jailexpire = ?, partnerId = ?, marriageItemId = ? WHERE id = ?", Statement.RETURN_GENERATED_KEYS);
if (gmLevel < 1 && level > 199) {
ps.setInt(1, isCygnus() ? 120 : 200);
} else {
@@ -6437,7 +6501,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
ps.setString(48, dataString);
ps.setInt(49, quest_fame);
ps.setLong(50, jailExpiration);
ps.setInt(51, id);
ps.setInt(51, partnerId);
ps.setInt(52, marriageItemid);
ps.setInt(53, id);
int updateRows = ps.executeUpdate();
if (updateRows < 1) {
@@ -7147,9 +7213,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
if (item == null){ //Basic check
return(0);
}
if (ItemConstants.isRechargable(item.getItemId())) {
int itemid = item.getItemId();
if (ItemConstants.isRechargable(itemid)) {
quantity = item.getQuantity();
} else if (ItemConstants.isWeddingToken(itemid) || ItemConstants.isWeddingRing(itemid)) {
return(0);
}
if (quantity < 0) {
return(0);
}
@@ -8012,6 +8083,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
this.showHint("#ePLAYER EQUIPMENTS:#n\r\n\r\n" + showMsg, 400);
}
}
public void broadcastMarriageMessage() {
MapleGuild guild = this.getGuild();
if(guild != null) {
guild.broadcast(MaplePacketCreator.marriageMessage(0, name));
}
MapleFamily family = this.getFamily();
if(family != null) {
family.broadcast(MaplePacketCreator.marriageMessage(1, name));
}
}
public Map<String, MapleEvents> getEvents() {
return events;
+2
View File
@@ -783,6 +783,7 @@ public class MapleClient {
private void removePlayer() {
try {
player.setAwayFromWorld(true);
player.notifyMapTransferToPartner(-1);
player.cancelAllBuffs(true);
player.cancelAllDebuffs();
@@ -1294,6 +1295,7 @@ public class MapleClient {
player.unregisterChairBuff();
server.getPlayerBuffStorage().addBuffsToStorage(player.getId(), player.getAllBuffs());
player.setAwayFromWorld(true);
player.notifyMapTransferToPartner(-1);
player.cancelAllBuffs(true);
player.cancelBuffExpireTask();
player.cancelDiseaseExpireTask();
+4
View File
@@ -92,4 +92,8 @@ public class MapleFamily {
public Map<Integer, MapleFamilyEntry> getMembers() {
return members;
}
public void broadcast(byte[] packet) {
// family currently not developed
}
}
+34
View File
@@ -68,6 +68,40 @@ public class MapleRing implements Comparable<MapleRing> {
}
}
public static void removeRing(final MapleRing ring) {
try {
if (ring == null) {
return;
}
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM rings WHERE id=?");
ps.setInt(1, ring.getRingId());
ps.addBatch();
ps.setInt(1, ring.getPartnerRingId());
ps.addBatch();
ps.executeBatch();
ps.close();
ps = con.prepareStatement("UPDATE inventoryequipment SET ringid=-1 WHERE ringid=?");
ps.setInt(1, ring.getRingId());
ps.addBatch();
ps.setInt(1, ring.getPartnerRingId());
ps.addBatch();
ps.executeBatch();
ps.close();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
public static int createRing(int itemid, final MapleCharacter partner1, final MapleCharacter partner2) {
try {
if (partner1 == null) {
+5 -3
View File
@@ -2434,8 +2434,6 @@ public class Commands {
}
break;
case "debugpacket":
player.getMap().broadcastMessage(MaplePacketCreator.customPacket(joinStringFrom(sub, 1)));
break;
@@ -2519,6 +2517,10 @@ public class Commands {
player.dropMessage(6, "Total Task: " + tMan.getTaskCount() + " Current Task: " + tMan.getQueuedTasks() + " Active Task: " + tMan.getActiveCount() + " Completed Task: " + tMan.getCompletedTaskCount());
break;
case "debugmarriage":
c.getChannelServer().debugMarriageStatus();
break;
default:
return false;
}
@@ -2726,7 +2728,7 @@ public class Commands {
else return true;
}
public static boolean executeSolaxiaPlayerCommand(MapleClient c, String[] sub, char heading) {
public static boolean executeHeavenMsPlayerCommand(MapleClient c, String[] sub, char heading) {
Channel cserv = c.getChannelServer();
Server srv = Server.getInstance();
+8
View File
@@ -179,4 +179,12 @@ public final class ItemConstants {
public static boolean isEquipment(int itemId) {
return itemId < 2000000 && itemId != 0;
}
public static boolean isWeddingRing(int itemId) {
return itemId >= 1112803 && itemId <= 1112809;
}
public static boolean isWeddingToken(int itemId) {
return itemId >= 4031357 && itemId <= 4031364;
}
}
+5
View File
@@ -158,6 +158,11 @@ public class ServerConstants {
public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
//Wedding Configuration
public static final int WEDDING_RESERVATION_DELAY = 3; //Minimum idle slots before processing a wedding reservation.
public static final int WEDDING_RESERVATION_TIMEOUT = 10; //Limit time in minutes for the couple to show up before cancelling the wedding reservation.
public static final int WEDDING_RESERVATION_INTERVAL = 60; //Time between wedding starts in minutes.
//Event End Timestamp
public static final long EVENT_END_TIMESTAMP = 1428897600000L;
+2
View File
@@ -248,6 +248,8 @@ public final class PacketProcessor {
registerHandler(RecvOpcode.MONSTER_CARNIVAL, new MonsterCarnivalHandler());
registerHandler(RecvOpcode.REMOTE_STORE, new RemoteStoreHandler());
registerHandler(RecvOpcode.WEDDING_ACTION, new WeddingHandler());
registerHandler(RecvOpcode.WEDDING_TALK, new WeddingTalkHandler());
registerHandler(RecvOpcode.WEDDING_TALK_MORE, new WeddingTalkMoreHandler());
registerHandler(RecvOpcode.WATER_OF_LIFE, new UseWaterOfLifeHandler());
registerHandler(RecvOpcode.ADMIN_CHAT, new AdminChatHandler());
registerHandler(RecvOpcode.MOVE_DRAGON, new MoveDragonHandler());
+3 -1
View File
@@ -114,7 +114,6 @@ public enum RecvOpcode {
QUEST_ACTION(0x6B),
//lolno
SKILL_MACRO(0x6E),
SPOUSE_CHAT(0x6F),
USE_ITEM_REWARD(0x70),
MAKER_SKILL(0x71),
USE_REMOTE(0x74),
@@ -122,6 +121,7 @@ public enum RecvOpcode {
ADMIN_CHAT(0x76),
PARTYCHAT(0x77),
WHISPER(0x78),
SPOUSE_CHAT(0x79),
MESSENGER(0x7A),
PLAYER_INTERACTION(0x7B),
PARTY_OPERATION(0x7C),
@@ -137,6 +137,8 @@ public enum RecvOpcode {
RPS_ACTION(0x88),
RING_ACTION(0x89),
WEDDING_ACTION(0x8A),
WEDDING_TALK(0x8B),
WEDDING_TALK_MORE(0x8B),
ALLIANCE_OPERATION(0x8F),
OPEN_FAMILY(0x92),
ADD_FAMILY(0x93),
+1 -1
View File
@@ -67,7 +67,7 @@ public enum SendOpcode {
OPEN_FULL_CLIENT_DOWNLOAD_LINK(0x28),
MEMO_RESULT(0x29),
MAP_TRANSFER_RESULT(0x2A),
ANTI_MACRO_RESULT(0x2B),
WEDDING_PHOTO(0x2B), //ANTI_MACRO_RESULT(0x2B),
CLAIM_RESULT(0x2D),
CLAIM_AVAILABLE_TIME(0x2E),
CLAIM_STATUS_CHANGED(0x2F),
+2 -1
View File
@@ -340,9 +340,10 @@ public class Server implements Runnable {
worldRecommendedList.add(new Pair<>(i, p.getProperty("whyamirecommended" + i)));
worlds.add(world);
channels.add(new HashMap<Integer, String>());
long bootTime = System.currentTimeMillis();
for (int j = 0; j < Integer.parseInt(p.getProperty("channels" + i)); j++) {
int channelid = j + 1;
Channel channel = new Channel(i, channelid);
Channel channel = new Channel(i, channelid, bootTime);
world.addChannel(channel);
channels.get(i).put(channelid, channel.getIP());
}
+313 -1
View File
@@ -24,6 +24,7 @@ package net.server.channel;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -41,6 +42,8 @@ import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import net.MapleServerHandler;
import net.mina.MapleCodecFactory;
import net.server.Server;
import net.server.world.World;
import net.server.PlayerStorage;
import net.server.world.MapleParty;
import net.server.world.MaplePartyCharacter;
@@ -65,6 +68,7 @@ import server.maps.MapleMap;
import server.maps.MapleMapFactory;
import server.maps.MapleMiniDungeon;
import tools.MaplePacketCreator;
import tools.Pair;
import client.MapleCharacter;
import constants.ServerConstants;
import server.maps.MapleMiniDungeonInfo;
@@ -92,15 +96,30 @@ public final class Channel {
private Map<Integer, Integer> dojoParty = new HashMap<>();
private Map<Integer, MapleMiniDungeon> dungeons = new HashMap<>();
private List<Integer> chapelReservationQueue = new LinkedList<>();
private List<Integer> cathedralReservationQueue = new LinkedList<>();
private ScheduledFuture<?> chapelReservationTask;
private ScheduledFuture<?> cathedralReservationTask;
private Integer ongoingChapel = null;
private Boolean ongoingChapelType = null;
private Set<Integer> ongoingChapelGuests = null;
private Integer ongoingCathedral = null;
private Boolean ongoingCathedralType = null;
private Set<Integer> ongoingCathedralGuests = null;
private long ongoingStartTime;
private ReentrantReadWriteLock merchantLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.MERCHANT, true);
private ReadLock merchRlock = merchantLock.readLock();
private WriteLock merchWlock = merchantLock.writeLock();
private Lock lock = new MonitoredReentrantLock(MonitoredLockType.CHANNEL, true);
public Channel(final int world, final int channel) {
public Channel(final int world, final int channel, long startTime) {
this.world = world;
this.channel = channel;
this.ongoingStartTime = startTime + 10000; // rude approach to a world's last channel boot time, placeholder for the 1st wedding reservation ever
this.mapFactory = new MapleMapFactory(null, MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz")), MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/String.wz")), world, channel);
try {
eventSM = new EventScriptManager(this, getEvents());
@@ -528,4 +547,297 @@ public final class Channel {
lock.unlock();
}
}
public Pair<Boolean, Pair<Integer, Set<Integer>>> getNextWeddingReservation(boolean cathedral) {
Integer ret;
lock.lock();
try {
List<Integer> weddingReservationQueue = (cathedral ? cathedralReservationQueue : chapelReservationQueue);
if(weddingReservationQueue.isEmpty()) return null;
ret = weddingReservationQueue.remove(0);
if(ret == null) return null;
} finally {
lock.unlock();
}
World wserv = Server.getInstance().getWorld(world);
Pair<Integer, Integer> coupleId = wserv.getMarriageQueuedCouple(ret);
Pair<Boolean, Set<Integer>> typeGuests = wserv.removeMarriageQueued(ret);
Pair<String, String> couple = new Pair<>(MapleCharacter.getNameById(coupleId.getLeft()), MapleCharacter.getNameById(coupleId.getRight()));
wserv.dropMessage(6, "[WEDDING] " + couple.getLeft() + " and " + couple.getRight() + "'s wedding will start soon, and it will be held at the " + (cathedral ? "Cathedral" : "Chapel") + " in Amoria, on channel " + channel + ". Cheers for their love!!");
return new Pair<>(typeGuests.getLeft(), new Pair<>(ret, typeGuests.getRight()));
}
public boolean isWeddingReserved(Integer weddingId) {
World wserv = Server.getInstance().getWorld(world);
lock.lock();
try {
return wserv.isMarriageQueued(weddingId) || weddingId.equals(ongoingCathedral) || weddingId.equals(ongoingChapel);
} finally {
lock.unlock();
}
}
public int getWeddingReservationStatus(Integer weddingId, boolean cathedral) {
if(weddingId == null) return -1;
lock.lock();
try {
if(cathedral) {
if(weddingId.equals(ongoingCathedral)) return 0;
for(int i = 0; i < cathedralReservationQueue.size(); i++) {
if(weddingId.equals(cathedralReservationQueue.get(i))) {
return i + 1;
}
}
} else {
if(weddingId.equals(ongoingChapel)) return 0;
for(int i = 0; i < chapelReservationQueue.size(); i++) {
if(weddingId.equals(chapelReservationQueue.get(i))) {
return i + 1;
}
}
}
return -1;
} finally {
lock.unlock();
}
}
public int pushWeddingReservation(Integer weddingId, boolean cathedral, boolean premium, Integer groomId, Integer brideId) {
if(weddingId == null || isWeddingReserved(weddingId)) return -1;
World wserv = Server.getInstance().getWorld(world);
wserv.putMarriageQueued(weddingId, cathedral, premium, groomId, brideId);
lock.lock();
try {
List<Integer> weddingReservationQueue = (cathedral ? cathedralReservationQueue : chapelReservationQueue);
int delay = ServerConstants.WEDDING_RESERVATION_DELAY - 1 - weddingReservationQueue.size();
for(int i = 0; i < delay; i++) {
weddingReservationQueue.add(null); // push empty slots to fill the waiting time
}
weddingReservationQueue.add(weddingId);
return weddingReservationQueue.size();
} finally {
lock.unlock();
}
}
public boolean isOngoingWeddingGuest(boolean cathedral, int playerId) {
lock.lock();
try {
if(cathedral) {
return ongoingCathedralGuests != null && ongoingCathedralGuests.contains(playerId);
} else {
return ongoingChapelGuests != null && ongoingChapelGuests.contains(playerId);
}
} finally {
lock.unlock();
}
}
public Integer getOngoingWedding(boolean cathedral) {
lock.lock();
try {
return cathedral ? ongoingCathedral : ongoingChapel;
} finally {
lock.unlock();
}
}
public Boolean getOngoingWeddingType(boolean cathedral) {
lock.lock();
try {
return cathedral ? ongoingCathedralType : ongoingChapelType;
} finally {
lock.unlock();
}
}
public void closeOngoingWedding(boolean cathedral) {
lock.lock();
try {
if(cathedral) {
ongoingCathedral = null;
ongoingCathedralType = null;
ongoingCathedralGuests = null;
} else {
ongoingChapel = null;
ongoingChapelType = null;
ongoingChapelGuests = null;
}
} finally {
lock.unlock();
}
}
public void setOngoingWedding(final boolean cathedral, Boolean premium, Integer weddingId, Set<Integer> guests) {
lock.lock();
try {
if(cathedral) {
ongoingCathedral = weddingId;
ongoingCathedralType = premium;
ongoingCathedralGuests = guests;
} else {
ongoingChapel = weddingId;
ongoingChapelType = premium;
ongoingChapelGuests = guests;
}
} finally {
lock.unlock();
}
ongoingStartTime = System.currentTimeMillis();
if(weddingId != null) {
ScheduledFuture<?> weddingTask = TimerManager.getInstance().schedule(new Runnable() {
@Override
public void run() {
closeOngoingWedding(cathedral);
}
}, ServerConstants.WEDDING_RESERVATION_TIMEOUT * 60 * 1000);
if(cathedral) {
cathedralReservationTask = weddingTask;
} else {
chapelReservationTask = weddingTask;
}
}
}
public synchronized boolean acceptOngoingWedding(final boolean cathedral) { // couple succeeded to show up and started the ceremony
if(cathedral) {
if(cathedralReservationTask == null) return false;
cathedralReservationTask.cancel(false);
cathedralReservationTask = null;
} else {
if(chapelReservationTask == null) return false;
chapelReservationTask.cancel(false);
chapelReservationTask = null;
}
return true;
}
private static String getTimeLeft(long futureTime) {
StringBuilder str = new StringBuilder();
long leftTime = futureTime - System.currentTimeMillis();
if(leftTime < 0) {
return null;
}
byte mode = 0;
if(leftTime / (60*1000) > 0) {
mode++; //counts minutes
if(leftTime / (60*60*1000) > 0)
mode++; //counts hours
}
switch(mode) {
case 2:
int hours = (int) ((leftTime / (1000*60*60)));
str.append(hours + " hours, ");
case 1:
int minutes = (int) ((leftTime / (1000*60)) % 60);
str.append(minutes + " minutes, ");
default:
int seconds = (int) (leftTime / 1000) % 60 ;
str.append(seconds + " seconds");
}
return str.toString();
}
public long getWeddingTicketExpireTime(int resSlot) {
return ongoingStartTime + getRelativeWeddingTicketExpireTime(resSlot);
}
public static long getRelativeWeddingTicketExpireTime(int resSlot) {
return (resSlot * ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
}
public String getWeddingReservationTimeLeft(Integer weddingId) {
if(weddingId == null) return null;
lock.lock();
try {
boolean cathedral = true;
int resStatus;
resStatus = getWeddingReservationStatus(weddingId, true);
if(resStatus < 0) {
cathedral = false;
resStatus = getWeddingReservationStatus(weddingId, false);
if(resStatus < 0) {
return null;
}
}
String venue = (cathedral ? "Cathedral" : "Chapel");
if(resStatus == 0) {
return venue + " - RIGHT NOW";
}
return venue + " - " + getTimeLeft(ongoingStartTime + (resStatus * ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000)) + " from now";
} finally {
lock.unlock();
}
}
public Pair<Integer, Integer> getWeddingCoupleForGuest(int guestId, boolean cathedral) {
lock.lock();
try {
return (isOngoingWeddingGuest(cathedral, guestId)) ? Server.getInstance().getWorld(world).getRelationshipCouple(getOngoingWedding(cathedral)) : null;
} finally {
lock.unlock();
}
}
public void dropMessage(int type, String message) {
for (MapleCharacter player : getPlayerStorage().getAllCharacters()) {
player.dropMessage(type, message);
}
}
public void debugMarriageStatus() {
System.out.println(" ----- WORLD DATA -----");
Server.getInstance().getWorld(world).debugMarriageStatus();
System.out.println(" ----- CH. " + channel + " -----");
System.out.println(" ----- CATHEDRAL -----");
System.out.println("Current Queue: " + cathedralReservationQueue);
System.out.println("Cancel Task: " + (cathedralReservationTask != null));
System.out.println("Ongoing wid: " + ongoingCathedral);
System.out.println();
System.out.println("Ongoing wid: " + ongoingCathedral + " isPremium: " + ongoingCathedralType);
System.out.println("Guest list: " + ongoingCathedralGuests);
System.out.println();
System.out.println(" ----- CHAPEL -----");
System.out.println("Current Queue: " + chapelReservationQueue);
System.out.println("Cancel Task: " + (chapelReservationTask != null));
System.out.println("Ongoing wid: " + ongoingChapel);
System.out.println();
System.out.println("Ongoing wid: " + ongoingChapel + " isPremium: " + ongoingChapelType);
System.out.println("Guest list: " + ongoingChapelGuests);
System.out.println();
System.out.println("Starttime: " + ongoingStartTime);
}
}
@@ -204,11 +204,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
Equip equip = (Equip) item;
if(equip.getRingId() >= 0) {
MapleRing ring = MapleRing.loadFromDb(equip.getRingId());
if (ring.getItemId() > 1112012) {
chr.addFriendshipRing(ring);
} else {
chr.addCrushRing(ring);
}
chr.addPlayerRing(ring);
}
}
}
@@ -281,8 +277,8 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
} else if (action == 0x23) { //Friendship :3
slea.readInt(); //Birthday
// if (checkBirthday(c, birthday)) {
slea.readInt(); //Birthday
// if (checkBirthday(c, birthday)) {
int payment = slea.readByte();
slea.skip(3); //0s
int snID = slea.readInt();
@@ -60,6 +60,7 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler {
mc.unregisterChairBuff();
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(mc.getId(), mc.getAllBuffs());
mc.setAwayFromWorld(true);
mc.notifyMapTransferToPartner(-1);
mc.cancelAllBuffs(true);
mc.cancelBuffExpireTask();
mc.cancelDiseaseExpireTask();
@@ -69,6 +69,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
chr.unregisterChairBuff();
Server.getInstance().getPlayerBuffStorage().addBuffsToStorage(chr.getId(), chr.getAllBuffs());
chr.setAwayFromWorld(true);
chr.notifyMapTransferToPartner(-1);
chr.cancelAllBuffs(true);
chr.cancelBuffExpireTask();
chr.cancelDiseaseExpireTask();
@@ -51,7 +51,7 @@ public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
String[] sp = s.split(" ");
sp[0] = sp[0].toLowerCase().substring(1);
if(Commands.executeSolaxiaPlayerCommand(c, sp, heading)) {
if(Commands.executeHeavenMsPlayerCommand(c, sp, heading)) {
String command = "";
for (String used : sp) {
command += used + " ";
@@ -54,6 +54,7 @@ import constants.GameConstants;
import constants.ServerConstants;
import java.util.Collections;
import java.util.Comparator;
import tools.packets.Wedding;
public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
@@ -255,6 +256,16 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
player.updateCouponRates();
player.receivePartyMemberHP();
if(player.getPartnerId() > 0) {
int partnerId = player.getPartnerId();
final MapleCharacter partner = c.getWorldServer().getPlayerStorage().getCharacterById(partnerId);
if(partner != null && !partner.isAwayFromWorld()) {
player.announce(Wedding.OnNotifyWeddingPartnerTransfer(partnerId, partner.getMapId()));
partner.announce(Wedding.OnNotifyWeddingPartnerTransfer(player.getId(), player.getMapId()));
}
}
}
private static void showDueyNotification(MapleClient c, MapleCharacter player) {
@@ -25,86 +25,477 @@ package net.server.channel.handlers;
//import java.sql.PreparedStatement;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.MapleInventoryType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
//import tools.DatabaseConnection;
import net.AbstractMaplePacketHandler;
import server.MapleInventoryManipulator;
import tools.DatabaseConnection;
import tools.data.input.SeekableLittleEndianAccessor;
//import scripting.npc.NPCScriptManager;
import tools.Pair;
import tools.MaplePacketCreator;
import tools.packets.Wedding;
import net.server.world.World;
import net.server.channel.Channel;
import server.MapleItemInformationProvider;
import client.MapleRing;
import client.inventory.Equip;
import client.inventory.Item;
/**
* @author Jvlaple
* @author Ronan (major overhaul on Ring handling mechanics)
*/
public final class RingActionHandler extends AbstractMaplePacketHandler {
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte mode = slea.readByte();
MapleCharacter player = c.getPlayer();
switch (mode) {
case 0: //Send
String partnerName = slea.readMapleAsciiString();
MapleCharacter partner = c.getChannelServer().getPlayerStorage().getCharacterByName(partnerName);
if (partnerName.equalsIgnoreCase(player.getName())) {
c.getPlayer().dropMessage(1, "You cannot put your own name in it.");
return;
} else if (partner == null) {
c.getPlayer().dropMessage(1, partnerName + " was not found on this channel. If you are both logged in, please make sure you are in the same channel.");
return;
} else if (partner.getGender() == player.getGender()) {
c.getPlayer().dropMessage(1, "Your partner is the same gender as you.");
return;
} //else if (player.isMarried() && partner.isMarried())
// NPCScriptManager.getInstance().start(partner.getClient(), 9201002, "marriagequestion", player);
break;
case 1: //Cancel send
c.getPlayer().dropMessage(1, "You've cancelled the request.");
boolean accepted = slea.readByte() > 0;
String proposerName = slea.readMapleAsciiString();
if (accepted) {
c.announce(MaplePacketCreator.sendEngagementRequest(proposerName));
}
break;
case 2:
slea.readByte(); //type
case 3: //Drop Ring
/*
if (player.getPartner() != null) {
try {
Connection con = DatabaseConnection.getConnection();
int pid = 0;
if (player.getGender() == 0)
pid = player.getId();
else
pid = player.getPartner().getId();//we have an engagements SQL?
PreparedStatement ps = con.prepareStatement("DELETE FROM engagements WHERE husbandid = ?");
ps.setInt(1, pid);
ps.executeUpdate();
ps.close();
ps = con.prepareStatement("UPDATE characters SET marriagequest = 0 WHERE id = ?, and WHERE id = ?");
ps.setInt(1, player.getId());
ps.setInt(2, player.getPartner().getId());
ps.executeUpdate();
ps.close();
con.close();
} catch (Exception ex) {
ex.printStackTrace();
}
c.getPlayer().dropMessage(1, "Your engagement has been broken up.");
break;
}*/
break;
case 9: // groom's wishlist
int amount = slea.readShort();
if (amount > 10) {
amount = 10;
}
String[] items = new String[10];
for (int i = 0; i < amount; i++) {
items[i] = slea.readMapleAsciiString();
}
c.announce(MaplePacketCreator.sendGroomWishlist()); //WTF<
break;
default:
System.out.println("NEW RING ACTION " + mode);
break;
private static int getBoxId(int useItemId) {
return useItemId == 2240000 ? 4031357 : (useItemId == 2240001 ? 4031359 : (useItemId == 2240002 ? 4031361 : (useItemId == 2240003 ? 4031363 : (1112300 + (useItemId - 2240004)))));
}
public static void sendEngageProposal(final MapleClient c, final String name, final int itemid) {
final int newBoxId = getBoxId(itemid);
final MapleCharacter target = c.getChannelServer().getPlayerStorage().getCharacterByName(name);
final MapleCharacter source = c.getPlayer();
// TODO: get the correct packet bytes for these popups
if (source.isMarried()) {
source.dropMessage(1, "You're already married!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (source.getPartnerId() > 0) {
source.dropMessage(1, "You're already engaged!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (source.getMarriageItemId() > 0) {
source.dropMessage(1, "You're already engaging someone!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (target == null) {
source.dropMessage(1, "Unable to find " + name + " on this channel.");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (target == source) {
source.dropMessage(1, "You can't engage yourself.");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (!target.getMap().equals(source.getMap())) {
source.dropMessage(1, "Make sure your partner is on the same map!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (!source.haveItem(itemid) || itemid < 2240000 || itemid > 2240015) {
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (target.isMarried()) {
source.dropMessage(1, "The player is already married!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (target.getPartnerId() > 0 || target.getMarriageItemId() > 0) {
source.dropMessage(1, "The player is already engaged!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (target.getGender() != 1) {
source.dropMessage(1, "You may only propose to a girl!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (!MapleInventoryManipulator.checkSpace(c, newBoxId, 1, "")) {
source.dropMessage(5, "You don't have a ETC slot available right now!");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
} else if (!MapleInventoryManipulator.checkSpace(target.getClient(), newBoxId + 1, 1, "")) {
source.dropMessage(5, "The girl you proposed doesn't have a ETC slot available right now.");
source.announce(Wedding.OnMarriageResult((byte) 0));
return;
}
source.setMarriageItemId(itemid);
target.announce(Wedding.OnMarriageRequest(source.getName(), source.getId()));
}
private static void eraseEngagementOffline(int characterId) {
try {
Connection con = DatabaseConnection.getConnection();
eraseEngagementOffline(characterId, con);
con.close();
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
private static void eraseEngagementOffline(int characterId, Connection con) throws SQLException {
PreparedStatement ps = con.prepareStatement("UPDATE characters SET marriageItemId=-1, partnerId=-1 WHERE id=?");
ps.setInt(1, characterId);
ps.executeUpdate();
ps.close();
}
private static void breakEngagementOffline(int characterId) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT marriageItemId FROM characters WHERE id=?");
ps.setInt(1, characterId);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int marriageItemId = rs.getInt("marriageItemId");
if (marriageItemId > 0) {
PreparedStatement ps2 = con.prepareStatement("UPDATE inventoryitems SET expiration=0 WHERE itemid=? AND characterid=?");
ps2.setInt(1, marriageItemId);
ps2.setInt(2, characterId);
ps2.executeUpdate();
ps2.close();
}
}
rs.close();
ps.close();
eraseEngagementOffline(characterId, con);
con.close();
} catch (SQLException ex) {
System.out.println("Error updating offline breakup " + ex.getMessage());
}
}
private synchronized static void breakMarriage(MapleCharacter chr) {
int partnerid = chr.getPartnerId();
if(partnerid <= 0) return;
chr.getClient().getWorldServer().deleteRelationship(chr.getId(), partnerid);
MapleRing.removeRing(chr.getMarriageRing());
MapleCharacter partner = chr.getClient().getWorldServer().getPlayerStorage().getCharacterById(partnerid);
if(partner == null) {
eraseEngagementOffline(partnerid);
} else {
partner.dropMessage(5, chr.getName() + " has decided to break up the marriage.");
//partner.announce(Wedding.OnMarriageResult((byte) 0)); ok, how to gracefully unengage someone without the need to cc?
resetRingId(partner);
partner.setPartnerId(-1);
partner.setMarriageItemId(-1);
partner.addMarriageRing(null);
}
chr.dropMessage(5, "You have successfully break the marriage with " + MapleCharacter.getNameById(partnerid) + ".");
//chr.announce(Wedding.OnMarriageResult((byte) 0));
resetRingId(chr);
chr.setPartnerId(-1);
chr.setMarriageItemId(-1);
chr.addMarriageRing(null);
}
private static void resetRingId(MapleCharacter player) {
int ringitemid = player.getMarriageRing().getItemId();
Item it = player.getInventory(MapleInventoryType.EQUIP).findById(ringitemid);
if(it == null) {
it = player.getInventory(MapleInventoryType.EQUIPPED).findById(ringitemid);
}
if(it != null) {
Equip eqp = (Equip) it;
eqp.setRingId(-1);
}
}
private synchronized static void breakEngagement(MapleCharacter chr) {
int partnerid = chr.getPartnerId();
int marriageitemid = chr.getMarriageItemId();
chr.getClient().getWorldServer().deleteRelationship(chr.getId(), partnerid);
MapleCharacter partner = chr.getClient().getWorldServer().getPlayerStorage().getCharacterById(partnerid);
if(partner == null) {
breakEngagementOffline(partnerid);
} else {
partner.dropMessage(5, chr.getName() + " has decided to break up the engagement.");
int partnerMarriageitemid = marriageitemid + ((chr.getGender() == 0) ? 1 : -1);
if(partner.haveItem(partnerMarriageitemid)) {
MapleInventoryManipulator.removeById(partner.getClient(), MapleInventoryType.ETC, partnerMarriageitemid, (short) 1, false, false);
}
//partner.announce(Wedding.OnMarriageResult((byte) 0)); ok, how to gracefully unengage someone without the need to cc?
partner.setPartnerId(-1);
partner.setMarriageItemId(-1);
}
if(chr.haveItem(marriageitemid)) {
MapleInventoryManipulator.removeById(chr.getClient(), MapleInventoryType.ETC, marriageitemid, (short) 1, false, false);
}
chr.dropMessage(5, "You have successfully break the engagement with " + MapleCharacter.getNameById(partnerid) + ".");
//chr.announce(Wedding.OnMarriageResult((byte) 0));
chr.setPartnerId(-1);
chr.setMarriageItemId(-1);
}
public static void breakMarriageRing(MapleCharacter chr, final int wItemId) {
final MapleInventoryType type = MapleInventoryType.getByType((byte) (wItemId / 1000000));
final Item wItem = chr.getInventory(type).findById(wItemId);
final boolean weddingToken = (wItem != null && type == MapleInventoryType.ETC && wItemId / 10000 == 403);
final boolean weddingRing = (wItem != null && wItemId / 10 == 111280);
if (weddingRing) {
if(chr.getPartnerId() > 0) {
breakMarriage(chr);
}
chr.getMap().disappearingItemDrop(chr, chr, wItem, chr.getPosition());
} else if (weddingToken) {
if (chr.getPartnerId() > 0) {
breakEngagement(chr);
}
chr.getMap().disappearingItemDrop(chr, chr, wItem, chr.getPosition());
}
}
public static void giveMarriageRings(MapleCharacter player, MapleCharacter partner, int marriageRingId) {
int ringid = MapleRing.createRing(marriageRingId, player, partner);
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Item ringObj = ii.getEquipById(marriageRingId);
Equip ringEqp = (Equip) ringObj;
ringEqp.setRingId(ringid);
player.addMarriageRing(MapleRing.loadFromDb(ringid));
MapleInventoryManipulator.addFromDrop(player.getClient(), ringEqp, false, -1);
player.broadcastMarriageMessage();
ringObj = ii.getEquipById(marriageRingId);
ringEqp = (Equip) ringObj;
ringEqp.setRingId(ringid + 1);
partner.addMarriageRing(MapleRing.loadFromDb(ringid + 1));
MapleInventoryManipulator.addFromDrop(partner.getClient(), ringEqp, false, -1);
partner.broadcastMarriageMessage();
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte mode = slea.readByte();
String name;
byte slot;
switch(mode) {
case 0: // Send Proposal
sendEngageProposal(c, slea.readMapleAsciiString(), slea.readInt());
break;
case 1: // Cancel Proposal
System.out.println("Cancel Ring Action: " + slea.toString()); // log packet and see if any bytes
if(c.getPlayer().getMarriageItemId() / 1000000 != 4) {
c.getPlayer().setMarriageItemId(-1);
}
break;
case 2: // Accept/Deny Proposal
final boolean accepted = slea.readByte() > 0;
name = slea.readMapleAsciiString();
final int id = slea.readInt();
final MapleCharacter source = c.getWorldServer().getPlayerStorage().getCharacterByName(name);
final MapleCharacter target = c.getPlayer();
if (source == null) {
target.announce(MaplePacketCreator.enableActions());
return;
}
final int itemid = source.getMarriageItemId();
if (target.getPartnerId() > 0 || source.getId() != id || itemid <= 0 || !source.haveItem(itemid) || source.getPartnerId() > 0 || !source.isAlive() || !target.isAlive()) {
target.announce(MaplePacketCreator.enableActions());
return;
}
if (accepted) {
final int newItemId = getBoxId(itemid);
if (!MapleInventoryManipulator.checkSpace(c, newItemId, 1, "") || !MapleInventoryManipulator.checkSpace(source.getClient(), newItemId, 1, "")) {
target.announce(MaplePacketCreator.enableActions());
return;
}
try {
MapleInventoryManipulator.removeById(source.getClient(), MapleInventoryType.USE, itemid, 1, false, false);
int marriageId = c.getWorldServer().createRelationship(source.getId(), target.getId());
source.setPartnerId(target.getId()); // engage them (new marriageitemid, partnerid for both)
target.setPartnerId(source.getId());
source.setMarriageItemId(newItemId);
target.setMarriageItemId(newItemId + 1);
MapleInventoryManipulator.addById(source.getClient(), newItemId, (short) 1);
MapleInventoryManipulator.addById(c, (newItemId + 1), (short) 1);
source.announce(Wedding.OnMarriageResult(marriageId, source, false));
target.announce(Wedding.OnMarriageResult(marriageId, source, false));
source.announce(Wedding.OnNotifyWeddingPartnerTransfer(target.getId(), target.getMapId()));
target.announce(Wedding.OnNotifyWeddingPartnerTransfer(source.getId(), source.getMapId()));
} catch (Exception e) {
System.out.println("Error with engagement " + e.getMessage());
}
} else {
source.dropMessage(1, "She has politely declined your engagement request.");
source.announce(Wedding.OnMarriageResult((byte) 0));
source.setMarriageItemId(-1);
}
break;
case 3: // Break Engagement
breakMarriageRing(c.getPlayer(), slea.readInt());
break;
case 5: // Invite %s to Wedding
name = slea.readMapleAsciiString();
int marriageId = slea.readInt();
slot = slea.readByte(); // this is an int
int itemId;
try {
itemId = c.getPlayer().getInventory(MapleInventoryType.ETC).getItem(slot).getItemId();
} catch(NullPointerException npe) {
c.announce(MaplePacketCreator.enableActions());
return;
}
if((itemId != 4031377 && itemId != 4031395) || !c.getPlayer().haveItem(itemId)) {
c.announce(MaplePacketCreator.enableActions());
return;
}
String groom = c.getPlayer().getName(), bride = MapleCharacter.getNameById(c.getPlayer().getPartnerId());
int guest = MapleCharacter.getIdByName(name);
if (groom == null || bride == null || groom.equals("") || bride.equals("") || guest <= 0) {
c.getPlayer().dropMessage(5, "Unable to find " + name + "!");
return;
}
try {
World wserv = c.getWorldServer();
Pair<Boolean, Boolean> registration = wserv.getMarriageQueuedLocation(marriageId);
if(registration != null) {
if(wserv.addMarriageGuest(marriageId, guest)) {
boolean cathedral = registration.getLeft();
int newItemId = cathedral ? 4031407 : 4031406;
Channel cserv = c.getChannelServer();
int resStatus = cserv.getWeddingReservationStatus(marriageId, cathedral);
if(resStatus > 0) {
long expiration = cserv.getWeddingTicketExpireTime(resStatus + 1);
MapleCharacter guestChr = c.getWorldServer().getPlayerStorage().getCharacterById(guest);
if(guestChr != null && MapleInventoryManipulator.checkSpace(guestChr.getClient(), newItemId, 1, "") && MapleInventoryManipulator.addById(guestChr.getClient(), newItemId, (short) 1, expiration)) {
guestChr.dropMessage(6, "[WEDDING] You've been invited to " + groom + " and " + bride + "'s Wedding!");
} else {
c.getPlayer().sendNote(name, "You've been invited to " + groom + " and " + bride + "'s Wedding! Receive your invitation from Duey!", (byte) 0);
Item weddingTicket = new Item(newItemId, (short) 0, (short) 1);
weddingTicket.setExpiration(expiration);
DueyHandler.addItemToDB(weddingTicket, 1, 0, groom, guest);
}
} else {
c.getPlayer().dropMessage(5, "Wedding is already under way. You cannot invite any more guests for the event.");
}
} else {
c.getPlayer().dropMessage(5, "'" + name + "' is already invited for your marriage.");
}
} else {
c.getPlayer().dropMessage(5, "Invitation was not sent to '" + name + "'. Either the time for your marriage reservation already came or it was not found.");
}
} catch (SQLException ex) {
ex.printStackTrace();
return;
}
c.getAbstractPlayerInteraction().gainItem(itemId, (short) -1);
break;
case 6: // Open Wedding Invitation
slot = (byte) slea.readInt();
int invitationid = slea.readInt();
if(invitationid == 4031406 || invitationid == 4031407) {
Item item = c.getPlayer().getInventory(MapleInventoryType.ETC).getItem(slot);
if(item == null || item.getItemId() != invitationid) {
c.announce(MaplePacketCreator.enableActions());
return;
}
// collision case: most soon-to-come wedding will show up
Pair<Integer, Integer> coupleId = c.getWorldServer().getWeddingCoupleForGuest(c.getPlayer().getId(), invitationid == 4031407);
if (coupleId != null) {
int groomId = coupleId.getLeft(), brideId = coupleId.getRight();
c.announce(Wedding.sendWeddingInvitation(MapleCharacter.getNameById(groomId), MapleCharacter.getNameById(brideId)));
}
}
break;
case 9: // Groom and Bride's Wishlist
short size = slea.readShort();
List<String> itemnames = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
itemnames.add(slea.readMapleAsciiString());
}
System.out.println("G&B WISHLIST: " + itemnames);
/*
if (c.getPlayer().getMarriageItemId() > -1) {
switch(c.getPlayer().getMarriageItemId()) {
case 10: // Premium Cathedral
c.getAbstractPlayerInteraction().gainItem(4031375, (short)1);
c.getAbstractPlayerInteraction().gainItem(4031395, (short)15);
break;
case 11: // Normal Cathedral
c.getAbstractPlayerInteraction().gainItem(4031480, (short)1);
c.getAbstractPlayerInteraction().gainItem(4031395, (short)15);
break;
case 20: // Premium Chapel
c.getAbstractPlayerInteraction().gainItem(4031376, (short)1);
c.getAbstractPlayerInteraction().gainItem(4031377, (short)15);
break;
case 21: // Normal Chapel
c.getAbstractPlayerInteraction().gainItem(4031481, (short)1);
c.getAbstractPlayerInteraction().gainItem(4031377, (short)15);
break;
default: {
System.out.println("Invalid Wedding Type for player " + c.getPlayer().getName() + "!");
break;
}
}
//c.getPlayer().setMarriageItemId(-1); ?????
}
if (c.getPlayer().getWishlist() == null) {
c.getPlayer().registerWishlist(itemnames);
}
if (c.getPlayer().getWedding() != null) {
if (c.getPlayer().getGender() == 0 ? c.getPlayer().getWedding().isExistantGroom(c.getPlayer().getId()) : c.getPlayer().getWedding().isExistantBride(c.getPlayer().getId())) {
c.getPlayer().getWedding().registerWishlist(c.getPlayer().getGender() == 1, itemnames);
}
}
*/
break;
default:
System.out.println("Unhandled RING_ACTION Mode: " + slea.toString());
break;
}
c.getSession().write(MaplePacketCreator.enableActions());
}
}
@@ -21,36 +21,29 @@
*/
package net.server.channel.handlers;
//import client.MapleCharacter;
import client.MapleCharacter;
import client.MapleClient;
//import client.command.CommandProcessor;
import net.AbstractMaplePacketHandler;
//import tools.MaplePacketCreator;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class SpouseChatHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
System.out.println(slea.toString());
// slea.readMapleAsciiString();//recipient
// String msg = slea.readMapleAsciiString();
// if (!CommandProcessor.processCommand(c, msg))
// if (c.getPlayer().isMarried()) {
// MapleCharacter wife = c.getChannelServer().getPlayerStorage().getCharacterById(c.getPlayer().getPartnerId());
// if (wife != null) {
// wife.getClient().announce(MaplePacketCreator.sendSpouseChat(c.getPlayer(), msg));
// c.announce(MaplePacketCreator.sendSpouseChat(c.getPlayer(), msg));
// } else
// try {
// if (c.getChannelServer().getWorldInterface().isConnected(wife.getName())) {
// c.getChannelServer().getWorldInterface().sendSpouseChat(c.getPlayer().getName(), wife.getName(), msg);
// c.announce(MaplePacketCreator.sendSpouseChat(c.getPlayer(), msg));
// } else
// c.getPlayer().message("You are either not married or your spouse is currently offline.");
// } catch (Exception e) {
// e.printStackTrace();
// c.getPlayer().message("You are either not married or your spouse is currently offline.");
// c.getChannelServer().reconnectWorld();
// }
// }
slea.readMapleAsciiString();//recipient
String msg = slea.readMapleAsciiString();
int partnerId = c.getPlayer().getPartnerId();
if (partnerId > 0) { // yay marriage
MapleCharacter spouse = c.getWorldServer().getPlayerStorage().getCharacterById(partnerId);
if (spouse != null) {
spouse.announce(MaplePacketCreator.OnCoupleMessage(c.getPlayer().getName(), msg, true));
c.announce(MaplePacketCreator.OnCoupleMessage(c.getPlayer().getName(), msg, true));
} else {
c.getPlayer().dropMessage(5, "Your spouse is currently offline.");
}
} else {
c.getPlayer().dropMessage(5, "You don't have a spouse.");
}
}
}
@@ -1,39 +1,93 @@
/*
* To change this template, choose Tools | Templates
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.MapleCharacter;
import client.MapleClient;
import constants.ItemConstants;
import tools.DatabaseConnection;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import net.AbstractMaplePacketHandler;
import server.MapleInventoryManipulator;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.packets.Wedding;
/**
*
* @author Kevin
* @author Eric
*/
public class WeddingHandler extends AbstractMaplePacketHandler {
@Override
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
//System.out.println("Wedding Packet: " + slea);
MapleCharacter chr = c.getPlayer();
byte operation = slea.readByte();
switch (operation) {
case 0x06://Add an item to the Wedding Registry
short slot = slea.readShort();
int itemid = slea.readInt();
short quantity = slea.readShort();
MapleInventoryType type = ItemConstants.getInventoryType(itemid);
Item item = chr.getInventory(type).getItem(slot);
if (itemid == item.getItemId() && quantity <= item.getQuantity()) {
c.announce(MaplePacketCreator.addItemToWeddingRegistry(chr, item));
public final class WeddingHandler extends AbstractMaplePacketHandler {
/*
public static final void OnWeddingProgress(byte action, MapleClient c) {
// -- Pelvis Bebop:
// 0x00: "We are gathered here today..."
// 0x01: "Very well! I pronounce you..."
// 0x02: "You two truly are a sight to..."
// 0x03: Wedding Ceremony Ended, initialize the Wedding Effect upon the two married characters
// -- High Priest John: (Unknown action bytes)
// 0x00: " "
// 0x01: " "
// 0x02: "Do you wish to bless this couple?..."
// 0x03: Wedding Ceremony Ended, initialize the Wedding Effect upon the two married characters
if (c.getPlayer().getWedding() != null) {
if (c.getPlayer().getGender() == 0 ? c.getPlayer().getWedding().isExistantGroom(c.getPlayer().getId()) : c.getPlayer().getWedding().isExistantBride(c.getPlayer().getId())) {
c.getPlayer().getMap().broadcastMessage(Wedding.OnWeddingProgress(action == 2, c.getPlayer().getId(), c.getPlayer().getPartnerId(), (byte)(action+1)));
c.getPlayer().getWedding().incrementStage();
c.getPlayer().getPartner().getWedding().incrementStage(); // pls don't b a bitch and throw npe ):<
if (action == 2) {
c.getPlayer().setMarried(true);
c.getChannelServer().getPlayerStorage().getCharacterById(c.getPlayer().getPartnerId()).setMarried(true);
}
}
}
c.announce(MaplePacketCreator.enableActions());
}
public static final void OnWeddingGiftResult(SeekableLittleEndianAccessor slea, MapleClient c) {
System.out.println("New WEDDING_GIFT_RESULT: " + slea.toString());
byte mode = slea.readByte();
switch(mode) {
case 0x06: // "SEND ITEM"
short slot = slea.readShort(); // isn't this a byte? o.O
int itemId = slea.readInt();
short quantity = slea.readShort();
if (c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).getItem((byte)slot).getItemId() == itemId && c.getPlayer().getInventory(InventoryConstants.getInventoryType(itemId)).getItem((byte)slot).getQuantity() >= quantity) {
if (c.getPlayer().getWedding() == null) {
c.getPlayer().startWedding(); // TODO
}
List<String> itemnames = new ArrayList<>();
Item item = c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).getItem((byte)slot);
boolean bride = false;
c.getPlayer().getWedding().registerWishlistItem(item, bride);
c.announce(Wedding.OnWeddingGiftResult((byte)11, itemnames, c.getPlayer().getWedding().getWishlistItems(bride))); // todo: remove item from inventory if success
}
case 0x08: // "EXIT"
if (slea.available() != 0) {
System.out.println("WEDDING_GIFT_RESULT: " + slea.toString());
}
c.announce(MaplePacketCreator.enableActions());
break;
default: {
System.out.println("Unknown Mode Found: " + mode + " : " + slea.toString());
}
}
}
}
*/
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.announce(MaplePacketCreator.enableActions());
}
}
@@ -0,0 +1,53 @@
/*
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 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 net.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import scripting.event.EventInstanceManager;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.packets.Wedding;
/**
*
* @author Ronan
*/
public final class WeddingTalkHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
byte action = slea.readByte();
if(action == 1) {
EventInstanceManager eim = c.getPlayer().getEventInstance();
if(eim != null && !(c.getPlayer().getId() == eim.getIntProperty("groomId") || c.getPlayer().getId() == eim.getIntProperty("brideId"))) {
c.announce(Wedding.OnWeddingProgress(false, 0, 0, (byte) 2));
} else {
c.announce(Wedding.OnWeddingProgress(true, 0, 0, (byte) 3));
}
} else {
c.announce(Wedding.OnWeddingProgress(true, 0, 0, (byte) 3));
}
c.announce(MaplePacketCreator.enableActions());
}
}
@@ -0,0 +1,47 @@
/*
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 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 net.server.channel.handlers;
import client.MapleClient;
import net.AbstractMaplePacketHandler;
import scripting.event.EventInstanceManager;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
import tools.packets.Wedding;
/**
*
* @author Ronan
*/
public final class WeddingTalkMoreHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
EventInstanceManager eim = c.getPlayer().getEventInstance();
if(eim != null && !(c.getPlayer().getId() == eim.getIntProperty("groomId") || c.getPlayer().getId() == eim.getIntProperty("brideId"))) {
eim.gridInsert(c.getPlayer(), 1);
c.getPlayer().dropMessage(5, "High Priest John: Your blessings have been added to their love. What a noble act for a lovely couple!");
}
c.announce(Wedding.OnWeddingProgress(true, 0, 0, (byte) 3));
c.announce(MaplePacketCreator.enableActions());
}
}
@@ -0,0 +1,56 @@
/*
This file is part of the HeavenMS (MapleSolaxiaV2) MapleStory Server
Copyleft (L) 2017 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 net.server.worker;
import java.util.Set;
import net.server.world.World;
import net.server.channel.Channel;
import tools.Pair;
/**
* @author Ronan
*/
public class WeddingReservationWorker extends BaseWorker implements Runnable {
@Override
public void run() {
for(Channel ch : wserv.getChannels()) {
Pair<Boolean, Pair<Integer, Set<Integer>>> wedding;
wedding = ch.getNextWeddingReservation(true); // start cathedral
if(wedding != null) {
ch.setOngoingWedding(true, wedding.getLeft(), wedding.getRight().getLeft(), wedding.getRight().getRight());
} else {
ch.setOngoingWedding(true, null, null, null);
}
wedding = ch.getNextWeddingReservation(false); // start chapel
if(wedding != null) {
ch.setOngoingWedding(false, wedding.getLeft(), wedding.getRight().getLeft(), wedding.getRight().getRight());
} else {
ch.setOngoingWedding(false, null, null, null);
}
}
}
public WeddingReservationWorker(World world) {
super(world);
}
}
+251 -24
View File
@@ -31,7 +31,9 @@ import constants.ServerConstants;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -58,6 +60,7 @@ import server.maps.AbstractMapleMapObject;
import net.server.worker.CharacterAutosaverWorker;
import net.server.worker.MountTirednessWorker;
import net.server.worker.PetFullnessWorker;
import net.server.worker.WeddingReservationWorker;
import net.server.PlayerStorage;
import net.server.Server;
import net.server.channel.Channel;
@@ -83,10 +86,14 @@ public class World {
private Map<Integer, MapleMessenger> messengers = new HashMap<>();
private AtomicInteger runningMessengerId = new AtomicInteger();
private Map<Integer, MapleFamily> families = new LinkedHashMap<>();
private Map<Integer, Integer> relationships = new HashMap<>();
private Map<Integer, Pair<Integer, Integer>> relationshipCouples = new HashMap<>();
private Map<Integer, MapleGuildSummary> gsStore = new HashMap<>();
private PlayerStorage players = new PlayerStorage();
private Set<Integer> queuedGuilds = new HashSet<>();
private Map<Integer, Pair<Pair<Boolean, Boolean>, Pair<Integer, Integer>>> queuedMarriages = new HashMap<>();
private Map<Integer, Set<Integer>> marriageGuests = new HashMap<>();
private Map<Integer, MapleParty> parties = new HashMap<>();
private AtomicInteger runningPartyId = new AtomicInteger();
@@ -113,6 +120,7 @@ public class World {
private long merchantUpdate;
private ScheduledFuture<?> charactersSchedule;
private ScheduledFuture<?> marriagesSchedule;
public World(int world, int flag, String eventmsg, int exprate, int droprate, int mesorate, int questrate) {
this.id = world;
@@ -128,9 +136,11 @@ public class World {
petUpdate = System.currentTimeMillis();
mountUpdate = petUpdate;
petsSchedule = TimerManager.getInstance().register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
mountsSchedule = TimerManager.getInstance().register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
charactersSchedule = TimerManager.getInstance().register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
TimerManager tman = TimerManager.getInstance();
petsSchedule = tman.register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000);
mountsSchedule = tman.register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000);
charactersSchedule = tman.register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000);
marriagesSchedule = tman.register(new WeddingReservationWorker(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000);
}
public List<Channel> getChannels() {
@@ -371,6 +381,96 @@ public class World {
queuedGuilds.remove(guildId);
}
public boolean isMarriageQueued(int marriageId) {
return queuedMarriages.containsKey(marriageId);
}
public Pair<Boolean, Boolean> getMarriageQueuedLocation(int marriageId) {
Pair<Pair<Boolean, Boolean>, Pair<Integer, Integer>> qm = queuedMarriages.get(marriageId);
return (qm != null) ? qm.getLeft() : null;
}
public Pair<Integer, Integer> getMarriageQueuedCouple(int marriageId) {
Pair<Pair<Boolean, Boolean>, Pair<Integer, Integer>> qm = queuedMarriages.get(marriageId);
return (qm != null) ? qm.getRight() : null;
}
public void putMarriageQueued(int marriageId, boolean cathedral, boolean premium, int groomId, int brideId) {
queuedMarriages.put(marriageId, new Pair<>(new Pair<>(cathedral, premium), new Pair<>(groomId, brideId)));
marriageGuests.put(marriageId, new HashSet());
}
public Pair<Boolean, Set<Integer>> removeMarriageQueued(int marriageId) {
Boolean type = queuedMarriages.remove(marriageId).getLeft().getRight();
Set<Integer> guests = marriageGuests.remove(marriageId);
return new Pair<>(type, guests);
}
public synchronized boolean addMarriageGuest(int marriageId, int playerId) {
Set<Integer> guests = marriageGuests.get(marriageId);
if(guests != null) {
if(guests.contains(playerId)) return false;
guests.add(playerId);
return true;
}
return false;
}
public Pair<Integer, Integer> getWeddingCoupleForGuest(int guestId, Boolean cathedral) {
for(Channel ch : channels) {
Pair<Integer, Integer> p = ch.getWeddingCoupleForGuest(guestId, cathedral);
if(p != null) {
return p;
}
}
List<Integer> possibleWeddings = new LinkedList<>();
for(Entry<Integer, Set<Integer>> mg : new HashSet<>(marriageGuests.entrySet())) {
if(mg.getValue().contains(guestId)) {
Pair<Boolean, Boolean> loc = getMarriageQueuedLocation(mg.getKey());
if(loc != null && cathedral.equals(loc.getLeft())) {
possibleWeddings.add(mg.getKey());
}
}
}
int pwSize = possibleWeddings.size();
if(pwSize == 0) {
return null;
} else if(pwSize > 1) {
int selectedPw = -1;
int selectedPos = Integer.MAX_VALUE;
for(Integer pw : possibleWeddings) {
for(Channel ch : channels) {
int pos = ch.getWeddingReservationStatus(pw, cathedral);
if(pos != -1) {
if(pos < selectedPos) {
selectedPos = pos;
selectedPw = pw;
break;
}
}
}
}
if(selectedPw == -1) return null;
possibleWeddings.clear();
possibleWeddings.add(selectedPw);
}
return getMarriageQueuedCouple(possibleWeddings.get(0));
}
public void debugMarriageStatus() {
System.out.println("Queued marriages: " + queuedMarriages);
System.out.println("Guest list: " + marriageGuests);
}
public MapleParty createParty(MaplePartyCharacter chrfor) {
int partyid = runningPartyId.getAndIncrement();
MapleParty party = new MapleParty(partyid, chrfor);
@@ -1028,33 +1128,160 @@ public class World {
}
public List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> getAvailableItemBundles(int itemid) {
List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> hmsAvailable = new ArrayList<>();
List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> hmsAvailable = new ArrayList<>();
for (MapleHiredMerchant hm : getActiveMerchants()) {
List<MaplePlayerShopItem> itemBundles = hm.sendAvailableBundles(itemid);
for(MaplePlayerShopItem mpsi : itemBundles) {
hmsAvailable.add(new Pair<>(mpsi, (AbstractMapleMapObject) hm));
}
for (MapleHiredMerchant hm : getActiveMerchants()) {
List<MaplePlayerShopItem> itemBundles = hm.sendAvailableBundles(itemid);
for(MaplePlayerShopItem mpsi : itemBundles) {
hmsAvailable.add(new Pair<>(mpsi, (AbstractMapleMapObject) hm));
}
}
for (MaplePlayerShop ps : getActivePlayerShops()) {
List<MaplePlayerShopItem> itemBundles = ps.sendAvailableBundles(itemid);
for(MaplePlayerShopItem mpsi : itemBundles) {
hmsAvailable.add(new Pair<>(mpsi, (AbstractMapleMapObject) ps));
}
}
Collections.sort(hmsAvailable, new Comparator<Pair<MaplePlayerShopItem, AbstractMapleMapObject>>() {
@Override
public int compare(Pair<MaplePlayerShopItem, AbstractMapleMapObject> p1, Pair<MaplePlayerShopItem, AbstractMapleMapObject> p2) {
return p1.getLeft().getPrice() - p2.getLeft().getPrice();
}
});
hmsAvailable.subList(0, Math.min(hmsAvailable.size(), 200)); //truncates the list to have up to 200 elements
return hmsAvailable;
}
private void pushRelationshipCouple(Pair<Integer, Pair<Integer, Integer>> couple) {
int mid = couple.getLeft(), hid = couple.getRight().getLeft(), wid = couple.getRight().getRight();
relationshipCouples.put(mid, couple.getRight());
relationships.put(hid, mid);
relationships.put(wid, mid);
}
public Pair<Integer, Integer> getRelationshipCouple(int relationshipId) {
Pair<Integer, Integer> rc = relationshipCouples.get(relationshipId);
if(rc == null) {
Pair<Integer, Pair<Integer, Integer>> couple = getRelationshipCoupleFromDb(relationshipId, true);
if(couple == null) return null;
pushRelationshipCouple(couple);
rc = couple.getRight();
}
return rc;
}
public int getRelationshipId(int playerId) {
Integer ret = relationships.get(playerId);
if(ret == null) {
Pair<Integer, Pair<Integer, Integer>> couple = getRelationshipCoupleFromDb(playerId, false);
if(couple == null) return -1;
pushRelationshipCouple(couple);
ret = couple.getLeft();
}
return ret;
}
private static Pair<Integer, Pair<Integer, Integer>> getRelationshipCoupleFromDb(int id, boolean usingMarriageId) {
try {
Connection con = DatabaseConnection.getConnection();
Integer mid = null, hid = null, wid = null;
PreparedStatement ps;
if(usingMarriageId) {
ps = con.prepareStatement("SELECT * FROM marriages WHERE marriageid = ?");
ps.setInt(1, id);
} else {
ps = con.prepareStatement("SELECT * FROM marriages WHERE husbandid = ? OR wifeid = ?");
ps.setInt(1, id);
ps.setInt(2, id);
}
for (MaplePlayerShop ps : getActivePlayerShops()) {
List<MaplePlayerShopItem> itemBundles = ps.sendAvailableBundles(itemid);
for(MaplePlayerShopItem mpsi : itemBundles) {
hmsAvailable.add(new Pair<>(mpsi, (AbstractMapleMapObject) ps));
}
ResultSet rs = ps.executeQuery();
if(rs.next()) {
mid = rs.getInt("marriageid");
hid = rs.getInt("husbandid");
wid = rs.getInt("wifeid");
}
rs.close();
ps.close();
con.close();
return (mid == null) ? null : new Pair<>(mid, new Pair<>(hid, wid));
} catch (SQLException se) {
se.printStackTrace();
return null;
}
}
public int createRelationship(int groomId, int brideId) {
int ret = addRelationshipToDb(groomId, brideId);
pushRelationshipCouple(new Pair<>(ret, new Pair<>(groomId, brideId)));
return ret;
}
private static int addRelationshipToDb(int groomId, int brideId) {
try {
Connection con = DatabaseConnection.getConnection();
Collections.sort(hmsAvailable, new Comparator<Pair<MaplePlayerShopItem, AbstractMapleMapObject>>() {
@Override
public int compare(Pair<MaplePlayerShopItem, AbstractMapleMapObject> p1, Pair<MaplePlayerShopItem, AbstractMapleMapObject> p2) {
return p1.getLeft().getPrice() - p2.getLeft().getPrice();
}
});
PreparedStatement ps = con.prepareStatement("INSERT INTO marriages (husbandid, wifeid) VALUES (?, ?)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, groomId);
ps.setInt(2, brideId);
ps.executeUpdate();
hmsAvailable.subList(0, Math.min(hmsAvailable.size(), 200)); //truncates the list to have up to 200 elements
return hmsAvailable;
ResultSet rs = ps.getGeneratedKeys();
rs.next();
int ret = rs.getInt(1);
rs.close();
ps.close();
con.close();
return ret;
} catch (SQLException se) {
se.printStackTrace();
return -1;
}
}
public void deleteRelationship(int playerId, int partnerId) {
int relationshipId = relationships.get(playerId);
deleteRelationshipFromDb(relationshipId);
relationshipCouples.remove(relationshipId);
relationships.remove(playerId);
relationships.remove(partnerId);
}
private static void deleteRelationshipFromDb(int playerId) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("DELETE FROM marriages WHERE marriageid = ?");
ps.setInt(1, playerId);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public void dropMessage(int type, String message) {
for (MapleCharacter player : getPlayerStorage().getAllCharacters()) {
player.dropMessage(type, message);
}
}
public final void shutdown() {
+2 -4
View File
@@ -32,6 +32,7 @@ import client.inventory.ModifyInventory;
import client.newyear.NewYearCardRecord;
import constants.ItemConstants;
import constants.ServerConstants;
import net.server.channel.handlers.RingActionHandler;
import java.awt.Point;
import java.util.ArrayList;
@@ -580,10 +581,7 @@ public class MapleInventoryManipulator {
NewYearCardRecord.removeAllNewYearCard(false, c.getPlayer());
c.getAbstractPlayerInteraction().removeAll(4301000);
}
}
boolean weddingRing = source.getItemId() == 1112803 || source.getItemId() == 1112806 || source.getItemId() == 1112807 || source.getItemId() == 1112809;
if (weddingRing) {
} else if (ItemConstants.isWeddingRing(source.getItemId())) {
c.getPlayer().getMap().disappearingItemDrop(c.getPlayer(), c.getPlayer(), target, dropPos);
} else if (c.getPlayer().getMap().getEverlast()) {
if (ii.isDropRestricted(target.getItemId()) || ii.isCash(target.getItemId()) || isDroppedItemRestricted(target)) {
+4 -20
View File
@@ -1047,35 +1047,19 @@ public class MapleMap {
}
public void broadcastBalrogVictory(String leaderName) {
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
player.dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive.");
}
}
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive.");
}
public void broadcastHorntailVictory() {
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
player.dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!");
}
}
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!");
}
public void broadcastZakumVictory() {
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
player.dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!");
}
}
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!");
}
public void broadcastPinkBeanVictory(int channel) {
for (Channel cserv : Server.getInstance().getWorld(world).getChannels()) {
for (MapleCharacter player : cserv.getPlayerStorage().getAllCharacters()) {
player.dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!");
}
}
Server.getInstance().getWorld(world).dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!");
}
public void killMonster(final MapleMonster monster, final MapleCharacter chr, final boolean withDrops) {
+43 -63
View File
@@ -189,7 +189,7 @@ public class MaplePacketCreator {
mplew.writeInt(0);
}
private static void addCharLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean mega) {
protected static void addCharLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean mega) {
mplew.write(chr.getGender());
mplew.write(chr.getSkinColor().getId()); // skin color
mplew.writeInt(chr.getFace()); // face
@@ -346,15 +346,15 @@ public class MaplePacketCreator {
}
}
private static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item) {
addItemInfo(mplew, item, false);
}
private static void addExpirationTime(final MaplePacketLittleEndianWriter mplew, long time) {
mplew.writeLong(getTime(time));
}
private static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item, boolean zeroPosition) {
private static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item) {
addItemInfo(mplew, item, false);
}
protected static void addItemInfo(final MaplePacketLittleEndianWriter mplew, Item item, boolean zeroPosition) {
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
boolean isCash = ii.isCash(item.getItemId());
boolean isPet = item.getPetId() > -1;
@@ -4367,13 +4367,27 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] sendSpouseChat(MapleCharacter wife, String msg) {
/*
public static byte[] sendSpouseChat(MapleCharacter partner, String msg) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue());
mplew.writeMapleAsciiString(wife.getName());
mplew.writeMapleAsciiString(partner.getName());
mplew.writeMapleAsciiString(msg);
return mplew.getPacket();
}
*/
public static byte[] OnCoupleMessage(String fiance, String text, boolean spouse) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue());
mplew.write(spouse ? 5 : 4); // v2 = CInPacket::Decode1(a1) - 4;
if (spouse) { // if ( v2 ) {
mplew.writeMapleAsciiString(fiance);
}
mplew.write(spouse ? 5 : 1);
mplew.writeMapleAsciiString(text);
return mplew.getPacket();
}
public static byte[] addMessengerPlayer(String from, MapleCharacter chr, int position, int channel) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
@@ -6430,49 +6444,6 @@ public class MaplePacketCreator {
return mplew.getPacket();
}
public static byte[] sendEngagementRequest(String name) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MARRIAGE_REQUEST.getValue()); //<name> has requested engagement. Will you accept this proposal?
mplew.write(0);
mplew.writeMapleAsciiString(name); // name
mplew.writeInt(10); // playerid
return mplew.getPacket();
}
public static byte[] sendGroomWishlist() {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.MARRIAGE_REQUEST.getValue()); //<name> has requested engagement. Will you accept this proposal?
mplew.write(9);
return mplew.getPacket();
}
public static byte[] sendBrideWishList(List<Item> items) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.WEDDING_GIFT_RESULT.getValue());
mplew.write(0x0A);
mplew.writeLong(-1); // ?
mplew.writeInt(0); // ?
mplew.write(items.size());
for (Item item : items) {
addItemInfo(mplew, item, true);
}
return mplew.getPacket();
}
public static byte[] addItemToWeddingRegistry(MapleCharacter chr, Item item) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.WEDDING_GIFT_RESULT.getValue());
mplew.write(0x0B);
mplew.writeInt(0);
for (int i = 0; i < 0; i++) // f4
{
mplew.write(0);
}
addItemInfo(mplew, item, true);
return mplew.getPacket();
}
public static byte[] sendFamilyJoinResponse(boolean accepted, String added) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST_RESULT.getValue());
@@ -6660,7 +6631,7 @@ public class MaplePacketCreator {
public static byte[] marriageMessage(int type, String charname) {
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SendOpcode.NOTIFY_MARRIAGE.getValue());
mplew.write(type);
mplew.write(type); // 0: guild, 1: family
mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol
return mplew.getPacket();
@@ -6780,17 +6751,26 @@ public class MaplePacketCreator {
mplew.writeInt(0);
mplew.writeInt(ring.getItemId());
}
mplew.writeShort(chr.getMarriageRing() != null ? 1 : 0);
int marriageId = 30000;
if (chr.getMarriageRing() != null) {
mplew.writeInt(marriageId);
mplew.writeInt(chr.getId());
mplew.writeInt(chr.getMarriageRing().getPartnerChrId());
mplew.writeShort(3);
mplew.writeInt(chr.getMarriageRing().getRingId());
mplew.writeInt(chr.getMarriageRing().getPartnerRingId());
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : chr.getMarriageRing().getPartnerName(), '\0', 13));
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getMarriageRing().getPartnerName() : chr.getName(), '\0', 13));
if(chr.getPartnerId() > 0) {
MapleRing marriageRing = chr.getMarriageRing();
mplew.writeShort(1);
mplew.writeInt(chr.getRelationshipId());
mplew.writeInt(chr.getGender() == 0 ? chr.getId() : chr.getPartnerId());
mplew.writeInt(chr.getGender() == 0 ? chr.getPartnerId() : chr.getId());
mplew.writeShort((marriageRing != null) ? 3 : 1);
if (marriageRing != null) {
mplew.writeInt(marriageRing.getItemId());
mplew.writeInt(marriageRing.getItemId());
} else {
mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
}
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : MapleCharacter.getNameById(chr.getPartnerId()), '\0', 13));
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? MapleCharacter.getNameById(chr.getPartnerId()) : chr.getName(), '\0', 13));
} else {
mplew.writeShort(0);
}
}
+452
View File
@@ -0,0 +1,452 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package tools.packets;
import client.inventory.Item;
import client.inventory.MapleInventoryType;
import client.MapleCharacter;
import java.util.ArrayList;
import java.util.List;
import tools.MaplePacketCreator;
import tools.StringUtil;
import tools.data.output.MaplePacketLittleEndianWriter;
/**
* CField_Wedding, CField_WeddingPhoto, CWeddingMan, OnMarriageResult, and all Wedding/Marriage enum/structs.
*
* @author Eric
*/
public class Wedding extends MaplePacketCreator {
private static final short MARRIAGE_REQUEST = 0x48;
private static final short MARRIAGE_RESULT = 0x49;
private static final short WEDDING_GIFT_RESULT = 0x4A;
private static final short NOTIFY_MARRIED_PARTNER_MAP_TRANSFER = 0x4B;
private static final short WEDDING_PHOTO = 0x2B;
private static final short WEDDING_PROGRESS = 0x140;
private static final short WEDDING_CEREMONY_END = 0x141;
/*
00000000 CWeddingMan struc ; (sizeof=0x104)
00000000 vfptr dd ? ; offset
00000004 ___u1 $01CBC6800BD386B8A8FD818EAD990BEC ?
0000000C m_mCharIDToMarriageNo ZMap<unsigned long,unsigned long,unsigned long> ?
00000024 m_mReservationPending ZMap<unsigned long,ZRef<GW_WeddingReservation>,unsigned long> ?
0000003C m_mReservationPendingGroom ZMap<unsigned long,ZRef<CUser>,unsigned long> ?
00000054 m_mReservationPendingBride ZMap<unsigned long,ZRef<CUser>,unsigned long> ?
0000006C m_mReservationStartUser ZMap<unsigned long,unsigned long,unsigned long> ?
00000084 m_mReservationCompleted ZMap<unsigned long,ZRef<GW_WeddingReservation>,unsigned long> ?
0000009C m_mGroomWishList ZMap<unsigned long,ZRef<ZArray<ZXString<char> > >,unsigned long> ?
000000B4 m_mBrideWishList ZMap<unsigned long,ZRef<ZArray<ZXString<char> > >,unsigned long> ?
000000CC m_mEngagementPending ZMap<unsigned long,ZRef<GW_MarriageRecord>,unsigned long> ?
000000E4 m_nCurrentWeddingState dd ?
000000E8 m_dwCurrentWeddingNo dd ?
000000EC m_dwCurrentWeddingMap dd ?
000000F0 m_bIsReservationLoaded dd ?
000000F4 m_dwNumGuestBless dd ?
000000F8 m_bPhotoSuccess dd ?
000000FC m_tLastUpdate dd ?
00000100 m_bStartWeddingCeremony dd ?
00000104 CWeddingMan ends
*/
public class Field_Wedding {
public int m_nNoticeCount;
public int m_nCurrentStep;
public int m_nBlessStartTime;
}
public class Field_WeddingPhoto {
public boolean m_bPictureTook;
}
public class GW_WeddingReservation {
public int dwReservationNo;
public int dwGroom, dwBride;
public String sGroomName, sBrideName;
public int usWeddingType;
}
public class WeddingWishList {
public MapleCharacter pUser;
public int dwMarriageNo;
public int nGender;
public int nWLType;
public int nSlotCount;
public List<String> asWishList = new ArrayList<>();
public int usModifiedFlag; // dword
public boolean bLoaded;
}
public class GW_WeddingWishList {
public final int WEDDINGWL_MAX = 0xA; // enum WEDDINGWL
public int dwReservationNo;
public byte nGender;
public String sItemName;
}
public enum MarriageStatus {
SINGLE(0x0),
ENGAGED(0x1),
RESERVED(0x2),
MARRIED(0x3);
private int ms;
private MarriageStatus(int ms) {
this.ms = ms;
}
public int getMarriageStatus() {
return ms;
}
}
public enum MarriageRequest {
AddMarriageRecord(0x0),
SetMarriageRecord(0x1),
DeleteMarriageRecord(0x2),
LoadReservation(0x3),
AddReservation(0x4),
DeleteReservation(0x5),
GetReservation(0x6);
private int req;
private MarriageRequest(int req) {
this.req = req;
}
public int getMarriageRequest() {
return req;
}
}
public enum WeddingType {
CATHEDRAL(0x1),
VEGAS(0x2),
CATHEDRAL_PREMIUM(0xA),
CATHEDRAL_NORMAL(0xB),
VEGAS_PREMIUM(0x14),
VEGAS_NORMAL(0x15);
private int wt;
private WeddingType(int wt) {
this.wt = wt;
}
public int getType() {
return wt;
}
}
public enum WeddingMap {
WEDDINGTOWN(680000000),
CHAPEL_STARTMAP(680000110),
CATHEDRAL_STARTMAP(680000210),
PHOTOMAP(680000300),
EXITMAP(680000500);
private int wm;
private WeddingMap(int wm) {
this.wm = wm;
}
public int getMap() {
return wm;
}
}
public enum WeddingItem {
WR_MOONSTONE(1112803), // Wedding Ring
WR_STARGEM(1112806),
WR_GOLDENHEART(1112807),
WR_SILVERSWAN(1112809),
ERB_MOONSTONE(2240000), // Engagement Ring Box
ERB_STARGEM(2240001),
ERB_GOLDENHEART(2240002),
ERB_SILVERSWAN(2240003),
ERBE_MOONSTONE(4031357), // Engagement Ring Box (Empty)
ER_MOONSTONE(4031358), // Engagement Ring
ERBE_STARGEM(4031359),
ER_STARGEM(4031360),
ERBE_GOLDENHEART(4031361),
ER_GOLDENHEART(4031362),
ERBE_SILVERSWAN(4031363),
ER_SILVERSWAN(4031364),
PARENTS_BLESSING(4031373), // Parents Blessing
OFFICIATORS_PERMISSION(4031374), // Officiator's Permission
WR_CATHEDRAL_PREMIUM(4031375), // Wedding Ring?
WR_VEGAS_PREMIUM(4031376),
IB_VEGAS(4031377), // toSend invitation
IB_CATHEDRAL(4031395), // toSend invitation
IG_VEGAS(4031406), // rcvd invitation
IG_CATHEDRAL(4031407), // rcvd invitation
OB_FORCOUPLE(4031424), // Onyx Box? For Couple
WR_CATHEDRAL_NORMAL(4031480), // Wedding Ring?
WR_VEGAS_NORMAL(4031481),
WT_CATHEDRAL_NORMAL(5251000), // Wedding Ticket
WT_VEGAS_NORMAL(5251001),
WT_VEGAS_PREMIUM(5251002),
WT_CATHEDRAL_PREMIUM(5251003);
private int wi;
private WeddingItem(int wi) {
this.wi = wi;
}
public int getItem() {
return wi;
}
}
/**
* <name> has requested engagement. Will you accept this proposal?
*
* @param name
* @param playerid
* @return mplew
*/
public static byte[] OnMarriageRequest(String name, int playerid) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(MARRIAGE_REQUEST);
mplew.write(0); //mode, 0 = engage, 1 = cancel, 2 = answer.. etc
mplew.writeMapleAsciiString(name); // name
mplew.writeInt(playerid); // playerid
return mplew.getPacket();
}
/**
* A quick rundown of how (I think based off of enough BMS searching) WeddingPhoto_OnTakePhoto works:
* - We send this packet with (first) the Groom / Bride IGNs
* - We then send a fieldId (unsure about this part at the moment, 90% sure it's the id of the map)
* - After this, we write an integer of the amount of characters within the current map (which is the Cake Map -- exclude users within Exit Map)
* - Once we've retrieved the size of the characters, we begin to write information about them (Encode their name, guild, etc info)
* - Now that we've Encoded our character data, we begin to Encode the ScreenShotPacket which requires a TemplateID, IGN, and their positioning
* - Finally, after encoding all of our data, we send this packet out to a MapGen application server
* - The MapGen server will then retrieve the packet byte array and convert the bytes into a ImageIO 2D JPG output
* - The result after converting into a JPG will then be remotely uploaded to /weddings/ with ReservedGroomName_ReservedBrideName to be displayed on the web server.
*
* - Will no longer continue Wedding Photos, needs a WvsMapGen :(
*
* @param ReservedGroomName The groom IGN of the wedding
* @param ReservedBrideName The bride IGN of the wedding
* @param m_dwField The current field id (the id of the cake map, ex. 680000300)
* @param m_uCount The current user count (equal to m_dwUsers.size)
* @param m_dwUsers The List of all MapleCharacter guests within the current cake map to be encoded
* @return mplew (MaplePacket) Byte array to be converted and read for byte[]->ImageIO
*/
public static byte[] OnTakePhoto(String ReservedGroomName, String ReservedBrideName, int m_dwField, List<MapleCharacter> m_dwUsers) { // OnIFailedAtWeddingPhotos
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(WEDDING_PHOTO); // v53 header, convert -> v83
mplew.writeMapleAsciiString(ReservedGroomName);
mplew.writeMapleAsciiString(ReservedBrideName);
mplew.writeInt(m_dwField); // field id?
mplew.writeInt(m_dwUsers.size());
for (MapleCharacter guest : m_dwUsers) {
// Begin Avatar Encoding
addCharLook(mplew, guest, false); // CUser::EncodeAvatar
mplew.writeInt(30000); // v20 = *(_DWORD *)(v13 + 2192) -- new groom marriage ID??
mplew.writeInt(30000); // v20 = *(_DWORD *)(v13 + 2192) -- new bride marriage ID??
mplew.writeMapleAsciiString(guest.getName());
mplew.writeMapleAsciiString(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getName() : "");
mplew.writeShort(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoBG() : 0);
mplew.write(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoBGColor() : 0);
mplew.writeShort(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogo() : 0);
mplew.write(guest.getGuildId() > 0 && guest.getGuild() != null ? guest.getGuild().getLogoColor() : 0);
mplew.writeShort(guest.getPosition().x); // v18 = *(_DWORD *)(v13 + 3204);
mplew.writeShort(guest.getPosition().y); // v20 = *(_DWORD *)(v13 + 3208);
// Begin Screenshot Encoding
mplew.write(1); // // if ( *(_DWORD *)(v13 + 288) ) { COutPacket::Encode1(&thisa, v20);
// CPet::EncodeScreenShotPacket(*(CPet **)(v13 + 288), &thisa);
mplew.writeInt(1); // dwTemplateID
mplew.writeMapleAsciiString(guest.getName()); // m_sName
mplew.writeShort(guest.getPosition().x); // m_ptCurPos.x
mplew.writeShort(guest.getPosition().y); // m_ptCurPos.y
mplew.write(guest.getStance()); // guest.m_bMoveAction
}
return mplew.getPacket();
}
/**
* Enable spouse chat and their engagement ring without @relog
*
* @param marriageId
* @param chr
* @param wedding
* @return mplew
*/
public static byte[] OnMarriageResult(int marriageId, MapleCharacter chr, boolean wedding) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(MARRIAGE_RESULT);
mplew.write(11);
mplew.writeInt(marriageId);
mplew.writeInt(chr.getGender() == 0 ? chr.getId() : chr.getPartnerId());
mplew.writeInt(chr.getGender() == 0 ? chr.getPartnerId() : chr.getId());
mplew.writeShort(wedding ? 3 : 1);
if (wedding) {
mplew.writeInt(chr.getMarriageItemId());
mplew.writeInt(chr.getMarriageItemId());
} else {
mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
mplew.writeInt(1112803); // Engagement Ring's Outcome (doesn't matter for engagement)
}
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? chr.getName() : MapleCharacter.getNameById(chr.getPartnerId()), '\0', 13));
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getGender() == 0 ? MapleCharacter.getNameById(chr.getPartnerId()) : chr.getName(), '\0', 13));
return mplew.getPacket();
}
/**
* To exit the Engagement Window (Waiting for her response...), we send a GMS-like pop-up.
*
* @param msg
* @return mplew
*/
public static byte[] OnMarriageResult(final byte msg) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(MARRIAGE_RESULT);
mplew.write(msg);
if (msg == 36) {
mplew.write(1);
mplew.writeMapleAsciiString("You are now engaged.");
}
return mplew.getPacket();
}
/**
* The World Map includes 'loverPos' in which this packet controls
*
* @param partner
* @param mapid
* @return mplew
*/
public static byte[] OnNotifyWeddingPartnerTransfer(int partner, int mapid) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(NOTIFY_MARRIED_PARTNER_MAP_TRANSFER);
mplew.writeInt(mapid);
mplew.writeInt(partner);
return mplew.getPacket();
}
/**
* The wedding packet to display Pelvis Bebop and enable the Wedding Ceremony Effect between two characters
* CField_Wedding::OnWeddingProgress - Stages
* CField_Wedding::OnWeddingCeremonyEnd - Wedding Ceremony Effect
*
* @param SetBlessEffect
* @param groom
* @param bride
* @param step
* @return mplew
*/
public static byte[] OnWeddingProgress(boolean SetBlessEffect, int groom, int bride, byte step) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(SetBlessEffect ? WEDDING_CEREMONY_END : WEDDING_PROGRESS);
if (!SetBlessEffect) { // in order for ceremony packet to send, byte step = 2 must be sent first
mplew.write(step);
}
mplew.writeInt(groom);
mplew.writeInt(bride);
return mplew.getPacket();
}
/**
* When we open a Wedding Invitation, we display the Bride & Groom
*
* @param groom
* @param bride
* @return mplew
*/
public static byte[] sendWeddingInvitation(String groom, String bride) {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(MARRIAGE_RESULT);
mplew.write(15);
mplew.writeMapleAsciiString(groom);
mplew.writeMapleAsciiString(bride);
mplew.writeShort(1); // 0 = Cathedral Normal?, 1 = Cathedral Premium?, 2 = Chapel Normal?
return mplew.getPacket();
}
public static byte[] sendWishList() { // fuck my life
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(MARRIAGE_REQUEST);
mplew.write(9);
return mplew.getPacket();
}
/**
* Handles all of WeddingWishlist packets
*
* @param mode
* @param itemnames
* @param items
* @return mplew
*/
public static byte[] OnWeddingGiftResult(byte mode, List<String> itemnames, List<Item> items) {
// if (itemnames == null || itemnames.size() < 1) { // for now lol
// itemnames = new ArrayList<>();
// itemnames.add("mesos");
// itemnames.add("rare items");
// itemnames.add("more mesos");
// }
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(WEDDING_GIFT_RESULT);
mplew.write(mode);
switch(mode) {
case 0x09: { // Load Wedding Registry
mplew.write(itemnames.size());
for (String names : itemnames) {
mplew.writeMapleAsciiString(names);
}
mplew.write(itemnames.size());
for (String names : itemnames) {
mplew.writeMapleAsciiString(names);
}
// need to load items somehow
break;
}
case 0xA: // Load Bride's Wishlist
case 0xF: // 10, 15, 16 = CWishListRecvDlg::OnPacket
case 0xB: { // Add Item to Wedding Registry
// 11 : You have sent a gift | 12 : You cannot give more than one present for each wishlist | 13 : Failed to send the gift. | 14 : Failed to send the gift.
if (mode == 0xB) {
mplew.write(itemnames.size());
for (String names : itemnames) {
mplew.writeMapleAsciiString(names);
}
}
switch (items.get((items.size() - 1)).getInventoryType()) {
case EQUIP:
mplew.writeLong(4);
break;
case USE:
mplew.writeLong(8);
break;
case SETUP:
mplew.writeLong(16);
break;
case ETC:
mplew.writeLong(32);
break;
default: // impossible flag, cash item can't be sent
if (items.get((items.size() - 1)).getInventoryType() != MapleInventoryType.CASH) {
mplew.writeLong(0);
}
}
if (mode == 0xA) { // random unknown bytes involved within Bride's Wishlist
mplew.writeInt(0);
}
mplew.write(items.size());
for (Item item : items) {
MaplePacketCreator.addItemInfo(mplew, item, true);
}
break;
}
default: {
System.out.println("Unknown Wishlist Mode: " + mode);
break;
}
}
return mplew.getPacket();
}
}