8413 lines
393 KiB
Java
8413 lines
393 KiB
Java
/*
|
|
This file is part of the OdinMS Maple Story Server
|
|
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
|
Matthias Butz <matze@odinms.de>
|
|
Jan Christian Meyer <vimes@odinms.de>
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation version 3 as published by
|
|
the Free Software Foundation. You may not use, modify or distribute
|
|
this program under any other version of the GNU Affero General Public
|
|
License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package tools;
|
|
|
|
import client.*;
|
|
import client.MapleCharacter.SkillEntry;
|
|
import client.inventory.*;
|
|
import client.inventory.Equip.ScrollResult;
|
|
import client.keybind.MapleKeyBinding;
|
|
import client.keybind.MapleQuickslotBinding;
|
|
import client.newyear.NewYearCardRecord;
|
|
import client.status.MonsterStatus;
|
|
import client.status.MonsterStatusEffect;
|
|
import config.YamlConfig;
|
|
import constants.game.ExpTable;
|
|
import constants.game.GameConstants;
|
|
import constants.inventory.ItemConstants;
|
|
import constants.skills.Buccaneer;
|
|
import constants.skills.Corsair;
|
|
import constants.skills.ThunderBreaker;
|
|
import net.opcodes.SendOpcode;
|
|
import net.server.PlayerCoolDownValueHolder;
|
|
import net.server.Server;
|
|
import net.server.channel.Channel;
|
|
import net.server.channel.handlers.PlayerInteractionHandler;
|
|
import net.server.channel.handlers.SummonDamageHandler.SummonAttackEntry;
|
|
import net.server.guild.MapleAlliance;
|
|
import net.server.guild.MapleGuild;
|
|
import net.server.guild.MapleGuildCharacter;
|
|
import net.server.guild.MapleGuildSummary;
|
|
import net.server.world.MapleParty;
|
|
import net.server.world.MaplePartyCharacter;
|
|
import net.server.world.PartyOperation;
|
|
import net.server.world.World;
|
|
import server.CashShop.CashItem;
|
|
import server.CashShop.CashItemFactory;
|
|
import server.CashShop.SpecialCashItem;
|
|
import server.*;
|
|
import server.events.gm.MapleSnowball;
|
|
import server.life.MapleMonster;
|
|
import server.life.MapleNPC;
|
|
import server.life.MaplePlayerNPC;
|
|
import server.life.MobSkill;
|
|
import server.maps.*;
|
|
import server.maps.MapleMiniGame.MiniGameResult;
|
|
import server.movement.LifeMovementFragment;
|
|
import tools.data.input.SeekableLittleEndianAccessor;
|
|
import tools.data.output.LittleEndianWriter;
|
|
import tools.data.output.MaplePacketLittleEndianWriter;
|
|
|
|
import java.awt.*;
|
|
import java.net.InetAddress;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.util.List;
|
|
import java.util.*;
|
|
import java.util.Map.Entry;
|
|
|
|
/**
|
|
*
|
|
* @author Frz
|
|
*/
|
|
public class MaplePacketCreator {
|
|
|
|
public static final List<Pair<MapleStat, Integer>> EMPTY_STATUPDATE = Collections.emptyList();
|
|
private final static long FT_UT_OFFSET = 116444736010800000L + (10000L * TimeZone.getDefault().getOffset(System.currentTimeMillis())); // normalize with timezone offset suggested by Ari
|
|
private final static long DEFAULT_TIME = 150842304000000000L;//00 80 05 BB 46 E6 17 02
|
|
public final static long ZERO_TIME = 94354848000000000L;//00 40 E0 FD 3B 37 4F 01
|
|
private final static long PERMANENT = 150841440000000000L; // 00 C0 9B 90 7D E5 17 02
|
|
|
|
private static long getTime(long utcTimestamp) {
|
|
if (utcTimestamp < 0 && utcTimestamp >= -3) {
|
|
if (utcTimestamp == -1) {
|
|
return DEFAULT_TIME; //high number ll
|
|
} else if (utcTimestamp == -2) {
|
|
return ZERO_TIME;
|
|
} else {
|
|
return PERMANENT;
|
|
}
|
|
}
|
|
|
|
return utcTimestamp * 10000 + FT_UT_OFFSET;
|
|
}
|
|
|
|
public static byte[] showHpHealed(int cid, int amount) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(0x0A); //Type
|
|
mplew.write(amount);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addRemainingSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
int[] remainingSp = chr.getRemainingSps();
|
|
int effectiveLength = 0;
|
|
for (int j : remainingSp) {
|
|
if (j > 0) {
|
|
effectiveLength++;
|
|
}
|
|
}
|
|
|
|
mplew.write(effectiveLength);
|
|
for (int i = 0; i < remainingSp.length; i++) {
|
|
if (remainingSp[i] > 0) {
|
|
mplew.write(i + 1);
|
|
mplew.write(remainingSp[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void addCharStats(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeInt(chr.getId()); // character id
|
|
mplew.writeAsciiString(StringUtil.getRightPaddedStr(chr.getName(), '\0', 13));
|
|
mplew.write(chr.getGender()); // gender (0 = male, 1 = female)
|
|
mplew.write(chr.getSkinColor().getId()); // skin color
|
|
mplew.writeInt(chr.getFace()); // face
|
|
mplew.writeInt(chr.getHair()); // hair
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
MaplePet pet = chr.getPet(i);
|
|
if (pet != null) //Checked GMS.. and your pets stay when going into the cash shop.
|
|
{
|
|
mplew.writeLong(pet.getUniqueId());
|
|
} else {
|
|
mplew.writeLong(0);
|
|
}
|
|
}
|
|
|
|
mplew.write(chr.getLevel()); // level
|
|
mplew.writeShort(chr.getJob().getId()); // job
|
|
mplew.writeShort(chr.getStr()); // str
|
|
mplew.writeShort(chr.getDex()); // dex
|
|
mplew.writeShort(chr.getInt()); // int
|
|
mplew.writeShort(chr.getLuk()); // luk
|
|
mplew.writeShort(chr.getHp()); // hp (?)
|
|
mplew.writeShort(chr.getClientMaxHp()); // maxhp
|
|
mplew.writeShort(chr.getMp()); // mp (?)
|
|
mplew.writeShort(chr.getClientMaxMp()); // maxmp
|
|
mplew.writeShort(chr.getRemainingAp()); // remaining ap
|
|
if (GameConstants.hasSPTable(chr.getJob())) {
|
|
addRemainingSkillInfo(mplew, chr);
|
|
} else {
|
|
mplew.writeShort(chr.getRemainingSp()); // remaining sp
|
|
}
|
|
mplew.writeInt(chr.getExp()); // current exp
|
|
mplew.writeShort(chr.getFame()); // fame
|
|
mplew.writeInt(chr.getGachaExp()); //Gacha Exp
|
|
mplew.writeInt(chr.getMapId()); // current map id
|
|
mplew.write(chr.getInitialSpawnpoint()); // spawnpoint
|
|
mplew.writeInt(0);
|
|
}
|
|
|
|
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
|
|
mplew.write(mega ? 0 : 1);
|
|
mplew.writeInt(chr.getHair()); // hair
|
|
addCharEquips(mplew, chr);
|
|
}
|
|
|
|
private static void addCharacterInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeLong(-1);
|
|
mplew.write(0);
|
|
addCharStats(mplew, chr);
|
|
mplew.write(chr.getBuddylist().getCapacity());
|
|
|
|
if (chr.getLinkedName() == null) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
mplew.writeMapleAsciiString(chr.getLinkedName());
|
|
}
|
|
|
|
mplew.writeInt(chr.getMeso());
|
|
addInventoryInfo(mplew, chr);
|
|
addSkillInfo(mplew, chr);
|
|
addQuestInfo(mplew, chr);
|
|
addMiniGameInfo(mplew, chr);
|
|
addRingInfo(mplew, chr);
|
|
addTeleportInfo(mplew, chr);
|
|
addMonsterBookInfo(mplew, chr);
|
|
addNewYearInfo(mplew, chr);
|
|
addAreaInfo(mplew, chr);//assuming it stayed here xd
|
|
mplew.writeShort(0);
|
|
}
|
|
|
|
private static void addNewYearInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
Set<NewYearCardRecord> received = chr.getReceivedNewYearRecords();
|
|
|
|
mplew.writeShort(received.size());
|
|
for(NewYearCardRecord nyc : received) {
|
|
encodeNewYearCard(nyc, mplew);
|
|
}
|
|
}
|
|
|
|
private static void addTeleportInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
final List<Integer> tele = chr.getTrockMaps();
|
|
final List<Integer> viptele = chr.getVipTrockMaps();
|
|
for (int i = 0; i < 5; i++) {
|
|
mplew.writeInt(tele.get(i));
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
mplew.writeInt(viptele.get(i));
|
|
}
|
|
}
|
|
|
|
private static void addMiniGameInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeShort(0);
|
|
/*for (int m = size; m > 0; m--) {//nexon does this :P
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
}*/
|
|
}
|
|
|
|
private static void addAreaInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
Map<Short, String> areaInfos = chr.getAreaInfos();
|
|
mplew.writeShort(areaInfos.size());
|
|
for (Short area : areaInfos.keySet()) {
|
|
mplew.writeShort(area);
|
|
mplew.writeMapleAsciiString(areaInfos.get(area));
|
|
}
|
|
}
|
|
|
|
private static void addCharEquips(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
MapleInventory equip = chr.getInventory(MapleInventoryType.EQUIPPED);
|
|
Collection<Item> ii = MapleItemInformationProvider.getInstance().canWearEquipment(chr, equip.list());
|
|
Map<Short, Integer> myEquip = new LinkedHashMap<>();
|
|
Map<Short, Integer> maskedEquip = new LinkedHashMap<>();
|
|
for (Item item : ii) {
|
|
short pos = (byte) (item.getPosition() * -1);
|
|
if (pos < 100 && myEquip.get(pos) == null) {
|
|
myEquip.put(pos, item.getItemId());
|
|
} else if (pos > 100 && pos != 111) { // don't ask. o.o
|
|
pos -= 100;
|
|
if (myEquip.get(pos) != null) {
|
|
maskedEquip.put(pos, myEquip.get(pos));
|
|
}
|
|
myEquip.put(pos, item.getItemId());
|
|
} else if (myEquip.get(pos) != null) {
|
|
maskedEquip.put(pos, item.getItemId());
|
|
}
|
|
}
|
|
for (Entry<Short, Integer> entry : myEquip.entrySet()) {
|
|
mplew.write(entry.getKey());
|
|
mplew.writeInt(entry.getValue());
|
|
}
|
|
mplew.write(0xFF);
|
|
for (Entry<Short, Integer> entry : maskedEquip.entrySet()) {
|
|
mplew.write(entry.getKey());
|
|
mplew.writeInt(entry.getValue());
|
|
}
|
|
mplew.write(0xFF);
|
|
Item cWeapon = equip.getItem((short) -111);
|
|
mplew.writeInt(cWeapon != null ? cWeapon.getItemId() : 0);
|
|
for (int i = 0; i < 3; i++) {
|
|
if (chr.getPet(i) != null) {
|
|
mplew.writeInt(chr.getPet(i).getItemId());
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte[] setExtraPendantSlot(boolean toggleExtraSlot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_EXTRA_PENDANT_SLOT.getValue());
|
|
mplew.writeBool(toggleExtraSlot);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addCharEntry(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean viewall) {
|
|
addCharStats(mplew, chr);
|
|
addCharLook(mplew, chr, false);
|
|
if (!viewall) {
|
|
mplew.write(0);
|
|
}
|
|
if (chr.isGM() || chr.isGmJob()) { // thanks Daddy Egg (Ubaware), resinate for noticing GM jobs crashing on non-GM players account
|
|
mplew.write(0);
|
|
return;
|
|
}
|
|
mplew.write(1); // world rank enabled (next 4 ints are not sent if disabled) Short??
|
|
mplew.writeInt(chr.getRank()); // world rank
|
|
mplew.writeInt(chr.getRankMove()); // move (negative is downwards)
|
|
mplew.writeInt(chr.getJobRank()); // job rank
|
|
mplew.writeInt(chr.getJobRankMove()); // move (negative is downwards)
|
|
}
|
|
|
|
private static void addQuestInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
List<MapleQuestStatus> started = chr.getStartedQuests();
|
|
int startedSize = 0;
|
|
for (MapleQuestStatus qs : started) {
|
|
if (qs.getInfoNumber() > 0) {
|
|
startedSize++;
|
|
}
|
|
startedSize++;
|
|
}
|
|
mplew.writeShort(startedSize);
|
|
for (MapleQuestStatus qs : started) {
|
|
mplew.writeShort(qs.getQuest().getId());
|
|
mplew.writeMapleAsciiString(qs.getProgressData());
|
|
|
|
short infoNumber = qs.getInfoNumber();
|
|
if (infoNumber > 0) {
|
|
MapleQuestStatus iqs = chr.getQuest(infoNumber);
|
|
mplew.writeShort(infoNumber);
|
|
mplew.writeMapleAsciiString(iqs.getProgressData());
|
|
}
|
|
}
|
|
List<MapleQuestStatus> completed = chr.getCompletedQuests();
|
|
mplew.writeShort(completed.size());
|
|
for (MapleQuestStatus qs : completed) {
|
|
mplew.writeShort(qs.getQuest().getId());
|
|
mplew.writeLong(getTime(qs.getCompletionTime()));
|
|
}
|
|
}
|
|
|
|
private static void addExpirationTime(final MaplePacketLittleEndianWriter mplew, long time) {
|
|
mplew.writeLong(getTime(time)); // offset expiration time issue found thanks to Thora
|
|
}
|
|
|
|
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;
|
|
boolean isRing = false;
|
|
Equip equip = null;
|
|
short pos = item.getPosition();
|
|
byte itemType = item.getItemType();
|
|
if (itemType == 1) {
|
|
equip = (Equip) item;
|
|
isRing = equip.getRingId() > -1;
|
|
}
|
|
if (!zeroPosition) {
|
|
if (equip != null) {
|
|
if (pos < 0) {
|
|
pos *= -1;
|
|
}
|
|
mplew.writeShort(pos > 100 ? pos - 100 : pos);
|
|
} else {
|
|
mplew.write(pos);
|
|
}
|
|
}
|
|
mplew.write(itemType);
|
|
mplew.writeInt(item.getItemId());
|
|
mplew.writeBool(isCash);
|
|
if (isCash) {
|
|
mplew.writeLong(isPet ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId());
|
|
}
|
|
addExpirationTime(mplew, item.getExpiration());
|
|
if (isPet) {
|
|
MaplePet pet = item.getPet();
|
|
mplew.writeAsciiString(StringUtil.getRightPaddedStr(pet.getName(), '\0', 13));
|
|
mplew.write(pet.getLevel());
|
|
mplew.writeShort(pet.getCloseness());
|
|
mplew.write(pet.getFullness());
|
|
addExpirationTime(mplew, item.getExpiration());
|
|
mplew.writeInt(pet.getPetFlag()); /* pet flags noticed by lrenex & Spoon */
|
|
|
|
mplew.write(new byte[]{(byte) 0x50, (byte) 0x46}); //wonder what this is
|
|
mplew.writeInt(0);
|
|
return;
|
|
}
|
|
if (equip == null) {
|
|
mplew.writeShort(item.getQuantity());
|
|
mplew.writeMapleAsciiString(item.getOwner());
|
|
mplew.writeShort(item.getFlag()); // flag
|
|
|
|
if (ItemConstants.isRechargeable(item.getItemId())) {
|
|
mplew.writeInt(2);
|
|
mplew.write(new byte[]{(byte) 0x54, 0, 0, (byte) 0x34});
|
|
}
|
|
return;
|
|
}
|
|
mplew.write(equip.getUpgradeSlots()); // upgrade slots
|
|
mplew.write(equip.getLevel()); // level
|
|
mplew.writeShort(equip.getStr()); // str
|
|
mplew.writeShort(equip.getDex()); // dex
|
|
mplew.writeShort(equip.getInt()); // int
|
|
mplew.writeShort(equip.getLuk()); // luk
|
|
mplew.writeShort(equip.getHp()); // hp
|
|
mplew.writeShort(equip.getMp()); // mp
|
|
mplew.writeShort(equip.getWatk()); // watk
|
|
mplew.writeShort(equip.getMatk()); // matk
|
|
mplew.writeShort(equip.getWdef()); // wdef
|
|
mplew.writeShort(equip.getMdef()); // mdef
|
|
mplew.writeShort(equip.getAcc()); // accuracy
|
|
mplew.writeShort(equip.getAvoid()); // avoid
|
|
mplew.writeShort(equip.getHands()); // hands
|
|
mplew.writeShort(equip.getSpeed()); // speed
|
|
mplew.writeShort(equip.getJump()); // jump
|
|
mplew.writeMapleAsciiString(equip.getOwner()); // owner name
|
|
mplew.writeShort(equip.getFlag()); //Item Flags
|
|
|
|
if (isCash) {
|
|
for (int i = 0; i < 10; i++) {
|
|
mplew.write(0x40);
|
|
}
|
|
} else {
|
|
int itemLevel = equip.getItemLevel();
|
|
|
|
long expNibble = (ExpTable.getExpNeededForLevel(ii.getEquipLevelReq(item.getItemId())) * equip.getItemExp());
|
|
expNibble /= ExpTable.getEquipExpNeededForLevel(itemLevel);
|
|
|
|
mplew.write(0);
|
|
mplew.write(itemLevel); //Item Level
|
|
mplew.writeInt((int) expNibble);
|
|
mplew.writeInt(equip.getVicious()); //WTF NEXON ARE YOU SERIOUS?
|
|
mplew.writeLong(0);
|
|
}
|
|
mplew.writeLong(getTime(-2));
|
|
mplew.writeInt(-1);
|
|
|
|
}
|
|
|
|
private static void addInventoryInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
for (byte i = 1; i <= 5; i++) {
|
|
mplew.write(chr.getInventory(MapleInventoryType.getByType(i)).getSlotLimit());
|
|
}
|
|
mplew.writeLong(getTime(-2));
|
|
MapleInventory iv = chr.getInventory(MapleInventoryType.EQUIPPED);
|
|
Collection<Item> equippedC = iv.list();
|
|
List<Item> equipped = new ArrayList<>(equippedC.size());
|
|
List<Item> equippedCash = new ArrayList<>(equippedC.size());
|
|
for (Item item : equippedC) {
|
|
if (item.getPosition() <= -100) {
|
|
equippedCash.add(item);
|
|
} else {
|
|
equipped.add(item);
|
|
}
|
|
}
|
|
for (Item item : equipped) { // equipped doesn't actually need sorting, thanks Pllsz
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.writeShort(0); // start of equip cash
|
|
for (Item item : equippedCash) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.writeShort(0); // start of equip inventory
|
|
for (Item item : chr.getInventory(MapleInventoryType.EQUIP).list()) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.writeInt(0);
|
|
for (Item item : chr.getInventory(MapleInventoryType.USE).list()) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.write(0);
|
|
for (Item item : chr.getInventory(MapleInventoryType.SETUP).list()) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.write(0);
|
|
for (Item item : chr.getInventory(MapleInventoryType.ETC).list()) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
mplew.write(0);
|
|
for (Item item : chr.getInventory(MapleInventoryType.CASH).list()) {
|
|
addItemInfo(mplew, item);
|
|
}
|
|
}
|
|
|
|
private static void addSkillInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.write(0); // start of skills
|
|
Map<Skill, MapleCharacter.SkillEntry> skills = chr.getSkills();
|
|
int skillsSize = skills.size();
|
|
// We don't want to include any hidden skill in this, so subtract them from the size list and ignore them.
|
|
for (Entry<Skill, SkillEntry> skill : skills.entrySet()) {
|
|
if (GameConstants.isHiddenSkills(skill.getKey().getId())) {
|
|
skillsSize--;
|
|
}
|
|
}
|
|
mplew.writeShort(skillsSize);
|
|
for (Entry<Skill, SkillEntry> skill : skills.entrySet()) {
|
|
if (GameConstants.isHiddenSkills(skill.getKey().getId())) {
|
|
continue;
|
|
}
|
|
mplew.writeInt(skill.getKey().getId());
|
|
mplew.writeInt(skill.getValue().skillevel);
|
|
addExpirationTime(mplew, skill.getValue().expiration);
|
|
if (skill.getKey().isFourthJob()) {
|
|
mplew.writeInt(skill.getValue().masterlevel);
|
|
}
|
|
}
|
|
mplew.writeShort(chr.getAllCooldowns().size());
|
|
for (PlayerCoolDownValueHolder cooling : chr.getAllCooldowns()) {
|
|
mplew.writeInt(cooling.skillId);
|
|
int timeLeft = (int) (cooling.length + cooling.startTime - System.currentTimeMillis());
|
|
mplew.writeShort(timeLeft / 1000);
|
|
}
|
|
}
|
|
|
|
private static void addMonsterBookInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeInt(chr.getMonsterBookCover()); // cover
|
|
mplew.write(0);
|
|
Map<Integer, Integer> cards = chr.getMonsterBook().getCards();
|
|
mplew.writeShort(cards.size());
|
|
for (Entry<Integer, Integer> all : cards.entrySet()) {
|
|
mplew.writeShort(all.getKey() % 10000); // Id
|
|
mplew.write(all.getValue()); // Level
|
|
}
|
|
}
|
|
|
|
public static byte[] sendGuestTOS() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUEST_ID_LOGIN.getValue());
|
|
mplew.writeShort(0x100);
|
|
mplew.writeInt(Randomizer.nextInt(999999));
|
|
mplew.writeLong(0);
|
|
mplew.writeLong(getTime(-2));
|
|
mplew.writeLong(getTime(System.currentTimeMillis()));
|
|
mplew.writeInt(0);
|
|
mplew.writeMapleAsciiString("http://maplesolaxia.com");
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a hello packet.
|
|
*
|
|
* @param mapleVersion The maple client version.
|
|
* @param sendIv the IV in use by the server for sending
|
|
* @param recvIv the IV in use by the server for receiving
|
|
* @return
|
|
*/
|
|
public static byte[] getHello(short mapleVersion, byte[] sendIv, byte[] recvIv) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
|
|
mplew.writeShort(0x0E);
|
|
mplew.writeShort(mapleVersion);
|
|
mplew.writeShort(1);
|
|
mplew.write(49);
|
|
mplew.write(recvIv);
|
|
mplew.write(sendIv);
|
|
mplew.write(8);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a ping packet.
|
|
*
|
|
* @return The packet.
|
|
*/
|
|
public static byte[] getPing() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2);
|
|
mplew.writeShort(SendOpcode.PING.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a login failed packet.
|
|
*
|
|
* Possible values for <code>reason</code>:<br> 3: ID deleted or blocked<br>
|
|
* 4: Incorrect password<br> 5: Not a registered id<br> 6: System error<br>
|
|
* 7: Already logged in<br> 8: System error<br> 9: System error<br> 10:
|
|
* Cannot process so many connections<br> 11: Only users older than 20 can
|
|
* use this channel<br> 13: Unable to log on as master at this ip<br> 14:
|
|
* Wrong gateway or personal info and weird korean button<br> 15: Processing
|
|
* request with that korean button!<br> 16: Please verify your account
|
|
* through email...<br> 17: Wrong gateway or personal info<br> 21: Please
|
|
* verify your account through email...<br> 23: License agreement<br> 25:
|
|
* Maple Europe notice =[ FUCK YOU NEXON<br> 27: Some weird full client
|
|
* notice, probably for trial versions<br>
|
|
*
|
|
* @param reason The reason logging in failed.
|
|
* @return The login failed packet.
|
|
*/
|
|
public static byte[] getLoginFailed(int reason) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
|
|
mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue());
|
|
mplew.write(reason);
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a login failed packet.
|
|
*
|
|
* Possible values for <code>reason</code>:<br> 2: ID deleted or blocked<br>
|
|
* 3: ID deleted or blocked<br> 4: Incorrect password<br> 5: Not a
|
|
* registered id<br> 6: Trouble logging into the game?<br> 7: Already logged
|
|
* in<br> 8: Trouble logging into the game?<br> 9: Trouble logging into the
|
|
* game?<br> 10: Cannot process so many connections<br> 11: Only users older
|
|
* than 20 can use this channel<br> 12: Trouble logging into the game?<br>
|
|
* 13: Unable to log on as master at this ip<br> 14: Wrong gateway or
|
|
* personal info and weird korean button<br> 15: Processing request with
|
|
* that korean button!<br> 16: Please verify your account through
|
|
* email...<br> 17: Wrong gateway or personal info<br> 21: Please verify
|
|
* your account through email...<br> 23: Crashes<br> 25: Maple Europe notice
|
|
* =[ FUCK YOU NEXON<br> 27: Some weird full client notice, probably for
|
|
* trial versions<br>
|
|
*
|
|
* @param reason The reason logging in failed.
|
|
* @return The login failed packet.
|
|
*/
|
|
public static byte[] getAfterLoginError(int reason) {//same as above o.o
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
|
|
mplew.writeShort(SendOpcode.SELECT_CHARACTER_BY_VAC.getValue());
|
|
mplew.writeShort(reason);//using other types than stated above = CRASH
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendPolice() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAKE_GM_NOTICE.getValue());
|
|
mplew.write(0);//doesn't even matter what value
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendPolice(String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DATA_CRC_CHECK_FAILED.getValue());
|
|
mplew.writeMapleAsciiString(text);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPermBan(byte reason) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue());
|
|
mplew.write(2); // Account is banned
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
mplew.write(0);
|
|
mplew.writeLong(getTime(-1));
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTempBan(long timestampTill, byte reason) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(17);
|
|
mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue());
|
|
mplew.write(2);
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
mplew.write(reason);
|
|
mplew.writeLong(getTime(timestampTill)); // Tempban date is handled as a 64-bit long, number of 100NS intervals since 1/1/1601. Lulz.
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a successful authentication packet.
|
|
*
|
|
* @param c
|
|
* @return the successful authentication packet
|
|
*/
|
|
public static byte[] getAuthSuccess(MapleClient c) {
|
|
Server.getInstance().loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB.
|
|
Server.getInstance().loadAccountStorages(c);
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue());
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(c.getAccID());
|
|
mplew.write(c.getGender());
|
|
|
|
boolean canFly = Server.getInstance().canFly(c.getAccID());
|
|
mplew.writeBool((YamlConfig.config.server.USE_ENFORCE_ADMIN_ACCOUNT || canFly) ? c.getGMLevel() > 1 : false); // thanks Steve(kaito1410) for pointing the GM account boolean here
|
|
mplew.write(((YamlConfig.config.server.USE_ENFORCE_ADMIN_ACCOUNT || canFly) && c.getGMLevel() > 1) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish.
|
|
mplew.write(0); // Country Code.
|
|
|
|
mplew.writeMapleAsciiString(c.getAccountName());
|
|
mplew.write(0);
|
|
|
|
mplew.write(0); // IsQuietBan
|
|
mplew.writeLong(0);//IsQuietBanTimeStamp
|
|
mplew.writeLong(0); //CreationTimeStamp
|
|
|
|
mplew.writeInt(1); // 1: Remove the "Select the world you want to play in"
|
|
|
|
mplew.write(YamlConfig.config.server.ENABLE_PIN && !c.canBypassPin() ? 0 : 1); // 0 = Pin-System Enabled, 1 = Disabled
|
|
mplew.write(YamlConfig.config.server.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null || c.getPic().equals("") ? 0 : 1) : 2); // 0 = Register PIC, 1 = Ask for PIC, 2 = Disabled
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet detailing a PIN operation.
|
|
*
|
|
* Possible values for <code>mode</code>:<br> 0 - PIN was accepted<br> 1 -
|
|
* Register a new PIN<br> 2 - Invalid pin / Reenter<br> 3 - Connection
|
|
* failed due to system error<br> 4 - Enter the pin
|
|
*
|
|
* @param mode The mode.
|
|
* @return
|
|
*/
|
|
private static byte[] pinOperation(byte mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.CHECK_PINCODE.getValue());
|
|
mplew.write(mode);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] pinRegistered() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.UPDATE_PINCODE.getValue());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] requestPin() {
|
|
return pinOperation((byte) 4);
|
|
}
|
|
|
|
public static byte[] requestPinAfterFailure() {
|
|
return pinOperation((byte) 2);
|
|
}
|
|
|
|
public static byte[] registerPin() {
|
|
return pinOperation((byte) 1);
|
|
}
|
|
|
|
public static byte[] pinAccepted() {
|
|
return pinOperation((byte) 0);
|
|
}
|
|
|
|
public static byte[] wrongPic() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.CHECK_SPW_RESULT.getValue());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet detailing a server and its channels.
|
|
*
|
|
* @param serverId
|
|
* @param serverName The name of the server.
|
|
* @param flag
|
|
* @param eventmsg
|
|
* @param channelLoad Load of the channel - 1200 seems to be max.
|
|
* @return The server info packet.
|
|
*/
|
|
public static byte[] getServerList(int serverId, String serverName, int flag, String eventmsg, List<Channel> channelLoad) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVERLIST.getValue());
|
|
mplew.write(serverId);
|
|
mplew.writeMapleAsciiString(serverName);
|
|
mplew.write(flag);
|
|
mplew.writeMapleAsciiString(eventmsg);
|
|
mplew.write(100); // rate modifier, don't ask O.O!
|
|
mplew.write(0); // event xp * 2.6 O.O!
|
|
mplew.write(100); // rate modifier, don't ask O.O!
|
|
mplew.write(0); // drop rate * 2.6
|
|
mplew.write(0);
|
|
mplew.write(channelLoad.size());
|
|
for (Channel ch : channelLoad) {
|
|
mplew.writeMapleAsciiString(serverName + "-" + ch.getId());
|
|
mplew.writeInt(ch.getChannelCapacity());
|
|
|
|
// thanks GabrielSin for this channel packet structure part
|
|
mplew.write(1);// nWorldID
|
|
mplew.write(ch.getId() - 1);// nChannelID
|
|
mplew.writeBool(false);// bAdultChannel
|
|
}
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet saying that the server list is over.
|
|
*
|
|
* @return The end of server list packet.
|
|
*/
|
|
public static byte[] getEndOfServerList() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.SERVERLIST.getValue());
|
|
mplew.write(0xFF);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet detailing a server status message.
|
|
*
|
|
* Possible values for <code>status</code>:<br> 0 - Normal<br> 1 - Highly
|
|
* populated<br> 2 - Full
|
|
*
|
|
* @param status The server status.
|
|
* @return The server status packet.
|
|
*/
|
|
public static byte[] getServerStatus(int status) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.SERVERSTATUS.getValue());
|
|
mplew.writeShort(status);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client the IP of the channel server.
|
|
*
|
|
* @param inetAddr The InetAddress of the requested channel server.
|
|
* @param port The port the channel is on.
|
|
* @param clientId The ID of the client.
|
|
* @return The server IP packet.
|
|
*/
|
|
public static byte[] getServerIP(InetAddress inetAddr, int port, int clientId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVER_IP.getValue());
|
|
mplew.writeShort(0);
|
|
byte[] addr = inetAddr.getAddress();
|
|
mplew.write(addr);
|
|
mplew.writeShort(port);
|
|
mplew.writeInt(clientId);
|
|
mplew.write(new byte[]{0, 0, 0, 0, 0});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client the IP of the new channel.
|
|
*
|
|
* @param inetAddr The InetAddress of the requested channel server.
|
|
* @param port The port the channel is on.
|
|
* @return The server IP packet.
|
|
*/
|
|
public static byte[] getChannelChange(InetAddress inetAddr, int port) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHANGE_CHANNEL.getValue());
|
|
mplew.write(1);
|
|
byte[] addr = inetAddr.getAddress();
|
|
mplew.write(addr);
|
|
mplew.writeShort(port);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet with a list of characters.
|
|
*
|
|
* @param c The MapleClient to load characters of.
|
|
* @param serverId The ID of the server requested.
|
|
* @param status The charlist request result.
|
|
* @return The character list packet.
|
|
*
|
|
* Possible values for <code>status</code>:
|
|
* <br> 2: ID deleted or blocked<br>
|
|
* <br> 3: ID deleted or blocked<br>
|
|
* <br> 4: Incorrect password<br>
|
|
* <br> 5: Not an registered ID<br>
|
|
* <br> 6: Trouble logging in?<br>
|
|
* <br> 10: Server handling too many connections<br>
|
|
* <br> 11: Only 20 years or older<br>
|
|
* <br> 13: Unable to log as master at IP<br>
|
|
* <br> 14: Wrong gateway or personal info<br>
|
|
* <br> 15: Still processing request<br>
|
|
* <br> 16: Verify account via email<br>
|
|
* <br> 17: Wrong gateway or personal info<br>
|
|
* <br> 21: Verify account via email<br>
|
|
*/
|
|
public static byte[] getCharList(MapleClient c, int serverId, int status) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHARLIST.getValue());
|
|
mplew.write(status);
|
|
List<MapleCharacter> chars = c.loadCharacters(serverId);
|
|
mplew.write((byte) chars.size());
|
|
for (MapleCharacter chr : chars) {
|
|
addCharEntry(mplew, chr, false);
|
|
}
|
|
|
|
mplew.write(YamlConfig.config.server.ENABLE_PIC && !c.canBypassPic() ? (c.getPic() == null || c.getPic().equals("") ? 0 : 1) : 2);
|
|
mplew.writeInt(YamlConfig.config.server.COLLECTIVE_CHARSLOT ? chars.size() + c.getAvailableCharacterSlots() : c.getCharacterSlots());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] enableTV() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.ENABLE_TV.getValue());
|
|
mplew.writeInt(0);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Removes TV
|
|
*
|
|
* @return The Remove TV Packet
|
|
*/
|
|
public static byte[] removeTV() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2);
|
|
mplew.writeShort(SendOpcode.REMOVE_TV.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends MapleTV
|
|
*
|
|
* @param chr The character shown in TV
|
|
* @param messages The message sent with the TV
|
|
* @param type The type of TV
|
|
* @param partner The partner shown with chr
|
|
* @return the SEND_TV packet
|
|
*/
|
|
public static byte[] sendTV(MapleCharacter chr, List<String> messages, int type, MapleCharacter partner) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SEND_TV.getValue());
|
|
mplew.write(partner != null ? 3 : 1);
|
|
mplew.write(type); //Heart = 2 Star = 1 Normal = 0
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
if (partner != null) {
|
|
mplew.writeMapleAsciiString(partner.getName());
|
|
} else {
|
|
mplew.writeShort(0);
|
|
}
|
|
for (int i = 0; i < messages.size(); i++) {
|
|
if (i == 4 && messages.get(4).length() > 15) {
|
|
mplew.writeMapleAsciiString(messages.get(4).substring(0, 15));
|
|
} else {
|
|
mplew.writeMapleAsciiString(messages.get(i));
|
|
}
|
|
}
|
|
mplew.writeInt(1337); // time limit shit lol 'Your thing still start in blah blah seconds'
|
|
if (partner != null) {
|
|
addCharLook(mplew, partner, false);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets character info for a character.
|
|
*
|
|
* @param chr The character to get info about.
|
|
* @return The character info packet.
|
|
*/
|
|
public static byte[] getCharInfo(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_FIELD.getValue());
|
|
mplew.writeInt(chr.getClient().getChannel() - 1);
|
|
mplew.write(1);
|
|
mplew.write(1);
|
|
mplew.writeShort(0);
|
|
for (int i = 0; i < 3; i++) {
|
|
mplew.writeInt(Randomizer.nextInt());
|
|
}
|
|
addCharacterInfo(mplew, chr);
|
|
mplew.writeLong(getTime(System.currentTimeMillis()));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets an empty stat update.
|
|
*
|
|
* @return The empty stat update packet.
|
|
*/
|
|
public static byte[] enableActions() {
|
|
return updatePlayerStats(EMPTY_STATUPDATE, true, null);
|
|
}
|
|
|
|
/**
|
|
* Gets an update for specified stats.
|
|
*
|
|
* @param stats The list of stats to update.
|
|
* @param enableActions Allows actions after the update.
|
|
* @param chr The update target.
|
|
* @return The stat update packet.
|
|
*/
|
|
public static byte[] updatePlayerStats(List<Pair<MapleStat, Integer>> stats, boolean enableActions, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STAT_CHANGED.getValue());
|
|
mplew.write(enableActions ? 1 : 0);
|
|
int updateMask = 0;
|
|
for (Pair<MapleStat, Integer> statupdate : stats) {
|
|
updateMask |= statupdate.getLeft().getValue();
|
|
}
|
|
List<Pair<MapleStat, Integer>> mystats = stats;
|
|
if (mystats.size() > 1) {
|
|
mystats.sort((o1, o2) -> {
|
|
int val1 = o1.getLeft().getValue();
|
|
int val2 = o2.getLeft().getValue();
|
|
return (val1 < val2 ? -1 : (val1 == val2 ? 0 : 1));
|
|
});
|
|
}
|
|
mplew.writeInt(updateMask);
|
|
for (Pair<MapleStat, Integer> statupdate : mystats) {
|
|
if (statupdate.getLeft().getValue() >= 1) {
|
|
if (statupdate.getLeft().getValue() == 0x1) {
|
|
mplew.write(statupdate.getRight().byteValue());
|
|
} else if (statupdate.getLeft().getValue() <= 0x4) {
|
|
mplew.writeInt(statupdate.getRight());
|
|
} else if (statupdate.getLeft().getValue() < 0x20) {
|
|
mplew.write(statupdate.getRight().shortValue());
|
|
} else if (statupdate.getLeft().getValue() == 0x8000) {
|
|
if (GameConstants.hasSPTable(chr.getJob())) {
|
|
addRemainingSkillInfo(mplew, chr);
|
|
} else {
|
|
mplew.writeShort(statupdate.getRight().shortValue());
|
|
}
|
|
} else if (statupdate.getLeft().getValue() < 0xFFFF) {
|
|
mplew.writeShort(statupdate.getRight().shortValue());
|
|
} else if (statupdate.getLeft().getValue() == 0x20000) {
|
|
mplew.writeShort(statupdate.getRight().shortValue());
|
|
} else {
|
|
mplew.writeInt(statupdate.getRight());
|
|
}
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to change maps.
|
|
*
|
|
* @param to The <code>MapleMap</code> to warp to.
|
|
* @param spawnPoint The spawn portal number to spawn at.
|
|
* @param chr The character warping to <code>to</code>
|
|
* @return The map change packet.
|
|
*/
|
|
public static byte[] getWarpToMap(MapleMap to, int spawnPoint, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_FIELD.getValue());
|
|
mplew.writeInt(chr.getClient().getChannel() - 1);
|
|
mplew.writeInt(0);//updated
|
|
mplew.write(0);//updated
|
|
mplew.writeInt(to.getId());
|
|
mplew.write(spawnPoint);
|
|
mplew.writeShort(chr.getHp());
|
|
mplew.writeBool(false);
|
|
mplew.writeLong(getTime(Server.getInstance().getCurrentTime()));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getWarpToMap(MapleMap to, int spawnPoint, Point spawnPosition, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_FIELD.getValue());
|
|
mplew.writeInt(chr.getClient().getChannel() - 1);
|
|
mplew.writeInt(0);//updated
|
|
mplew.write(0);//updated
|
|
mplew.writeInt(to.getId());
|
|
mplew.write(spawnPoint);
|
|
mplew.writeShort(chr.getHp());
|
|
mplew.writeBool(true);
|
|
mplew.writeInt(spawnPosition.x); // spawn position placement thanks to Arnah (Vertisy)
|
|
mplew.writeInt(spawnPosition.y);
|
|
mplew.writeLong(getTime(Server.getInstance().getCurrentTime()));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet to spawn a portal.
|
|
*
|
|
* @param townId The ID of the town the portal goes to.
|
|
* @param targetId The ID of the target.
|
|
* @param pos Where to put the portal.
|
|
* @return The portal spawn packet.
|
|
*/
|
|
public static byte[] spawnPortal(int townId, int targetId, Point pos) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(14);
|
|
mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue());
|
|
mplew.writeInt(townId);
|
|
mplew.writeInt(targetId);
|
|
mplew.writePos(pos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet to spawn a door.
|
|
*
|
|
* @param ownerid The door's owner ID.
|
|
* @param pos The position of the door.
|
|
* @param launched Already deployed the door.
|
|
* @return The remove door packet.
|
|
*/
|
|
public static byte[] spawnDoor(int ownerid, Point pos, boolean launched) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11);
|
|
mplew.writeShort(SendOpcode.SPAWN_DOOR.getValue());
|
|
mplew.writeBool(launched);
|
|
mplew.writeInt(ownerid);
|
|
mplew.writePos(pos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet to remove a door.
|
|
*
|
|
* @param ownerid The door's owner ID.
|
|
* @param town
|
|
* @return The remove door packet.
|
|
*/
|
|
public static byte[] removeDoor(int ownerid, boolean town) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10);
|
|
if (town) {
|
|
mplew.writeShort(SendOpcode.SPAWN_PORTAL.getValue());
|
|
mplew.writeInt(999999999);
|
|
mplew.writeInt(999999999);
|
|
} else {
|
|
mplew.writeShort(SendOpcode.REMOVE_DOOR.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(ownerid);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet to spawn a special map object.
|
|
*
|
|
* @param summon
|
|
* @param skillLevel The level of the skill used.
|
|
* @param animated Animated spawn?
|
|
* @return The spawn packet for the map object.
|
|
*/
|
|
public static byte[] spawnSummon(MapleSummon summon, boolean animated) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(25);
|
|
mplew.writeShort(SendOpcode.SPAWN_SPECIAL_MAPOBJECT.getValue());
|
|
mplew.writeInt(summon.getOwner().getId());
|
|
mplew.writeInt(summon.getObjectId());
|
|
mplew.writeInt(summon.getSkill());
|
|
mplew.write(0x0A); //v83
|
|
mplew.write(summon.getSkillLevel());
|
|
mplew.writePos(summon.getPosition());
|
|
mplew.write(summon.getStance()); //bMoveAction & foothold, found thanks to Rien dev team
|
|
mplew.writeShort(0);
|
|
mplew.write(summon.getMovementType().getValue()); // 0 = don't move, 1 = follow (4th mage summons?), 2/4 = only tele follow, 3 = bird follow
|
|
mplew.write(summon.isPuppet() ? 0 : 1); // 0 and the summon can't attack - but puppets don't attack with 1 either ^.-
|
|
mplew.write(animated ? 0 : 1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet to remove a special map object.
|
|
*
|
|
* @param summon
|
|
* @param animated Animated removal?
|
|
* @return The packet removing the object.
|
|
*/
|
|
public static byte[] removeSummon(MapleSummon summon, boolean animated) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11);
|
|
mplew.writeShort(SendOpcode.REMOVE_SPECIAL_MAPOBJECT.getValue());
|
|
mplew.writeInt(summon.getOwner().getId());
|
|
mplew.writeInt(summon.getObjectId());
|
|
mplew.write(animated ? 4 : 1); // ?
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnKite(int oid, int itemid, String name, String msg, Point pos, int ft) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_KITE.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.writeInt(itemid);
|
|
mplew.writeMapleAsciiString(msg);
|
|
mplew.writeMapleAsciiString(name);
|
|
mplew.writeShort(pos.x);
|
|
mplew.writeShort(ft);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeKite(int objectid, int animationType) { // thanks to Arnah (Vertisy)
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_KITE.getValue());
|
|
mplew.write(animationType); // 0 is 10/10, 1 just vanishes
|
|
mplew.writeInt(objectid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendCannotSpawnKite() {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANNOT_SPAWN_KITE.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets the response to a relog request.
|
|
*
|
|
* @return The relog response packet.
|
|
*/
|
|
public static byte[] getRelogResponse() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.RELOG_RESPONSE.getValue());
|
|
mplew.write(1);//1 O.O Must be more types ):
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a server message packet.
|
|
*
|
|
* @param message The message to convey.
|
|
* @return The server message packet.
|
|
*/
|
|
public static byte[] serverMessage(String message) {
|
|
return serverMessage(4, (byte) 0, message, true, false, 0);
|
|
}
|
|
|
|
/**
|
|
* Gets a server notice packet.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: [Notice]<br> 1: Popup<br>
|
|
* 2: Megaphone<br> 3: Super Megaphone<br> 4: Scrolling message at top<br>
|
|
* 5: Pink Text<br> 6: Lightblue Text
|
|
*
|
|
* @param type The type of the notice.
|
|
* @param message The message to convey.
|
|
* @return The server notice packet.
|
|
*/
|
|
public static byte[] serverNotice(int type, String message) {
|
|
return serverMessage(type, (byte) 0, message, false, false, 0);
|
|
}
|
|
|
|
/**
|
|
* Gets a server notice packet.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: [Notice]<br> 1: Popup<br>
|
|
* 2: Megaphone<br> 3: Super Megaphone<br> 4: Scrolling message at top<br>
|
|
* 5: Pink Text<br> 6: Lightblue Text
|
|
*
|
|
* @param type The type of the notice.
|
|
* @param channel The channel this notice was sent on.
|
|
* @param message The message to convey.
|
|
* @return The server notice packet.
|
|
*/
|
|
public static byte[] serverNotice(int type, String message, int npc) {
|
|
return serverMessage(type, 0, message, false, false, npc);
|
|
}
|
|
|
|
public static byte[] serverNotice(int type, int channel, String message) {
|
|
return serverMessage(type, channel, message, false, false, 0);
|
|
}
|
|
|
|
public static byte[] serverNotice(int type, int channel, String message, boolean smegaEar) {
|
|
return serverMessage(type, channel, message, false, smegaEar, 0);
|
|
}
|
|
|
|
/**
|
|
* Gets a server message packet.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: [Notice]<br> 1: Popup<br>
|
|
* 2: Megaphone<br> 3: Super Megaphone<br> 4: Scrolling message at top<br>
|
|
* 5: Pink Text<br> 6: Lightblue Text<br> 7: BroadCasting NPC
|
|
*
|
|
* @param type The type of the notice.
|
|
* @param channel The channel this notice was sent on.
|
|
* @param message The message to convey.
|
|
* @param servermessage Is this a scrolling ticker?
|
|
* @return The server notice packet.
|
|
*/
|
|
private static byte[] serverMessage(int type, int channel, String message, boolean servermessage, boolean megaEar, int npc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue());
|
|
mplew.write(type);
|
|
if (servermessage) {
|
|
mplew.write(1);
|
|
}
|
|
mplew.writeMapleAsciiString(message);
|
|
if (type == 3) {
|
|
mplew.write(channel - 1); // channel
|
|
mplew.writeBool(megaEar);
|
|
} else if (type == 6) {
|
|
mplew.writeInt(0);
|
|
} else if (type == 7) { // npc
|
|
mplew.writeInt(npc);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a Avatar Super Megaphone packet.
|
|
*
|
|
* @param chr The character name.
|
|
* @param medal The medal text.
|
|
* @param channel Which channel.
|
|
* @param itemId Which item used.
|
|
* @param message The message sent.
|
|
* @param ear Whether or not the ear is shown for whisper.
|
|
* @return
|
|
*/
|
|
public static byte[] getAvatarMega(MapleCharacter chr, String medal, int channel, int itemId, List<String> message, boolean ear) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_AVATAR_MEGAPHONE.getValue());
|
|
mplew.writeInt(itemId);
|
|
mplew.writeMapleAsciiString(medal + chr.getName());
|
|
for (String s : message) {
|
|
mplew.writeMapleAsciiString(s);
|
|
}
|
|
mplew.writeInt(channel - 1); // channel
|
|
mplew.writeBool(ear);
|
|
addCharLook(mplew, chr, true);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
* Sends a packet to remove the tiger megaphone
|
|
* @return
|
|
*/
|
|
public static byte[] byeAvatarMega() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CLEAR_AVATAR_MEGAPHONE.getValue());
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends the Gachapon green message when a user uses a gachapon ticket.
|
|
*
|
|
* @param item
|
|
* @param town
|
|
* @param player
|
|
* @return
|
|
*/
|
|
public static byte[] gachaponMessage(Item item, String town, MapleCharacter player) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue());
|
|
mplew.write(0x0B);
|
|
mplew.writeMapleAsciiString(player.getName() + " : got a(n)");
|
|
mplew.writeInt(0); //random?
|
|
mplew.writeMapleAsciiString(town);
|
|
addItemInfo(mplew, item, true);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnNPC(MapleNPC life) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(24);
|
|
mplew.writeShort(SendOpcode.SPAWN_NPC.getValue());
|
|
mplew.writeInt(life.getObjectId());
|
|
mplew.writeInt(life.getId());
|
|
mplew.writeShort(life.getPosition().x);
|
|
mplew.writeShort(life.getCy());
|
|
if (life.getF() == 1) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
}
|
|
mplew.writeShort(life.getFh());
|
|
mplew.writeShort(life.getRx0());
|
|
mplew.writeShort(life.getRx1());
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnNPCRequestController(MapleNPC life, boolean MiniMap) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(23);
|
|
mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(life.getObjectId());
|
|
mplew.writeInt(life.getId());
|
|
mplew.writeShort(life.getPosition().x);
|
|
mplew.writeShort(life.getCy());
|
|
if (life.getF() == 1) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
}
|
|
mplew.writeShort(life.getFh());
|
|
mplew.writeShort(life.getRx0());
|
|
mplew.writeShort(life.getRx1());
|
|
mplew.writeBool(MiniMap);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a spawn monster packet.
|
|
*
|
|
* @param life The monster to spawn.
|
|
* @param newSpawn Is it a new spawn?
|
|
* @return The spawn monster packet.
|
|
*/
|
|
public static byte[] spawnMonster(MapleMonster life, boolean newSpawn) {
|
|
return spawnMonsterInternal(life, false, newSpawn, false, 0, false);
|
|
}
|
|
|
|
/**
|
|
* Gets a spawn monster packet.
|
|
*
|
|
* @param life The monster to spawn.
|
|
* @param newSpawn Is it a new spawn?
|
|
* @param effect The spawn effect.
|
|
* @return The spawn monster packet.
|
|
*/
|
|
public static byte[] spawnMonster(MapleMonster life, boolean newSpawn, int effect) {
|
|
return spawnMonsterInternal(life, false, newSpawn, false, effect, false);
|
|
}
|
|
|
|
/**
|
|
* Gets a control monster packet.
|
|
*
|
|
* @param life The monster to give control to.
|
|
* @param newSpawn Is it a new spawn?
|
|
* @param aggro Aggressive monster?
|
|
* @return The monster control packet.
|
|
*/
|
|
public static byte[] controlMonster(MapleMonster life, boolean newSpawn, boolean aggro) {
|
|
return spawnMonsterInternal(life, true, newSpawn, aggro, 0, false);
|
|
}
|
|
|
|
/**
|
|
* Removes a monster invisibility.
|
|
*
|
|
* @param life
|
|
* @return
|
|
*/
|
|
public static byte[] removeMonsterInvisibility(MapleMonster life) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(life.getObjectId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Makes a monster invisible for Ariant PQ.
|
|
*
|
|
* @param life
|
|
* @return
|
|
*/
|
|
public static byte[] makeMonsterInvisible(MapleMonster life) {
|
|
return spawnMonsterInternal(life, true, false, false, 0, true);
|
|
}
|
|
|
|
private static void encodeParentlessMobSpawnEffect(MaplePacketLittleEndianWriter mplew, boolean newSpawn, int effect) {
|
|
if (effect > 0) {
|
|
mplew.write(effect);
|
|
mplew.write(0);
|
|
mplew.writeShort(0);
|
|
if (effect == 15) {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
mplew.write(newSpawn ? -2 : -1);
|
|
}
|
|
|
|
private static void encodeTemporary(MaplePacketLittleEndianWriter mplew, Map<MonsterStatus, MonsterStatusEffect> stati) {
|
|
int pCounter = -1, mCounter = -1;
|
|
|
|
writeLongEncodeTemporaryMask(mplew, stati.keySet()); // packet structure mapped thanks to Eric
|
|
|
|
for (Entry<MonsterStatus, MonsterStatusEffect> s : stati.entrySet()) {
|
|
MonsterStatusEffect mse = s.getValue();
|
|
mplew.writeShort(mse.getStati().get(s.getKey()));
|
|
|
|
MobSkill mobSkill = mse.getMobSkill();
|
|
if (mobSkill != null) {
|
|
mplew.writeShort(mobSkill.getSkillId());
|
|
mplew.writeShort(mobSkill.getSkillLevel());
|
|
|
|
switch(s.getKey()) {
|
|
case WEAPON_REFLECT:
|
|
pCounter = mobSkill.getX();
|
|
break;
|
|
|
|
case MAGIC_REFLECT:
|
|
mCounter = mobSkill.getY();
|
|
break;
|
|
}
|
|
} else {
|
|
Skill skill = mse.getSkill();
|
|
mplew.writeInt(skill != null ? skill.getId() : 0);
|
|
}
|
|
|
|
mplew.writeShort(-1); // duration
|
|
}
|
|
|
|
// reflect packet structure found thanks to Arnah (Vertisy)
|
|
if(pCounter != -1) mplew.writeInt(pCounter);// wPCounter_
|
|
if(mCounter != -1) mplew.writeInt(mCounter);// wMCounter_
|
|
if(pCounter != -1 || mCounter != -1) mplew.writeInt(100);// nCounterProb_
|
|
}
|
|
|
|
/**
|
|
* Internal function to handler monster spawning and controlling.
|
|
*
|
|
* @param life The mob to perform operations with.
|
|
* @param requestController Requesting control of mob?
|
|
* @param newSpawn New spawn (fade in?)
|
|
* @param aggro Aggressive mob?
|
|
* @param effect The spawn effect to use.
|
|
* @return The spawn/control packet.
|
|
*/
|
|
private static byte[] spawnMonsterInternal(MapleMonster life, boolean requestController, boolean newSpawn, boolean aggro, int effect, boolean makeInvis) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
if (makeInvis) {
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(life.getObjectId());
|
|
return mplew.getPacket();
|
|
}
|
|
if (requestController) {
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue());
|
|
mplew.write(aggro ? 2 : 1);
|
|
} else {
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue());
|
|
}
|
|
mplew.writeInt(life.getObjectId());
|
|
mplew.write(life.getController() == null ? 5 : 1);
|
|
mplew.writeInt(life.getId());
|
|
|
|
if (requestController) {
|
|
encodeTemporary(mplew, life.getStati()); // thanks shot for noticing encode temporary buffs missing
|
|
} else {
|
|
mplew.skip(16);
|
|
}
|
|
|
|
mplew.writePos(life.getPosition());
|
|
mplew.write(life.getStance());
|
|
mplew.writeShort(0); //Origin FH //life.getStartFh()
|
|
mplew.writeShort(life.getFh());
|
|
|
|
|
|
/**
|
|
* -4: Fake -3: Appear after linked mob is dead -2: Fade in 1: Smoke 3:
|
|
* King Slime spawn 4: Summoning rock thing, used for 3rd job? 6:
|
|
* Magical shit 7: Smoke shit 8: 'The Boss' 9/10: Grim phantom shit?
|
|
* 11/12: Nothing? 13: Frankenstein 14: Angry ^ 15: Orb animation thing,
|
|
* ?? 16: ?? 19: Mushroom castle boss thing
|
|
*/
|
|
|
|
if (life.getParentMobOid() != 0) {
|
|
MapleMonster parentMob = life.getMap().getMonsterByOid(life.getParentMobOid());
|
|
if(parentMob != null && parentMob.isAlive()) {
|
|
mplew.write(effect != 0 ? effect : -3);
|
|
mplew.writeInt(life.getParentMobOid());
|
|
} else {
|
|
encodeParentlessMobSpawnEffect(mplew, newSpawn, effect);
|
|
}
|
|
} else {
|
|
encodeParentlessMobSpawnEffect(mplew, newSpawn, effect);
|
|
}
|
|
|
|
mplew.write(life.getTeam());
|
|
mplew.writeInt(0); // getItemEffect
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Handles monsters not being targettable, such as Zakum's first body.
|
|
*
|
|
* @param life The mob to spawn as non-targettable.
|
|
* @param effect The effect to show when spawning.
|
|
* @return The packet to spawn the mob as non-targettable.
|
|
*/
|
|
public static byte[] spawnFakeMonster(MapleMonster life, int effect) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(life.getObjectId());
|
|
mplew.write(5);
|
|
mplew.writeInt(life.getId());
|
|
encodeTemporary(mplew, life.getStati());
|
|
mplew.writePos(life.getPosition());
|
|
mplew.write(life.getStance());
|
|
mplew.writeShort(0);//life.getStartFh()
|
|
mplew.writeShort(life.getFh());
|
|
if (effect > 0) {
|
|
mplew.write(effect);
|
|
mplew.write(0);
|
|
mplew.writeShort(0);
|
|
}
|
|
mplew.writeShort(-2);
|
|
mplew.write(life.getTeam());
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Makes a monster previously spawned as non-targettable, targettable.
|
|
*
|
|
* @param life The mob to make targettable.
|
|
* @return The packet to make the mob targettable.
|
|
*/
|
|
public static byte[] makeMonsterReal(MapleMonster life) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER.getValue());
|
|
mplew.writeInt(life.getObjectId());
|
|
mplew.write(5);
|
|
mplew.writeInt(life.getId());
|
|
encodeTemporary(mplew, life.getStati());
|
|
mplew.writePos(life.getPosition());
|
|
mplew.write(life.getStance());
|
|
mplew.writeShort(0);//life.getStartFh()
|
|
mplew.writeShort(life.getFh());
|
|
mplew.writeShort(-1);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a stop control monster packet.
|
|
*
|
|
* @param oid The ObjectID of the monster to stop controlling.
|
|
* @return The stop control monster packet.
|
|
*/
|
|
public static byte[] stopControllingMonster(int oid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.SPAWN_MONSTER_CONTROL.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(oid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a response to a move monster packet.
|
|
*
|
|
* @param objectid The ObjectID of the monster being moved.
|
|
* @param moveid The movement ID.
|
|
* @param currentMp The current MP of the monster.
|
|
* @param useSkills Can the monster use skills?
|
|
* @return The move response packet.
|
|
*/
|
|
public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills) {
|
|
return moveMonsterResponse(objectid, moveid, currentMp, useSkills, 0, 0);
|
|
}
|
|
|
|
/**
|
|
* Gets a response to a move monster packet.
|
|
*
|
|
* @param objectid The ObjectID of the monster being moved.
|
|
* @param moveid The movement ID.
|
|
* @param currentMp The current MP of the monster.
|
|
* @param useSkills Can the monster use skills?
|
|
* @param skillId The skill ID for the monster to use.
|
|
* @param skillLevel The level of the skill to use.
|
|
* @return The move response packet.
|
|
*/
|
|
|
|
public static byte[] moveMonsterResponse(int objectid, short moveid, int currentMp, boolean useSkills, int skillId, int skillLevel) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(13);
|
|
mplew.writeShort(SendOpcode.MOVE_MONSTER_RESPONSE.getValue());
|
|
mplew.writeInt(objectid);
|
|
mplew.writeShort(moveid);
|
|
mplew.writeBool(useSkills);
|
|
mplew.writeShort(currentMp);
|
|
mplew.write(skillId);
|
|
mplew.write(skillLevel);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a general chat packet.
|
|
*
|
|
* @param cidfrom The character ID who sent the chat.
|
|
* @param text The text of the chat.
|
|
* @param whiteBG
|
|
* @param show
|
|
* @return The general chat packet.
|
|
*/
|
|
public static byte[] getChatText(int cidfrom, String text, boolean gm, int show) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHATTEXT.getValue());
|
|
mplew.writeInt(cidfrom);
|
|
mplew.writeBool(gm);
|
|
mplew.writeMapleAsciiString(text);
|
|
mplew.write(show);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show an EXP increase.
|
|
*
|
|
* @param gain The amount of EXP gained.
|
|
* @param inChat In the chat box?
|
|
* @param white White text or yellow?
|
|
* @return The exp gained packet.
|
|
*/
|
|
public static byte[] getShowExpGain(int gain, int equip, int party, boolean inChat, boolean white) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(3); // 3 = exp, 4 = fame, 5 = mesos, 6 = guildpoints
|
|
mplew.writeBool(white);
|
|
mplew.writeInt(gain);
|
|
mplew.writeBool(inChat);
|
|
mplew.writeInt(0); // bonus event exp
|
|
mplew.write(0); // third monster kill event
|
|
mplew.write(0); // RIP byte, this is always a 0
|
|
mplew.writeInt(0); //wedding bonus
|
|
if (inChat) { // quest bonus rate stuff
|
|
mplew.write(0);
|
|
}
|
|
|
|
mplew.write(0); //0 = party bonus, 100 = 1x Bonus EXP, 200 = 2x Bonus EXP
|
|
mplew.writeInt(party); // party bonus
|
|
mplew.writeInt(equip); //equip bonus
|
|
mplew.writeInt(0); //Internet Cafe Bonus
|
|
mplew.writeInt(0); //Rainbow Week Bonus
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show a fame gain.
|
|
*
|
|
* @param gain How many fame gained.
|
|
* @return The meso gain packet.
|
|
*/
|
|
public static byte[] getShowFameGain(int gain) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(4);
|
|
mplew.writeInt(gain);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show a meso gain.
|
|
*
|
|
* @param gain How many mesos gained.
|
|
* @return The meso gain packet.
|
|
*/
|
|
public static byte[] getShowMesoGain(int gain) {
|
|
return getShowMesoGain(gain, false);
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show a meso gain.
|
|
*
|
|
* @param gain How many mesos gained.
|
|
* @param inChat Show in the chat window?
|
|
* @return The meso gain packet.
|
|
*/
|
|
public static byte[] getShowMesoGain(int gain, boolean inChat) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
if (!inChat) {
|
|
mplew.write(0);
|
|
mplew.writeShort(1); //v83
|
|
} else {
|
|
mplew.write(5);
|
|
}
|
|
mplew.writeInt(gain);
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show a item gain.
|
|
*
|
|
* @param itemId The ID of the item gained.
|
|
* @param quantity How many items gained.
|
|
* @return The item gain packet.
|
|
*/
|
|
public static byte[] getShowItemGain(int itemId, short quantity) {
|
|
return getShowItemGain(itemId, quantity, false);
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client to show an item gain.
|
|
*
|
|
* @param itemId The ID of the item gained.
|
|
* @param quantity The number of items gained.
|
|
* @param inChat Show in the chat window?
|
|
* @return The item gain packet.
|
|
*/
|
|
public static byte[] getShowItemGain(int itemId, short quantity, boolean inChat) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
if (inChat) {
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(3);
|
|
mplew.write(1);
|
|
mplew.writeInt(itemId);
|
|
mplew.writeInt(quantity);
|
|
} else {
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(itemId);
|
|
mplew.writeInt(quantity);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] killMonster(int oid, boolean animation) {
|
|
return killMonster(oid, animation ? 1 : 0);
|
|
}
|
|
|
|
/**
|
|
* Gets a packet telling the client that a monster was killed.
|
|
*
|
|
* @param oid The objectID of the killed monster.
|
|
* @param animation 0 = dissapear, 1 = fade out, 2+ = special
|
|
* @return The kill monster packet.
|
|
*/
|
|
public static byte[] killMonster(int oid, int animation) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.KILL_MONSTER.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.write(animation);
|
|
mplew.write(animation);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateMapItemObject(MapleMapItem drop, boolean giveOwnership) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue());
|
|
mplew.write(2);
|
|
mplew.writeInt(drop.getObjectId());
|
|
mplew.writeBool(drop.getMeso() > 0);
|
|
mplew.writeInt(drop.getItemId());
|
|
mplew.writeInt(giveOwnership ? 0 : -1);
|
|
mplew.write(drop.hasExpiredOwnershipTime() ? 2 : drop.getDropType());
|
|
mplew.writePos(drop.getPosition());
|
|
mplew.writeInt(giveOwnership ? 0 : -1);
|
|
|
|
if (drop.getMeso() == 0) {
|
|
addExpirationTime(mplew, drop.getItem().getExpiration());
|
|
}
|
|
mplew.write(drop.isPlayerDrop() ? 0 : 1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] dropItemFromMapObject(MapleCharacter player, MapleMapItem drop, Point dropfrom, Point dropto, byte mod) {
|
|
int dropType = drop.getDropType();
|
|
if (drop.hasClientsideOwnership(player) && dropType < 3) {
|
|
dropType = 2;
|
|
}
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DROP_ITEM_FROM_MAPOBJECT.getValue());
|
|
mplew.write(mod);
|
|
mplew.writeInt(drop.getObjectId());
|
|
mplew.writeBool(drop.getMeso() > 0); // 1 mesos, 0 item, 2 and above all item meso bag,
|
|
mplew.writeInt(drop.getItemId()); // drop object ID
|
|
mplew.writeInt(drop.getClientsideOwnerId()); // owner charid/partyid :)
|
|
mplew.write(dropType); // 0 = timeout for non-owner, 1 = timeout for non-owner's party, 2 = FFA, 3 = explosive/FFA
|
|
mplew.writePos(dropto);
|
|
mplew.writeInt(drop.getDropper().getObjectId()); // dropper oid, found thanks to Li Jixue
|
|
|
|
if (mod != 2) {
|
|
mplew.writePos(dropfrom);
|
|
mplew.writeShort(0);//Fh?
|
|
}
|
|
if (drop.getMeso() == 0) {
|
|
addExpirationTime(mplew, drop.getItem().getExpiration());
|
|
}
|
|
mplew.write(drop.isPlayerDrop() ? 0 : 1); //pet EQP pickup
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Guild Name & Mark update packet, thanks to Arnah (Vertisy)
|
|
*
|
|
* @param guildName The Guild name, blank for nothing.
|
|
*/
|
|
public static byte[] guildNameChanged(int chrid, String guildName){
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_NAME_CHANGED.getValue());
|
|
mplew.writeInt(chrid);
|
|
mplew.writeMapleAsciiString(guildName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildMarkChanged(int chrid, MapleGuild guild){
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_MARK_CHANGED.getValue());
|
|
mplew.writeInt(chrid);
|
|
mplew.writeShort(guild.getLogoBG());
|
|
mplew.write(guild.getLogoBGColor());
|
|
mplew.writeShort(guild.getLogo());
|
|
mplew.write(guild.getLogoColor());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeForeignBuffs(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(0); //v83
|
|
mplew.write(0xFC);
|
|
mplew.write(1);
|
|
if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) {
|
|
mplew.writeInt(2);
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
long buffmask = 0;
|
|
Integer buffvalue = null;
|
|
if ((chr.getBuffedValue(MapleBuffStat.DARKSIGHT) != null || chr.getBuffedValue(MapleBuffStat.WIND_WALK) != null) && !chr.isHidden()) {
|
|
buffmask |= MapleBuffStat.DARKSIGHT.getValue();
|
|
}
|
|
if (chr.getBuffedValue(MapleBuffStat.COMBO) != null) {
|
|
buffmask |= MapleBuffStat.COMBO.getValue();
|
|
buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.COMBO));
|
|
}
|
|
if (chr.getBuffedValue(MapleBuffStat.SHADOWPARTNER) != null) {
|
|
buffmask |= MapleBuffStat.SHADOWPARTNER.getValue();
|
|
}
|
|
if (chr.getBuffedValue(MapleBuffStat.SOULARROW) != null) {
|
|
buffmask |= MapleBuffStat.SOULARROW.getValue();
|
|
}
|
|
if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) {
|
|
buffvalue = Integer.valueOf(chr.getBuffedValue(MapleBuffStat.MORPH));
|
|
}
|
|
mplew.writeInt((int) ((buffmask >> 32) & 0xffffffffL));
|
|
if (buffvalue != null) {
|
|
if (chr.getBuffedValue(MapleBuffStat.MORPH) != null) { //TEST
|
|
mplew.writeShort(buffvalue);
|
|
} else {
|
|
mplew.write(buffvalue.byteValue());
|
|
}
|
|
}
|
|
mplew.writeInt((int) (buffmask & 0xffffffffL));
|
|
|
|
// Energy Charge
|
|
mplew.writeInt(chr.getEnergyBar() == 15000 ? 1 : 0);
|
|
mplew.writeShort(0);
|
|
mplew.skip(4);
|
|
|
|
boolean dashBuff = chr.getBuffedValue(MapleBuffStat.DASH) != null;
|
|
// Dash Speed
|
|
mplew.writeInt(dashBuff ? 1 << 24 : 0);
|
|
mplew.skip(11);
|
|
mplew.writeShort(0);
|
|
// Dash Jump
|
|
mplew.skip(9);
|
|
mplew.writeInt(dashBuff ? 1 << 24 : 0);
|
|
mplew.writeShort(0);
|
|
mplew.write(0);
|
|
|
|
// Monster Riding
|
|
Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING);
|
|
if (bv != null) {
|
|
MapleMount mount = chr.getMount();
|
|
if (mount != null) {
|
|
mplew.writeInt(mount.getItemId());
|
|
mplew.writeInt(mount.getSkillId());
|
|
} else {
|
|
mplew.writeLong(0);
|
|
}
|
|
} else {
|
|
mplew.writeLong(0);
|
|
}
|
|
|
|
int CHAR_MAGIC_SPAWN = Randomizer.nextInt(); // skill references found thanks to Rien dev team
|
|
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
|
// Speed Infusion
|
|
mplew.skip(8);
|
|
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
|
mplew.write(0);
|
|
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
|
mplew.writeShort(0);
|
|
// Homing Beacon
|
|
mplew.skip(9);
|
|
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
|
mplew.writeInt(0);
|
|
// Zombify
|
|
mplew.skip(9);
|
|
mplew.writeInt(CHAR_MAGIC_SPAWN);
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(0);
|
|
}
|
|
|
|
/**
|
|
* Gets a packet spawning a player as a mapobject to other clients.
|
|
*
|
|
* @param target The client receiving this packet.
|
|
* @param chr The character to spawn to other clients.
|
|
* @param enteringField Whether the character to spawn is not yet present in the map or already is.
|
|
* @return The spawn player packet.
|
|
*/
|
|
public static byte[] spawnPlayerMapObject(MapleClient target, MapleCharacter chr, boolean enteringField) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_PLAYER.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(chr.getLevel()); //v83
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
if (chr.getGuildId() < 1) {
|
|
mplew.writeMapleAsciiString("");
|
|
mplew.write(new byte[6]);
|
|
} else {
|
|
MapleGuildSummary gs = chr.getClient().getWorldServer().getGuildSummary(chr.getGuildId(), chr.getWorld());
|
|
if (gs != null) {
|
|
mplew.writeMapleAsciiString(gs.getName());
|
|
mplew.writeShort(gs.getLogoBG());
|
|
mplew.write(gs.getLogoBGColor());
|
|
mplew.writeShort(gs.getLogo());
|
|
mplew.write(gs.getLogoColor());
|
|
} else {
|
|
mplew.writeMapleAsciiString("");
|
|
mplew.write(new byte[6]);
|
|
}
|
|
}
|
|
|
|
writeForeignBuffs(mplew, chr);
|
|
|
|
mplew.writeShort(chr.getJob().getId());
|
|
|
|
/* replace "mplew.writeShort(chr.getJob().getId())" with this snippet for 3rd person FJ animation on all classes
|
|
if (chr.getJob().isA(MapleJob.HERMIT) || chr.getJob().isA(MapleJob.DAWNWARRIOR2) || chr.getJob().isA(MapleJob.NIGHTWALKER2)) {
|
|
mplew.writeShort(chr.getJob().getId());
|
|
} else {
|
|
mplew.writeShort(412);
|
|
}*/
|
|
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeInt(chr.getInventory(MapleInventoryType.CASH).countById(5110000));
|
|
mplew.writeInt(chr.getItemEffect());
|
|
mplew.writeInt(ItemConstants.getInventoryType(chr.getChair()) == MapleInventoryType.SETUP ? chr.getChair() : 0);
|
|
|
|
if(enteringField) {
|
|
Point spawnPos = new Point(chr.getPosition());
|
|
spawnPos.y -= 42;
|
|
mplew.writePos(spawnPos);
|
|
mplew.write(6);
|
|
} else {
|
|
mplew.writePos(chr.getPosition());
|
|
mplew.write(chr.getStance());
|
|
}
|
|
|
|
mplew.writeShort(0);//chr.getFh()
|
|
mplew.write(0);
|
|
MaplePet[] pet = chr.getPets();
|
|
for (int i = 0; i < 3; i++) {
|
|
if (pet[i] != null) {
|
|
addPetInfo(mplew, pet[i], false);
|
|
}
|
|
}
|
|
mplew.write(0); //end of pets
|
|
if (chr.getMount() == null) {
|
|
mplew.writeInt(1); // mob level
|
|
mplew.writeLong(0); // mob exp + tiredness
|
|
} else {
|
|
mplew.writeInt(chr.getMount().getLevel());
|
|
mplew.writeInt(chr.getMount().getExp());
|
|
mplew.writeInt(chr.getMount().getTiredness());
|
|
}
|
|
|
|
MaplePlayerShop mps = chr.getPlayerShop();
|
|
if (mps != null && mps.isOwner(chr)) {
|
|
if (mps.hasFreeSlot()) {
|
|
addAnnounceBox(mplew, mps, mps.getVisitors().length);
|
|
} else {
|
|
addAnnounceBox(mplew, mps, 1);
|
|
}
|
|
} else {
|
|
MapleMiniGame miniGame = chr.getMiniGame();
|
|
if (miniGame != null && miniGame.isOwner(chr)) {
|
|
if (miniGame.hasFreeSlot()) {
|
|
addAnnounceBox(mplew, miniGame, 1, 0);
|
|
} else {
|
|
addAnnounceBox(mplew, miniGame, 2, miniGame.isMatchInProgress() ? 1 : 0);
|
|
}
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
|
|
if (chr.getChalkboard() != null) {
|
|
mplew.write(1);
|
|
mplew.writeMapleAsciiString(chr.getChalkboard());
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
addRingLook(mplew, chr, true); // crush
|
|
addRingLook(mplew, chr, false); // friendship
|
|
addMarriageRingLook(target, mplew, chr);
|
|
encodeNewYearCardInfo(mplew, chr); // new year seems to crash sometimes...
|
|
mplew.write(0);
|
|
mplew.write(0);
|
|
mplew.write(chr.getTeam());//only needed in specific fields
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void encodeNewYearCardInfo(MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
Set<NewYearCardRecord> newyears = chr.getReceivedNewYearRecords();
|
|
if(!newyears.isEmpty()) {
|
|
mplew.write(1);
|
|
|
|
mplew.writeInt(newyears.size());
|
|
for(NewYearCardRecord nyc : newyears) {
|
|
mplew.writeInt(nyc.getId());
|
|
}
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
|
|
public static byte[] onNewYearCardRes(MapleCharacter user, int cardId, int mode, int msg) {
|
|
NewYearCardRecord newyear = user.getNewYearRecord(cardId);
|
|
return onNewYearCardRes(user, newyear, mode, msg);
|
|
}
|
|
|
|
public static byte[] onNewYearCardRes(MapleCharacter user, NewYearCardRecord newyear, int mode, int msg) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NEW_YEAR_CARD_RES.getValue());
|
|
mplew.write(mode);
|
|
switch (mode) {
|
|
case 4: // Successfully sent a New Year Card\r\n to %s.
|
|
case 6: // Successfully received a New Year Card.
|
|
encodeNewYearCard(newyear, mplew);
|
|
break;
|
|
|
|
case 8: // Successfully deleted a New Year Card.
|
|
mplew.writeInt(newyear.getId());
|
|
break;
|
|
|
|
case 5: // Nexon's stupid and makes 4 modes do the same operation..
|
|
case 7:
|
|
case 9:
|
|
case 0xB:
|
|
// 0x10: You have no free slot to store card.\r\ntry later on please.
|
|
// 0x11: You have no card to send.
|
|
// 0x12: Wrong inventory information !
|
|
// 0x13: Cannot find such character !
|
|
// 0x14: Incoherent Data !
|
|
// 0x15: An error occured during DB operation.
|
|
// 0x16: An unknown error occured !
|
|
// 0xF: You cannot send a card to yourself !
|
|
mplew.write(msg);
|
|
break;
|
|
|
|
case 0xA: // GetUnreceivedList_Done
|
|
int nSN = 1;
|
|
mplew.writeInt(nSN);
|
|
if ((nSN - 1) <= 98 && nSN > 0) {//lol nexon are you kidding
|
|
for (int i = 0; i < nSN; i++) {
|
|
mplew.writeInt(newyear.getId());
|
|
mplew.writeInt(newyear.getSenderId());
|
|
mplew.writeMapleAsciiString(newyear.getSenderName());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0xC: // NotiArrived
|
|
mplew.writeInt(newyear.getId());
|
|
mplew.writeMapleAsciiString(newyear.getSenderName());
|
|
break;
|
|
|
|
case 0xD: // BroadCast_AddCardInfo
|
|
mplew.writeInt(newyear.getId());
|
|
mplew.writeInt(user.getId());
|
|
break;
|
|
|
|
case 0xE: // BroadCast_RemoveCardInfo
|
|
mplew.writeInt(newyear.getId());
|
|
break;
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void encodeNewYearCard(NewYearCardRecord newyear, MaplePacketLittleEndianWriter mplew) {
|
|
mplew.writeInt(newyear.getId());
|
|
mplew.writeInt(newyear.getSenderId());
|
|
mplew.writeMapleAsciiString(newyear.getSenderName());
|
|
mplew.writeBool(newyear.isSenderCardDiscarded());
|
|
mplew.writeLong(newyear.getDateSent());
|
|
mplew.writeInt(newyear.getReceiverId());
|
|
mplew.writeMapleAsciiString(newyear.getReceiverName());
|
|
mplew.writeBool(newyear.isReceiverCardDiscarded());
|
|
mplew.writeBool(newyear.isReceiverCardReceived());
|
|
mplew.writeLong(newyear.getDateReceived());
|
|
mplew.writeMapleAsciiString(newyear.getMessage());
|
|
}
|
|
|
|
private static void addRingLook(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr, boolean crush) {
|
|
List<MapleRing> rings;
|
|
if (crush) {
|
|
rings = chr.getCrushRings();
|
|
} else {
|
|
rings = chr.getFriendshipRings();
|
|
}
|
|
boolean yes = false;
|
|
for (MapleRing ring : rings) {
|
|
if (ring.equipped()) {
|
|
if (yes == false) {
|
|
yes = true;
|
|
mplew.write(1);
|
|
}
|
|
mplew.writeInt(ring.getRingId());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(ring.getPartnerRingId());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(ring.getItemId());
|
|
}
|
|
}
|
|
if (yes == false) {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
|
|
private static void addMarriageRingLook(MapleClient target, final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
MapleRing ring = chr.getMarriageRing();
|
|
|
|
if (ring == null || !ring.equipped()) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
|
|
MapleCharacter targetChr = target.getPlayer();
|
|
if (targetChr != null && targetChr.getPartnerId() == chr.getId()) {
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
} else {
|
|
mplew.writeInt(chr.getId());
|
|
mplew.writeInt(ring.getPartnerChrId());
|
|
}
|
|
|
|
mplew.writeInt(ring.getItemId());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds a announcement box to an existing MaplePacketLittleEndianWriter.
|
|
*
|
|
* @param mplew The MaplePacketLittleEndianWriter to add an announcement box
|
|
* to.
|
|
* @param shop The shop to announce.
|
|
*/
|
|
private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop, int availability) {
|
|
mplew.write(4);
|
|
mplew.writeInt(shop.getObjectId());
|
|
mplew.writeMapleAsciiString(shop.getDescription());
|
|
mplew.write(0);
|
|
mplew.write(0);
|
|
mplew.write(1);
|
|
mplew.write(availability);
|
|
mplew.write(0);
|
|
}
|
|
|
|
private static void addAnnounceBox(final MaplePacketLittleEndianWriter mplew, MapleMiniGame game, int ammount, int joinable) {
|
|
mplew.write(game.getGameType().getValue());
|
|
mplew.writeInt(game.getObjectId()); // gameid/shopid
|
|
mplew.writeMapleAsciiString(game.getDescription()); // desc
|
|
mplew.writeBool(!game.getPassword().isEmpty()); // password here, thanks GabrielSin
|
|
mplew.write(game.getPieceType());
|
|
mplew.write(ammount);
|
|
mplew.write(2); //player capacity
|
|
mplew.write(joinable);
|
|
}
|
|
|
|
private static void updateHiredMerchantBoxInfo(MaplePacketLittleEndianWriter mplew, MapleHiredMerchant hm) {
|
|
byte[] roomInfo = hm.getShopRoomInfo();
|
|
|
|
mplew.write(5);
|
|
mplew.writeInt(hm.getObjectId());
|
|
mplew.writeMapleAsciiString(hm.getDescription());
|
|
mplew.write(hm.getItemId() % 100);
|
|
mplew.write(roomInfo); // visitor capacity here, thanks GabrielSin
|
|
}
|
|
|
|
public static byte[] updateHiredMerchantBox(MapleHiredMerchant hm) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_HIRED_MERCHANT.getValue());
|
|
mplew.writeInt(hm.getOwnerId());
|
|
|
|
updateHiredMerchantBoxInfo(mplew, hm);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void updatePlayerShopBoxInfo(final MaplePacketLittleEndianWriter mplew, MaplePlayerShop shop) {
|
|
byte[] roomInfo = shop.getShopRoomInfo();
|
|
|
|
mplew.write(4);
|
|
mplew.writeInt(shop.getObjectId());
|
|
mplew.writeMapleAsciiString(shop.getDescription());
|
|
mplew.write(0); // pw
|
|
mplew.write(shop.getItemId() % 100);
|
|
mplew.write(roomInfo[0]); // curPlayers
|
|
mplew.write(roomInfo[1]); // maxPlayers
|
|
mplew.write(0);
|
|
}
|
|
|
|
public static byte[] updatePlayerShopBox(MaplePlayerShop shop) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
|
|
mplew.writeInt(shop.getOwner().getId());
|
|
|
|
updatePlayerShopBoxInfo(mplew, shop);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removePlayerShopBox(MaplePlayerShop shop) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
|
|
mplew.writeInt(shop.getOwner().getId());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] facialExpression(MapleCharacter from, int expression) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(10);
|
|
mplew.writeShort(SendOpcode.FACIAL_EXPRESSION.getValue());
|
|
mplew.writeInt(from.getId());
|
|
mplew.writeInt(expression);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void rebroadcastMovementList(LittleEndianWriter lew, SeekableLittleEndianAccessor slea, long movementDataLength) {
|
|
//movement command length is sent by client, probably not a big issue? (could be calculated on server)
|
|
//if multiple write/reads are slow, could use (and cache?) a byte[] buffer
|
|
for(long i = 0; i < movementDataLength; i++) {
|
|
lew.write(slea.readByte());
|
|
}
|
|
}
|
|
|
|
private static void serializeMovementList(LittleEndianWriter lew, List<LifeMovementFragment> moves) {
|
|
lew.write(moves.size());
|
|
for(LifeMovementFragment move : moves) {
|
|
move.serialize(lew);
|
|
}
|
|
}
|
|
|
|
public static byte[] movePlayer(int cid, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MOVE_PLAYER.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(0);
|
|
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] moveSummon(int cid, int oid, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MOVE_SUMMON.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(oid);
|
|
mplew.writePos(startPos);
|
|
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] moveMonster(int oid, boolean skillPossible, int skill, int skillId, int skillLevel, int pOption, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MOVE_MONSTER.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.write(0);
|
|
mplew.writeBool(skillPossible);
|
|
mplew.write(skill);
|
|
mplew.write(skillId);
|
|
mplew.write(skillLevel);
|
|
mplew.writeShort(pOption);
|
|
mplew.writePos(startPos);
|
|
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] summonAttack(int cid, int summonOid, byte direction, List<SummonAttackEntry> allDamage) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
//b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00
|
|
mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(summonOid);
|
|
mplew.write(0); // char level
|
|
mplew.write(direction);
|
|
mplew.write(allDamage.size());
|
|
for (SummonAttackEntry attackEntry : allDamage) {
|
|
mplew.writeInt(attackEntry.getMonsterOid()); // oid
|
|
mplew.write(6); // who knows
|
|
mplew.writeInt(attackEntry.getDamage()); // damage
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
public static byte[] summonAttack(int cid, int summonSkillId, byte direction, List<SummonAttackEntry> allDamage) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
//b2 00 29 f7 00 00 9a a3 04 00 c8 04 01 94 a3 04 00 06 ff 2b 00
|
|
mplew.writeShort(SendOpcode.SUMMON_ATTACK.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(summonSkillId);
|
|
mplew.write(direction);
|
|
mplew.write(4);
|
|
mplew.write(allDamage.size());
|
|
for (SummonAttackEntry attackEntry : allDamage) {
|
|
mplew.writeInt(attackEntry.getMonsterOid()); // oid
|
|
mplew.write(6); // who knows
|
|
mplew.writeInt(attackEntry.getDamage()); // damage
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
*/
|
|
|
|
public static byte[] closeRangeAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map<Integer, List<Integer>> damage, int speed, int direction, int display) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CLOSE_RANGE_ATTACK.getValue());
|
|
addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rangedAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map<Integer, List<Integer>> damage, int speed, int direction, int display) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RANGED_ATTACK.getValue());
|
|
addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, projectile, damage, speed, direction, display);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] magicAttack(MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, Map<Integer, List<Integer>> damage, int charge, int speed, int direction, int display) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAGIC_ATTACK.getValue());
|
|
addAttackBody(mplew, chr, skill, skilllevel, stance, numAttackedAndDamage, 0, damage, speed, direction, display);
|
|
if (charge != -1) {
|
|
mplew.writeInt(charge);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addAttackBody(LittleEndianWriter lew, MapleCharacter chr, int skill, int skilllevel, int stance, int numAttackedAndDamage, int projectile, Map<Integer, List<Integer>> damage, int speed, int direction, int display) {
|
|
lew.writeInt(chr.getId());
|
|
lew.write(numAttackedAndDamage);
|
|
lew.write(0x5B);//?
|
|
lew.write(skilllevel);
|
|
if (skilllevel > 0) {
|
|
lew.writeInt(skill);
|
|
}
|
|
lew.write(display);
|
|
lew.write(direction);
|
|
lew.write(stance);
|
|
lew.write(speed);
|
|
lew.write(0x0A);
|
|
lew.writeInt(projectile);
|
|
for (Integer oned : damage.keySet()) {
|
|
List<Integer> onedList = damage.get(oned);
|
|
if (onedList != null) {
|
|
lew.writeInt(oned);
|
|
lew.write(0x0);
|
|
if (skill == 4211006) {
|
|
lew.write(onedList.size());
|
|
}
|
|
for (Integer eachd : onedList) {
|
|
lew.writeInt(eachd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte[] throwGrenade(int cid, Point p, int keyDown, int skillId, int skillLevel) { // packets found thanks to GabrielSin
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.THROW_GRENADE.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(p.x);
|
|
mplew.writeInt(p.y);
|
|
mplew.writeInt(keyDown);
|
|
mplew.writeInt(skillId);
|
|
mplew.writeInt(skillLevel);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// someone thought it was a good idea to handle floating point representation through packets ROFL
|
|
private static int doubleToShortBits(double d) {
|
|
return (int) (Double.doubleToLongBits(d) >> 48);
|
|
}
|
|
|
|
public static byte[] getNPCShop(MapleClient c, int sid, List<MapleShopItem> items) {
|
|
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.OPEN_NPC_SHOP.getValue());
|
|
mplew.writeInt(sid);
|
|
mplew.writeShort(items.size()); // item count
|
|
for (MapleShopItem item : items) {
|
|
mplew.writeInt(item.getItemId());
|
|
mplew.writeInt(item.getPrice());
|
|
mplew.writeInt(item.getPrice() == 0 ? item.getPitch() : 0); //Perfect Pitch
|
|
mplew.writeInt(0); //Can be used x minutes after purchase
|
|
mplew.writeInt(0); //Hmm
|
|
if (!ItemConstants.isRechargeable(item.getItemId())) {
|
|
mplew.writeShort(1); // stacksize o.o
|
|
mplew.writeShort(item.getBuyable());
|
|
} else {
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(doubleToShortBits(ii.getUnitPrice(item.getItemId())));
|
|
mplew.writeShort(ii.getSlotMax(c, item.getItemId()));
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/* 00 = /
|
|
* 01 = You don't have enough in stock
|
|
* 02 = You do not have enough mesos
|
|
* 03 = Please check if your inventory is full or not
|
|
* 05 = You don't have enough in stock
|
|
* 06 = Due to an error, the trade did not happen
|
|
* 07 = Due to an error, the trade did not happen
|
|
* 08 = /
|
|
* 0D = You need more items
|
|
* 0E = CRASH; LENGTH NEEDS TO BE LONGER :O
|
|
*/
|
|
public static byte[] shopTransaction(byte code) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.CONFIRM_SHOP_TRANSACTION.getValue());
|
|
mplew.write(code);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateInventorySlotLimit(int type, int newLimit) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.INVENTORY_GROW.getValue());
|
|
mplew.write(type);
|
|
mplew.write(newLimit);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] modifyInventory(boolean updateTick, final List<ModifyInventory> mods) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.INVENTORY_OPERATION.getValue());
|
|
mplew.writeBool(updateTick);
|
|
mplew.write(mods.size());
|
|
//mplew.write(0); v104 :)
|
|
int addMovement = -1;
|
|
for (ModifyInventory mod : mods) {
|
|
mplew.write(mod.getMode());
|
|
mplew.write(mod.getInventoryType());
|
|
mplew.writeShort(mod.getMode() == 2 ? mod.getOldPosition() : mod.getPosition());
|
|
switch (mod.getMode()) {
|
|
case 0: {//add item
|
|
addItemInfo(mplew, mod.getItem(), true);
|
|
break;
|
|
}
|
|
case 1: {//update quantity
|
|
mplew.writeShort(mod.getQuantity());
|
|
break;
|
|
}
|
|
case 2: {//move
|
|
mplew.writeShort(mod.getPosition());
|
|
if (mod.getPosition() < 0 || mod.getOldPosition() < 0) {
|
|
addMovement = mod.getOldPosition() < 0 ? 1 : 2;
|
|
}
|
|
break;
|
|
}
|
|
case 3: {//remove
|
|
if (mod.getPosition() < 0) {
|
|
addMovement = 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
mod.clear();
|
|
}
|
|
if (addMovement > -1) {
|
|
mplew.write(addMovement);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getScrollEffect(int chr, ScrollResult scrollSuccess, boolean legendarySpirit, boolean whiteScroll) { // thanks to Rien dev team
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_SCROLL_EFFECT.getValue());
|
|
mplew.writeInt(chr);
|
|
mplew.writeBool(scrollSuccess == ScrollResult.SUCCESS);
|
|
mplew.writeBool(scrollSuccess == ScrollResult.CURSE);
|
|
mplew.writeBool(legendarySpirit);
|
|
mplew.writeBool(whiteScroll);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removePlayerFromMap(int cid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_PLAYER_FROM_MAP.getValue());
|
|
mplew.writeInt(cid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] catchMessage(int message) { // not done, I guess
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BRIDLE_MOB_CATCH_FAIL.getValue());
|
|
mplew.write(message); // 1 = too strong, 2 = Elemental Rock
|
|
mplew.writeInt(0);//Maybe itemid?
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showAllCharacter(int chars, int unk) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11);
|
|
mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue());
|
|
mplew.write(chars > 0 ? 1 : 5); // 2: already connected to server, 3 : unk error (view-all-characters), 5 : cannot find any
|
|
mplew.writeInt(chars);
|
|
mplew.writeInt(unk);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showAriantScoreBoard() { // thanks lrenex for pointing match's end scoreboard packet
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ARIANT_ARENA_SHOW_RESULT.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateAriantPQRanking(final MapleCharacter chr, final int score) {
|
|
return updateAriantPQRanking(new LinkedHashMap<MapleCharacter, Integer>(){{put(chr, score);}});
|
|
}
|
|
|
|
public static byte[] updateAriantPQRanking(Map<MapleCharacter, Integer> playerScore) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ARIANT_ARENA_USER_SCORE.getValue());
|
|
mplew.write(playerScore.size());
|
|
for (Entry<MapleCharacter, Integer> e : playerScore.entrySet()) {
|
|
mplew.writeMapleAsciiString(e.getKey().getName());
|
|
mplew.writeInt(e.getValue());
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateWitchTowerScore(int score) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.WITCH_TOWER_SCORE_UPDATE.getValue());
|
|
mplew.write(score);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] silentRemoveItemFromMap(int oid) {
|
|
return removeItemFromMap(oid, 1, 0);
|
|
}
|
|
|
|
/**
|
|
* animation: 0 - expire<br/> 1 - without animation<br/> 2 - pickup<br/> 4 -
|
|
* explode<br/> cid is ignored for 0 and 1
|
|
*
|
|
* @param oid
|
|
* @param animation
|
|
* @param cid
|
|
* @return
|
|
*/
|
|
public static byte[] removeItemFromMap(int oid, int animation, int cid) {
|
|
return removeItemFromMap(oid, animation, cid, false, 0);
|
|
}
|
|
|
|
/**
|
|
* animation: 0 - expire<br/> 1 - without animation<br/> 2 - pickup<br/> 4 -
|
|
* explode<br/> cid is ignored for 0 and 1.<br /><br />Flagging pet as true
|
|
* will make a pet pick up the item.
|
|
*
|
|
* @param oid
|
|
* @param animation
|
|
* @param cid
|
|
* @param pet
|
|
* @param slot
|
|
* @return
|
|
*/
|
|
public static byte[] removeItemFromMap(int oid, int animation, int cid, boolean pet, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_ITEM_FROM_MAP.getValue());
|
|
mplew.write(animation); // expire
|
|
mplew.writeInt(oid);
|
|
if (animation >= 2) {
|
|
mplew.writeInt(cid);
|
|
if (pet) {
|
|
mplew.write(slot);
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateCharLook(MapleClient target, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_LOOK.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(1);
|
|
addCharLook(mplew, chr, false);
|
|
addRingLook(mplew, chr, true);
|
|
addRingLook(mplew, chr, false);
|
|
addMarriageRingLook(target, mplew, chr);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] damagePlayer(int skill, int monsteridfrom, int cid, int damage, int fake, int direction, boolean pgmr, int pgmr_1, boolean is_pg, int oid, int pos_x, int pos_y) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DAMAGE_PLAYER.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(skill);
|
|
mplew.writeInt(damage);
|
|
if(skill != -4) {
|
|
mplew.writeInt(monsteridfrom);
|
|
mplew.write(direction);
|
|
if (pgmr) {
|
|
mplew.write(pgmr_1);
|
|
mplew.write(is_pg ? 1 : 0);
|
|
mplew.writeInt(oid);
|
|
mplew.write(6);
|
|
mplew.writeShort(pos_x);
|
|
mplew.writeShort(pos_y);
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.writeShort(0);
|
|
}
|
|
mplew.writeInt(damage);
|
|
if (fake > 0) {
|
|
mplew.writeInt(fake);
|
|
}
|
|
} else {
|
|
mplew.writeInt(damage);
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendMapleLifeCharacterInfo() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue());
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendMapleLifeNameError() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAPLELIFE_RESULT.getValue());
|
|
mplew.writeInt(2);
|
|
mplew.writeInt(3);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendMapleLifeError(int code) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAPLELIFE_ERROR.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(code);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] charNameResponse(String charname, boolean nameUsed) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHAR_NAME_RESPONSE.getValue());
|
|
mplew.writeMapleAsciiString(charname);
|
|
mplew.write(nameUsed ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addNewCharEntry(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ADD_NEW_CHAR_ENTRY.getValue());
|
|
mplew.write(0);
|
|
addCharEntry(mplew, chr, false);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* State :
|
|
* 0x00 = success
|
|
* 0x06 = Trouble logging into the game?
|
|
* 0x09 = Unknown error
|
|
* 0x0A = Could not be processed due to too many connection requests to the server.
|
|
* 0x12 = invalid bday
|
|
* 0x14 = incorrect pic
|
|
* 0x16 = Cannot delete a guild master.
|
|
* 0x18 = Cannot delete a character with a pending wedding.
|
|
* 0x1A = Cannot delete a character with a pending world transfer.
|
|
* 0x1D = Cannot delete a character that has a family.
|
|
*
|
|
* @param cid
|
|
* @param state
|
|
* @return
|
|
*/
|
|
public static byte[] deleteCharResponse(int cid, int state) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DELETE_CHAR_RESPONSE.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(state);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] selectWorld(int world) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.LAST_CONNECTED_WORLD.getValue());
|
|
mplew.writeInt(world);//According to GMS, it should be the world that contains the most characters (most active)
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendRecommended(List<Pair<Integer, String>> worlds) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RECOMMENDED_WORLD_MESSAGE.getValue());
|
|
mplew.write(worlds.size());//size
|
|
for (Pair<Integer, String> world : worlds) {
|
|
mplew.writeInt(world.getLeft());
|
|
mplew.writeMapleAsciiString(world.getRight());
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param chr
|
|
* @param isSelf
|
|
* @return
|
|
*/
|
|
public static byte[] charInfo(MapleCharacter chr) {
|
|
//3D 00 0A 43 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHAR_INFO.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(chr.getLevel());
|
|
mplew.writeShort(chr.getJob().getId());
|
|
mplew.writeShort(chr.getFame());
|
|
mplew.write(chr.getMarriageRing() != null ? 1 : 0);
|
|
String guildName = "";
|
|
String allianceName = "";
|
|
if (chr.getGuildId() > 0) {
|
|
MapleGuild mg = Server.getInstance().getGuild(chr.getGuildId());
|
|
guildName = mg.getName();
|
|
|
|
MapleAlliance alliance = Server.getInstance().getAlliance(chr.getGuild().getAllianceId());
|
|
if (alliance != null) {
|
|
allianceName = alliance.getName();
|
|
}
|
|
}
|
|
mplew.writeMapleAsciiString(guildName);
|
|
mplew.writeMapleAsciiString(allianceName); // does not seem to work
|
|
mplew.write(0); // pMedalInfo, thanks to Arnah (Vertisy)
|
|
|
|
MaplePet[] pets = chr.getPets();
|
|
Item inv = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -114);
|
|
for (int i = 0; i < 3; i++) {
|
|
if (pets[i] != null) {
|
|
mplew.write(pets[i].getUniqueId());
|
|
mplew.writeInt(pets[i].getItemId()); // petid
|
|
mplew.writeMapleAsciiString(pets[i].getName());
|
|
mplew.write(pets[i].getLevel()); // pet level
|
|
mplew.writeShort(pets[i].getCloseness()); // pet closeness
|
|
mplew.write(pets[i].getFullness()); // pet fullness
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(inv != null ? inv.getItemId() : 0);
|
|
}
|
|
}
|
|
mplew.write(0); //end of pets
|
|
|
|
Item mount; //mounts can potentially crash the client if the player's level is not properly checked
|
|
if (chr.getMount() != null && (mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18)) != null && MapleItemInformationProvider.getInstance().getEquipLevelReq(mount.getItemId()) <= chr.getLevel()) {
|
|
MapleMount mmount = chr.getMount();
|
|
mplew.write(mmount.getId()); //mount
|
|
mplew.writeInt(mmount.getLevel()); //level
|
|
mplew.writeInt(mmount.getExp()); //exp
|
|
mplew.writeInt(mmount.getTiredness()); //tiredness
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
mplew.write(chr.getCashShop().getWishList().size());
|
|
for (int sn : chr.getCashShop().getWishList()) {
|
|
mplew.writeInt(sn);
|
|
}
|
|
|
|
MonsterBook book = chr.getMonsterBook();
|
|
mplew.writeInt(book.getBookLevel());
|
|
mplew.writeInt(book.getNormalCard());
|
|
mplew.writeInt(book.getSpecialCard());
|
|
mplew.writeInt(book.getTotalCards());
|
|
mplew.writeInt(chr.getMonsterBookCover() > 0 ? MapleItemInformationProvider.getInstance().getCardMobId(chr.getMonsterBookCover()) : 0);
|
|
Item medal = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -49);
|
|
if (medal != null) {
|
|
mplew.writeInt(medal.getItemId());
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
ArrayList<Short> medalQuests = new ArrayList<>();
|
|
List<MapleQuestStatus> completed = chr.getCompletedQuests();
|
|
for (MapleQuestStatus qs : completed) {
|
|
if (qs.getQuest().getId() >= 29000) { // && q.getQuest().getId() <= 29923
|
|
medalQuests.add(qs.getQuest().getId());
|
|
}
|
|
}
|
|
|
|
Collections.sort(medalQuests);
|
|
mplew.writeShort(medalQuests.size());
|
|
for (Short s : medalQuests) {
|
|
mplew.writeShort(s);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* It is important that statups is in the correct order (see declaration
|
|
* order in MapleBuffStat) since this method doesn't do automagical
|
|
* reordering.
|
|
*
|
|
* @param buffid
|
|
* @param bufflength
|
|
* @param statups
|
|
* @return
|
|
*/
|
|
//1F 00 00 00 00 00 03 00 00 40 00 00 00 E0 00 00 00 00 00 00 00 00 E0 01 8E AA 4F 00 00 C2 EB 0B E0 01 8E AA 4F 00 00 C2 EB 0B 0C 00 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 44 02 8E AA 4F 00 00 C2 EB 0B 00 00 E0 7A 1D 00 8E AA 4F 00 00 00 00 00 00 00 00 03
|
|
public static byte[] giveBuff(int buffid, int bufflength, List<Pair<MapleBuffStat, Integer>> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
|
|
boolean special = false;
|
|
writeLongMask(mplew, statups);
|
|
for (Pair<MapleBuffStat, Integer> statup : statups) {
|
|
if (statup.getLeft().equals(MapleBuffStat.MONSTER_RIDING) || statup.getLeft().equals(MapleBuffStat.HOMING_BEACON)) {
|
|
special = true;
|
|
}
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
mplew.writeInt(buffid);
|
|
mplew.writeInt(bufflength);
|
|
}
|
|
mplew.writeInt(0);
|
|
mplew.write(0);
|
|
mplew.writeInt(statups.get(0).getRight()); //Homing beacon ...
|
|
|
|
if (special) {
|
|
mplew.skip(3);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param cid
|
|
* @param statups
|
|
* @param mount
|
|
* @return
|
|
*/
|
|
public static byte[] showMonsterRiding(int cid, MapleMount mount) { //Gtfo with this, this is just giveForeignBuff
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeLong(MapleBuffStat.MONSTER_RIDING.getValue());
|
|
mplew.writeLong(0);
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(mount.getItemId());
|
|
mplew.writeInt(mount.getSkillId());
|
|
mplew.writeInt(0); //Server Tick value.
|
|
mplew.writeShort(0);
|
|
mplew.write(0); //Times you have been buffed
|
|
return mplew.getPacket();
|
|
}
|
|
/* mplew.writeInt(cid);
|
|
writeLongMask(mplew, statups);
|
|
for (Pair<MapleBuffStat, Integer> statup : statups) {
|
|
if (morph) {
|
|
mplew.writeInt(statup.getRight().intValue());
|
|
} else {
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
}
|
|
}
|
|
mplew.writeShort(0);
|
|
mplew.write(0);*/
|
|
|
|
/**
|
|
*
|
|
* @param c
|
|
* @param quest
|
|
* @return
|
|
*/
|
|
public static byte[] forfeitQuest(short quest) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(1);
|
|
mplew.writeShort(quest);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param c
|
|
* @param quest
|
|
* @return
|
|
*/
|
|
public static byte[] completeQuest(short quest, long time) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(1);
|
|
mplew.writeShort(quest);
|
|
mplew.write(2);
|
|
mplew.writeLong(getTime(time));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param c
|
|
* @param quest
|
|
* @param npc
|
|
* @param progress
|
|
* @return
|
|
*/
|
|
|
|
public static byte[] updateQuestInfo(short quest, int npc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(8); //0x0A in v95
|
|
mplew.writeShort(quest);
|
|
mplew.writeInt(npc);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addQuestTimeLimit(final short quest, final int time) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(6);
|
|
mplew.writeShort(1);//Size but meh, when will there be 2 at the same time? And it won't even replace the old one :)
|
|
mplew.writeShort(quest);
|
|
mplew.writeInt(time);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeQuestTimeLimit(final short quest) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(7);
|
|
mplew.writeShort(1);//Position
|
|
mplew.writeShort(quest);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateQuest(MapleCharacter chr, MapleQuestStatus qs, boolean infoUpdate) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(1);
|
|
if (infoUpdate) {
|
|
MapleQuestStatus iqs = chr.getQuest(qs.getInfoNumber());
|
|
mplew.writeShort(iqs.getQuestID());
|
|
mplew.write(1);
|
|
mplew.writeMapleAsciiString(iqs.getProgressData());
|
|
} else {
|
|
mplew.writeShort(qs.getQuest().getId());
|
|
mplew.write(qs.getStatus().getId());
|
|
mplew.writeMapleAsciiString(qs.getProgressData());
|
|
}
|
|
mplew.skip(5);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeLongMaskD(final MaplePacketLittleEndianWriter mplew, List<Pair<MapleDisease, Integer>> statups) {
|
|
long firstmask = 0;
|
|
long secondmask = 0;
|
|
for (Pair<MapleDisease, Integer> statup : statups) {
|
|
if (statup.getLeft().isFirst()) {
|
|
firstmask |= statup.getLeft().getValue();
|
|
} else {
|
|
secondmask |= statup.getLeft().getValue();
|
|
}
|
|
}
|
|
mplew.writeLong(firstmask);
|
|
mplew.writeLong(secondmask);
|
|
}
|
|
|
|
public static byte[] giveDebuff(List<Pair<MapleDisease, Integer>> statups, MobSkill skill) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
|
|
writeLongMaskD(mplew, statups);
|
|
for (Pair<MapleDisease, Integer> statup : statups) {
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
mplew.writeShort(skill.getSkillId());
|
|
mplew.writeShort(skill.getSkillLevel());
|
|
mplew.writeInt((int) skill.getDuration());
|
|
}
|
|
mplew.writeShort(0); // ??? wk charges have 600 here o.o
|
|
mplew.writeShort(900);//Delay
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] giveForeignDebuff(int cid, List<Pair<MapleDisease, Integer>> statups, MobSkill skill) {
|
|
// Poison damage visibility and missing diseases status visibility, extended through map transitions thanks to Ronan
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskD(mplew, statups);
|
|
for (Pair<MapleDisease, Integer> statup : statups) {
|
|
if (statup.getLeft() == MapleDisease.POISON) {
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
}
|
|
mplew.writeShort(skill.getSkillId());
|
|
mplew.writeShort(skill.getSkillLevel());
|
|
}
|
|
mplew.writeShort(0); // same as give_buff
|
|
mplew.writeShort(900);//Delay
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelForeignFirstDebuff(int cid, long mask) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeLong(mask);
|
|
mplew.writeLong(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelForeignDebuff(int cid, long mask) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeLong(0);
|
|
mplew.writeLong(mask);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] giveForeignBuff(int cid, List<Pair<MapleBuffStat, Integer>> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMask(mplew, statups);
|
|
for (Pair<MapleBuffStat, Integer> statup : statups) {
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
}
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelForeignBuff(int cid, List<MapleBuffStat> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskFromList(mplew, statups);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelBuff(List<MapleBuffStat> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue());
|
|
writeLongMaskFromList(mplew, statups);
|
|
mplew.write(1);//?
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeLongMask(final MaplePacketLittleEndianWriter mplew, List<Pair<MapleBuffStat, Integer>> statups) {
|
|
long firstmask = 0;
|
|
long secondmask = 0;
|
|
for (Pair<MapleBuffStat, Integer> statup : statups) {
|
|
if (statup.getLeft().isFirst()) {
|
|
firstmask |= statup.getLeft().getValue();
|
|
} else {
|
|
secondmask |= statup.getLeft().getValue();
|
|
}
|
|
}
|
|
mplew.writeLong(firstmask);
|
|
mplew.writeLong(secondmask);
|
|
}
|
|
|
|
private static void writeLongMaskFromList(final MaplePacketLittleEndianWriter mplew, List<MapleBuffStat> statups) {
|
|
long firstmask = 0;
|
|
long secondmask = 0;
|
|
for (MapleBuffStat statup : statups) {
|
|
if (statup.isFirst()) {
|
|
firstmask |= statup.getValue();
|
|
} else {
|
|
secondmask |= statup.getValue();
|
|
}
|
|
}
|
|
mplew.writeLong(firstmask);
|
|
mplew.writeLong(secondmask);
|
|
}
|
|
|
|
private static void writeLongEncodeTemporaryMask(final MaplePacketLittleEndianWriter mplew, Collection<MonsterStatus> stati) {
|
|
int[] masks = new int[4];
|
|
|
|
for (MonsterStatus statup : stati) {
|
|
int pos = statup.isFirst() ? 0 : 2;
|
|
for (int i = 0; i < 2; i++) {
|
|
masks[pos + i] |= statup.getValue() >> 32 * i;
|
|
}
|
|
}
|
|
|
|
for (int mask : masks) {
|
|
mplew.writeInt(mask);
|
|
}
|
|
}
|
|
|
|
public static byte[] cancelDebuff(long mask) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
|
mplew.writeShort(SendOpcode.CANCEL_BUFF.getValue());
|
|
mplew.writeLong(0);
|
|
mplew.writeLong(mask);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeLongMaskSlowD(final MaplePacketLittleEndianWriter mplew) {
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(2048);
|
|
mplew.writeLong(0);
|
|
}
|
|
|
|
public static byte[] giveForeignSlowDebuff(int cid, List<Pair<MapleDisease, Integer>> statups, MobSkill skill) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskSlowD(mplew);
|
|
for (Pair<MapleDisease, Integer> statup : statups) {
|
|
if (statup.getLeft() == MapleDisease.POISON) {
|
|
mplew.writeShort(statup.getRight().shortValue());
|
|
}
|
|
mplew.writeShort(skill.getSkillId());
|
|
mplew.writeShort(skill.getSkillLevel());
|
|
}
|
|
mplew.writeShort(0); // same as give_buff
|
|
mplew.writeShort(900);//Delay
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelForeignSlowDebuff(int cid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskSlowD(mplew);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeLongMaskChair(final MaplePacketLittleEndianWriter mplew) {
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(262144);
|
|
mplew.writeLong(0);
|
|
}
|
|
|
|
public static byte[] giveForeignChairSkillEffect(int cid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskChair(mplew);
|
|
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(100);
|
|
mplew.writeShort(1);
|
|
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(900);
|
|
|
|
mplew.skip(7);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// packet found thanks to Ronan
|
|
public static byte[] giveForeignWKChargeEffect(int cid, int buffid, List<Pair<MapleBuffStat, Integer>> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMask(mplew, statups);
|
|
mplew.writeInt(buffid);
|
|
mplew.writeShort(600);
|
|
mplew.writeShort(1000);//Delay
|
|
mplew.write(1);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelForeignChairSkillEffect(int cid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
|
mplew.writeShort(SendOpcode.CANCEL_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMaskChair(mplew);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopChat(MapleCharacter chr, String chat, boolean owner) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
|
|
mplew.write(owner ? 0 : 1);
|
|
mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopNewVisitor(MapleCharacter chr, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
|
|
mplew.write(slot);
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopRemoveVisitor(int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
if (slot != 0) {
|
|
mplew.writeShort(slot);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradePartnerAdd(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
|
|
mplew.write(1);
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] tradeInvite(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.INVITE.getCode());
|
|
mplew.write(3);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
mplew.write(new byte[]{(byte) 0xB7, (byte) 0x50, 0, 0});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradeMesoSet(byte number, int meso) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.SET_MESO.getCode());
|
|
mplew.write(number);
|
|
mplew.writeInt(meso);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradeItemAdd(byte number, Item item) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.SET_ITEMS.getCode());
|
|
mplew.write(number);
|
|
mplew.write(item.getPosition());
|
|
addItemInfo(mplew, item, true);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopItemUpdate(MaplePlayerShop shop) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode());
|
|
mplew.write(shop.getItems().size());
|
|
for (MaplePlayerShopItem item : shop.getItems()) {
|
|
mplew.writeShort(item.getBundles());
|
|
mplew.writeShort(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopOwnerUpdate(MaplePlayerShop.SoldItem item, int position) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.UPDATE_PLAYERSHOP.getCode());
|
|
mplew.write(position);
|
|
mplew.writeShort(item.getQuantity());
|
|
mplew.writeMapleAsciiString(item.getBuyer());
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param c
|
|
* @param shop
|
|
* @param owner
|
|
* @return
|
|
*/
|
|
public static byte[] getPlayerShop(MaplePlayerShop shop, boolean owner) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(4);
|
|
mplew.write(4);
|
|
mplew.write(owner ? 0 : 1);
|
|
|
|
if (owner) {
|
|
List<MaplePlayerShop.SoldItem> sold = shop.getSold();
|
|
mplew.write(sold.size());
|
|
for (MaplePlayerShop.SoldItem s : sold) {
|
|
mplew.writeInt(s.getItemId());
|
|
mplew.writeShort(s.getQuantity());
|
|
mplew.writeInt(s.getMesos());
|
|
mplew.writeMapleAsciiString(s.getBuyer());
|
|
}
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
|
|
addCharLook(mplew, shop.getOwner(), false);
|
|
mplew.writeMapleAsciiString(shop.getOwner().getName());
|
|
|
|
MapleCharacter[] visitors = shop.getVisitors();
|
|
for(int i = 0; i < 3; i++) {
|
|
if(visitors[i] != null) {
|
|
mplew.write(i + 1);
|
|
addCharLook(mplew, visitors[i], false);
|
|
mplew.writeMapleAsciiString(visitors[i].getName());
|
|
}
|
|
}
|
|
|
|
mplew.write(0xFF);
|
|
mplew.writeMapleAsciiString(shop.getDescription());
|
|
List<MaplePlayerShopItem> items = shop.getItems();
|
|
mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax
|
|
mplew.write(items.size());
|
|
for (MaplePlayerShopItem item : items) {
|
|
mplew.writeShort(item.getBundles());
|
|
mplew.writeShort(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradeStart(MapleClient c, MapleTrade trade, byte number) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(3);
|
|
mplew.write(2);
|
|
mplew.write(number);
|
|
if (number == 1) {
|
|
mplew.write(0);
|
|
addCharLook(mplew, trade.getPartner().getChr(), false);
|
|
mplew.writeMapleAsciiString(trade.getPartner().getChr().getName());
|
|
}
|
|
mplew.write(number);
|
|
addCharLook(mplew, c.getPlayer(), false);
|
|
mplew.writeMapleAsciiString(c.getPlayer().getName());
|
|
mplew.write(0xFF);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradeConfirmation() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.CONFIRM.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Possible values for <code>operation</code>:<br> 2: Trade cancelled, by the
|
|
* other character<br> 7: Trade successful<br> 8: Trade unsuccessful<br>
|
|
* 9: Cannot carry more one-of-a-kind items<br> 12: Cannot trade on different maps<br>
|
|
* 13: Cannot trade, game files damaged<br>
|
|
*
|
|
* @param number
|
|
* @param operation
|
|
* @return
|
|
*/
|
|
public static byte[] getTradeResult(byte number, byte operation) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
mplew.write(number);
|
|
mplew.write(operation);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Possible values for <code>speaker</code>:<br> 0: Npc talking (left)<br>
|
|
* 1: Npc talking (right)<br> 2: Player talking (left)<br> 3: Player talking
|
|
* (left)<br>
|
|
*
|
|
* @param npc Npcid
|
|
* @param msgType
|
|
* @param talk
|
|
* @param endBytes
|
|
* @param speaker
|
|
* @return
|
|
*/
|
|
public static byte[] getNPCTalk(int npc, byte msgType, String talk, String endBytes, byte speaker) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(4); // ?
|
|
mplew.writeInt(npc);
|
|
mplew.write(msgType);
|
|
mplew.write(speaker);
|
|
mplew.writeMapleAsciiString(talk);
|
|
mplew.write(HexTool.getByteArrayFromHexString(endBytes));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getDimensionalMirror(String talk) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(4); // ?
|
|
mplew.writeInt(9010022);
|
|
mplew.write(0x0E);
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeMapleAsciiString(talk);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getNPCTalkStyle(int npc, String talk, int[] styles) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(4); // ?
|
|
mplew.writeInt(npc);
|
|
mplew.write(7);
|
|
mplew.write(0); //speaker
|
|
mplew.writeMapleAsciiString(talk);
|
|
mplew.write(styles.length);
|
|
for (int style : styles) {
|
|
mplew.writeInt(style);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getNPCTalkNum(int npc, String talk, int def, int min, int max) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(4); // ?
|
|
mplew.writeInt(npc);
|
|
mplew.write(3);
|
|
mplew.write(0); //speaker
|
|
mplew.writeMapleAsciiString(talk);
|
|
mplew.writeInt(def);
|
|
mplew.writeInt(min);
|
|
mplew.writeInt(max);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getNPCTalkText(int npc, String talk, String def) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(4); // Doesn't matter
|
|
mplew.writeInt(npc);
|
|
mplew.write(2);
|
|
mplew.write(0); //speaker
|
|
mplew.writeMapleAsciiString(talk);
|
|
mplew.writeMapleAsciiString(def);//:D
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// NPC Quiz packets thanks to Eric
|
|
public static byte[] OnAskQuiz(int nSpeakerTypeID, int nSpeakerTemplateID, int nResCode, String sTitle, String sProblemText, String sHintText, int nMinInput, int nMaxInput, int tRemainInitialQuiz) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(nSpeakerTypeID);
|
|
mplew.writeInt(nSpeakerTemplateID);
|
|
mplew.write(0x6);
|
|
mplew.write(0);
|
|
mplew.write(nResCode);
|
|
if (nResCode == 0x0) {//fail has no bytes <3
|
|
mplew.writeMapleAsciiString(sTitle);
|
|
mplew.writeMapleAsciiString(sProblemText);
|
|
mplew.writeMapleAsciiString(sHintText);
|
|
mplew.writeShort(nMinInput);
|
|
mplew.writeShort(nMaxInput);
|
|
mplew.writeInt(tRemainInitialQuiz);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] OnAskSpeedQuiz(int nSpeakerTypeID, int nSpeakerTemplateID, int nResCode, int nType, int dwAnswer, int nCorrect, int nRemain, int tRemainInitialQuiz) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NPC_TALK.getValue());
|
|
mplew.write(nSpeakerTypeID);
|
|
mplew.writeInt(nSpeakerTemplateID);
|
|
mplew.write(0x7);
|
|
mplew.write(0);
|
|
mplew.write(nResCode);
|
|
if (nResCode == 0x0) {//fail has no bytes <3
|
|
mplew.writeInt(nType);
|
|
mplew.writeInt(dwAnswer);
|
|
mplew.writeInt(nCorrect);
|
|
mplew.writeInt(nRemain);
|
|
mplew.writeInt(tRemainInitialQuiz);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBuffeffect(int cid, int skillid, int effectid) {
|
|
return showBuffeffect(cid, skillid, effectid, (byte) 3);
|
|
}
|
|
|
|
public static byte[] showBuffeffect(int cid, int skillid, int effectid, byte direction) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(effectid); //buff level
|
|
mplew.writeInt(skillid);
|
|
mplew.write(direction);
|
|
mplew.write(1);
|
|
mplew.writeLong(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBuffeffect(int cid, int skillid, int skilllv, int effectid, byte direction) { // updated packet structure found thanks to Rien dev team
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(effectid);
|
|
mplew.writeInt(skillid);
|
|
mplew.write(0);
|
|
mplew.write(skilllv);
|
|
mplew.write(direction);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showOwnBuffEffect(int skillid, int effectid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(effectid);
|
|
mplew.writeInt(skillid);
|
|
mplew.write(0xA9);
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showOwnBerserk(int skilllevel, boolean Berserk) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(1320006);
|
|
mplew.write(0xA9);
|
|
mplew.write(skilllevel);
|
|
mplew.write(Berserk ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBerserk(int cid, int skilllevel, boolean Berserk) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(1);
|
|
mplew.writeInt(1320006);
|
|
mplew.write(0xA9);
|
|
mplew.write(skilllevel);
|
|
mplew.write(Berserk ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateSkill(int skillid, int level, int masterlevel, long expiration) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_SKILLS.getValue());
|
|
mplew.write(1);
|
|
mplew.writeShort(1);
|
|
mplew.writeInt(skillid);
|
|
mplew.writeInt(level);
|
|
mplew.writeInt(masterlevel);
|
|
addExpirationTime(mplew, expiration);
|
|
mplew.write(4);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getShowQuestCompletion(int id) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.QUEST_CLEAR.getValue());
|
|
mplew.writeShort(id);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getKeymap(Map<Integer, MapleKeyBinding> keybindings) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.KEYMAP.getValue());
|
|
mplew.write(0);
|
|
for (int x = 0; x < 90; x++) {
|
|
MapleKeyBinding binding = keybindings.get(x);
|
|
if (binding != null) {
|
|
mplew.write(binding.getType());
|
|
mplew.writeInt(binding.getAction());
|
|
} else {
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] QuickslotMappedInit(MapleQuickslotBinding pQuickslot)
|
|
{
|
|
final MaplePacketLittleEndianWriter pOutPacket = new MaplePacketLittleEndianWriter();
|
|
|
|
pOutPacket.writeShort(SendOpcode.QUICKSLOT_INIT.getValue());
|
|
pQuickslot.Encode(pOutPacket);
|
|
|
|
return pOutPacket.getPacket();
|
|
}
|
|
|
|
public static byte[] getWhisper(String sender, int channel, String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.WHISPER.getValue());
|
|
mplew.write(0x12);
|
|
mplew.writeMapleAsciiString(sender);
|
|
mplew.writeShort(channel - 1); // I guess this is the channel
|
|
mplew.writeMapleAsciiString(text);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param target name of the target character
|
|
* @param reply error code: 0x0 = cannot find char, 0x1 = success
|
|
* @return the MaplePacket
|
|
*/
|
|
public static byte[] getWhisperReply(String target, byte reply) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.WHISPER.getValue());
|
|
mplew.write(0x0A); // whisper?
|
|
mplew.writeMapleAsciiString(target);
|
|
mplew.write(reply);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getInventoryFull() {
|
|
return modifyInventory(true, Collections.<ModifyInventory>emptyList());
|
|
}
|
|
|
|
public static byte[] getShowInventoryFull() {
|
|
return getShowInventoryStatus(0xff);
|
|
}
|
|
|
|
public static byte[] showItemUnavailable() {
|
|
return getShowInventoryStatus(0xfe);
|
|
}
|
|
|
|
public static byte[] getShowInventoryStatus(int mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(0);
|
|
mplew.write(mode);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getStorage(int npcId, byte slots, Collection<Item> items, int meso) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(0x16);
|
|
mplew.writeInt(npcId);
|
|
mplew.write(slots);
|
|
mplew.writeShort(0x7E);
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(meso);
|
|
mplew.writeShort(0);
|
|
mplew.write((byte) items.size());
|
|
for (Item item : items) {
|
|
addItemInfo(mplew, item, true);
|
|
}
|
|
mplew.writeShort(0);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
* 0x0A = Inv full
|
|
* 0x0B = You do not have enough mesos
|
|
* 0x0C = One-Of-A-Kind error
|
|
*/
|
|
public static byte[] getStorageError(byte i) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(i);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] mesoStorage(byte slots, int meso) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(0x13);
|
|
mplew.write(slots);
|
|
mplew.writeShort(2);
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(meso);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] storeStorage(byte slots, MapleInventoryType type, Collection<Item> items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(0xD);
|
|
mplew.write(slots);
|
|
mplew.writeShort(type.getBitfieldEncoding());
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(0);
|
|
mplew.write(items.size());
|
|
for (Item item : items) {
|
|
addItemInfo(mplew, item, true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] takeOutStorage(byte slots, MapleInventoryType type, Collection<Item> items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(0x9);
|
|
mplew.write(slots);
|
|
mplew.writeShort(type.getBitfieldEncoding());
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(0);
|
|
mplew.write(items.size());
|
|
for (Item item : items) {
|
|
addItemInfo(mplew, item, true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] arrangeStorage(byte slots, Collection<Item> items) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
|
|
mplew.writeShort(SendOpcode.STORAGE.getValue());
|
|
mplew.write(0xF);
|
|
mplew.write(slots);
|
|
mplew.write(124);
|
|
mplew.skip(10);
|
|
mplew.write(items.size());
|
|
for (Item item : items) {
|
|
addItemInfo(mplew, item, true);
|
|
}
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param oid
|
|
* @param remhppercentage
|
|
* @return
|
|
*/
|
|
public static byte[] showMonsterHP(int oid, int remhppercentage) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_MONSTER_HP.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.write(remhppercentage);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBossHP(int oid, int currHP, int maxHP, byte tagColor, byte tagBgColor) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(5);
|
|
mplew.writeInt(oid);
|
|
mplew.writeInt(currHP);
|
|
mplew.writeInt(maxHP);
|
|
mplew.write(tagColor);
|
|
mplew.write(tagBgColor);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static Pair<Integer, Integer> normalizedCustomMaxHP(long currHP, long maxHP) {
|
|
int sendHP, sendMaxHP;
|
|
|
|
if(maxHP <= Integer.MAX_VALUE) {
|
|
sendHP = (int) currHP;
|
|
sendMaxHP = (int) maxHP;
|
|
} else {
|
|
float f = ((float) currHP) / maxHP;
|
|
|
|
sendHP = (int) (Integer.MAX_VALUE * f);
|
|
sendMaxHP = Integer.MAX_VALUE;
|
|
}
|
|
|
|
return new Pair<>(sendHP, sendMaxHP);
|
|
}
|
|
|
|
public static byte[] customShowBossHP(byte call, int oid, long currHP, long maxHP, byte tagColor, byte tagBgColor) {
|
|
Pair<Integer, Integer> customHP = normalizedCustomMaxHP(currHP, maxHP);
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(call);
|
|
mplew.writeInt(oid);
|
|
mplew.writeInt(customHP.left);
|
|
mplew.writeInt(customHP.right);
|
|
mplew.write(tagColor);
|
|
mplew.write(tagBgColor);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] giveFameResponse(int mode, String charname, int newfame) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue());
|
|
mplew.write(0);
|
|
mplew.writeMapleAsciiString(charname);
|
|
mplew.write(mode);
|
|
mplew.writeShort(newfame);
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* status can be: <br> 0: ok, use giveFameResponse<br> 1: the username is
|
|
* incorrectly entered<br> 2: users under level 15 are unable to toggle with
|
|
* fame.<br> 3: can't raise or drop fame anymore today.<br> 4: can't raise
|
|
* or drop fame for this character for this month anymore.<br> 5: received
|
|
* fame, use receiveFame()<br> 6: level of fame neither has been raised nor
|
|
* dropped due to an unexpected error
|
|
*
|
|
* @param status
|
|
* @return
|
|
*/
|
|
public static byte[] giveFameErrorResponse(int status) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue());
|
|
mplew.write(status);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] receiveFame(int mode, String charnameFrom) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAME_RESPONSE.getValue());
|
|
mplew.write(5);
|
|
mplew.writeMapleAsciiString(charnameFrom);
|
|
mplew.write(mode);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] partyCreated(MapleParty party, int partycharid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.write(8);
|
|
mplew.writeInt(party.getId());
|
|
|
|
Map<Integer, MapleDoor> partyDoors = party.getDoors();
|
|
if (partyDoors.size() > 0) {
|
|
MapleDoor door = partyDoors.get(partycharid);
|
|
|
|
if(door != null) {
|
|
MapleDoorObject mdo = door.getAreaDoor();
|
|
mplew.writeInt(mdo.getTo().getId());
|
|
mplew.writeInt(mdo.getFrom().getId());
|
|
mplew.writeInt(mdo.getPosition().x);
|
|
mplew.writeInt(mdo.getPosition().y);
|
|
} else {
|
|
mplew.writeInt(999999999);
|
|
mplew.writeInt(999999999);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
}
|
|
} else {
|
|
mplew.writeInt(999999999);
|
|
mplew.writeInt(999999999);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] partyInvite(MapleCharacter from) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.write(4);
|
|
mplew.writeInt(from.getParty().getId());
|
|
mplew.writeMapleAsciiString(from.getName());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] partySearchInvite(MapleCharacter from) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.write(4);
|
|
mplew.writeInt(from.getParty().getId());
|
|
mplew.writeMapleAsciiString("PS: " + from.getName());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* 10: A beginner can't create a party. 1/5/6/11/14/19: Your request for a
|
|
* party didn't work due to an unexpected error. 12: Quit as leader of the
|
|
* party. 13: You have yet to join a party.
|
|
* 16: Already have joined a party. 17: The party you're trying to join is
|
|
* already in full capacity. 19: Unable to find the requested character in
|
|
* this channel. 25: Cannot kick another user in this map. 28/29: Leadership
|
|
* can only be given to a party member in the vicinity. 30: Change leadership
|
|
* only on same channel.
|
|
*
|
|
* @param message
|
|
* @return
|
|
*/
|
|
public static byte[] partyStatusMessage(int message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.write(message);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* 21: Player is blocking any party invitations, 22: Player is taking care of
|
|
* another invitation, 23: Player have denied request to the party.
|
|
*
|
|
* @param message
|
|
* @param charname
|
|
* @return
|
|
*/
|
|
public static byte[] partyStatusMessage(int message, String charname) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.write(message);
|
|
mplew.writeMapleAsciiString(charname);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addPartyStatus(int forchannel, MapleParty party, LittleEndianWriter lew, boolean leaving) {
|
|
List<MaplePartyCharacter> partymembers = new ArrayList<>(party.getMembers());
|
|
while (partymembers.size() < 6) {
|
|
partymembers.add(new MaplePartyCharacter());
|
|
}
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
lew.writeInt(partychar.getId());
|
|
}
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
lew.writeAsciiString(getRightPaddedStr(partychar.getName(), '\0', 13));
|
|
}
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
lew.writeInt(partychar.getJobId());
|
|
}
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
lew.writeInt(partychar.getLevel());
|
|
}
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
if (partychar.isOnline()) {
|
|
lew.writeInt(partychar.getChannel() - 1);
|
|
} else {
|
|
lew.writeInt(-2);
|
|
}
|
|
}
|
|
lew.writeInt(party.getLeader().getId());
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
if (partychar.getChannel() == forchannel) {
|
|
lew.writeInt(partychar.getMapId());
|
|
} else {
|
|
lew.writeInt(0);
|
|
}
|
|
}
|
|
|
|
Map<Integer, MapleDoor> partyDoors = party.getDoors();
|
|
for (MaplePartyCharacter partychar : partymembers) {
|
|
if (partychar.getChannel() == forchannel && !leaving) {
|
|
if (partyDoors.size() > 0) {
|
|
MapleDoor door = partyDoors.get(partychar.getId());
|
|
if(door != null) {
|
|
MapleDoorObject mdo = door.getTownDoor();
|
|
lew.writeInt(mdo.getTown().getId());
|
|
lew.writeInt(mdo.getArea().getId());
|
|
lew.writeInt(mdo.getPosition().x);
|
|
lew.writeInt(mdo.getPosition().y);
|
|
} else {
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(0);
|
|
lew.writeInt(0);
|
|
}
|
|
} else {
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(0);
|
|
lew.writeInt(0);
|
|
}
|
|
} else {
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(999999999);
|
|
lew.writeInt(0);
|
|
lew.writeInt(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static byte[] updateParty(int forChannel, MapleParty party, PartyOperation op, MaplePartyCharacter target) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
switch (op) {
|
|
case DISBAND:
|
|
case EXPEL:
|
|
case LEAVE:
|
|
mplew.write(0x0C);
|
|
mplew.writeInt(party.getId());
|
|
mplew.writeInt(target.getId());
|
|
if (op == PartyOperation.DISBAND) {
|
|
mplew.write(0);
|
|
mplew.writeInt(party.getId());
|
|
} else {
|
|
mplew.write(1);
|
|
if (op == PartyOperation.EXPEL) {
|
|
mplew.write(1);
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
mplew.writeMapleAsciiString(target.getName());
|
|
addPartyStatus(forChannel, party, mplew, false);
|
|
}
|
|
break;
|
|
case JOIN:
|
|
mplew.write(0xF);
|
|
mplew.writeInt(party.getId());
|
|
mplew.writeMapleAsciiString(target.getName());
|
|
addPartyStatus(forChannel, party, mplew, false);
|
|
break;
|
|
case SILENT_UPDATE:
|
|
case LOG_ONOFF:
|
|
mplew.write(0x7);
|
|
mplew.writeInt(party.getId());
|
|
addPartyStatus(forChannel, party, mplew, false);
|
|
break;
|
|
case CHANGE_LEADER:
|
|
mplew.write(0x1B);
|
|
mplew.writeInt(target.getId());
|
|
mplew.write(0);
|
|
break;
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] partyPortal(int townId, int targetId, Point position) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue());
|
|
mplew.writeShort(0x23);
|
|
mplew.writeInt(townId);
|
|
mplew.writeInt(targetId);
|
|
mplew.writePos(position);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updatePartyMemberHP(int cid, int curhp, int maxhp) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_PARTYMEMBER_HP.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(curhp);
|
|
mplew.writeInt(maxhp);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* mode: 0 buddychat; 1 partychat; 2 guildchat
|
|
*
|
|
* @param name
|
|
* @param chattext
|
|
* @param mode
|
|
* @return
|
|
*/
|
|
public static byte[] multiChat(String name, String chattext, int mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MULTICHAT.getValue());
|
|
mplew.write(mode);
|
|
mplew.writeMapleAsciiString(name);
|
|
mplew.writeMapleAsciiString(chattext);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void writeIntMask(final MaplePacketLittleEndianWriter mplew, Map<MonsterStatus, Integer> stats) {
|
|
int firstmask = 0;
|
|
int secondmask = 0;
|
|
for (MonsterStatus stat : stats.keySet()) {
|
|
if (stat.isFirst()) {
|
|
firstmask |= stat.getValue();
|
|
} else {
|
|
secondmask |= stat.getValue();
|
|
}
|
|
}
|
|
mplew.writeInt(firstmask);
|
|
mplew.writeInt(secondmask);
|
|
}
|
|
|
|
public static byte[] applyMonsterStatus(final int oid, final MonsterStatusEffect mse, final List<Integer> reflection) {
|
|
Map<MonsterStatus, Integer> stati = mse.getStati();
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.APPLY_MONSTER_STATUS.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.writeLong(0);
|
|
writeIntMask(mplew, stati);
|
|
for (Map.Entry<MonsterStatus, Integer> stat : stati.entrySet()) {
|
|
mplew.writeShort(stat.getValue());
|
|
if (mse.isMonsterSkill()) {
|
|
mplew.writeShort(mse.getMobSkill().getSkillId());
|
|
mplew.writeShort(mse.getMobSkill().getSkillLevel());
|
|
} else {
|
|
mplew.writeInt(mse.getSkill().getId());
|
|
}
|
|
mplew.writeShort(-1); // might actually be the buffTime but it's not displayed anywhere
|
|
}
|
|
int size = stati.size(); // size
|
|
if (reflection != null) {
|
|
for (Integer ref : reflection) {
|
|
mplew.writeInt(ref);
|
|
}
|
|
if (reflection.size() > 0) {
|
|
size /= 2; // This gives 2 buffs per reflection but it's really one buff
|
|
}
|
|
}
|
|
mplew.write(size); // size
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelMonsterStatus(int oid, Map<MonsterStatus, Integer> stats) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_MONSTER_STATUS.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.writeLong(0);
|
|
writeIntMask(mplew, stats);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getClock(int time) { // time in seconds
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CLOCK.getValue());
|
|
mplew.write(2); // clock type. if you send 3 here you have to send another byte (which does not matter at all) before the timestamp
|
|
mplew.writeInt(time);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getClockTime(int hour, int min, int sec) { // Current Time
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CLOCK.getValue());
|
|
mplew.write(1); //Clock-Type
|
|
mplew.write(hour);
|
|
mplew.write(min);
|
|
mplew.write(sec);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeClock() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STOP_CLOCK.getValue());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnMist(int oid, int ownerCid, int skill, int level, MapleMist mist) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_MIST.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.writeInt(mist.isMobMist() ? 0 : mist.isPoisonMist() ? 1 : mist.isRecoveryMist() ? 4 : 2); // mob mist = 0, player poison = 1, smokescreen = 2, unknown = 3, recovery = 4
|
|
mplew.writeInt(ownerCid);
|
|
mplew.writeInt(skill);
|
|
mplew.write(level);
|
|
mplew.writeShort(mist.getSkillDelay()); // Skill delay
|
|
mplew.writeInt(mist.getBox().x);
|
|
mplew.writeInt(mist.getBox().y);
|
|
mplew.writeInt(mist.getBox().x + mist.getBox().width);
|
|
mplew.writeInt(mist.getBox().y + mist.getBox().height);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeMist(int oid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_MIST.getValue());
|
|
mplew.writeInt(oid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] damageSummon(int cid, int oid, int damage, int monsterIdFrom) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DAMAGE_SUMMON.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(oid);
|
|
mplew.write(12);
|
|
mplew.writeInt(damage); // damage display doesn't seem to work...
|
|
mplew.writeInt(monsterIdFrom);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] damageMonster(int oid, int damage) {
|
|
return damageMonster(oid, damage, 0, 0);
|
|
}
|
|
|
|
public static byte[] healMonster(int oid, int heal, int curhp, int maxhp) {
|
|
return damageMonster(oid, -heal, curhp, maxhp);
|
|
}
|
|
|
|
private static byte[] damageMonster(int oid, int damage, int curhp, int maxhp) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue());
|
|
mplew.writeInt(oid);
|
|
mplew.write(0);
|
|
mplew.writeInt(damage);
|
|
mplew.writeInt(curhp);
|
|
mplew.writeInt(maxhp);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateBuddylist(Collection<BuddylistEntry> buddylist) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BUDDYLIST.getValue());
|
|
mplew.write(7);
|
|
mplew.write(buddylist.size());
|
|
for (BuddylistEntry buddy : buddylist) {
|
|
if (buddy.isVisible()) {
|
|
mplew.writeInt(buddy.getCharacterId()); // cid
|
|
mplew.writeAsciiString(getRightPaddedStr(buddy.getName(), '\0', 13));
|
|
mplew.write(0); // opposite status
|
|
mplew.writeInt(buddy.getChannel() - 1);
|
|
mplew.writeAsciiString(getRightPaddedStr(buddy.getGroup(), '\0', 13));
|
|
mplew.writeInt(0);//mapid?
|
|
}
|
|
}
|
|
for (int x = 0; x < buddylist.size(); x++) {
|
|
mplew.writeInt(0);//mapid?
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] buddylistMessage(byte message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BUDDYLIST.getValue());
|
|
mplew.write(message);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] requestBuddylistAdd(int cidFrom, int cid, String nameFrom) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BUDDYLIST.getValue());
|
|
mplew.write(9);
|
|
mplew.writeInt(cidFrom);
|
|
mplew.writeMapleAsciiString(nameFrom);
|
|
mplew.writeInt(cidFrom);
|
|
mplew.writeAsciiString(getRightPaddedStr(nameFrom, '\0', 11));
|
|
mplew.write(0x09);
|
|
mplew.write(0xf0);
|
|
mplew.write(0x01);
|
|
mplew.writeInt(0x0f);
|
|
mplew.writeNullTerminatedAsciiString("Default Group");
|
|
mplew.writeInt(cid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateBuddyChannel(int characterid, int channel) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BUDDYLIST.getValue());
|
|
mplew.write(0x14);
|
|
mplew.writeInt(characterid);
|
|
mplew.write(0);
|
|
mplew.writeInt(channel);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] itemEffect(int characterid, int itemid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_EFFECT.getValue());
|
|
mplew.writeInt(characterid);
|
|
mplew.writeInt(itemid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateBuddyCapacity(int capacity) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BUDDYLIST.getValue());
|
|
mplew.write(0x15);
|
|
mplew.write(capacity);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showChair(int characterid, int itemid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_CHAIR.getValue());
|
|
mplew.writeInt(characterid);
|
|
mplew.writeInt(itemid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] cancelChair(int id) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_CHAIR.getValue());
|
|
if (id < 0) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
mplew.writeShort(id);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// is there a way to spawn reactors non-animated?
|
|
public static byte[] spawnReactor(MapleReactor reactor) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
Point pos = reactor.getPosition();
|
|
mplew.writeShort(SendOpcode.REACTOR_SPAWN.getValue());
|
|
mplew.writeInt(reactor.getObjectId());
|
|
mplew.writeInt(reactor.getId());
|
|
mplew.write(reactor.getState());
|
|
mplew.writePos(pos);
|
|
mplew.write(0);
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// is there a way to trigger reactors without performing the hit animation?
|
|
public static byte[] triggerReactor(MapleReactor reactor, int stance) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
Point pos = reactor.getPosition();
|
|
mplew.writeShort(SendOpcode.REACTOR_HIT.getValue());
|
|
mplew.writeInt(reactor.getObjectId());
|
|
mplew.write(reactor.getState());
|
|
mplew.writePos(pos);
|
|
mplew.write(stance);
|
|
mplew.writeShort(0);
|
|
mplew.write(5); // frame delay, set to 5 since there doesn't appear to be a fixed formula for it
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] destroyReactor(MapleReactor reactor) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
Point pos = reactor.getPosition();
|
|
mplew.writeShort(SendOpcode.REACTOR_DESTROY.getValue());
|
|
mplew.writeInt(reactor.getObjectId());
|
|
mplew.write(reactor.getState());
|
|
mplew.writePos(pos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] musicChange(String song) {
|
|
return environmentChange(song, 6);
|
|
}
|
|
|
|
public static byte[] showEffect(String effect) {
|
|
return environmentChange(effect, 3);
|
|
}
|
|
|
|
public static byte[] playSound(String sound) {
|
|
return environmentChange(sound, 4);
|
|
}
|
|
|
|
public static byte[] environmentChange(String env, int mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(mode);
|
|
mplew.writeMapleAsciiString(env);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] environmentMove(String env, int mode) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
|
|
mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF.getValue());
|
|
mplew.writeMapleAsciiString(env);
|
|
mplew.writeInt(mode); // 0: stop and back to start, 1: move
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] environmentMoveList(Set<Entry<String, Integer>> envList) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ONOFF_LIST.getValue());
|
|
mplew.writeInt(envList.size());
|
|
|
|
for(Entry<String, Integer> envMove : envList) {
|
|
mplew.writeMapleAsciiString(envMove.getKey());
|
|
mplew.writeInt(envMove.getValue());
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] environmentMoveReset() {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_OBSTACLE_ALL_RESET.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] startMapEffect(String msg, int itemid, boolean active) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue());
|
|
mplew.write(active ? 0 : 1);
|
|
mplew.writeInt(itemid);
|
|
if (active) {
|
|
mplew.writeMapleAsciiString(msg);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeMapEffect() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] mapEffect(String path) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(3);
|
|
mplew.writeMapleAsciiString(path);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] mapSound(String path) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(4);
|
|
mplew.writeMapleAsciiString(path);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showGuildInfo(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x1A); //signature for showing guild info
|
|
if (chr == null) { //show empty guild (used for leaving, expelled)
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
MapleGuild g = chr.getClient().getWorldServer().getGuild(chr.getMGC());
|
|
if (g == null) { //failed to read from DB - don't show a guild
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
mplew.write(1); //bInGuild
|
|
mplew.writeInt(g.getId());
|
|
mplew.writeMapleAsciiString(g.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(g.getRankTitle(i));
|
|
}
|
|
Collection<MapleGuildCharacter> members = g.getMembers();
|
|
mplew.write(members.size()); //then it is the size of all the members
|
|
for (MapleGuildCharacter mgc : members) {//and each of their character ids o_O
|
|
mplew.writeInt(mgc.getId());
|
|
}
|
|
for (MapleGuildCharacter mgc : members) {
|
|
mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13));
|
|
mplew.writeInt(mgc.getJobId());
|
|
mplew.writeInt(mgc.getLevel());
|
|
mplew.writeInt(mgc.getGuildRank());
|
|
mplew.writeInt(mgc.isOnline() ? 1 : 0);
|
|
mplew.writeInt(g.getSignature());
|
|
mplew.writeInt(mgc.getAllianceRank());
|
|
}
|
|
mplew.writeInt(g.getCapacity());
|
|
mplew.writeShort(g.getLogoBG());
|
|
mplew.write(g.getLogoBGColor());
|
|
mplew.writeShort(g.getLogo());
|
|
mplew.write(g.getLogoColor());
|
|
mplew.writeMapleAsciiString(g.getNotice());
|
|
mplew.writeInt(g.getGP());
|
|
mplew.writeInt(g.getAllianceId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildMemberOnline(int gid, int cid, boolean bOnline) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x3d);
|
|
mplew.writeInt(gid);
|
|
mplew.writeInt(cid);
|
|
mplew.write(bOnline ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildInvite(int gid, String charName) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x05);
|
|
mplew.writeInt(gid);
|
|
mplew.writeMapleAsciiString(charName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] createGuildMessage(String masterName, String guildName) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x3);
|
|
mplew.writeInt(0);
|
|
mplew.writeMapleAsciiString(masterName);
|
|
mplew.writeMapleAsciiString(guildName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a Heracle/guild message packet.
|
|
*
|
|
* Possible values for <code>code</code>:<br> 28: guild name already in use<br>
|
|
* 31: problem in locating players during agreement<br> 33/40: already joined a guild<br>
|
|
* 35: Cannot make guild<br> 36: problem in player agreement<br> 38: problem during forming guild<br>
|
|
* 41: max number of players in joining guild<br> 42: character can't be found this channel<br>
|
|
* 45/48: character not in guild<br> 52: problem in disbanding guild<br> 56: admin cannot make guild<br>
|
|
* 57: problem in increasing guild size<br>
|
|
*
|
|
*
|
|
* @param code The response code.
|
|
* @return The guild message packet.
|
|
*/
|
|
public static byte[] genericGuildMessage(byte code) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(code);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a guild message packet appended with target name.
|
|
*
|
|
* 53: player not accepting guild invites<br>
|
|
* 54: player already managing an invite<br> 55: player denied an invite<br>
|
|
*
|
|
* @param code The response code.
|
|
* @param targetName The initial player target of the invitation.
|
|
* @return The guild message packet.
|
|
*/
|
|
public static byte[] responseGuildMessage(byte code, String targetName) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(code);
|
|
mplew.writeMapleAsciiString(targetName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] newGuildMember(MapleGuildCharacter mgc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x27);
|
|
mplew.writeInt(mgc.getGuildId());
|
|
mplew.writeInt(mgc.getId());
|
|
mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13));
|
|
mplew.writeInt(mgc.getJobId());
|
|
mplew.writeInt(mgc.getLevel());
|
|
mplew.writeInt(mgc.getGuildRank()); //should be always 5 but whatevs
|
|
mplew.writeInt(mgc.isOnline() ? 1 : 0); //should always be 1 too
|
|
mplew.writeInt(1); //? could be guild signature, but doesn't seem to matter
|
|
mplew.writeInt(3);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
//someone leaving, mode == 0x2c for leaving, 0x2f for expelled
|
|
public static byte[] memberLeft(MapleGuildCharacter mgc, boolean bExpelled) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(bExpelled ? 0x2f : 0x2c);
|
|
mplew.writeInt(mgc.getGuildId());
|
|
mplew.writeInt(mgc.getId());
|
|
mplew.writeMapleAsciiString(mgc.getName());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
//rank change
|
|
public static byte[] changeRank(MapleGuildCharacter mgc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x40);
|
|
mplew.writeInt(mgc.getGuildId());
|
|
mplew.writeInt(mgc.getId());
|
|
mplew.write(mgc.getGuildRank());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildNotice(int gid, String notice) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x44);
|
|
mplew.writeInt(gid);
|
|
mplew.writeMapleAsciiString(notice);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildMemberLevelJobUpdate(MapleGuildCharacter mgc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x3C);
|
|
mplew.writeInt(mgc.getGuildId());
|
|
mplew.writeInt(mgc.getId());
|
|
mplew.writeInt(mgc.getLevel());
|
|
mplew.writeInt(mgc.getJobId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rankTitleChange(int gid, String[] ranks) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x3E);
|
|
mplew.writeInt(gid);
|
|
for (int i = 0; i < 5; i++) {
|
|
mplew.writeMapleAsciiString(ranks[i]);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildDisband(int gid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x32);
|
|
mplew.writeInt(gid);
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildQuestWaitingNotice(byte channel, int waitingPos) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x4C);
|
|
mplew.write(channel - 1);
|
|
mplew.write(waitingPos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildEmblemChange(int gid, short bg, byte bgcolor, short logo, byte logocolor) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x42);
|
|
mplew.writeInt(gid);
|
|
mplew.writeShort(bg);
|
|
mplew.write(bgcolor);
|
|
mplew.writeShort(logo);
|
|
mplew.write(logocolor);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guildCapacityChange(int gid, int capacity) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x3A);
|
|
mplew.writeInt(gid);
|
|
mplew.write(capacity);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static void addThread(final MaplePacketLittleEndianWriter mplew, ResultSet rs) throws SQLException {
|
|
mplew.writeInt(rs.getInt("localthreadid"));
|
|
mplew.writeInt(rs.getInt("postercid"));
|
|
mplew.writeMapleAsciiString(rs.getString("name"));
|
|
mplew.writeLong(getTime(rs.getLong("timestamp")));
|
|
mplew.writeInt(rs.getInt("icon"));
|
|
mplew.writeInt(rs.getInt("replycount"));
|
|
}
|
|
|
|
public static byte[] BBSThreadList(ResultSet rs, int start) throws SQLException {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue());
|
|
mplew.write(0x06);
|
|
if (!rs.last()) {
|
|
mplew.write(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
int threadCount = rs.getRow();
|
|
if (rs.getInt("localthreadid") == 0) { //has a notice
|
|
mplew.write(1);
|
|
addThread(mplew, rs);
|
|
threadCount--; //one thread didn't count (because it's a notice)
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
if (!rs.absolute(start + 1)) { //seek to the thread before where we start
|
|
rs.first(); //uh, we're trying to start at a place past possible
|
|
start = 0;
|
|
}
|
|
mplew.writeInt(threadCount);
|
|
mplew.writeInt(Math.min(10, threadCount - start));
|
|
for (int i = 0; i < Math.min(10, threadCount - start); i++) {
|
|
addThread(mplew, rs);
|
|
rs.next();
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showThread(int localthreadid, ResultSet threadRS, ResultSet repliesRS) throws SQLException, RuntimeException {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_BBS_PACKET.getValue());
|
|
mplew.write(0x07);
|
|
mplew.writeInt(localthreadid);
|
|
mplew.writeInt(threadRS.getInt("postercid"));
|
|
mplew.writeLong(getTime(threadRS.getLong("timestamp")));
|
|
mplew.writeMapleAsciiString(threadRS.getString("name"));
|
|
mplew.writeMapleAsciiString(threadRS.getString("startpost"));
|
|
mplew.writeInt(threadRS.getInt("icon"));
|
|
if (repliesRS != null) {
|
|
int replyCount = threadRS.getInt("replycount");
|
|
mplew.writeInt(replyCount);
|
|
int i;
|
|
for (i = 0; i < replyCount && repliesRS.next(); i++) {
|
|
mplew.writeInt(repliesRS.getInt("replyid"));
|
|
mplew.writeInt(repliesRS.getInt("postercid"));
|
|
mplew.writeLong(getTime(repliesRS.getLong("timestamp")));
|
|
mplew.writeMapleAsciiString(repliesRS.getString("content"));
|
|
}
|
|
if (i != replyCount || repliesRS.next()) {
|
|
throw new RuntimeException(String.valueOf(threadRS.getInt("threadid")));
|
|
}
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showGuildRanks(int npcid, ResultSet rs) throws SQLException {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x49);
|
|
mplew.writeInt(npcid);
|
|
if (!rs.last()) { //no guilds o.o
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
mplew.writeInt(rs.getRow()); //number of entries
|
|
rs.beforeFirst();
|
|
while (rs.next()) {
|
|
mplew.writeMapleAsciiString(rs.getString("name"));
|
|
mplew.writeInt(rs.getInt("GP"));
|
|
mplew.writeInt(rs.getInt("logo"));
|
|
mplew.writeInt(rs.getInt("logoColor"));
|
|
mplew.writeInt(rs.getInt("logoBG"));
|
|
mplew.writeInt(rs.getInt("logoBGColor"));
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showPlayerRanks(int npcid, List<Pair<String, Integer>> worldRanking) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x49);
|
|
mplew.writeInt(npcid);
|
|
if (worldRanking.isEmpty()) {
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
mplew.writeInt(worldRanking.size());
|
|
for (Pair<String, Integer> wr : worldRanking) {
|
|
mplew.writeMapleAsciiString(wr.getLeft());
|
|
mplew.writeInt(wr.getRight());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateGP(int gid, int GP) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue());
|
|
mplew.write(0x48);
|
|
mplew.writeInt(gid);
|
|
mplew.writeInt(GP);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] skillEffect(MapleCharacter from, int skillId, int level, byte flags, int speed, byte direction) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SKILL_EFFECT.getValue());
|
|
mplew.writeInt(from.getId());
|
|
mplew.writeInt(skillId);
|
|
mplew.write(level);
|
|
mplew.write(flags);
|
|
mplew.write(speed);
|
|
mplew.write(direction); //Mmmk
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] skillCancel(MapleCharacter from, int skillId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_SKILL_EFFECT.getValue());
|
|
mplew.writeInt(from.getId());
|
|
mplew.writeInt(skillId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] catchMonster(int mobOid, byte success) { // updated packet structure found thanks to Rien dev team
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CATCH_MONSTER.getValue());
|
|
mplew.writeInt(mobOid);
|
|
mplew.write(success);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] catchMonster(int mobOid, int itemid, byte success) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CATCH_MONSTER_WITH_ITEM.getValue());
|
|
mplew.writeInt(mobOid);
|
|
mplew.writeInt(itemid);
|
|
mplew.write(success);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a player hint.
|
|
*
|
|
* @param hint The hint it's going to send.
|
|
* @param width How tall the box is going to be.
|
|
* @param height How long the box is going to be.
|
|
* @return The player hint packet.
|
|
*/
|
|
public static byte[] sendHint(String hint, int width, int height) {
|
|
if (width < 1) {
|
|
width = hint.length() * 10;
|
|
if (width < 40) {
|
|
width = 40;
|
|
}
|
|
}
|
|
if (height < 5) {
|
|
height = 5;
|
|
}
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_HINT.getValue());
|
|
mplew.writeMapleAsciiString(hint);
|
|
mplew.writeShort(width);
|
|
mplew.writeShort(height);
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] messengerInvite(String from, int messengerid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x03);
|
|
mplew.writeMapleAsciiString(from);
|
|
mplew.write(0);
|
|
mplew.writeInt(messengerid);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
public static byte[] sendSpouseChat(MapleCharacter partner, String msg) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPOUSE_CHAT.getValue());
|
|
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();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x00);
|
|
mplew.write(position);
|
|
addCharLook(mplew, chr, true);
|
|
mplew.writeMapleAsciiString(from);
|
|
mplew.write(channel);
|
|
mplew.write(0x00);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeMessengerPlayer(int position) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x02);
|
|
mplew.write(position);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateMessengerPlayer(String from, MapleCharacter chr, int position, int channel) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x07);
|
|
mplew.write(position);
|
|
addCharLook(mplew, chr, true);
|
|
mplew.writeMapleAsciiString(from);
|
|
mplew.write(channel);
|
|
mplew.write(0x00);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] joinMessenger(int position) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x01);
|
|
mplew.write(position);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] messengerChat(String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(0x06);
|
|
mplew.writeMapleAsciiString(text);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] messengerNote(String text, int mode, int mode2) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MESSENGER.getValue());
|
|
mplew.write(mode);
|
|
mplew.writeMapleAsciiString(text);
|
|
mplew.write(mode2);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addPetInfo(final MaplePacketLittleEndianWriter mplew, MaplePet pet, boolean showpet) {
|
|
mplew.write(1);
|
|
if (showpet) {
|
|
mplew.write(0);
|
|
}
|
|
|
|
mplew.writeInt(pet.getItemId());
|
|
mplew.writeMapleAsciiString(pet.getName());
|
|
mplew.writeLong(pet.getUniqueId());
|
|
mplew.writePos(pet.getPos());
|
|
mplew.write(pet.getStance());
|
|
mplew.writeInt(pet.getFh());
|
|
}
|
|
|
|
public static byte[] showPet(MapleCharacter chr, MaplePet pet, boolean remove, boolean hunger) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_PET.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(chr.getPetIndex(pet));
|
|
if (remove) {
|
|
mplew.write(0);
|
|
mplew.write(hunger ? 1 : 0);
|
|
} else {
|
|
addPetInfo(mplew, pet, true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] movePet(int cid, int pid, byte slot, List<LifeMovementFragment> moves) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MOVE_PET.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(slot);
|
|
mplew.writeInt(pid);
|
|
serializeMovementList(mplew, moves);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] petChat(int cid, byte index, int act, String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PET_CHAT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(index);
|
|
mplew.write(0);
|
|
mplew.write(act);
|
|
mplew.writeMapleAsciiString(text);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] petFoodResponse(int cid, byte index, boolean success, boolean balloonType) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PET_COMMAND.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(index);
|
|
mplew.write(1);
|
|
mplew.writeBool(success);
|
|
mplew.writeBool(balloonType);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] commandResponse(int cid, byte index, boolean talk, int animation, boolean balloonType) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PET_COMMAND.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(index);
|
|
mplew.write(0);
|
|
mplew.write(animation);
|
|
mplew.writeBool(!talk);
|
|
mplew.writeBool(balloonType);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showOwnPetLevelUp(byte index) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(4);
|
|
mplew.write(0);
|
|
mplew.write(index); // Pet Index
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showPetLevelUp(MapleCharacter chr, byte index) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(4);
|
|
mplew.write(0);
|
|
mplew.write(index);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] changePetName(MapleCharacter chr, String newname, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PET_NAMECHANGE.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(0);
|
|
mplew.writeMapleAsciiString(newname);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static final byte[] loadExceptionList(final int cid, final int petId, final byte petIdx, final List<Integer> data) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PET_EXCEPTION_LIST.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(petIdx);
|
|
mplew.writeLong(petId);
|
|
mplew.write(data.size());
|
|
for (final Integer ids : data) {
|
|
mplew.writeInt(ids);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] petStatUpdate(MapleCharacter chr) {
|
|
// this actually does nothing... packet structure and stats needs to be uncovered
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.STAT_CHANGED.getValue());
|
|
int mask = 0;
|
|
mask |= MapleStat.PET.getValue();
|
|
mplew.write(0);
|
|
mplew.writeInt(mask);
|
|
MaplePet[] pets = chr.getPets();
|
|
for (int i = 0; i < 3; i++) {
|
|
if (pets[i] != null) {
|
|
mplew.writeLong(pets[i].getUniqueId());
|
|
} else {
|
|
mplew.writeLong(0);
|
|
}
|
|
}
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForcedEquip(int team) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FORCED_MAP_EQUIP.getValue());
|
|
if (team > -1) {
|
|
mplew.write(team); // 00 = red, 01 = blue
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] summonSkill(int cid, int summonSkillId, int newStance) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SUMMON_SKILL.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.writeInt(summonSkillId);
|
|
mplew.write(newStance);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] skillCooldown(int sid, int time) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.COOLDOWN.getValue());
|
|
mplew.writeInt(sid);
|
|
mplew.writeShort(time);//Int in v97
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] skillBookResult(MapleCharacter chr, int skillid, int maxlevel, boolean canuse, boolean success) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SKILL_LEARN_ITEM_RESULT.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(1);
|
|
mplew.writeInt(skillid);
|
|
mplew.writeInt(maxlevel);
|
|
mplew.write(canuse ? 1 : 0);
|
|
mplew.write(success ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMacros(SkillMacro[] macros) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MACRO_SYS_DATA_INIT.getValue());
|
|
int count = 0;
|
|
for (int i = 0; i < 5; i++) {
|
|
if (macros[i] != null) {
|
|
count++;
|
|
}
|
|
}
|
|
mplew.write(count);
|
|
for (int i = 0; i < 5; i++) {
|
|
SkillMacro macro = macros[i];
|
|
if (macro != null) {
|
|
mplew.writeMapleAsciiString(macro.getName());
|
|
mplew.write(macro.getShout());
|
|
mplew.writeInt(macro.getSkill1());
|
|
mplew.writeInt(macro.getSkill2());
|
|
mplew.writeInt(macro.getSkill3());
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showAllCharacterInfo(int worldid, List<MapleCharacter> chars, boolean usePic) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.VIEW_ALL_CHAR.getValue());
|
|
mplew.write(0);
|
|
mplew.write(worldid);
|
|
mplew.write(chars.size());
|
|
for (MapleCharacter chr : chars) {
|
|
addCharEntry(mplew, chr, true);
|
|
}
|
|
mplew.write(usePic ? 1 : 2);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateMount(int charid, MapleMount mount, boolean levelup) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_TAMING_MOB_INFO.getValue());
|
|
mplew.writeInt(charid);
|
|
mplew.writeInt(mount.getLevel());
|
|
mplew.writeInt(mount.getExp());
|
|
mplew.writeInt(mount.getTiredness());
|
|
mplew.write(levelup ? (byte) 1 : (byte) 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] crogBoatPacket(boolean type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CONTI_MOVE.getValue());
|
|
mplew.write(10);
|
|
mplew.write(type ? 4 : 5);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] boatPacket(boolean type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CONTI_STATE.getValue());
|
|
mplew.write(type ? 1 : 2);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGame(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(1);
|
|
mplew.write(0);
|
|
mplew.write(owner ? 0 : 1);
|
|
mplew.write(0);
|
|
addCharLook(mplew, minigame.getOwner(), false);
|
|
mplew.writeMapleAsciiString(minigame.getOwner().getName());
|
|
if (minigame.getVisitor() != null) {
|
|
MapleCharacter visitor = minigame.getVisitor();
|
|
mplew.write(1);
|
|
addCharLook(mplew, visitor, false);
|
|
mplew.writeMapleAsciiString(visitor.getName());
|
|
}
|
|
mplew.write(0xFF);
|
|
mplew.write(0);
|
|
mplew.writeInt(1);
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, true));
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, true));
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, true));
|
|
mplew.writeInt(minigame.getOwnerScore());
|
|
if (minigame.getVisitor() != null) {
|
|
MapleCharacter visitor = minigame.getVisitor();
|
|
mplew.write(1);
|
|
mplew.writeInt(1);
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, true));
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, true));
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, true));
|
|
mplew.writeInt(minigame.getVisitorScore());
|
|
}
|
|
mplew.write(0xFF);
|
|
mplew.writeMapleAsciiString(minigame.getDescription());
|
|
mplew.write(piece);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameReady(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.READY.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameUnReady(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.UN_READY.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameStart(MapleMiniGame game, int loser) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.START.getCode());
|
|
mplew.write(loser);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameSkipOwner(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.SKIP.getCode());
|
|
mplew.write(0x01);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameRequestTie(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.REQUEST_TIE.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameDenyTie(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ANSWER_TIE.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* 1 = Room already closed 2 = Can't enter due full cappacity 3 = Other requests at this minute
|
|
* 4 = Can't do while dead 5 = Can't do while middle event 6 = This character unable to do it
|
|
* 7, 20 = Not allowed to trade anymore 9 = Can only trade on same map 10 = May not open store near portal
|
|
* 11, 14 = Can't start game here 12 = Can't open store at this channel 13 = Can't estabilish miniroom
|
|
* 15 = Stores only an the free market 16 = Lists the rooms at FM (?) 17 = You may not enter this store
|
|
* 18 = Owner undergoing store maintenance 19 = Unable to enter tournament room 21 = Not enough mesos to enter
|
|
* 22 = Incorrect password
|
|
*
|
|
* @param status
|
|
* @return
|
|
*/
|
|
public static byte[] getMiniRoomError(int status) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(0);
|
|
mplew.write(status);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameSkipVisitor(MapleMiniGame game) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.writeShort(PlayerInteractionHandler.Action.SKIP.getCode());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameMoveOmok(MapleMiniGame game, int move1, int move2, int move3) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(12);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.MOVE_OMOK.getCode());
|
|
mplew.writeInt(move1);
|
|
mplew.writeInt(move2);
|
|
mplew.write(move3);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameNewVisitor(MapleMiniGame minigame, MapleCharacter chr, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
|
|
mplew.write(slot);
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
mplew.writeInt(1);
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.WIN, true));
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.TIE, true));
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.LOSS, true));
|
|
mplew.writeInt(minigame.getVisitorScore());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameRemoveVisitor() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] getMiniGameResult(MapleMiniGame game, int tie, int result, int forfeit) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.GET_RESULT.getCode());
|
|
|
|
int matchResultType;
|
|
if (tie == 0 && forfeit != 1) {
|
|
matchResultType = 0;
|
|
} else if (tie != 0) {
|
|
matchResultType = 1;
|
|
} else {
|
|
matchResultType = 2;
|
|
}
|
|
|
|
mplew.write(matchResultType);
|
|
mplew.writeBool(result == 2); // host/visitor wins
|
|
|
|
boolean omok = game.isOmok();
|
|
if (matchResultType == 1) {
|
|
mplew.write(0);
|
|
mplew.writeShort(0);
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses
|
|
mplew.writeInt(game.getOwnerScore()); // points
|
|
|
|
mplew.writeInt(0); // unknown
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses
|
|
mplew.writeInt(game.getVisitorScore()); // points
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties
|
|
mplew.writeInt(game.getOwner().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses
|
|
mplew.writeInt(game.getOwnerScore()); // points
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.WIN, omok)); // wins
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.TIE, omok)); // ties
|
|
mplew.writeInt(game.getVisitor().getMiniGamePoints(MiniGameResult.LOSS, omok)); // losses
|
|
mplew.writeInt(game.getVisitorScore()); // points
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMiniGameOwnerWin(MapleMiniGame game, boolean forfeit) {
|
|
return getMiniGameResult(game, 0, 1, forfeit ? 1 : 0);
|
|
}
|
|
|
|
public static byte[] getMiniGameVisitorWin(MapleMiniGame game, boolean forfeit) {
|
|
return getMiniGameResult(game, 0, 2, forfeit ? 1 : 0);
|
|
}
|
|
|
|
public static byte[] getMiniGameTie(MapleMiniGame game) {
|
|
return getMiniGameResult(game, 1, 3, 0);
|
|
}
|
|
|
|
public static byte[] getMiniGameClose(boolean visitor, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
mplew.writeBool(visitor);
|
|
mplew.write(type); /* 2 : CRASH 3 : The room has been closed 4 : You have left the room 5 : You have been expelled */
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMatchCard(MapleClient c, MapleMiniGame minigame, boolean owner, int piece) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(2);
|
|
mplew.write(2);
|
|
mplew.write(owner ? 0 : 1);
|
|
mplew.write(0);
|
|
addCharLook(mplew, minigame.getOwner(), false);
|
|
mplew.writeMapleAsciiString(minigame.getOwner().getName());
|
|
if (minigame.getVisitor() != null) {
|
|
MapleCharacter visitor = minigame.getVisitor();
|
|
mplew.write(1);
|
|
addCharLook(mplew, visitor, false);
|
|
mplew.writeMapleAsciiString(visitor.getName());
|
|
}
|
|
mplew.write(0xFF);
|
|
mplew.write(0);
|
|
mplew.writeInt(2);
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.WIN, false));
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.TIE, false));
|
|
mplew.writeInt(minigame.getOwner().getMiniGamePoints(MiniGameResult.LOSS, false));
|
|
|
|
//set vs
|
|
mplew.writeInt(minigame.getOwnerScore());
|
|
if (minigame.getVisitor() != null) {
|
|
MapleCharacter visitor = minigame.getVisitor();
|
|
mplew.write(1);
|
|
mplew.writeInt(2);
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.WIN, false));
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.TIE, false));
|
|
mplew.writeInt(visitor.getMiniGamePoints(MiniGameResult.LOSS, false));
|
|
mplew.writeInt(minigame.getVisitorScore());
|
|
}
|
|
mplew.write(0xFF);
|
|
mplew.writeMapleAsciiString(minigame.getDescription());
|
|
mplew.write(piece);
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMatchCardStart(MapleMiniGame game, int loser) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.START.getCode());
|
|
mplew.write(loser);
|
|
|
|
int last;
|
|
if (game.getMatchesToWin() > 10) {
|
|
last = 30;
|
|
} else if (game.getMatchesToWin() > 6) {
|
|
last = 20;
|
|
} else {
|
|
last = 12;
|
|
}
|
|
|
|
mplew.write(last);
|
|
for (int i = 0; i < last; i++) {
|
|
mplew.writeInt(game.getCardId(i));
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMatchCardNewVisitor(MapleMiniGame minigame, MapleCharacter chr, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
|
|
mplew.write(slot);
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
mplew.writeInt(1);
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.WIN, false));
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.TIE, false));
|
|
mplew.writeInt(chr.getMiniGamePoints(MiniGameResult.LOSS, false));
|
|
mplew.writeInt(minigame.getVisitorScore());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMatchCardSelect(MapleMiniGame game, int turn, int slot, int firstslot, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.SELECT_CARD.getCode());
|
|
mplew.write(turn);
|
|
if (turn == 1) {
|
|
mplew.write(slot);
|
|
} else if (turn == 0) {
|
|
mplew.write(slot);
|
|
mplew.write(firstslot);
|
|
mplew.write(type);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// RPS_GAME packets thanks to Arnah (Vertisy)
|
|
public static byte[] openRPSNPC() {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RPS_GAME.getValue());
|
|
mplew.write(8);// open npc
|
|
mplew.writeInt(9000019);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rpsMesoError(int mesos) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RPS_GAME.getValue());
|
|
mplew.write(0x06);
|
|
if (mesos != -1) {
|
|
mplew.writeInt(mesos);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rpsSelection(byte selection, byte answer) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RPS_GAME.getValue());
|
|
mplew.write(0x0B);// 11l
|
|
mplew.write(selection);
|
|
mplew.write(answer);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rpsMode(byte mode) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.RPS_GAME.getValue());
|
|
mplew.write(mode);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] fredrickMessage(byte operation) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FREDRICK_MESSAGE.getValue());
|
|
mplew.write(operation);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getFredrick(byte op) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FREDRICK.getValue());
|
|
mplew.write(op);
|
|
|
|
switch (op) {
|
|
case 0x24:
|
|
mplew.skip(8);
|
|
break;
|
|
default:
|
|
mplew.write(0);
|
|
break;
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getFredrick(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FREDRICK.getValue());
|
|
mplew.write(0x23);
|
|
mplew.writeInt(9030000); // Fredrick
|
|
mplew.writeInt(32272); //id
|
|
mplew.skip(5);
|
|
mplew.writeInt(chr.getMerchantNetMeso());
|
|
mplew.write(0);
|
|
try {
|
|
List<Pair<Item, MapleInventoryType>> items = ItemFactory.MERCHANT.loadItems(chr.getId(), false);
|
|
mplew.write(items.size());
|
|
|
|
for (Pair<Item, MapleInventoryType> item : items) {
|
|
addItemInfo(mplew, item.getLeft(), true);
|
|
}
|
|
} catch (SQLException e) {
|
|
e.printStackTrace();
|
|
}
|
|
mplew.skip(3);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addOmokBox(MapleCharacter chr, int ammount, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
addAnnounceBox(mplew, chr.getMiniGame(), ammount, type);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addMatchCardBox(MapleCharacter chr, int ammount, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
addAnnounceBox(mplew, chr.getMiniGame(), ammount, type);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeMinigameBox(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.UPDATE_CHAR_BOX.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerShopChat(MapleCharacter chr, String chat, byte slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
|
|
mplew.write(slot);
|
|
mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getTradeChat(MapleCharacter chr, String chat, boolean owner) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
|
|
mplew.write(owner ? 0 : 1);
|
|
mplew.writeMapleAsciiString(chr.getName() + " : " + chat);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantBox() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header.
|
|
mplew.write(0x07);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// 0: Success
|
|
// 1: The room is already closed.
|
|
// 2: You can't enter the room due to full capacity.
|
|
// 3: Other requests are being fulfilled this minute.
|
|
// 4: You can't do it while you're dead.
|
|
// 7: You are not allowed to trade other items at this point.
|
|
// 17: You may not enter this store.
|
|
// 18: The owner of the store is currently undergoing store maintenance. Please try again in a bit.
|
|
// 23: This can only be used inside the Free Market.
|
|
// default: This character is unable to do it.
|
|
public static byte[] getOwlMessage(int msg) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
|
|
mplew.writeShort(SendOpcode.SHOP_LINK_RESULT.getValue());
|
|
mplew.write(msg); // depending on the byte sent, a different message is sent.
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] owlOfMinerva(MapleClient c, int itemid, List<Pair<MaplePlayerShopItem, AbstractMapleMapObject>> hmsAvailable) {
|
|
byte itemType = ItemConstants.getInventoryType(itemid).getType();
|
|
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue()); // header.
|
|
mplew.write(6);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(itemid);
|
|
mplew.writeInt(hmsAvailable.size());
|
|
for (Pair<MaplePlayerShopItem, AbstractMapleMapObject> hme : hmsAvailable) {
|
|
MaplePlayerShopItem item = hme.getLeft();
|
|
AbstractMapleMapObject mo = hme.getRight();
|
|
|
|
if(mo instanceof MaplePlayerShop) {
|
|
MaplePlayerShop ps = (MaplePlayerShop) mo;
|
|
MapleCharacter owner = ps.getOwner();
|
|
|
|
mplew.writeMapleAsciiString(owner.getName());
|
|
mplew.writeInt(owner.getMapId());
|
|
mplew.writeMapleAsciiString(ps.getDescription());
|
|
mplew.writeInt(item.getBundles());
|
|
mplew.writeInt(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
mplew.writeInt(owner.getId());
|
|
mplew.write(owner.getClient().getChannel() - 1);
|
|
} else {
|
|
MapleHiredMerchant hm = (MapleHiredMerchant) mo;
|
|
|
|
mplew.writeMapleAsciiString(hm.getOwner());
|
|
mplew.writeInt(hm.getMapId());
|
|
mplew.writeMapleAsciiString(hm.getDescription());
|
|
mplew.writeInt(item.getBundles());
|
|
mplew.writeInt(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
mplew.writeInt(hm.getOwnerId());
|
|
mplew.write(hm.getChannel() - 1);
|
|
}
|
|
|
|
mplew.write(itemType);
|
|
if (itemType == MapleInventoryType.EQUIP.getType()) {
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getOwlOpen(List<Integer> owlLeaderboards) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
|
|
mplew.writeShort(SendOpcode.SHOP_SCANNER_RESULT.getValue());
|
|
mplew.write(7);
|
|
mplew.write(owlLeaderboards.size());
|
|
for (Integer i : owlLeaderboards) {
|
|
mplew.writeInt(i);
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] retrieveFirstMessage() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header.
|
|
mplew.write(0x09);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] remoteChannelChange(byte ch) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ENTRUSTED_SHOP_CHECK_RESULT.getValue()); // header.
|
|
mplew.write(0x10);
|
|
mplew.writeInt(0);//No idea yet
|
|
mplew.write(ch);
|
|
return mplew.getPacket();
|
|
}
|
|
/*
|
|
* Possible things for ENTRUSTED_SHOP_CHECK_RESULT
|
|
* 0x0E = 00 = Renaming Failed - Can't find the merchant, 01 = Renaming successful
|
|
* 0x10 = Changes channel to the store (Store is open at Channel 1, do you want to change channels?)
|
|
* 0x11 = You cannot sell any items when managing.. blabla
|
|
* 0x12 = FKING POPUP LOL
|
|
*/
|
|
|
|
public static byte[] getHiredMerchant(MapleCharacter chr, MapleHiredMerchant hm, boolean firstTime) {//Thanks Dustin
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(0x05);
|
|
mplew.write(0x04);
|
|
mplew.writeShort(hm.getVisitorSlotThreadsafe(chr) + 1);
|
|
mplew.writeInt(hm.getItemId());
|
|
mplew.writeMapleAsciiString("Hired Merchant");
|
|
|
|
MapleCharacter[] visitors = hm.getVisitors();
|
|
for (int i = 0; i < 3; i++) {
|
|
if (visitors[i] != null) {
|
|
mplew.write(i + 1);
|
|
addCharLook(mplew, visitors[i], false);
|
|
mplew.writeMapleAsciiString(visitors[i].getName());
|
|
}
|
|
}
|
|
mplew.write(-1);
|
|
if (hm.isOwner(chr)) {
|
|
List<Pair<String, Byte>> msgList = hm.getMessages();
|
|
|
|
mplew.writeShort(msgList.size());
|
|
for (Pair<String, Byte> stringBytePair : msgList) {
|
|
mplew.writeMapleAsciiString(stringBytePair.getLeft());
|
|
mplew.write(stringBytePair.getRight());
|
|
}
|
|
} else {
|
|
mplew.writeShort(0);
|
|
}
|
|
mplew.writeMapleAsciiString(hm.getOwner());
|
|
if (hm.isOwner(chr)) {
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(hm.getTimeOpen());
|
|
mplew.write(firstTime ? 1 : 0);
|
|
List<MapleHiredMerchant.SoldItem> sold = hm.getSold();
|
|
mplew.write(sold.size());
|
|
for (MapleHiredMerchant.SoldItem s : sold) {
|
|
mplew.writeInt(s.getItemId());
|
|
mplew.writeShort(s.getQuantity());
|
|
mplew.writeInt(s.getMesos());
|
|
mplew.writeMapleAsciiString(s.getBuyer());
|
|
}
|
|
mplew.writeInt(chr.getMerchantMeso());//:D?
|
|
}
|
|
mplew.writeMapleAsciiString(hm.getDescription());
|
|
mplew.write(0x10); //TODO SLOTS, which is 16 for most stores...slotMax
|
|
mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso());
|
|
mplew.write(hm.getItems().size());
|
|
if (hm.getItems().isEmpty()) {
|
|
mplew.write(0);//Hmm??
|
|
} else {
|
|
for (MaplePlayerShopItem item : hm.getItems()) {
|
|
mplew.writeShort(item.getBundles());
|
|
mplew.writeShort(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateHiredMerchant(MapleHiredMerchant hm, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.UPDATE_MERCHANT.getCode());
|
|
mplew.writeInt(hm.isOwner(chr) ? chr.getMerchantMeso() : chr.getMeso());
|
|
mplew.write(hm.getItems().size());
|
|
for (MaplePlayerShopItem item : hm.getItems()) {
|
|
mplew.writeShort(item.getBundles());
|
|
mplew.writeShort(item.getItem().getQuantity());
|
|
mplew.writeInt(item.getPrice());
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantChat(String message, byte slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT.getCode());
|
|
mplew.write(PlayerInteractionHandler.Action.CHAT_THING.getCode());
|
|
mplew.write(slot);
|
|
mplew.writeMapleAsciiString(message);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantVisitorLeave(int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
if (slot != 0) {
|
|
mplew.write(slot);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantOwnerLeave() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantOwnerMaintenanceLeave() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.REAL_CLOSE_MERCHANT.getCode());
|
|
mplew.write(5);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantMaintenanceMessage() {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.ROOM.getCode());
|
|
mplew.write(0x00);
|
|
mplew.write(0x12);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] leaveHiredMerchant(int slot, int status2) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.EXIT.getCode());
|
|
mplew.write(slot);
|
|
mplew.write(status2);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hiredMerchantVisitorAdd(MapleCharacter chr, int slot) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(PlayerInteractionHandler.Action.VISIT.getCode());
|
|
mplew.write(slot);
|
|
addCharLook(mplew, chr, false);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnHiredMerchantBox(MapleHiredMerchant hm) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_HIRED_MERCHANT.getValue());
|
|
mplew.writeInt(hm.getOwnerId());
|
|
mplew.writeInt(hm.getItemId());
|
|
mplew.writeShort((short) hm.getPosition().getX());
|
|
mplew.writeShort((short) hm.getPosition().getY());
|
|
mplew.writeShort(0);
|
|
mplew.writeMapleAsciiString(hm.getOwner());
|
|
mplew.write(0x05);
|
|
mplew.writeInt(hm.getObjectId());
|
|
mplew.writeMapleAsciiString(hm.getDescription());
|
|
mplew.write(hm.getItemId() % 100);
|
|
mplew.write(new byte[]{1, 4});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeHiredMerchantBox(int id) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DESTROY_HIRED_MERCHANT.getValue());
|
|
mplew.writeInt(id);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnPlayerNPC(MaplePlayerNPC npc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(npc.getObjectId());
|
|
mplew.writeInt(npc.getScriptId());
|
|
mplew.writeShort(npc.getPosition().x);
|
|
mplew.writeShort(npc.getCY());
|
|
mplew.write(npc.getDirection());
|
|
mplew.writeShort(npc.getFH());
|
|
mplew.writeShort(npc.getRX0());
|
|
mplew.writeShort(npc.getRX1());
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getPlayerNPC(MaplePlayerNPC npc) { // thanks to Arnah
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue());
|
|
mplew.write(0x01);
|
|
mplew.writeInt(npc.getScriptId());
|
|
mplew.writeMapleAsciiString(npc.getName());
|
|
mplew.write(npc.getGender());
|
|
mplew.write(npc.getSkin());
|
|
mplew.writeInt(npc.getFace());
|
|
mplew.write(0);
|
|
mplew.writeInt(npc.getHair());
|
|
Map<Short, Integer> equip = npc.getEquips();
|
|
Map<Short, Integer> myEquip = new LinkedHashMap<>();
|
|
Map<Short, Integer> maskedEquip = new LinkedHashMap<>();
|
|
for(short position : equip.keySet()) {
|
|
short pos = (byte) (position * -1);
|
|
if(pos < 100 && myEquip.get(pos) == null) {
|
|
myEquip.put(pos, equip.get(position));
|
|
} else if((pos > 100 && pos != 111) || pos == -128) { // don't ask. o.o
|
|
pos -= 100;
|
|
if(myEquip.get(pos) != null) {
|
|
maskedEquip.put(pos, myEquip.get(pos));
|
|
}
|
|
myEquip.put(pos, equip.get(position));
|
|
} else if(myEquip.get(pos) != null) {
|
|
maskedEquip.put(pos, equip.get(position));
|
|
}
|
|
}
|
|
for(Entry<Short, Integer> entry : myEquip.entrySet()) {
|
|
mplew.write(entry.getKey());
|
|
mplew.writeInt(entry.getValue());
|
|
}
|
|
mplew.write(0xFF);
|
|
for(Entry<Short, Integer> entry : maskedEquip.entrySet()) {
|
|
mplew.write(entry.getKey());
|
|
mplew.writeInt(entry.getValue());
|
|
}
|
|
mplew.write(0xFF);
|
|
Integer cWeapon = equip.get((byte) -111);
|
|
if(cWeapon != null) {
|
|
mplew.writeInt(cWeapon);
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
for(int i = 0; i < 3; i++) {
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removePlayerNPC(int oid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.IMITATED_NPC_DATA.getValue());
|
|
mplew.write(0x00);
|
|
mplew.writeInt(oid);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendYellowTip(String tip) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_WEEK_EVENT_MESSAGE.getValue());
|
|
mplew.write(0xFF);
|
|
mplew.writeMapleAsciiString(tip);
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] givePirateBuff(List<Pair<MapleBuffStat, Integer>> statups, int buffid, int duration) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION;
|
|
mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
|
|
writeLongMask(mplew, statups);
|
|
mplew.writeShort(0);
|
|
for (Pair<MapleBuffStat, Integer> stat : statups) {
|
|
mplew.writeInt(stat.getRight().shortValue());
|
|
mplew.writeInt(buffid);
|
|
mplew.skip(infusion ? 10 : 5);
|
|
mplew.writeShort(duration);
|
|
}
|
|
mplew.skip(3);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] giveForeignPirateBuff(int cid, int buffid, int time, List<Pair<MapleBuffStat, Integer>> statups) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
boolean infusion = buffid == Buccaneer.SPEED_INFUSION || buffid == ThunderBreaker.SPEED_INFUSION || buffid == Corsair.SPEED_INFUSION;
|
|
mplew.writeShort(SendOpcode.GIVE_FOREIGN_BUFF.getValue());
|
|
mplew.writeInt(cid);
|
|
writeLongMask(mplew, statups);
|
|
mplew.writeShort(0);
|
|
for (Pair<MapleBuffStat, Integer> statup : statups) {
|
|
mplew.writeInt(statup.getRight().shortValue());
|
|
mplew.writeInt(buffid);
|
|
mplew.skip(infusion ? 10 : 5);
|
|
mplew.writeShort(time);
|
|
}
|
|
mplew.writeShort(0);
|
|
mplew.write(2);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendMTS(List<MTSItemInfo> items, int tab, int type, int page, int pages) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x15); //operation
|
|
mplew.writeInt(pages * 16); //testing, change to 10 if fails
|
|
mplew.writeInt(items.size()); //number of items
|
|
mplew.writeInt(tab);
|
|
mplew.writeInt(type);
|
|
mplew.writeInt(page);
|
|
mplew.write(1);
|
|
mplew.write(1);
|
|
for (MTSItemInfo item : items) {
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
mplew.writeInt(item.getID()); //id
|
|
mplew.writeInt(item.getTaxes()); //this + below = price
|
|
mplew.writeInt(item.getPrice()); //price
|
|
mplew.writeInt(0);
|
|
mplew.writeLong(getTime(item.getEndingDate()));
|
|
mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?)
|
|
mplew.writeMapleAsciiString(item.getSeller()); //char name
|
|
for (int j = 0; j < 28; j++) {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] noteSendMsg() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.MEMO_RESULT.getValue());
|
|
mplew.write(4);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
* 0 = Player online, use whisper
|
|
* 1 = Check player's name
|
|
* 2 = Receiver inbox full
|
|
*/
|
|
public static byte[] noteError(byte error) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.MEMO_RESULT.getValue());
|
|
mplew.write(5);
|
|
mplew.write(error);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showNotes(ResultSet notes, int count) throws SQLException {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MEMO_RESULT.getValue());
|
|
mplew.write(3);
|
|
mplew.write(count);
|
|
for (int i = 0; i < count; i++) {
|
|
mplew.writeInt(notes.getInt("id"));
|
|
mplew.writeMapleAsciiString(notes.getString("from") + " ");//Stupid nexon forgot space lol
|
|
mplew.writeMapleAsciiString(notes.getString("message"));
|
|
mplew.writeLong(getTime(notes.getLong("timestamp")));
|
|
mplew.write(notes.getByte("fame"));//FAME :D
|
|
notes.next();
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] useChalkboard(MapleCharacter chr, boolean close) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CHALKBOARD.getValue());
|
|
mplew.writeInt(chr.getId());
|
|
if (close) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(1);
|
|
mplew.writeMapleAsciiString(chr.getChalkboard());
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] trockRefreshMapList(MapleCharacter chr, boolean delete, boolean vip) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAP_TRANSFER_RESULT.getValue());
|
|
mplew.write(delete ? 2 : 3);
|
|
if (vip) {
|
|
mplew.write(1);
|
|
List<Integer> map = chr.getVipTrockMaps();
|
|
for (int i = 0; i < 10; i++) {
|
|
mplew.writeInt(map.get(i));
|
|
}
|
|
} else {
|
|
mplew.write(0);
|
|
List<Integer> map = chr.getTrockMaps();
|
|
for (int i = 0; i < 5; i++) {
|
|
mplew.writeInt(map.get(i));
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/* 1: cannot find char info,
|
|
2: cannot transfer under 20,
|
|
3: cannot send banned,
|
|
4: cannot send married,
|
|
5: cannot send guild leader,
|
|
6: cannot send if account already requested transfer,
|
|
7: cannot transfer within 30days,
|
|
8: must quit family,
|
|
9: unknown error
|
|
*/
|
|
public static byte[] sendWorldTransferRules(int error, MapleClient c) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_CHECK_TRANSFER_WORLD_POSSIBLE_RESULT.getValue());
|
|
mplew.writeInt(0); //ignored
|
|
mplew.write(error);
|
|
mplew.writeInt(0);
|
|
mplew.writeBool(error == 0); //0 = ?, otherwise list servers
|
|
if(error == 0) {
|
|
List<World> worlds = Server.getInstance().getWorlds();
|
|
mplew.writeInt(worlds.size());
|
|
for(World world : worlds) {
|
|
mplew.writeMapleAsciiString(GameConstants.WORLD_NAMES[world.getId()]);
|
|
}
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showWorldTransferSuccess(Item item, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0xA0);
|
|
addCashItemInformation(mplew, item, accountId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/* 0: no error, send rules
|
|
1: name change already submitted
|
|
2: name change within a month
|
|
3: recently banned
|
|
4: unknown error
|
|
*/
|
|
public static byte[] sendNameTransferRules(int error) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE_POSSIBLE_RESULT.getValue());
|
|
mplew.writeInt(0);
|
|
mplew.write(error);
|
|
mplew.writeInt(0);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/* 0: Name available
|
|
* >0: Name is in use
|
|
* <0: Unknown error
|
|
*/
|
|
|
|
public static byte[] sendNameTransferCheck(String availableName, boolean canUseName) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_CHECK_NAME_CHANGE.getValue());
|
|
//Send provided name back to client to add to temporary cache of checked & accepted names
|
|
mplew.writeMapleAsciiString(availableName);
|
|
mplew.writeBool(!canUseName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showNameChangeSuccess(Item item, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0x9E);
|
|
addCashItemInformation(mplew, item, accountId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showNameChangeCancel(boolean success) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_NAME_CHANGE_RESULT.getValue());
|
|
mplew.writeBool(success);
|
|
if(!success) mplew.write(0);
|
|
//mplew.writeMapleAsciiString("Custom message."); //only if ^ != 0
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showWorldTransferCancel(boolean success) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CANCEL_TRANSFER_WORLD_RESULT.getValue());
|
|
mplew.writeBool(success);
|
|
if(!success) mplew.write(0);
|
|
//mplew.writeMapleAsciiString("Custom message."); //only if ^ != 0
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showMTSCash(MapleCharacter p) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION2.getValue());
|
|
mplew.writeInt(p.getCashShop().getCash(4));
|
|
mplew.writeInt(p.getCashShop().getCash(2));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] MTSWantedListingOver(int nx, int items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x3D);
|
|
mplew.writeInt(nx);
|
|
mplew.writeInt(items);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] MTSConfirmSell() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x1D);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] MTSConfirmBuy() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x33);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] MTSFailBuy() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x34);
|
|
mplew.write(0x42);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] MTSConfirmTransfer(int quantity, int pos) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x27);
|
|
mplew.writeInt(quantity);
|
|
mplew.writeInt(pos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] notYetSoldInv(List<MTSItemInfo> items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x23);
|
|
mplew.writeInt(items.size());
|
|
if (!items.isEmpty()) {
|
|
for (MTSItemInfo item : items) {
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
mplew.writeInt(item.getID()); //id
|
|
mplew.writeInt(item.getTaxes()); //this + below = price
|
|
mplew.writeInt(item.getPrice()); //price
|
|
mplew.writeInt(0);
|
|
mplew.writeLong(getTime(item.getEndingDate()));
|
|
mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?)
|
|
mplew.writeMapleAsciiString(item.getSeller()); //char name
|
|
for (int i = 0; i < 28; i++) {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
} else {
|
|
mplew.writeInt(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] transferInventory(List<MTSItemInfo> items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MTS_OPERATION.getValue());
|
|
mplew.write(0x21);
|
|
mplew.writeInt(items.size());
|
|
if (!items.isEmpty()) {
|
|
for (MTSItemInfo item : items) {
|
|
addItemInfo(mplew, item.getItem(), true);
|
|
mplew.writeInt(item.getID()); //id
|
|
mplew.writeInt(item.getTaxes()); //taxes
|
|
mplew.writeInt(item.getPrice()); //price
|
|
mplew.writeInt(0);
|
|
mplew.writeLong(getTime(item.getEndingDate()));
|
|
mplew.writeMapleAsciiString(item.getSeller()); //account name (what was nexon thinking?)
|
|
mplew.writeMapleAsciiString(item.getSeller()); //char name
|
|
for (int i = 0; i < 28; i++) {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
}
|
|
mplew.write(0xD0 + items.size());
|
|
mplew.write(new byte[]{-1, -1, -1, 0});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showCouponRedeemedItems(int accountId, int maplePoints, int mesos, List<Item> cashItems, List<Pair<Integer, Integer>> items) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0x59);
|
|
mplew.write((byte)cashItems.size());
|
|
for(Item item : cashItems) {
|
|
addCashItemInformation(mplew, item, accountId);
|
|
}
|
|
mplew.writeInt(maplePoints);
|
|
mplew.writeInt(items.size());
|
|
for(Pair<Integer, Integer> itemPair : items) {
|
|
int quantity = itemPair.getLeft();
|
|
mplew.writeShort((short) quantity); //quantity (0 = 1 for cash items)
|
|
mplew.writeShort(0x1F); //0 = ?, >=0x20 = ?, <0x20 = ? (does nothing?)
|
|
mplew.writeInt(itemPair.getRight());
|
|
}
|
|
mplew.writeInt(mesos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showCash(MapleCharacter mc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.QUERY_CASH_RESULT.getValue());
|
|
|
|
mplew.writeInt(mc.getCashShop().getCash(1));
|
|
mplew.writeInt(mc.getCashShop().getCash(2));
|
|
mplew.writeInt(mc.getCashShop().getCash(4));
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] enableCSUse(MapleCharacter mc) {
|
|
return showCash(mc);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param target
|
|
* @param mapid
|
|
* @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel
|
|
* @return
|
|
*/
|
|
public static byte[] getFindReply(String target, int mapid, int MTSmapCSchannel) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.WHISPER.getValue());
|
|
mplew.write(9);
|
|
mplew.writeMapleAsciiString(target);
|
|
mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs
|
|
mplew.writeInt(mapid); // -1 if mts, cs
|
|
if (MTSmapCSchannel == 1) {
|
|
mplew.write(new byte[8]);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param target
|
|
* @param mapid
|
|
* @param MTSmapCSchannel 0: MTS 1: Map 2: CS 3: Different Channel
|
|
* @return
|
|
*/
|
|
public static byte[] getBuddyFindReply(String target, int mapid, int MTSmapCSchannel) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.WHISPER.getValue());
|
|
mplew.write(72);
|
|
mplew.writeMapleAsciiString(target);
|
|
mplew.write(MTSmapCSchannel); // 0: mts 1: map 2: cs
|
|
mplew.writeInt(mapid); // -1 if mts, cs
|
|
if (MTSmapCSchannel == 1) {
|
|
mplew.write(new byte[8]);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendAutoHpPot(int itemId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.AUTO_HP_POT.getValue());
|
|
mplew.writeInt(itemId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendAutoMpPot(int itemId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.AUTO_MP_POT.getValue());
|
|
mplew.writeInt(itemId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showOXQuiz(int questionSet, int questionId, boolean askQuestion) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.OX_QUIZ.getValue());
|
|
mplew.write(askQuestion ? 1 : 0);
|
|
mplew.write(questionSet);
|
|
mplew.writeShort(questionId);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateGender(MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.SET_GENDER.getValue());
|
|
mplew.write(chr.getGender());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] enableReport() { // thanks to snow
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.CLAIM_STATUS_CHANGED.getValue());
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] giveFinalAttack(int skillid, int time) { // packets found thanks to lailainoob
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GIVE_BUFF.getValue());
|
|
mplew.writeLong(0);
|
|
mplew.writeShort(0);
|
|
mplew.write(0);//some 80 and 0 bs DIRECTION
|
|
mplew.write(0x80);//let's just do 80, then 0
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(1);
|
|
mplew.writeInt(skillid);
|
|
mplew.writeInt(time);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] loadFamily(MapleCharacter player) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_PRIVILEGE_LIST.getValue());
|
|
mplew.writeInt(MapleFamilyEntitlement.values().length);
|
|
for (int i = 0; i < MapleFamilyEntitlement.values().length; i++) {
|
|
MapleFamilyEntitlement entitlement = MapleFamilyEntitlement.values()[i];
|
|
mplew.write(i <= 1 ? 1 : 2); //type
|
|
mplew.writeInt(entitlement.getRepCost());
|
|
mplew.writeInt(entitlement.getUsageLimit());
|
|
mplew.writeMapleAsciiString(entitlement.getName());
|
|
mplew.writeMapleAsciiString(entitlement.getDescription());
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Family Result Message
|
|
*
|
|
* Possible values for <code>type</code>:<br>
|
|
* 64: You cannot add this character as a junior.
|
|
* 65: The name could not be found or is not online.
|
|
* 66: You belong to the same family.
|
|
* 67: You do not belong to the same family.<br>
|
|
* 69: The character you wish to add as\r\na Junior must be in the same
|
|
* map.<br>
|
|
* 70: This character is already a Junior of another character.<br>
|
|
* 71: The Junior you wish to add\r\nmust be at a lower rank.<br>
|
|
* 72: The gap between you and your\r\njunior must be within 20 levels.<br>
|
|
* 73: Another character has requested to add this character.\r\nPlease try
|
|
* again later.<br>
|
|
* 74: Another character has requested a summon.\r\nPlease try again
|
|
* later.<br>
|
|
* 75: The summons has failed. Your current location or state does not allow
|
|
* a summons.<br>
|
|
* 76: The family cannot extend more than 1000 generations from above and
|
|
* below.<br>
|
|
* 77: The Junior you wish to add\r\nmust be over Level 10.<br>
|
|
* 78: You cannot add a Junior \r\nthat has requested to change worlds.<br>
|
|
* 79: You cannot add a Junior \r\nsince you've requested to change
|
|
* worlds.<br>
|
|
* 80: Separation is not possible due to insufficient Mesos.\r\nYou will
|
|
* need %d Mesos to\r\nseparate with a Senior.<br>
|
|
* 81: Separation is not possible due to insufficient Mesos.\r\nYou will
|
|
* need %d Mesos to\r\nseparate with a Junior.<br>
|
|
* 82: The Entitlement does not apply because your level does not match the
|
|
* corresponding area.<br>
|
|
*
|
|
* @param type The type
|
|
* @return Family Result packet
|
|
*/
|
|
public static byte[] sendFamilyMessage(int type, int mesos) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.FAMILY_RESULT.getValue());
|
|
mplew.writeInt(type);
|
|
mplew.writeInt(mesos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getFamilyInfo(MapleFamilyEntry f) {
|
|
if(f == null) return getEmptyFamilyInfo();
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_INFO_RESULT.getValue());
|
|
mplew.writeInt(f.getReputation()); // cur rep left
|
|
mplew.writeInt(f.getTotalReputation()); // tot rep left
|
|
mplew.writeInt(f.getTodaysRep()); // todays rep
|
|
mplew.writeShort(f.getJuniorCount()); // juniors added
|
|
mplew.writeShort(2); // juniors allowed
|
|
mplew.writeShort(0); //Unknown
|
|
mplew.writeInt(f.getFamily().getLeader().getChrId()); // Leader ID (Allows setting message)
|
|
mplew.writeMapleAsciiString(f.getFamily().getName());
|
|
mplew.writeMapleAsciiString(f.getFamily().getMessage()); //family message
|
|
mplew.writeInt(MapleFamilyEntitlement.values().length); //Entitlement info count
|
|
for(MapleFamilyEntitlement entitlement : MapleFamilyEntitlement.values()) {
|
|
mplew.writeInt(entitlement.ordinal()); //ID
|
|
mplew.writeInt(f.isEntitlementUsed(entitlement) ? 1 : 0); //Used count
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] getEmptyFamilyInfo() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_INFO_RESULT.getValue());
|
|
mplew.writeInt(0); // cur rep left
|
|
mplew.writeInt(0); // tot rep left
|
|
mplew.writeInt(0); // todays rep
|
|
mplew.writeShort(0); // juniors added
|
|
mplew.writeShort(2); // juniors allowed
|
|
mplew.writeShort(0); //Unknown
|
|
mplew.writeInt(0); // Leader ID (Allows setting message)
|
|
mplew.writeMapleAsciiString("");
|
|
mplew.writeMapleAsciiString(""); //family message
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showPedigree(MapleFamilyEntry entry) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_CHART_RESULT.getValue());
|
|
mplew.writeInt(entry.getChrId()); //ID of viewed player's pedigree, can't be leader?
|
|
List<MapleFamilyEntry> superJuniors = new ArrayList<>(4);
|
|
boolean hasOtherJunior = false;
|
|
int entryCount = 2; //2 guaranteed, leader and self
|
|
entryCount += Math.min(2, entry.getTotalSeniors());
|
|
//needed since MaplePacketLittleEndianWriter doesn't have any seek functionality
|
|
if(entry.getSenior() != null) {
|
|
if(entry.getSenior().getJuniorCount() == 2) {
|
|
entryCount++;
|
|
hasOtherJunior = true;
|
|
}
|
|
}
|
|
for(MapleFamilyEntry junior : entry.getJuniors()) {
|
|
if(junior == null) continue;
|
|
entryCount++;
|
|
for(MapleFamilyEntry superJunior : junior.getJuniors()) {
|
|
if(superJunior == null) continue;
|
|
entryCount++;
|
|
superJuniors.add(superJunior);
|
|
}
|
|
}
|
|
//write entries
|
|
boolean missingEntries = entryCount == 2; //pedigree requires at least 3 entries to show leader, might only have 2 if leader's juniors leave
|
|
if(missingEntries) entryCount++;
|
|
mplew.writeInt(entryCount); //player count
|
|
addPedigreeEntry(mplew, entry.getFamily().getLeader());
|
|
if(entry.getSenior() != null) {
|
|
if(entry.getSenior().getSenior() != null) addPedigreeEntry(mplew, entry.getSenior().getSenior());
|
|
addPedigreeEntry(mplew, entry.getSenior());
|
|
}
|
|
addPedigreeEntry(mplew, entry);
|
|
if(hasOtherJunior) { //must be sent after own entry
|
|
MapleFamilyEntry otherJunior = entry.getSenior().getOtherJunior(entry);
|
|
if(otherJunior != null) addPedigreeEntry(mplew, otherJunior);
|
|
}
|
|
if(missingEntries) addPedigreeEntry(mplew, entry);
|
|
for(MapleFamilyEntry junior : entry.getJuniors()) {
|
|
if(junior == null) continue;
|
|
addPedigreeEntry(mplew, junior);
|
|
for(MapleFamilyEntry superJunior : junior.getJuniors()) {
|
|
if(superJunior != null) addPedigreeEntry(mplew, superJunior);
|
|
}
|
|
}
|
|
mplew.writeInt(2 + superJuniors.size()); //member info count
|
|
// 0 = total seniors, -1 = total members, otherwise junior count of ID
|
|
mplew.writeInt(-1);
|
|
mplew.writeInt(entry.getFamily().getTotalMembers());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(entry.getTotalSeniors()); //client subtracts provided seniors
|
|
for(MapleFamilyEntry superJunior : superJuniors) {
|
|
mplew.writeInt(superJunior.getChrId());
|
|
mplew.writeInt(superJunior.getTotalJuniors());
|
|
}
|
|
mplew.writeInt(0); //another loop count (entitlements used)
|
|
//mplew.writeInt(1); //entitlement index
|
|
//mplew.writeInt(2); //times used
|
|
mplew.writeShort(entry.getJuniorCount() >= 2 ? 0 : 2); //0 disables Add button (only if viewing own pedigree)
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addPedigreeEntry(MaplePacketLittleEndianWriter mplew, MapleFamilyEntry entry) {
|
|
MapleCharacter chr = entry.getChr();
|
|
boolean isOnline = chr != null;
|
|
mplew.writeInt(entry.getChrId()); //ID
|
|
mplew.writeInt(entry.getSenior() != null ? entry.getSenior().getChrId() : 0); //parent ID
|
|
mplew.writeShort(entry.getJob().getId()); //job id
|
|
mplew.write(entry.getLevel()); //level
|
|
mplew.writeBool(isOnline); //isOnline
|
|
mplew.writeInt(entry.getReputation()); //current rep
|
|
mplew.writeInt(entry.getTotalReputation()); //total rep
|
|
mplew.writeInt(entry.getRepsToSenior()); //reps recorded to senior
|
|
mplew.writeInt(entry.getTodaysRep());
|
|
mplew.writeInt(isOnline ? ((chr.isAwayFromWorld() || chr.getCashShop().isOpened()) ? -1 : chr.getClient().getChannel() - 1) : 0);
|
|
mplew.writeInt(isOnline ? (int) (chr.getLoggedInTime() / 60000) : 0); //time online in minutes
|
|
mplew.writeMapleAsciiString(entry.getName()); //name
|
|
}
|
|
|
|
public static byte[] updateAreaInfo(int area, String info) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(0x0A); //0x0B in v95
|
|
mplew.writeShort(area);//infoNumber
|
|
mplew.writeMapleAsciiString(info);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getGPMessage(int gpChange) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(6);
|
|
mplew.writeInt(gpChange);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getItemMessage(int itemid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(7);
|
|
mplew.writeInt(itemid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addCard(boolean full, int cardid, int level) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11);
|
|
mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_CARD.getValue());
|
|
mplew.write(full ? 0 : 1);
|
|
mplew.writeInt(cardid);
|
|
mplew.writeInt(level);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showGainCard() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(0x0D);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForeignCardEffect(int id) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(id);
|
|
mplew.write(0x0D);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] changeCover(int cardid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.MONSTER_BOOK_SET_COVER.getValue());
|
|
mplew.writeInt(cardid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] aranGodlyStats() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FORCED_STAT_SET.getValue());
|
|
mplew.write(new byte[]{(byte) 0x1F, (byte) 0x0F, 0, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0xFF, 0, (byte) 0xE7, 3, (byte) 0xE7, 3, (byte) 0x78, (byte) 0x8C});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showIntro(String path) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(0x12);
|
|
mplew.writeMapleAsciiString(path);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showInfo(String path) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(0x17);
|
|
mplew.writeMapleAsciiString(path);
|
|
mplew.writeInt(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForeignInfo(int cid, String path) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(0x17);
|
|
mplew.writeMapleAsciiString(path);
|
|
mplew.writeInt(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a UI utility. 0x01 - Equipment Inventory. 0x02 - Stat Window. 0x03
|
|
* - Skill Window. 0x05 - Keyboard Settings. 0x06 - Quest window. 0x09 -
|
|
* Monsterbook Window. 0x0A - Char Info 0x0B - Guild BBS 0x12 - Monster
|
|
* Carnival Window 0x16 - Party Search. 0x17 - Item Creation Window. 0x1A -
|
|
* My Ranking O.O 0x1B - Family Window 0x1C - Family Pedigree 0x1D - GM
|
|
* Story Board /funny shet 0x1E - Envelop saying you got mail from an admin.
|
|
* lmfao 0x1F - Medal Window 0x20 - Maple Event (???) 0x21 - Invalid Pointer
|
|
* Crash
|
|
*
|
|
* @param ui
|
|
* @return
|
|
*/
|
|
public static byte[] openUI(byte ui) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.OPEN_UI.getValue());
|
|
mplew.write(ui);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] lockUI(boolean enable) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.LOCK_UI.getValue());
|
|
mplew.write(enable ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] disableUI(boolean enable) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DISABLE_UI.getValue());
|
|
mplew.write(enable ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] itemMegaphone(String msg, boolean whisper, int channel, Item item) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue());
|
|
mplew.write(8);
|
|
mplew.writeMapleAsciiString(msg);
|
|
mplew.write(channel - 1);
|
|
mplew.write(whisper ? 1 : 0);
|
|
if (item == null) {
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.write(item.getPosition());
|
|
addItemInfo(mplew, item, true);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeNPC(int oid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_NPC.getValue());
|
|
mplew.writeInt(oid);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeNPCController(int objectid) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
|
|
mplew.writeShort(SendOpcode.SPAWN_NPC_REQUEST_CONTROLLER.getValue());
|
|
mplew.write(0);
|
|
mplew.writeInt(objectid);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a report response
|
|
*
|
|
* Possible values for <code>mode</code>:<br> 0: You have succesfully
|
|
* reported the user.<br> 1: Unable to locate the user.<br> 2: You may only
|
|
* report users 10 times a day.<br> 3: You have been reported to the GM's by
|
|
* a user.<br> 4: Your request did not go through for unknown reasons.
|
|
* Please try again later.<br>
|
|
*
|
|
* @param mode The mode
|
|
* @return Report Reponse packet
|
|
*/
|
|
public static byte[] reportResponse(byte mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SUE_CHARACTER_RESULT.getValue());
|
|
mplew.write(mode);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendHammerData(int hammerUsed) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue());
|
|
mplew.write(0x39);
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(hammerUsed);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendHammerMessage() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.VICIOUS_HAMMER.getValue());
|
|
mplew.write(0x3D);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] playPortalSound() {
|
|
return showSpecialEffect(7);
|
|
}
|
|
|
|
public static byte[] showMonsterBookPickup() {
|
|
return showSpecialEffect(14);
|
|
}
|
|
|
|
public static byte[] showEquipmentLevelUp() {
|
|
return showSpecialEffect(15);
|
|
}
|
|
|
|
public static byte[] showItemLevelup() {
|
|
return showSpecialEffect(15);
|
|
}
|
|
|
|
public static byte[] showBuybackEffect() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(11);
|
|
mplew.writeInt(0);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForeignBuybackEffect(int cid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(11);
|
|
mplew.writeInt(0);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* 0 = Levelup 6 = Exp did not drop (Safety Charms) 7 = Enter portal sound
|
|
* 8 = Job change 9 = Quest complete 10 = Recovery 11 = Buff effect
|
|
* 14 = Monster book pickup 15 = Equipment levelup 16 = Maker Skill Success
|
|
* 17 = Buff effect w/ sfx 19 = Exp card [500, 200, 50] 21 = Wheel of destiny
|
|
* 26 = Spirit Stone
|
|
*
|
|
* @param effect
|
|
* @return
|
|
*/
|
|
public static byte[] showSpecialEffect(int effect) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(effect);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showMakerEffect(boolean makerSucceeded) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(16);
|
|
mplew.writeInt(makerSucceeded ? 0 : 1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForeignMakerEffect(int cid, boolean makerSucceeded) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(16);
|
|
mplew.writeInt(makerSucceeded ? 0 : 1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showForeignEffect(int effect) {
|
|
return showForeignEffect(-1, effect);
|
|
}
|
|
|
|
public static byte[] showForeignEffect(int cid, int effect) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(effect);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showOwnRecovery(byte heal) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(0x0A);
|
|
mplew.write(heal);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showRecovery(int cid, byte amount) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_FOREIGN_EFFECT.getValue());
|
|
mplew.writeInt(cid);
|
|
mplew.write(0x0A);
|
|
mplew.write(amount);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showWheelsLeft(int left) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_ITEM_GAIN_INCHAT.getValue());
|
|
mplew.write(0x15);
|
|
mplew.write(left);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateQuestFinish(short quest, int npc, short nextquest) { //Check
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue()); //0xF2 in v95
|
|
mplew.write(8);//0x0A in v95
|
|
mplew.writeShort(quest);
|
|
mplew.writeInt(npc);
|
|
mplew.writeShort(nextquest);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showInfoText(String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(9);
|
|
mplew.writeMapleAsciiString(text);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] questError(short quest) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(0x0A);
|
|
mplew.writeShort(quest);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] questFailure(byte type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(type);//0x0B = No meso, 0x0D = Worn by character, 0x0E = Not having the item ?
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] questExpire(short quest) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());
|
|
mplew.write(0x0F);
|
|
mplew.writeShort(quest);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// MAKER_RESULT packets thanks to Arnah (Vertisy)
|
|
public static byte[] makerResult(boolean success, int itemMade, int itemCount, int mesos, List<Pair<Integer, Integer>> itemsLost, int catalystID, List<Integer> INCBuffGems) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAKER_RESULT.getValue());
|
|
mplew.writeInt(success ? 0 : 1); // 0 = success, 1 = fail
|
|
mplew.writeInt(1); // 1 or 2 doesn't matter, same methods
|
|
mplew.writeBool(!success);
|
|
if (success) {
|
|
mplew.writeInt(itemMade);
|
|
mplew.writeInt(itemCount);
|
|
}
|
|
mplew.writeInt(itemsLost.size()); // Loop
|
|
for (Pair<Integer, Integer> item : itemsLost) {
|
|
mplew.writeInt(item.getLeft());
|
|
mplew.writeInt(item.getRight());
|
|
}
|
|
mplew.writeInt(INCBuffGems.size());
|
|
for (Integer gem : INCBuffGems) {
|
|
mplew.writeInt(gem);
|
|
}
|
|
if (catalystID != -1) {
|
|
mplew.write(1); // stimulator
|
|
mplew.writeInt(catalystID);
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
|
|
mplew.writeInt(mesos);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] makerResultCrystal(int itemIdGained, int itemIdLost) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAKER_RESULT.getValue());
|
|
mplew.writeInt(0); // Always successful!
|
|
mplew.writeInt(3); // Monster Crystal
|
|
mplew.writeInt(itemIdGained);
|
|
mplew.writeInt(itemIdLost);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] makerResultDesynth(int itemId, int mesos, List<Pair<Integer, Integer>> itemsGained) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAKER_RESULT.getValue());
|
|
mplew.writeInt(0); // Always successful!
|
|
mplew.writeInt(4); // Mode Desynth
|
|
mplew.writeInt(itemId); // Item desynthed
|
|
mplew.writeInt(itemsGained.size()); // Loop of items gained, (int, int)
|
|
for (Pair<Integer, Integer> item : itemsGained) {
|
|
mplew.writeInt(item.getLeft());
|
|
mplew.writeInt(item.getRight());
|
|
}
|
|
mplew.writeInt(mesos); // Mesos spent.
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] makerEnableActions() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MAKER_RESULT.getValue());
|
|
mplew.writeInt(0); // Always successful!
|
|
mplew.writeInt(0); // Monster Crystal
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getMultiMegaphone(String[] messages, int channel, boolean showEar) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SERVERMESSAGE.getValue());
|
|
mplew.write(0x0A);
|
|
if (messages[0] != null) {
|
|
mplew.writeMapleAsciiString(messages[0]);
|
|
}
|
|
mplew.write(messages.length);
|
|
for (int i = 1; i < messages.length; i++) {
|
|
if (messages[i] != null) {
|
|
mplew.writeMapleAsciiString(messages[i]);
|
|
}
|
|
}
|
|
for (int i = 0; i < 10; i++) {
|
|
mplew.write(channel - 1);
|
|
}
|
|
mplew.write(showEar ? 1 : 0);
|
|
mplew.write(1);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a gm effect packet (ie. hide, banned, etc.)
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0x04: You have successfully
|
|
* blocked access.<br>
|
|
* 0x05: The unblocking has been successful.<br> 0x06 with Mode 0: You have
|
|
* successfully removed the name from the ranks.<br> 0x06 with Mode 1: You
|
|
* have entered an invalid character name.<br> 0x10: GM Hide, mode
|
|
* determines whether or not it is on.<br> 0x1E: Mode 0: Failed to send
|
|
* warning Mode 1: Sent warning<br> 0x13 with Mode 0: + mapid 0x13 with Mode
|
|
* 1: + ch (FF = Unable to find merchant)
|
|
*
|
|
* @param type The type
|
|
* @param mode The mode
|
|
* @return The gm effect packet
|
|
*/
|
|
public static byte[] getGMEffect(int type, byte mode) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue());
|
|
mplew.write(type);
|
|
mplew.write(mode);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] findMerchantResponse(boolean map, int extra) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue());
|
|
mplew.write(0x13);
|
|
mplew.write(map ? 0 : 1); //00 = mapid, 01 = ch
|
|
if (map) {
|
|
mplew.writeInt(extra);
|
|
} else {
|
|
mplew.write(extra); //-1 = unable to find
|
|
}
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] disableMinimap() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ADMIN_RESULT.getValue());
|
|
mplew.writeShort(0x1C);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendFamilyInvite(int playerId, String inviter) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST.getValue());
|
|
mplew.writeInt(playerId);
|
|
mplew.writeMapleAsciiString(inviter);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendFamilySummonRequest(String familyName, String from) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_SUMMON_REQUEST.getValue());
|
|
mplew.writeMapleAsciiString(from);
|
|
mplew.writeMapleAsciiString(familyName);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendFamilyLoginNotice(String name, boolean loggedIn) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_NOTIFY_LOGIN_OR_LOGOUT.getValue());
|
|
mplew.writeBool(loggedIn);
|
|
mplew.writeMapleAsciiString(name);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendFamilyJoinResponse(boolean accepted, String added) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_JOIN_REQUEST_RESULT.getValue());
|
|
mplew.write(accepted ? 1 : 0);
|
|
mplew.writeMapleAsciiString(added);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getSeniorMessage(String name) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_JOIN_ACCEPTED.getValue());
|
|
mplew.writeMapleAsciiString(name);
|
|
mplew.writeInt(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendGainRep(int gain, String from) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FAMILY_REP_GAIN.getValue());
|
|
mplew.writeInt(gain);
|
|
mplew.writeMapleAsciiString(from);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtCashPackage(List<Item> cashPackage, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x89);
|
|
mplew.write(cashPackage.size());
|
|
|
|
for (Item item : cashPackage) {
|
|
addCashItemInformation(mplew, item, accountId);
|
|
}
|
|
|
|
mplew.writeShort(0);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtQuestItem(int itemId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x8D);
|
|
mplew.writeInt(1);
|
|
mplew.writeShort(1);
|
|
mplew.write(0x0B);
|
|
mplew.write(0);
|
|
mplew.writeInt(itemId);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
// Cash Shop Surprise packets found thanks to Arnah (Vertisy)
|
|
public static byte[] onCashItemGachaponOpenFailed(){
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue());
|
|
mplew.write(0xE4);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] onCashGachaponOpenSuccess(int accountid, long sn, int remainingBoxes, Item item, int itemid, int nSelectedItemCount, boolean bJackpot){
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue());
|
|
mplew.write(0xE5); // subopcode thanks to Ubaware
|
|
mplew.writeLong(sn);// sn of the box used
|
|
mplew.writeInt(remainingBoxes);
|
|
addCashItemInformation(mplew, item, accountid);
|
|
mplew.writeInt(itemid);// the itemid of the liSN?
|
|
mplew.write(nSelectedItemCount);// the total count now? o.O
|
|
mplew.writeBool(bJackpot);// "CashGachaponJackpot"
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void getGuildInfo(final MaplePacketLittleEndianWriter mplew, MapleGuild guild) {
|
|
mplew.writeInt(guild.getId());
|
|
mplew.writeMapleAsciiString(guild.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(guild.getRankTitle(i));
|
|
}
|
|
Collection<MapleGuildCharacter> members = guild.getMembers();
|
|
mplew.write(members.size());
|
|
for (MapleGuildCharacter mgc : members) {
|
|
mplew.writeInt(mgc.getId());
|
|
}
|
|
for (MapleGuildCharacter mgc : members) {
|
|
mplew.writeAsciiString(getRightPaddedStr(mgc.getName(), '\0', 13));
|
|
mplew.writeInt(mgc.getJobId());
|
|
mplew.writeInt(mgc.getLevel());
|
|
mplew.writeInt(mgc.getGuildRank());
|
|
mplew.writeInt(mgc.isOnline() ? 1 : 0);
|
|
mplew.writeInt(guild.getSignature());
|
|
mplew.writeInt(mgc.getAllianceRank());
|
|
}
|
|
mplew.writeInt(guild.getCapacity());
|
|
mplew.writeShort(guild.getLogoBG());
|
|
mplew.write(guild.getLogoBGColor());
|
|
mplew.writeShort(guild.getLogo());
|
|
mplew.write(guild.getLogoColor());
|
|
mplew.writeMapleAsciiString(guild.getNotice());
|
|
mplew.writeInt(guild.getGP());
|
|
mplew.writeInt(guild.getAllianceId());
|
|
}
|
|
|
|
public static byte[] getAllianceInfo(MapleAlliance alliance) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x0C);
|
|
mplew.write(1);
|
|
mplew.writeInt(alliance.getId());
|
|
mplew.writeMapleAsciiString(alliance.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(alliance.getRankTitle(i));
|
|
}
|
|
mplew.write(alliance.getGuilds().size());
|
|
mplew.writeInt(alliance.getCapacity()); // probably capacity
|
|
for (Integer guild : alliance.getGuilds()) {
|
|
mplew.writeInt(guild);
|
|
}
|
|
mplew.writeMapleAsciiString(alliance.getNotice());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateAllianceInfo(MapleAlliance alliance, int world) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x0F);
|
|
mplew.writeInt(alliance.getId());
|
|
mplew.writeMapleAsciiString(alliance.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(alliance.getRankTitle(i));
|
|
}
|
|
mplew.write(alliance.getGuilds().size());
|
|
for (Integer guild : alliance.getGuilds()) {
|
|
mplew.writeInt(guild);
|
|
}
|
|
mplew.writeInt(alliance.getCapacity()); // probably capacity
|
|
mplew.writeShort(0);
|
|
for (Integer guildid : alliance.getGuilds()) {
|
|
getGuildInfo(mplew, Server.getInstance().getGuild(guildid, world));
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getGuildAlliances(MapleAlliance alliance, int worldId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x0D);
|
|
mplew.writeInt(alliance.getGuilds().size());
|
|
for (Integer guild : alliance.getGuilds()) {
|
|
getGuildInfo(mplew, Server.getInstance().getGuild(guild, worldId));
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] addGuildToAlliance(MapleAlliance alliance, int newGuild, MapleClient c) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x12);
|
|
mplew.writeInt(alliance.getId());
|
|
mplew.writeMapleAsciiString(alliance.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(alliance.getRankTitle(i));
|
|
}
|
|
mplew.write(alliance.getGuilds().size());
|
|
for (Integer guild : alliance.getGuilds()) {
|
|
mplew.writeInt(guild);
|
|
}
|
|
mplew.writeInt(alliance.getCapacity());
|
|
mplew.writeMapleAsciiString(alliance.getNotice());
|
|
mplew.writeInt(newGuild);
|
|
getGuildInfo(mplew, Server.getInstance().getGuild(newGuild, c.getWorld(), null));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] allianceMemberOnline(MapleCharacter mc, boolean online) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x0E);
|
|
mplew.writeInt(mc.getGuild().getAllianceId());
|
|
mplew.writeInt(mc.getGuildId());
|
|
mplew.writeInt(mc.getId());
|
|
mplew.write(online ? 1 : 0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] allianceNotice(int id, String notice) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x1C);
|
|
mplew.writeInt(id);
|
|
mplew.writeMapleAsciiString(notice);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] changeAllianceRankTitle(int alliance, String[] ranks) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x1A);
|
|
mplew.writeInt(alliance);
|
|
for (int i = 0; i < 5; i++) {
|
|
mplew.writeMapleAsciiString(ranks[i]);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateAllianceJobLevel(MapleCharacter mc) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x18);
|
|
mplew.writeInt(mc.getGuild().getAllianceId());
|
|
mplew.writeInt(mc.getGuildId());
|
|
mplew.writeInt(mc.getId());
|
|
mplew.writeInt(mc.getLevel());
|
|
mplew.writeInt(mc.getJob().getId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeGuildFromAlliance(MapleAlliance alliance, int expelledGuild, int worldId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x10);
|
|
mplew.writeInt(alliance.getId());
|
|
mplew.writeMapleAsciiString(alliance.getName());
|
|
for (int i = 1; i <= 5; i++) {
|
|
mplew.writeMapleAsciiString(alliance.getRankTitle(i));
|
|
}
|
|
mplew.write(alliance.getGuilds().size());
|
|
for (Integer guild : alliance.getGuilds()) {
|
|
mplew.writeInt(guild);
|
|
}
|
|
mplew.writeInt(alliance.getCapacity());
|
|
mplew.writeMapleAsciiString(alliance.getNotice());
|
|
mplew.writeInt(expelledGuild);
|
|
getGuildInfo(mplew, Server.getInstance().getGuild(expelledGuild, worldId, null));
|
|
mplew.write(0x01);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] disbandAlliance(int alliance) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x1D);
|
|
mplew.writeInt(alliance);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] allianceInvite(int allianceid, MapleCharacter chr) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.ALLIANCE_OPERATION.getValue());
|
|
mplew.write(0x03);
|
|
mplew.writeInt(allianceid);
|
|
mplew.writeMapleAsciiString(chr.getName());
|
|
mplew.writeShort(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendMesoLimit() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TRADE_MONEY_LIMIT.getValue()); //Players under level 15 can only trade 1m per day
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] removeItemFromDuey(boolean remove, int Package) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARCEL.getValue());
|
|
mplew.write(0x17);
|
|
mplew.writeInt(Package);
|
|
mplew.write(remove ? 3 : 4);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendDueyParcelReceived(String from, boolean quick) { // thanks inhyuk
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARCEL.getValue());
|
|
mplew.write(0x19);
|
|
mplew.writeMapleAsciiString(from);
|
|
mplew.writeBool(quick);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendDueyParcelNotification(boolean quick) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARCEL.getValue());
|
|
mplew.write(0x1B);
|
|
mplew.writeBool(quick); // 0 : package received, 1 : quick delivery package
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendDueyMSG(byte operation) {
|
|
return sendDuey(operation, null);
|
|
}
|
|
|
|
public static byte[] sendDuey(int operation, List<DueyPackage> packages) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PARCEL.getValue());
|
|
mplew.write(operation);
|
|
if (operation == 8) {
|
|
mplew.write(0);
|
|
mplew.write(packages.size());
|
|
for (DueyPackage dp : packages) {
|
|
mplew.writeInt(dp.getPackageId());
|
|
mplew.writeAsciiString(dp.getSender());
|
|
for (int i = dp.getSender().length(); i < 13; i++) {
|
|
mplew.write(0);
|
|
}
|
|
|
|
mplew.writeInt(dp.getMesos());
|
|
mplew.writeLong(getTime(dp.sentTimeInMilliseconds()));
|
|
|
|
String msg = dp.getMessage();
|
|
if (msg != null) {
|
|
mplew.writeInt(1);
|
|
mplew.writeAsciiString(msg);
|
|
for (int i = msg.length(); i < 200; i++) {
|
|
mplew.write(0);
|
|
}
|
|
} else {
|
|
mplew.writeInt(0);
|
|
mplew.skip(200);
|
|
}
|
|
|
|
mplew.write(0);
|
|
if (dp.getItem() != null) {
|
|
mplew.write(1);
|
|
addItemInfo(mplew, dp.getItem(), true);
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
}
|
|
mplew.write(0);
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendDojoAnimation(byte firstByte, String animation) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(firstByte);
|
|
mplew.writeMapleAsciiString(animation);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getDojoInfo(String info) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(10);
|
|
mplew.write(new byte[]{(byte) 0xB7, 4});//QUEST ID f5
|
|
mplew.writeMapleAsciiString(info);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getDojoInfoMessage(String message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(9);
|
|
mplew.writeMapleAsciiString(message);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a "block" packet (ie. the cash shop is unavailable, etc)
|
|
*
|
|
* Possible values for <code>type</code>:<br> 1: The portal is closed for
|
|
* now.<br> 2: You cannot go to that place.<br> 3: Unable to approach due to
|
|
* the force of the ground.<br> 4: You cannot teleport to or on this
|
|
* map.<br> 5: Unable to approach due to the force of the ground.<br> 6:
|
|
* Only party members can enter this map.<br> 7: The Cash Shop is
|
|
* currently not available. Stay tuned...<br>
|
|
*
|
|
* @param type The type
|
|
* @return The "block" packet.
|
|
*/
|
|
public static byte[] blockedMessage(int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BLOCKED_MAP.getValue());
|
|
mplew.write(type);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Gets a "block" packet (ie. the cash shop is unavailable, etc)
|
|
*
|
|
* Possible values for <code>type</code>:<br> 1: You cannot move that
|
|
* channel. Please try again later.<br> 2: You cannot go into the cash shop.
|
|
* Please try again later.<br> 3: The Item-Trading Shop is currently
|
|
* unavailable. Please try again later.<br> 4: You cannot go into the trade
|
|
* shop, due to limitation of user count.<br> 5: You do not meet the minimum
|
|
* level requirement to access the Trade Shop.<br>
|
|
*
|
|
* @param type The type
|
|
* @return The "block" packet.
|
|
*/
|
|
public static byte[] blockedMessage2(int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BLOCKED_SERVER.getValue());
|
|
mplew.write(type);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] updateDojoStats(MapleCharacter chr, int belt) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(10);
|
|
mplew.write(new byte[]{(byte) 0xB7, 4}); //?
|
|
mplew.writeMapleAsciiString("pt=" + chr.getDojoPoints() + ";belt=" + belt + ";tuto=" + (chr.getFinishedDojoTutorial() ? "1" : "0"));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a "levelup" packet to the guild or family.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: <Family> ? has reached Lv.
|
|
* ?.<br> - The Reps you have received from ? will be reduced in half. 1:
|
|
* <Family> ? has reached Lv. ?.<br> 2: <Guild> ? has reached Lv. ?.<br>
|
|
*
|
|
* @param type The type
|
|
* @return The "levelup" packet.
|
|
*/
|
|
public static byte[] levelUpMessage(int type, int level, String charname) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NOTIFY_LEVELUP.getValue());
|
|
mplew.write(type);
|
|
mplew.writeInt(level);
|
|
mplew.writeMapleAsciiString(charname);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a "married" packet to the guild or family.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: <Guild ? is now married.
|
|
* Please congratulate them.<br> 1: <Family ? is now married. Please
|
|
* congratulate them.<br>
|
|
*
|
|
* @param type The type
|
|
* @return The "married" packet.
|
|
*/
|
|
public static byte[] marriageMessage(int type, String charname) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NOTIFY_MARRIAGE.getValue());
|
|
mplew.write(type); // 0: guild, 1: family
|
|
mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a "job advance" packet to the guild or family.
|
|
*
|
|
* Possible values for <code>type</code>:<br> 0: <Guild ? has advanced to
|
|
* a(an) ?.<br> 1: <Family ? has advanced to a(an) ?.<br>
|
|
*
|
|
* @param type The type
|
|
* @return The "job advance" packet.
|
|
*/
|
|
public static byte[] jobMessage(int type, int job, String charname) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.NOTIFY_JOB_CHANGE.getValue());
|
|
mplew.write(type);
|
|
mplew.writeInt(job); //Why fking int?
|
|
mplew.writeMapleAsciiString("> " + charname); //To fix the stupid packet lol
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param type - (0:Light&Long 1:Heavy&Short)
|
|
* @param delay - seconds
|
|
* @return
|
|
*/
|
|
public static byte[] trembleEffect(int type, int delay) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.FIELD_EFFECT.getValue());
|
|
mplew.write(1);
|
|
mplew.write(type);
|
|
mplew.writeInt(delay);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] getEnergy(String info, int amount) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SESSION_VALUE.getValue());
|
|
mplew.writeMapleAsciiString(info);
|
|
mplew.writeMapleAsciiString(Integer.toString(amount));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] dojoWarpUp() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DOJO_WARP_UP.getValue());
|
|
mplew.write(0);
|
|
mplew.write(6);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] itemExpired(int itemid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(2);
|
|
mplew.writeInt(itemid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static String getRightPaddedStr(String in, char padchar, int length) {
|
|
StringBuilder builder = new StringBuilder(in);
|
|
for (int x = in.length(); x < length; x++) {
|
|
builder.append(padchar);
|
|
}
|
|
return builder.toString();
|
|
}
|
|
|
|
public static byte[] MobDamageMobFriendly(MapleMonster mob, int damage, int remainingHp) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.DAMAGE_MONSTER.getValue());
|
|
mplew.writeInt(mob.getObjectId());
|
|
mplew.write(1); // direction ?
|
|
mplew.writeInt(damage);
|
|
mplew.writeInt(remainingHp);
|
|
mplew.writeInt(mob.getMaxHp());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] shopErrorMessage(int error, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PLAYER_INTERACTION.getValue());
|
|
mplew.write(0x0A);
|
|
mplew.write(type);
|
|
mplew.write(error);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static void addRingInfo(final MaplePacketLittleEndianWriter mplew, MapleCharacter chr) {
|
|
mplew.writeShort(chr.getCrushRings().size());
|
|
for (MapleRing ring : chr.getCrushRings()) {
|
|
mplew.writeInt(ring.getPartnerChrId());
|
|
mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13));
|
|
mplew.writeInt(ring.getRingId());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(ring.getPartnerRingId());
|
|
mplew.writeInt(0);
|
|
}
|
|
mplew.writeShort(chr.getFriendshipRings().size());
|
|
for (MapleRing ring : chr.getFriendshipRings()) {
|
|
mplew.writeInt(ring.getPartnerChrId());
|
|
mplew.writeAsciiString(getRightPaddedStr(ring.getPartnerName(), '\0', 13));
|
|
mplew.writeInt(ring.getRingId());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(ring.getPartnerRingId());
|
|
mplew.writeInt(0);
|
|
mplew.writeInt(ring.getItemId());
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
public static byte[] finishedSort(int inv) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.GATHER_ITEM_RESULT.getValue());
|
|
mplew.write(0);
|
|
mplew.write(inv);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] finishedSort2(int inv) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.SORT_ITEM_RESULT.getValue());
|
|
mplew.write(0);
|
|
mplew.write(inv);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] bunnyPacket() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHOW_STATUS_INFO.getValue());
|
|
mplew.write(9);
|
|
mplew.writeAsciiString("Protect the Moon Bunny!!!");
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hpqMessage(String text) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.BLOW_WEATHER.getValue()); // not 100% sure
|
|
mplew.write(0);
|
|
mplew.writeInt(5120016);
|
|
mplew.writeAsciiString(text);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showEventInstructions() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GMEVENT_INSTRUCTIONS.getValue());
|
|
mplew.write(0);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] leftKnockBack() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2);
|
|
mplew.writeShort(SendOpcode.LEFT_KNOCK_BACK.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] rollSnowBall(boolean entermap, int state, MapleSnowball ball0, MapleSnowball ball1) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SNOWBALL_STATE.getValue());
|
|
if (entermap) {
|
|
mplew.skip(21);
|
|
} else {
|
|
mplew.write(state);// 0 = move, 1 = roll, 2 is down disappear, 3 is up disappear
|
|
mplew.writeInt(ball0.getSnowmanHP() / 75);
|
|
mplew.writeInt(ball1.getSnowmanHP() / 75);
|
|
mplew.writeShort(ball0.getPosition());//distance snowball down, 84 03 = max
|
|
mplew.write(-1);
|
|
mplew.writeShort(ball1.getPosition());//distance snowball up, 84 03 = max
|
|
mplew.write(-1);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hitSnowBall(int what, int damage) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.HIT_SNOWBALL.getValue());
|
|
mplew.write(what);
|
|
mplew.writeInt(damage);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a Snowball Message<br>
|
|
*
|
|
* Possible values for <code>message</code>:<br> 1: ... Team's snowball has
|
|
* passed the stage 1.<br> 2: ... Team's snowball has passed the stage
|
|
* 2.<br> 3: ... Team's snowball has passed the stage 3.<br> 4: ... Team is
|
|
* attacking the snowman, stopping the progress<br> 5: ... Team is moving
|
|
* again<br>
|
|
*
|
|
* @param message
|
|
*
|
|
*/
|
|
public static byte[] snowballMessage(int team, int message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.SNOWBALL_MESSAGE.getValue());
|
|
mplew.write(team);// 0 is down, 1 is up
|
|
mplew.writeInt(message);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] coconutScore(int team1, int team2) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.COCONUT_SCORE.getValue());
|
|
mplew.writeShort(team1);
|
|
mplew.writeShort(team2);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] hitCoconut(boolean spawn, int id, int type) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.COCONUT_HIT.getValue());
|
|
if (spawn) {
|
|
mplew.writeShort(-1);
|
|
mplew.writeShort(5000);
|
|
mplew.write(0);
|
|
} else {
|
|
mplew.writeShort(id);
|
|
mplew.writeShort(1000);//delay till you can attack again!
|
|
mplew.write(type); // What action to do for the coconut.
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] customPacket(String packet) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.write(HexTool.getByteArrayFromHexString(packet));
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] customPacket(byte[] packet) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(packet.length);
|
|
mplew.write(packet);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnGuide(boolean spawn) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.SPAWN_GUIDE.getValue());
|
|
if (spawn) {
|
|
mplew.write(1);
|
|
} else {
|
|
mplew.write(0);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] talkGuide(String talk) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TALK_GUIDE.getValue());
|
|
mplew.write(0);
|
|
mplew.writeMapleAsciiString(talk);
|
|
mplew.write(new byte[]{(byte) 0xC8, 0, 0, 0, (byte) 0xA0, (byte) 0x0F, 0, 0});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] guideHint(int hint) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(11);
|
|
mplew.writeShort(SendOpcode.TALK_GUIDE.getValue());
|
|
mplew.write(1);
|
|
mplew.writeInt(hint);
|
|
mplew.writeInt(7000);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId) {
|
|
addCashItemInformation(mplew, item, accountId, null);
|
|
}
|
|
|
|
public static void addCashItemInformation(final MaplePacketLittleEndianWriter mplew, Item item, int accountId, String giftMessage) {
|
|
boolean isGift = giftMessage != null;
|
|
boolean isRing = false;
|
|
Equip equip = null;
|
|
if (item.getInventoryType().equals(MapleInventoryType.EQUIP)) {
|
|
equip = (Equip) item;
|
|
isRing = equip.getRingId() > -1;
|
|
}
|
|
mplew.writeLong(item.getPetId() > -1 ? item.getPetId() : isRing ? equip.getRingId() : item.getCashId());
|
|
if (!isGift) {
|
|
mplew.writeInt(accountId);
|
|
mplew.writeInt(0);
|
|
}
|
|
mplew.writeInt(item.getItemId());
|
|
if (!isGift) {
|
|
mplew.writeInt(item.getSN());
|
|
mplew.writeShort(item.getQuantity());
|
|
}
|
|
mplew.writeAsciiString(StringUtil.getRightPaddedStr(item.getGiftFrom(), '\0', 13));
|
|
if (isGift) {
|
|
mplew.writeAsciiString(StringUtil.getRightPaddedStr(giftMessage, '\0', 73));
|
|
return;
|
|
}
|
|
addExpirationTime(mplew, item.getExpiration());
|
|
mplew.writeLong(0);
|
|
}
|
|
|
|
public static byte[] showWishList(MapleCharacter mc, boolean update) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
if (update) {
|
|
mplew.write(0x55);
|
|
} else {
|
|
mplew.write(0x4F);
|
|
}
|
|
|
|
for (int sn : mc.getCashShop().getWishList()) {
|
|
mplew.writeInt(sn);
|
|
}
|
|
|
|
for (int i = mc.getCashShop().getWishList().size(); i < 10; i++) {
|
|
mplew.writeInt(0);
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtCashItem(Item item, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x57);
|
|
addCashItemInformation(mplew, item, accountId);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtCashRing(Item ring, String recipient, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0x87);
|
|
addCashItemInformation(mplew, ring, accountId);
|
|
mplew.writeMapleAsciiString(recipient);
|
|
mplew.writeInt(ring.getItemId());
|
|
mplew.writeShort(1); //quantity
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/*
|
|
* 00 = Due to an unknown error, failed
|
|
* A3 = Request timed out. Please try again.
|
|
* A4 = Due to an unknown error, failed + warpout
|
|
* A5 = You don't have enough cash.
|
|
* A6 = long as shet msg
|
|
* A7 = You have exceeded the allotted limit of price for gifts.
|
|
* A8 = You cannot send a gift to your own account. Log in on the char and purchase
|
|
* A9 = Please confirm whether the character's name is correct.
|
|
* AA = Gender restriction!
|
|
* AB = gift cannot be sent because recipient inv is full
|
|
* AC = exceeded the number of cash items you can have
|
|
* AD = check and see if the character name is wrong or there is gender restrictions
|
|
* //Skipped a few
|
|
* B0 = Wrong Coupon Code
|
|
* B1 = Disconnect from CS because of 3 wrong coupon codes < lol
|
|
* B2 = Expired Coupon
|
|
* B3 = Coupon has been used already
|
|
* B4 = Nexon internet cafes? lolfk
|
|
* B8 = Due to gender restrictions, the coupon cannot be used.
|
|
* BB = inv full
|
|
* BC = long as shet "(not?) available to purchase by a use at the premium" msg
|
|
* BD = invalid gift recipient
|
|
* BE = invalid receiver name
|
|
* BF = item unavailable to purchase at this hour
|
|
* C0 = not enough items in stock, therefore not available
|
|
* C1 = you have exceeded spending limit of NX
|
|
* C2 = not enough mesos? Lol not even 1 mesos xD
|
|
* C3 = cash shop unavailable during beta phase
|
|
* C4 = check birthday code
|
|
* C7 = only available to users buying cash item, whatever msg too long
|
|
* C8 = already applied for this
|
|
* CD = You have reached the daily purchase limit for the cash shop.
|
|
* D0 = coupon account limit reached
|
|
* D2 = coupon system currently unavailable
|
|
* D3 = item can only be used 15 days after registration
|
|
* D4 = not enough gift tokens
|
|
* D6 = fresh people cannot gift items lul
|
|
* D7 = bad people cannot gift items >:(
|
|
* D8 = cannot gift due to limitations
|
|
* D9 = cannot gift due to amount of gifted times
|
|
* DA = cannot be gifted due to technical difficulties
|
|
* DB = cannot transfer to char below level 20
|
|
* DC = cannot transfer char to same world
|
|
* DD = cannot transfer char to new server world
|
|
* DE = cannot transfer char out of this world
|
|
* DF = cannot transfer char due to no empty char slots
|
|
* E0 = event or free test time ended
|
|
* E6 = item cannot be purchased with MaplePoints
|
|
* E7 = lol sorry for the inconvenience, eh?
|
|
* E8 = cannot purchase by anyone under 7
|
|
*/
|
|
public static byte[] showCashShopMessage(byte message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(4);
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x5C);
|
|
mplew.write(message);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showCashInventory(MapleClient c) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x4B);
|
|
mplew.writeShort(c.getPlayer().getCashShop().getInventory().size());
|
|
|
|
for (Item item : c.getPlayer().getCashShop().getInventory()) {
|
|
addCashItemInformation(mplew, item, c.getAccID());
|
|
}
|
|
|
|
mplew.writeShort(c.getPlayer().getStorage().getSlots());
|
|
mplew.writeShort(c.getCharacterSlots());
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showGifts(List<Pair<Item, String>> gifts) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x4D);
|
|
mplew.writeShort(gifts.size());
|
|
|
|
for (Pair<Item, String> gift : gifts) {
|
|
addCashItemInformation(mplew, gift.getLeft(), 0, gift.getRight());
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showGiftSucceed(String to, CashItem item) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x5E); //0x5D, Couldn't be sent
|
|
mplew.writeMapleAsciiString(to);
|
|
mplew.writeInt(item.getItemId());
|
|
mplew.writeShort(item.getCount());
|
|
mplew.writeInt(item.getPrice());
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtInventorySlots(int type, short slots) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x60);
|
|
mplew.write(type);
|
|
mplew.writeShort(slots);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtStorageSlots(short slots) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x62);
|
|
mplew.writeShort(slots);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showBoughtCharacterSlot(short slots) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(5);
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x64);
|
|
mplew.writeShort(slots);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] takeFromCashInventory(Item item) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x68);
|
|
mplew.writeShort(item.getPosition());
|
|
addItemInfo(mplew, item, true);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] deleteCashItem(Item item) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0x6C);
|
|
mplew.writeLong(item.getCashId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] refundCashItem(Item item, int maplePoints) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
mplew.write(0x85);
|
|
mplew.writeLong(item.getCashId());
|
|
mplew.writeInt(maplePoints);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] putIntoCashInventory(Item item, int accountId) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.CASHSHOP_OPERATION.getValue());
|
|
|
|
mplew.write(0x6A);
|
|
addCashItemInformation(mplew, item, accountId);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] openCashShop(MapleClient c, boolean mts) throws Exception {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(mts ? SendOpcode.SET_ITC.getValue() : SendOpcode.SET_CASH_SHOP.getValue());
|
|
|
|
addCharacterInfo(mplew, c.getPlayer());
|
|
|
|
if (!mts) {
|
|
mplew.write(1);
|
|
}
|
|
|
|
mplew.writeMapleAsciiString(c.getAccountName());
|
|
if (mts) {
|
|
mplew.write(new byte[]{(byte) 0x88, 19, 0, 0, 7, 0, 0, 0, (byte) 0xF4, 1, 0, 0, (byte) 0x18, 0, 0, 0, (byte) 0xA8, 0, 0, 0, (byte) 0x70, (byte) 0xAA, (byte) 0xA7, (byte) 0xC5, (byte) 0x4E, (byte) 0xC1, (byte) 0xCA, 1});
|
|
} else {
|
|
mplew.writeInt(0);
|
|
List<SpecialCashItem> lsci = CashItemFactory.getSpecialCashItems();
|
|
mplew.writeShort(lsci.size());//Guess what
|
|
for (SpecialCashItem sci : lsci) {
|
|
mplew.writeInt(sci.getSN());
|
|
mplew.writeInt(sci.getModifier());
|
|
mplew.write(sci.getInfo());
|
|
}
|
|
mplew.skip(121);
|
|
|
|
List<List<Integer>> mostSellers = c.getWorldServer().getMostSellerCashItems();
|
|
for (int i = 1; i <= 8; i++) {
|
|
List<Integer> mostSellersTab = mostSellers.get(i);
|
|
|
|
for (int j = 0; j < 2; j++) {
|
|
for (Integer snid : mostSellersTab) {
|
|
mplew.writeInt(i);
|
|
mplew.writeInt(j);
|
|
mplew.writeInt(snid);
|
|
}
|
|
}
|
|
}
|
|
|
|
mplew.writeInt(0);
|
|
mplew.writeShort(0);
|
|
mplew.write(0);
|
|
mplew.writeInt(75);
|
|
}
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sendVegaScroll(int op) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.VEGA_SCROLL.getValue());
|
|
mplew.write(op);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] resetForcedStats() {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(2);
|
|
mplew.writeShort(SendOpcode.FORCED_STAT_RESET.getValue());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] showCombo(int count) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.SHOW_COMBO.getValue());
|
|
mplew.writeInt(count);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] earnTitleMessage(String msg) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SCRIPT_PROGRESS_MESSAGE.getValue());
|
|
mplew.writeMapleAsciiString(msg);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] CPUpdate(boolean party, int curCP, int totalCP, int team) { // CPQ
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
if (!party) {
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_OBTAINED_CP.getValue());
|
|
} else {
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_PARTY_CP.getValue());
|
|
mplew.write(team); // team?
|
|
}
|
|
mplew.writeShort(curCP);
|
|
mplew.writeShort(totalCP);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] CPQMessage(byte message) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(3);
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_MESSAGE.getValue());
|
|
mplew.write(message); // Message
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] playerSummoned(String name, int tab, int number) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_SUMMON.getValue());
|
|
mplew.write(tab);
|
|
mplew.write(number);
|
|
mplew.writeMapleAsciiString(name);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] playerDiedMessage(String name, int lostCP, int team) { // CPQ
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_DIED.getValue());
|
|
mplew.write(team); // team
|
|
mplew.writeMapleAsciiString(name);
|
|
mplew.write(lostCP);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] startMonsterCarnival(MapleCharacter chr, int team, int oposition) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(25);
|
|
mplew.writeShort(SendOpcode.MONSTER_CARNIVAL_START.getValue());
|
|
mplew.write(team); // team
|
|
mplew.writeShort(chr.getCP()); // Obtained CP - Used CP
|
|
mplew.writeShort(chr.getTotalCP()); // Total Obtained CP
|
|
mplew.writeShort(chr.getMonsterCarnival().getCP(team)); // Obtained CP - Used CP of the team
|
|
mplew.writeShort(chr.getMonsterCarnival().getTotalCP(team)); // Total Obtained CP of the team
|
|
mplew.writeShort(chr.getMonsterCarnival().getCP(oposition)); // Obtained CP - Used CP of the team
|
|
mplew.writeShort(chr.getMonsterCarnival().getTotalCP(oposition)); // Total Obtained CP of the team
|
|
mplew.writeShort(0); // Probably useless nexon shit
|
|
mplew.writeLong(0); // Probably useless nexon shit
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] sheepRanchInfo(byte wolf, byte sheep) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHEEP_RANCH_INFO.getValue());
|
|
mplew.write(wolf);
|
|
mplew.write(sheep);
|
|
return mplew.getPacket();
|
|
}
|
|
//Know what this is? ?? >=)
|
|
|
|
public static byte[] sheepRanchClothes(int id, byte clothes) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SHEEP_RANCH_CLOTHES.getValue());
|
|
mplew.writeInt(id); //Character id
|
|
mplew.write(clothes); //0 = sheep, 1 = wolf, 2 = Spectator (wolf without wool)
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] incubatorResult() {//lol
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8);
|
|
mplew.writeShort(SendOpcode.INCUBATOR_RESULT.getValue());
|
|
mplew.skip(6);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] pyramidGauge(int gauge) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(6);
|
|
mplew.writeShort(SendOpcode.PYRAMID_GAUGE.getValue());
|
|
mplew.writeInt(gauge);
|
|
return mplew.getPacket();
|
|
}
|
|
// f2
|
|
|
|
public static byte[] pyramidScore(byte score, int exp) {//Type cannot be higher than 4 (Rank D), otherwise you'll crash
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(7);
|
|
mplew.writeShort(SendOpcode.PYRAMID_SCORE.getValue());
|
|
mplew.write(score);
|
|
mplew.writeInt(exp);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] spawnDragon(MapleDragon dragon) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SPAWN_DRAGON.getValue());
|
|
mplew.writeInt(dragon.getOwner().getId());//objectid = owner id
|
|
mplew.writeShort(dragon.getPosition().x);
|
|
mplew.writeShort(0);
|
|
mplew.writeShort(dragon.getPosition().y);
|
|
mplew.writeShort(0);
|
|
mplew.write(dragon.getStance());
|
|
mplew.write(0);
|
|
mplew.writeShort(dragon.getOwner().getJob().getId());
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
public static byte[] moveDragon(MapleDragon dragon, Point startPos, SeekableLittleEndianAccessor movementSlea, long movementDataLength) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.MOVE_DRAGON.getValue());
|
|
mplew.writeInt(dragon.getOwner().getId());
|
|
mplew.writePos(startPos);
|
|
rebroadcastMovementList(mplew, movementSlea, movementDataLength);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Sends a request to remove Mir<br>
|
|
*
|
|
* @param charid - Needs the specific Character ID
|
|
* @return The packet
|
|
*
|
|
*/
|
|
public static byte[] removeDragon(int chrid) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.REMOVE_DRAGON.getValue());
|
|
mplew.writeInt(chrid);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Changes the current background effect to either being rendered or not.
|
|
* Data is still missing, so this is pretty binary at the moment in how it
|
|
* behaves.
|
|
*
|
|
* @param remove whether or not the remove or add the specified layer.
|
|
* @param layer the targeted layer for removal or addition.
|
|
* @param transition the time it takes to transition the effect.
|
|
*
|
|
* @return a packet to change the background effect of a specified layer.
|
|
*/
|
|
public static byte[] changeBackgroundEffect(boolean remove, int layer, int transition) {
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_BACK_EFFECT.getValue());
|
|
mplew.writeBool(remove);
|
|
mplew.writeInt(0); // not sure what this int32 does yet
|
|
mplew.write(layer);
|
|
mplew.writeInt(transition);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
/**
|
|
* Makes the NPCs provided set as scriptable, informing the client to search for js scripts for these NPCs even
|
|
* if they already have entries within the wz files.
|
|
*
|
|
* @param scriptableNpcIds Ids of npcs to enable scripts for.
|
|
* @return a packet which makes the npc's provided scriptable.
|
|
*/
|
|
public static byte[] setNPCScriptable(List<Integer> scriptableNpcIds) { // thanks to GabrielSin
|
|
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.SET_NPC_SCRIPTABLE.getValue());
|
|
mplew.write(scriptableNpcIds.size());
|
|
scriptableNpcIds.forEach(id -> {
|
|
mplew.writeInt(id);
|
|
mplew.writeMapleAsciiString("NPC " + id); // The client needs a name for the npc, but it doesn't seem to do anything.
|
|
mplew.writeInt(0); // start time
|
|
mplew.writeInt(Integer.MAX_VALUE); // end time
|
|
});
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] MassacreResult(byte nRank,int nIncExp) {
|
|
//CField_MassacreResult__OnMassacreResult @ 0x005617C5
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.PYRAMID_SCORE.getValue()); //MASSACRERESULT | 0x009E
|
|
mplew.write(nRank); //(0 - S) (1 - A) (2 - B) (3 - C) (4 - D) ( Else - Crash )
|
|
mplew.writeInt(nIncExp);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] GuildBoss_HealerMove(short nY) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_BOSS_HEALER_MOVE.getValue());
|
|
mplew.writeShort(nY); //New Y Position
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
|
|
private static byte[] GuildBoss_PulleyStateChange(byte nState) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.GUILD_BOSS_PULLEY_STATE_CHANGE.getValue());
|
|
mplew.write(nState);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] Tournament__Tournament(byte nState, byte nSubState) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TOURNAMENT.getValue());
|
|
mplew.write(nState);
|
|
mplew.write(nSubState);
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] Tournament__MatchTable(byte nState, byte nSubState) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TOURNAMENT_MATCH_TABLE.getValue()); //Prompts CMatchTableDlg Modal
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] Tournament__SetPrize(byte bSetPrize, byte bHasPrize,int nItemID1,int nItemID2) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TOURNAMENT_SET_PRIZE.getValue());
|
|
|
|
//0 = "You have failed the set the prize. Please check the item number again."
|
|
//1 = "You have successfully set the prize."
|
|
mplew.write(bSetPrize);
|
|
|
|
mplew.write(bHasPrize);
|
|
|
|
if(bHasPrize != 0)
|
|
{
|
|
mplew.writeInt(nItemID1);
|
|
mplew.writeInt(nItemID2);
|
|
}
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
private static byte[] Tournament__UEW(byte nState) {
|
|
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
|
mplew.writeShort(SendOpcode.TOURNAMENT_UEW.getValue());
|
|
|
|
//Is this a bitflag o.o ?
|
|
//2 = "You have reached the finals by default."
|
|
//4 = "You have reached the semifinals by default."
|
|
//8 or 16 = "You have reached the round of %n by default." | Encodes nState as %n ?!
|
|
mplew.write(nState);
|
|
|
|
return mplew.getPacket();
|
|
}
|
|
|
|
}
|