1398 lines
74 KiB
Java
1398 lines
74 KiB
Java
package net.dev213.ms.handlers.item;
|
|
|
|
import database.data.CharacterPotentialData;
|
|
import net.dev213.ms.Server;
|
|
import net.dev213.ms.client.Account;
|
|
import net.dev213.ms.client.Client;
|
|
import net.dev213.ms.client.character.BroadcastMsg;
|
|
import net.dev213.ms.client.character.Char;
|
|
import net.dev213.ms.client.character.ExtendSP;
|
|
import net.dev213.ms.client.character.avatar.BeautyAlbum;
|
|
import net.dev213.ms.client.character.items.*;
|
|
import net.dev213.ms.client.character.potential.CharacterPotential;
|
|
import net.dev213.ms.client.character.potential.CharacterPotentialMan;
|
|
import net.dev213.ms.client.character.quest.Quest;
|
|
import net.dev213.ms.client.character.skills.Option;
|
|
import net.dev213.ms.client.character.skills.Skill;
|
|
import net.dev213.ms.client.character.skills.temp.CharacterTemporaryStat;
|
|
import net.dev213.ms.client.character.skills.temp.TemporaryStatManager;
|
|
import net.dev213.ms.connection.InPacket;
|
|
import net.dev213.ms.connection.packet.*;
|
|
import net.dev213.ms.constants.*;
|
|
import net.dev213.ms.enums.*;
|
|
import net.dev213.ms.handlers.Handler;
|
|
import net.dev213.ms.handlers.header.InHeader;
|
|
import net.dev213.ms.life.pet.Pet;
|
|
import net.dev213.ms.life.pet.PetSkill;
|
|
import net.dev213.ms.loaders.FieldData;
|
|
import net.dev213.ms.loaders.ItemData;
|
|
import net.dev213.ms.loaders.SkillData;
|
|
import net.dev213.ms.loaders.StringData;
|
|
import net.dev213.ms.loaders.containerclasses.ItemInfo;
|
|
import net.dev213.ms.loaders.containerclasses.MakingSkillRecipe;
|
|
import net.dev213.ms.scripts.ScriptType;
|
|
import net.dev213.ms.util.Position;
|
|
import net.dev213.ms.util.Util;
|
|
import net.dev213.ms.world.World;
|
|
import net.dev213.ms.world.field.Field;
|
|
import net.dev213.ms.world.field.Portal;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
|
|
import java.text.NumberFormat;
|
|
import java.util.*;
|
|
|
|
import static net.dev213.ms.enums.ChatType.*;
|
|
import static net.dev213.ms.enums.EquipBaseStat.iuc;
|
|
import static net.dev213.ms.enums.EquipBaseStat.tuc;
|
|
import static net.dev213.ms.enums.InvType.*;
|
|
import static net.dev213.ms.enums.InventoryOperation.Move;
|
|
|
|
public class ItemHandler {
|
|
|
|
private static final Logger log = LogManager.getLogger(ItemHandler.class);
|
|
|
|
@Handler(op = InHeader.USER_PORTAL_SCROLL_USE_REQUEST)
|
|
public static void handleUserPortalScrollUseRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
Field field = chr.getField();
|
|
if ((field.getFieldLimit() & FieldOption.PortalScrollLimit.getVal()) > 0 || !field.isChannelField()) {
|
|
chr.chatMessage("You may not use a return scroll in this map.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
c.verifyTick(inPacket);
|
|
short slot = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
|
|
Item item = chr.getConsumeInventory().getItemBySlot(slot);
|
|
|
|
if (item == null || item.getItemId() != itemID || item.getQuantity() < 1 || !chr.isInValidState()) {
|
|
chr.dispose("You cannot use this return scroll right now.");
|
|
return;
|
|
}
|
|
|
|
ItemInfo ii = ItemData.getItemInfoByID(itemID);
|
|
Field toField;
|
|
|
|
if (itemID != 2030000) {
|
|
toField = chr.getOrCreateFieldByCurrentInstanceType(ii.getMoveTo());
|
|
} else {
|
|
toField = chr.getOrCreateFieldByCurrentInstanceType(field.getReturnMap());
|
|
}
|
|
Portal portal = toField.getDefaultPortal();
|
|
chr.warp(toField, portal);
|
|
chr.consumeItem(itemID, 1);
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.USER_STAT_CHANGE_ITEM_CANCEL_REQUEST)
|
|
public static void handleUserStatChangeItemCancelRequest(Char chr, InPacket inPacket) {
|
|
TemporaryStatManager tsm = chr.getTemporaryStatManager();
|
|
int itemID = inPacket.decodeInt();
|
|
tsm.removeStatsBySkill(itemID);
|
|
tsm.sendResetStatPacket();
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_SKILL_RESET_ITEM_USE_REQUEST)
|
|
public static void handleUserResetSP(Char chr, InPacket inPacket) {
|
|
if (inPacket != null) {
|
|
chr.getClient().verifyTick(inPacket);
|
|
short slot = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(slot);
|
|
if (item == null || itemID != item.getItemId() || itemID / 10 != 250000) {
|
|
chr.write(WvsContext.resetItemResult(true, chr.getId(), false, true));
|
|
return;
|
|
}
|
|
chr.consumeItem(item);
|
|
}
|
|
short jobID = chr.getJob();
|
|
List<Skill> skills = new ArrayList<>();
|
|
List<Integer> jobs = SkillConstants.getSkillRootFromJob(jobID);
|
|
ExtendSP extendSP = JobConstants.isExtendSpJob(jobID) ? chr.getAvatarData().getCharacterStat().getExtendSP() : null;
|
|
int sp = 0;
|
|
for (int job : jobs) {
|
|
if (JobConstants.isBeginnerJob((short) job)) {
|
|
continue;
|
|
}
|
|
for (Skill skill : SkillData.getSkillsByJob((short) job)) {
|
|
Skill curSkill = chr.getSkill(skill.getSkillId());
|
|
if (curSkill != null && SkillData.getSkillInfoById(skill.getSkillId()).getHyper() == 0) {
|
|
sp += curSkill.getCurrentLevel();
|
|
curSkill.setCurrentLevel(0);
|
|
skills.add(curSkill);
|
|
chr.addSkill(curSkill);
|
|
}
|
|
}
|
|
if (extendSP != null) {
|
|
byte jobLevel = (byte) JobConstants.getJobLevelDetail((short) job);
|
|
extendSP.setSpToJobLevel(jobLevel, extendSP.getSpByJobLevel(jobLevel) + sp);
|
|
sp = 0;
|
|
}
|
|
}
|
|
if (extendSP != null) {
|
|
chr.write(WvsContext.statChanged(Collections.singletonMap(Stat.sp, extendSP)));
|
|
} else {
|
|
chr.setStatAndSendPacket(Stat.sp, chr.getStat(Stat.sp) + sp);
|
|
}
|
|
if (!skills.isEmpty()) {
|
|
chr.write(WvsContext.changeSkillRecordResult(skills, true, false, false, false));
|
|
}
|
|
chr.write(WvsContext.resetItemResult(true, chr.getId(), true, true));
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_ABILITY_RESET_ITEM_USE_REQUEST)
|
|
public static void handleUserResetAP(Char chr, InPacket inPacket) {
|
|
if (inPacket != null) {
|
|
chr.getClient().verifyTick(inPacket);
|
|
short slot = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(slot);
|
|
if (item == null || itemID != item.getItemId() || itemID / 10 != 250100) {
|
|
chr.write(WvsContext.resetItemResult(true, chr.getId(), false, false));
|
|
return;
|
|
}
|
|
chr.consumeItem(item);
|
|
}
|
|
int ap = chr.getStat(Stat.ap);
|
|
ap += chr.getStat(Stat.str) - 4;
|
|
ap += chr.getStat(Stat.dex) - 4;
|
|
ap += chr.getStat(Stat.inte) - 4;
|
|
ap += chr.getStat(Stat.luk) - 4;
|
|
chr.setStat(Stat.str, 4);
|
|
chr.setStat(Stat.dex, 4);
|
|
chr.setStat(Stat.inte, 4);
|
|
chr.setStat(Stat.luk, 4);
|
|
chr.setStat(Stat.ap, ap);
|
|
Map<Stat, Object> stats = Map.of(Stat.str, (short) 4, Stat.dex, (short) 4, Stat.inte, (short) 4, Stat.luk, (short) 4, Stat.ap, (short) ap);
|
|
chr.write(WvsContext.statChanged(stats));
|
|
chr.write(WvsContext.resetItemResult(true, chr.getId(), true, false));
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_CONSUME_CASH_ITEM_USE_REQUEST)
|
|
public static void handleUserConsumeCashItemUseRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
Inventory cashInv = chr.getInventoryByType(InvType.CASH);
|
|
c.verifyTick(inPacket);
|
|
short pos = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
Item item = cashInv.getItemBySlot(pos);
|
|
ItemInfo itemInfo = ItemData.getItemInfoByID(itemID);
|
|
BeautyAlbum album = chr.getBeautyAlbum();
|
|
Item cube;
|
|
int cubeCount;
|
|
if (item == null || item.getItemId() != itemID) {
|
|
return;
|
|
}
|
|
if (itemID / 10000 == 553) {
|
|
// Reward items
|
|
if (itemID % 10000 < 3000) {
|
|
Object reward;
|
|
if (itemInfo != null && (reward = itemInfo.getRandomReward()) != null) {
|
|
if (reward instanceof Item) {
|
|
chr.addItemToInventory((Item) reward);
|
|
} else if (reward instanceof Integer && (int) reward != 0) {
|
|
chr.addMoney((int) reward);
|
|
} else {
|
|
chr.chatMessage("Oh, you're unlucky."); // should not happen
|
|
}
|
|
} else {
|
|
chr.chatMessage("Oh, you're unlucky.");
|
|
}
|
|
} else if (itemID == 5534000) { // Tim's Secret lab
|
|
short ePos = (short) inPacket.decodeInt();
|
|
InvType invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
Equip equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.dispose("Could not find equip.");
|
|
return;
|
|
} else if (!ItemConstants.canEquipHavePotential(equip)) {
|
|
chr.dispose("You cannot use Tim's Secret Lab on this item.");
|
|
return;
|
|
}
|
|
equip.setHiddenOptionBase(ItemGrade.HiddenRare.getVal(), 100);
|
|
c.write(FieldPacket.showItemUpgradeEffect(chr.getId(), true, false, itemID, equip.getItemId(), false));
|
|
equip.updateToChar(chr);
|
|
}
|
|
} else if (itemID / 10000 == 539) {
|
|
// Avatar Megaphones
|
|
List<String> lineList = new ArrayList<>();
|
|
for (int i = 0; i < 4; i++) {
|
|
String line = inPacket.decodeString();
|
|
lineList.add(line);
|
|
}
|
|
boolean whisperIcon = inPacket.decodeByte() != 0;
|
|
World world = c.getWorld();
|
|
world.broadcastPacket(WvsContext.setAvatarMegaphone(chr, itemID, lineList, whisperIcon));
|
|
|
|
} else if (itemID / 10000 == 519) {
|
|
// Pet Skill Items
|
|
long sn = inPacket.decodeLong();
|
|
PetSkill ps = ItemConstants.getPetSkillFromID(itemID);
|
|
if (ps == null) {
|
|
chr.chatMessage(String.format("Unhandled pet skill item %d", itemID));
|
|
return;
|
|
}
|
|
Item pi = chr.getCashInventory().getItemBySN(sn);
|
|
if (!(pi instanceof PetItem)) {
|
|
chr.chatMessage("Could not find that pet.");
|
|
return;
|
|
}
|
|
boolean add = itemID < 5191000; // add property doesn't include the "Slimming Medicine"
|
|
PetItem petItem = (PetItem) pi;
|
|
if (add) {
|
|
petItem.addPetSkill(ps);
|
|
} else {
|
|
petItem.removePetSkill(ps);
|
|
}
|
|
petItem.updateToChar(chr);
|
|
} else if (ItemConstants.isMiuMiuMerchant(itemID)) {
|
|
|
|
chr.getScriptManager().openShop(9090000);
|
|
|
|
} else if (ItemConstants.isPortableStorage(itemID)) {
|
|
|
|
chr.getScriptManager().openTrunk(1022005);
|
|
} else if (itemID / 10000 == 512) { // Weather Items
|
|
chr.getField().blowWeather(itemID, inPacket.decodeString(), 10, null);
|
|
int stateChangeItem = itemInfo.getStateChangeItem();
|
|
if (stateChangeItem != 0 && !ItemData.getItemInfoByID(stateChangeItem).getSpecStats().isEmpty()) {
|
|
chr.getField().getChars().forEach(it -> ItemBuffs.giveItemBuffsFromItemID(it, it.getTemporaryStatManager(), stateChangeItem));
|
|
}
|
|
} else {
|
|
|
|
Equip medal = (Equip) chr.getEquippedInventory().getFirstItemByBodyPart(BodyPart.Medal);
|
|
int medalInt = 0;
|
|
if (medal != null) {
|
|
medalInt = (medal.getAnvilId() == 0 ? medal.getItemId() : medal.getAnvilId()); // Check for Anvilled medal
|
|
}
|
|
String medalString = (medalInt == 0 ? "" : String.format("<%s> ", StringData.getItemStringById(medalInt)));
|
|
|
|
switch (itemID) {
|
|
case ItemConstants.HYPER_TELEPORT_ROCK: // Hyper Teleport Rock
|
|
short type = inPacket.decodeShort();
|
|
if (type == 0 || type == 1) {
|
|
int fieldId = inPacket.decodeInt();
|
|
Field field = chr.getOrCreateFieldByCurrentInstanceType(fieldId);
|
|
if (field == null || (chr.getField().getFieldLimit() & FieldOption.TeleportItemLimit.getVal()) > 0 ||
|
|
!FieldData.getWorldMapFields().contains(fieldId)) {
|
|
chr.chatMessage("You may not warp to that map, as you cannot teleport from your current map.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
chr.setInstance(null);
|
|
chr.warp(field);
|
|
} else {
|
|
String targetName = inPacket.decodeString();
|
|
int worldID = chr.getClient().getChannelInstance().getWorldId().getVal();
|
|
World world = Server.getInstance().getWorldById(worldID);
|
|
Char targetChr = world.getCharByName(targetName);
|
|
|
|
// Target doesn't exist or target char is not a regular player
|
|
if (targetChr == null || targetChr.getAccount().getAccountType().getVal() >= 1) {
|
|
chr.chatMessage(String.format("%s is not online.", targetName));
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
|
|
Position targetPosition = targetChr.getPosition();
|
|
|
|
Field targetField = targetChr.getField();
|
|
if (targetField == null || (targetField.getFieldLimit() & FieldOption.TeleportItemLimit.getVal()) > 0) {
|
|
chr.chatMessage("You may not warp to that map, as the targeted map cannot be teleported to.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
// Target is in an instanced Map
|
|
if (targetChr.getInstance() != null) {
|
|
chr.chatMessage(String.format("cannot find %s", targetName));
|
|
// Change channels & warp & teleport
|
|
} else if (targetChr.getClient().getChannel() != c.getChannel()) {
|
|
chr.setInstance(null);
|
|
chr.chatMessage(String.format("cannot find %s on this channel", targetName));
|
|
//chr.changeChannelAndWarp(targetChr.getClient().getChannel(), fieldId); // Makes you warp to player without being in the same CH
|
|
return;
|
|
// warp & teleport
|
|
} else if (targetChr.getFieldID() != chr.getFieldID()) {
|
|
chr.setInstance(null);
|
|
chr.warp(targetField);
|
|
chr.write(FieldPacket.teleport(targetPosition, chr));
|
|
// teleport
|
|
} else {
|
|
chr.write(FieldPacket.teleport(targetPosition, chr));
|
|
}
|
|
}
|
|
break;
|
|
case 5170000:
|
|
int petID = inPacket.decodeInt();
|
|
inPacket.decodeInt(); //??
|
|
String petName1 = inPacket.decodeString();
|
|
|
|
Pet petid = chr.getPetById(petID);
|
|
|
|
if (petName1.length() > 13) {
|
|
chr.chatMessage("no");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
|
|
if (petid != null) {
|
|
petid.setName(petName1);
|
|
petid.getItem().setName(petName1);
|
|
int idx = petid.getIdx();
|
|
chr.write(UserLocal.petNameChange(chr, idx, petName1));
|
|
}
|
|
break;
|
|
case ItemConstants.OCCULT_CUBE:
|
|
case ItemConstants.RED_CUBE: // Red Cube
|
|
case ItemConstants.BLACK_CUBE: // Black cube
|
|
cube = chr.getCashInventory().getItemByItemID(itemID);
|
|
cubeCount = cube.getQuantity();
|
|
cubeCount--;
|
|
|
|
short ePos = (short) inPacket.decodeInt();
|
|
InvType invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
Equip equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.chatMessage(SystemNotice, "Could not find equip.");
|
|
chr.dispose();
|
|
return;
|
|
} else if (equip.getBaseGrade() < ItemGrade.Rare.getVal()) {
|
|
String msg = String.format("Character %d tried to use cube (id %d) an equip without a potential (id %d)", chr.getId(), itemID, equip.getItemId());
|
|
chr.getOffenseManager().addOffense(msg);
|
|
chr.dispose();
|
|
return;
|
|
} else if (itemID == ItemConstants.OCCULT_CUBE && equip.getBaseGrade() > ItemGrade.Epic.getVal()) {
|
|
chr.chatMessage(SystemNotice, "You may only use this on Rare or Epic Items!");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
short hiddenValue = ItemGrade.getHiddenGradeByVal(equip.getBaseGrade()).getVal();
|
|
int tierUpChance = ItemConstants.getTierUpChance(itemID, hiddenValue);
|
|
boolean tierUp = tierUpChance > 0 && Util.succeedProp(tierUpChance);
|
|
if (tierUp && (itemID != ItemConstants.OCCULT_CUBE || equip.getBaseGrade() != ItemGrade.Epic.getVal())) {
|
|
hiddenValue++;
|
|
}
|
|
if (itemID == ItemConstants.RED_CUBE) {
|
|
equip.setHiddenOptionBase(hiddenValue, 0);
|
|
equip.releaseOptions(false);
|
|
chr.getField().broadcastPacket(UserPacket.showItemMemorialEffect(chr.getId(), true, itemID, ePos, pos));
|
|
c.write(FieldPacket.redCubeResult(chr.getId(), tierUp, itemID, ePos, equip, cubeCount));
|
|
// c.write(FieldPacket.showItemReleaseEffect(chr.getId(), ePos, false));
|
|
equip.updateToChar(chr);
|
|
if (invType == EQUIPPED) {
|
|
chr.recalcStats(equip.getBaseStatFlag());
|
|
}
|
|
} else {
|
|
if (chr.getMemorialCubeInfo() == null) {
|
|
chr.setMemorialCubeInfo(new MemorialCubeInfo(equip.deepCopy(), itemID));
|
|
}
|
|
Equip newEquip = chr.getMemorialCubeInfo().getEquip();
|
|
newEquip.setHiddenOptionBase(hiddenValue, 0);
|
|
newEquip.releaseOptions(false);
|
|
chr.getField().broadcastPacket(UserPacket.showItemMemorialEffect(chr.getId(), true, itemID, ePos, pos));
|
|
c.write(WvsContext.blackCubeResult(equip, chr.getMemorialCubeInfo(), cubeCount));
|
|
}
|
|
break;
|
|
case ItemConstants.VIOLET_CUBE: // Violet cube
|
|
ePos = (short) inPacket.decodeInt();
|
|
invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.chatMessage(SystemNotice, "Could not find equip.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
long number = equip.getId();
|
|
Equip copy = equip.deepCopy();
|
|
if (copy.getBaseGrade() < ItemGrade.Rare.getVal()) {
|
|
String msg = String.format("Character %d tried to use cube (id %d) an equip without a potential (id %d)", chr.getId(), itemID, equip.getItemId());
|
|
chr.getOffenseManager().addOffense(msg);
|
|
chr.dispose();
|
|
return;
|
|
} else if (chr.getMoney() < 36000) { // TODO: correct cost by level
|
|
c.write(WvsContext.broadcastMsg(BroadcastMsg.popUpMessage("You do not have enough mesos.")));
|
|
c.write(CUIHandler.violetCubeResult(0, 1, 0, Collections.emptyList()));
|
|
return;
|
|
}
|
|
byte line = (byte) Arrays.stream(copy.getOptionBase()).filter(option -> option > 0).count();
|
|
if (line <= 1) {
|
|
chr.chatMessage(SystemNotice, "You cannot use Violet Cube on this item.");
|
|
c.write(CUIHandler.violetCubeResult(0, 1, line, Collections.emptyList()));
|
|
return;
|
|
}
|
|
short optionGrade = ItemGrade.getHiddenGradeByVal(copy.getBaseGrade()).getVal();
|
|
tierUpChance = ItemConstants.getTierUpChance(itemID, optionGrade);
|
|
if (tierUpChance > 0 && Util.succeedProp(tierUpChance)) {
|
|
optionGrade++;
|
|
}
|
|
copy.setItemState(optionGrade);
|
|
List<Integer> options = new ArrayList<>(line * 2);
|
|
for (byte i = 0; i < line * 2; i++) {
|
|
options.add(copy.getRandomOption(false, i % 3)); // ensure 2 of 4/6 options are higher rank
|
|
}
|
|
Quest quest = chr.getQuestManager().getOrCreateQuestById(QuestConstants.VIOLET_CUBE_INFO);
|
|
quest.setProperty("o", options.toString().replace("[", "").replace("]", "").replace(" ", ""));
|
|
quest.setProperty("n", String.valueOf(number));
|
|
quest.setProperty("p", ePos);
|
|
quest.setProperty("c", line);
|
|
quest.setProperty("i", copy.getItemId());
|
|
quest.setProperty("og", optionGrade);
|
|
chr.write(WvsContext.questRecordExMessage(quest));
|
|
chr.deductMoney(36000); // TODO: correct cost by level
|
|
c.write(FieldPacket.showItemUnReleaseEffect(chr.getId(), true, itemID, 0, copy.getItemId()));
|
|
c.write(CUIHandler.violetCubeResult(0, 0, line, options));
|
|
chr.chatMessage(options.toString());
|
|
break;
|
|
case ItemConstants.BONUS_POT_CUBE: // Bonus Potential Cube
|
|
case ItemConstants.SPECIAL_BONUS_POT_CUBE: // [Special] Bonus Potential Cube
|
|
case ItemConstants.WHITE_BONUS_POT_CUBE: // White Bonus Potential Cube
|
|
cube = chr.getCashInventory().getItemByItemID(itemID);
|
|
cubeCount = cube.getQuantity();
|
|
cubeCount--;
|
|
|
|
if (c.getWorld().isReboot()) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d attempted to use a bonus potential cube in reboot world.", chr.getId()));
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
ePos = (short) inPacket.decodeInt();
|
|
invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.chatMessage(SystemNotice, "Could not find equip.");
|
|
chr.dispose();
|
|
return;
|
|
} else if (equip.getBonusGrade() < ItemGrade.Rare.getVal()) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to use cube (id %d) an equip without a potential (id %d)", chr.getId(), itemID, equip.getItemId()));
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
hiddenValue = ItemGrade.getHiddenGradeByVal(equip.getBonusGrade()).getVal();
|
|
tierUpChance = ItemConstants.getTierUpChance(itemID, hiddenValue);
|
|
tierUp = tierUpChance > 0 && Util.succeedProp(tierUpChance);
|
|
if (tierUp) {
|
|
hiddenValue++;
|
|
}
|
|
if (itemID != ItemConstants.WHITE_BONUS_POT_CUBE) {
|
|
equip.setHiddenOptionBonus(hiddenValue, 0);
|
|
equip.releaseOptions(true);
|
|
chr.getField().broadcastPacket(UserPacket.showItemMemorialEffect(chr.getId(), true, itemID, ePos, pos));
|
|
c.write(FieldPacket.bonusCubeResult(chr.getId(), tierUp, itemID, ePos, equip, cubeCount));
|
|
// c.write(FieldPacket.showItemReleaseEffect(chr.getId(), ePos, true));
|
|
equip.updateToChar(chr);
|
|
if (invType == EQUIPPED) {
|
|
chr.recalcStats(equip.getBaseStatFlag());
|
|
}
|
|
} else {
|
|
if (chr.getMemorialCubeInfo() == null) {
|
|
chr.setMemorialCubeInfo(new MemorialCubeInfo(equip.deepCopy(), itemID));
|
|
}
|
|
Equip newEquip = chr.getMemorialCubeInfo().getEquip();
|
|
newEquip.setHiddenOptionBonus(hiddenValue, 0);
|
|
newEquip.releaseOptions(true);
|
|
chr.getField().broadcastPacket(UserPacket.showItemMemorialEffect(chr.getId(), true, itemID, ePos, pos));
|
|
c.write(WvsContext.whiteCubeResult(equip, chr.getMemorialCubeInfo(), cubeCount));
|
|
}
|
|
break;
|
|
case 5520001: // Platinum Scissors of Karma
|
|
inPacket.decodeInt(); // 1
|
|
ePos = (short) inPacket.decodeInt();
|
|
equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.chatMessage("Could not find equip.");
|
|
chr.dispose();
|
|
return;
|
|
} else if (equip.hasAttribute(EquipAttribute.Locked)
|
|
|| !equip.hasAttribute(EquipAttribute.Untradable)
|
|
|| equip.hasAttribute(EquipAttribute.UntradableAfterTransaction)
|
|
|| equip.getCuttable() == 0) {
|
|
chr.chatMessage("You cannot use Scissors of Karma on this equip.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
equip.addAttribute(EquipAttribute.UntradableAfterTransaction);
|
|
equip.setTradeBlock(false);
|
|
equip.setEquipTradeBlock(true);
|
|
//equip.setCuttable((short) 0);
|
|
equip.updateToChar(chr);
|
|
break;
|
|
case 5750001: // Nebulite Diffuser
|
|
ePos = inPacket.decodeShort();
|
|
equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (equip == null || equip.getSocket(0) == 0 || equip.getSocket(0) == ItemConstants.EMPTY_SOCKET_ID) {
|
|
chr.chatMessage("That item currently does not have an active socket.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
equip.setSocket(0, ItemConstants.EMPTY_SOCKET_ID);
|
|
equip.updateToChar(chr);
|
|
break;
|
|
case 5072000: // Super Megaphone
|
|
String text = inPacket.decodeString();
|
|
boolean whisperIcon = inPacket.decodeByte() != 0;
|
|
World world = chr.getClient().getWorld();
|
|
BroadcastMsg smega = BroadcastMsg.megaphone(
|
|
String.format("%s%s : %s", medalString, chr.getName(), text),
|
|
(byte) chr.getClient().getChannelInstance().getChannelId(), whisperIcon, chr);
|
|
world.broadcastPacket(WvsContext.broadcastMsg(smega));
|
|
break;
|
|
case 5076000: // Item Megaphone
|
|
text = inPacket.decodeString();
|
|
whisperIcon = inPacket.decodeByte() != 0;
|
|
boolean eqpSelected = inPacket.decodeByte() != 0;
|
|
invType = EQUIP;
|
|
int itemPosition = 0;
|
|
if (eqpSelected) {
|
|
invType = InvType.getInvTypeByVal(inPacket.decodeInt());
|
|
itemPosition = inPacket.decodeInt();
|
|
if (invType == EQUIP && itemPosition < 0) {
|
|
invType = EQUIPPED;
|
|
}
|
|
}
|
|
Item broadcastedItem = chr.getInventoryByType(invType).getItemBySlot(itemPosition);
|
|
|
|
world = chr.getClient().getWorld();
|
|
smega = BroadcastMsg.itemMegaphone(String.format("%s%s : %s", medalString, chr.getName(), text),
|
|
(byte) chr.getClient().getChannelInstance().getChannelId(), whisperIcon, eqpSelected,
|
|
broadcastedItem, chr);
|
|
world.broadcastPacket(WvsContext.broadcastMsg(smega));
|
|
break;
|
|
case 5077000: // Triple Megaphone
|
|
byte stringListSize = inPacket.decodeByte();
|
|
List<String> stringList = new ArrayList<>();
|
|
for (int i = 0; i < stringListSize; i++) {
|
|
stringList.add(String.format("%s%s : %s", medalString, chr.getName(), inPacket.decodeString()));
|
|
}
|
|
whisperIcon = inPacket.decodeByte() != 0;
|
|
|
|
world = chr.getClient().getWorld();
|
|
smega = BroadcastMsg.tripleMegaphone(stringList,
|
|
(byte) chr.getClient().getChannelInstance().getChannelId(), whisperIcon, chr);
|
|
world.broadcastPacket(WvsContext.broadcastMsg(smega));
|
|
break;
|
|
case 5062400: // Fusion anvil
|
|
case 5062402: // Medal Fusion anvil
|
|
case 5062405: // Fusion anvil
|
|
int appearancePos = inPacket.decodeInt();
|
|
int functionPos = inPacket.decodeInt();
|
|
Inventory inv = chr.getEquipInventory();
|
|
Equip appearance = (Equip) inv.getItemBySlot(appearancePos);
|
|
Equip function = (Equip) inv.getItemBySlot(functionPos);
|
|
if (appearance == null || function == null) {
|
|
chr.dispose("Could not find equip.");
|
|
return;
|
|
} else if (appearance.getItemId() / 10000 != function.getItemId() / 10000) {
|
|
chr.dispose("Fusion only works on equipment of the same type. Please check the item you want to Fuse.");
|
|
return;
|
|
} else if (itemID == 5062402 && !ItemConstants.isMedal(appearance.getItemId())) {
|
|
chr.dispose("Medal Fusion Anvil only works on medals.");
|
|
return;
|
|
} else if (itemID != 5062402 && ItemConstants.isMedal(appearance.getItemId())) {
|
|
chr.dispose("Fusion Anvil doesn't work on medals.");
|
|
return;
|
|
}
|
|
if (appearance.getItemId() / 10000 == function.getItemId() / 10000) {
|
|
function.setOption(6, appearance.getItemId() % 10000, false);
|
|
}
|
|
function.updateToChar(chr);
|
|
break;
|
|
//These are semi buggy
|
|
case 5155000: //Elf to Human | anyone to Elf
|
|
if (chr.getCarta() == 1) {
|
|
chr.setCarta(0);
|
|
} else {
|
|
chr.setCarta(1);
|
|
}
|
|
break;
|
|
case 5155004: //Illium to Human | anyone to Illium
|
|
if (chr.getCarta() == 2) {
|
|
chr.setCarta(0);
|
|
} else {
|
|
chr.setCarta(2);
|
|
}
|
|
break;
|
|
case 5155005: //Ark to Human | anyone to Ark
|
|
if (chr.getCarta() == 3) {
|
|
chr.setCarta(0);
|
|
} else {
|
|
chr.setCarta(3);
|
|
}
|
|
break;
|
|
case 5068300: //Random Pet Box
|
|
int[] pets = new int[]{
|
|
5002106, 5002107, 5002108, 5000921, 5000922, 5000923, 5002076, 5002077, 5002078, 5002057, 5002058, 5002059, 5000954, 5000955, 5000956, 5002048, 5002049, 5002050, 5002045, 5002046, 5002047,
|
|
5000960, 5000961, 5000962, 5002066, 5002067, 5002068, 5002030, 5002031, 5002032, 5002040, 5002039, 5002036, 5002037, 5002038, 5002033, 5002034, 5002035, 5002028, 5002029, 5002021, 5002022,
|
|
5002023, 5002017, 5002011, 5002012, 5002013, 5002003, 5002004, 5002005, 5000997, 5000998, 5000999, 5000979, 5000980, 5000981, 5000977, 5000794, 5000973, 5000972, 5000971, 5000970, 5000964,
|
|
5000965, 5000966, 5000967, 5000968, 5000969, 5000909, 5000910, 5000911, 5000942, 5000943, 5000944, 5000939, 5000933, 5000934, 5000935, 5000915, 5000916, 5000917, 5000912, 5000913, 5000914,
|
|
5000906, 5000907, 5000908, 5000900, 5000901, 5000902, 5000846, 5000847, 5000848, 5000836, 5000835, 5000822, 5000823, 5000824, 5000812, 5000813, 5000814, 5000798, 5000793, 5000794, 5000796,
|
|
5000762, 5000763, 5000764, 5000696, 5000633, 5000634, 5000635, 5000565, 5000566, 5000567, 5000460, 5000461, 5000462, 5000677, 5000678, 5000443, 5000444, 5000445, 5000647, 5000648, 5000649,
|
|
5000636, 5000637, 5000638, 5000637, 5000638, 5000536, 5000537, 5000538, 5000456, 5000457, 5000458, 5000499, 5000405, 5000406, 5000407, 5000402, 5000403, 5000404, 5000385, 5000386, 5000387,
|
|
5000368, 5000341, 5000316
|
|
};
|
|
Random pet = new Random();
|
|
int randomIndex = pet.nextInt(pets.length);
|
|
int getRandomPet = pets[randomIndex];
|
|
String petName = StringData.getItemStringById(getRandomPet);
|
|
if (chr.canHold(getRandomPet, 1)) {
|
|
String worldTxt = (chr.getName() + " just got a cute " + petName + " from the Wisp's Wondrous Wonderberry");
|
|
chr.getWorld().broadcastPacket(UserLocal.chatMsg(MiracleTime, worldTxt));
|
|
chr.addItemToInventory(getRandomPet, 1);
|
|
} else {
|
|
chr.chatMessage("Make room in your cash Inventory!");
|
|
}
|
|
break;
|
|
case 5222058:
|
|
int[] chairs = new int[]{3018427, 3018425, 3018424, 3018416, 3018390, 3018389, 3018370, 3018369, 3018365, 3018358};
|
|
Random chair = new Random();
|
|
int randomcIndex = chair.nextInt(chairs.length);
|
|
int getRandomChair = chairs[randomcIndex];
|
|
String chairName = StringData.getItemStringById(getRandomChair);
|
|
if (chr.canHold(getRandomChair, 1)) {
|
|
String worldTxt = (chr.getName() + " just got a " + chairName + " from the Chair Box");
|
|
chr.getWorld().broadcastPacket(UserLocal.chatMsg(MiracleTime, worldTxt));
|
|
chr.addItemToInventory(getRandomChair, 1);
|
|
} else {
|
|
chr.chatMessage("Make room in your SetUp Inventory!");
|
|
}
|
|
break;
|
|
case 5062800: // Miracle Circulator
|
|
case 5062801:
|
|
CharacterPotentialMan cpm = chr.getPotentialMan();
|
|
if (cpm.getGrade() == 0) {
|
|
chr.dispose("You cannot use Miracle Circulator in your current state.");
|
|
return;
|
|
}
|
|
byte grade = cpm.getGrade();
|
|
// update grades
|
|
if (grade < CharPotGrade.Legendary.ordinal() && Util.succeedProp(GameConstants.BASE_CHAR_POT_UP_RATE)) {
|
|
grade++;
|
|
}
|
|
MiracleCirculatorInfo mci = new MiracleCirculatorInfo(itemID, item.getId());
|
|
List<CharacterPotential> potentials = CharacterPotentialMan.generateRandomPotential(3, grade, false, null);
|
|
potentials.sort(Comparator.comparingInt(CharacterPotentialData::getKey));
|
|
for (CharacterPotential cp : potentials) {
|
|
mci.getPotentials().add(cp);
|
|
chr.chatMessage("Key:" + cp.getKey() + " Grade:" + cp.getGrade() + " SkillID:" + cp.getSkillID()
|
|
+ "(" + StringData.getSkillStringById(cp.getSkillID()).getName() + ") SLV:" + cp.getSlv());
|
|
}
|
|
chr.setMiracleCirculatorInfo(mci);
|
|
c.write(WvsContext.miracleCirculatorResult(mci, pos));
|
|
break;
|
|
case 5570000:
|
|
inPacket.decodeInt(); // use hammer? useless though
|
|
ePos = (short) inPacket.decodeInt(); // equip slot
|
|
invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.write(WvsContext.viciousHammerItemUpgradeResult(192, 1, 0));
|
|
return;
|
|
}
|
|
short maxHammers = ItemConstants.MAX_HAMMER_SLOTS;
|
|
Equip defaultEquip = ItemData.getEquipById(equip.getItemId());
|
|
if (defaultEquip.isHasIUCMax()) {
|
|
maxHammers = defaultEquip.getIUCMax();
|
|
}
|
|
if (equip.getIuc() >= maxHammers) {
|
|
chr.write(WvsContext.viciousHammerItemUpgradeResult(192, 2, 0));
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to use Vicious's Hammer an invalid equip (id %d)",
|
|
chr.getId(), equip.getItemId()));
|
|
return;
|
|
}
|
|
if (!ItemConstants.canEquipGoldHammer(equip)) {
|
|
chr.write(WvsContext.viciousHammerItemUpgradeResult(192, 3, 0));
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to use Vicious' Hammer on an invalid equip (id %d)",
|
|
chr.getId(), equip.getItemId()));
|
|
return;
|
|
}
|
|
equip.addStat(iuc, 1); // +1 hammer used
|
|
equip.addStat(tuc, 1); // +1 upgrades available
|
|
equip.updateToChar(chr);
|
|
chr.write(WvsContext.viciousHammerItemUpgradeResult(190, 0, equip.getIuc()));
|
|
break;
|
|
case 5050100: // AP Reset Scroll
|
|
handleUserResetAP(chr, null);
|
|
break;
|
|
case 5051001: // SP Reset Scroll
|
|
handleUserResetSP(chr, null);
|
|
break;
|
|
case 5064000: // Shielding Ward (reg 12 stars)
|
|
case 5064003: // Superior Shielding Ward (reg 7 stars)
|
|
case 5064100: // Shield Scroll
|
|
case 5064300: // Guardian Scroll
|
|
case 5064400: // Return Scroll
|
|
case 5068100: // Pet Shield Scroll
|
|
ePos = inPacket.decodeShort();
|
|
inPacket.decodeByte();
|
|
invType = ePos < 0 ? EQUIPPED : EQUIP;
|
|
equip = (Equip) chr.getInventoryByType(invType).getItemBySlot(ePos);
|
|
if (equip == null) {
|
|
chr.dispose("Could not find equip.");
|
|
return;
|
|
} else if (itemID == 5064000 && equip.getChuc() >= 12 // TODO: superior item check
|
|
|| itemID == 5064003 && equip.getChuc() >= 7
|
|
|| itemID == 5068100 && equip.getItemId() / 10000 != EquipPrefix.PetWear.getVal()) {
|
|
chr.dispose("You cannot use this scroll on this item.");
|
|
return;
|
|
}
|
|
switch (itemID % 10000 / 100) {
|
|
case 40 -> equip.addAttribute(EquipAttribute.ProtectionScroll);
|
|
case 41, 81 -> equip.addAttribute(EquipAttribute.UpgradeCountProtection);
|
|
case 43 -> equip.addAttribute(EquipAttribute.ScrollProtection);
|
|
case 44 -> equip.addAttribute(EquipAttribute.ReturnScroll);
|
|
// TODO: add actual effects on server side
|
|
}
|
|
chr.chatMessage("The scroll effect is not implemented yet.");
|
|
equip.updateToChar(chr);
|
|
break;
|
|
case 5553000:
|
|
if (album.getHairSlot() < 50) {
|
|
album.setHairSlot(album.getHairSlot() + 1);
|
|
chr.write(UserLocal.beautyAlbumActions((byte) 0x5, 30000, album.getHairSlot(), album));
|
|
}
|
|
break;
|
|
case 5552000:
|
|
if (album.getFaceSlot() < 50) {
|
|
album.setFaceSlot(album.getFaceSlot() + 1);
|
|
chr.write(UserLocal.beautyAlbumActions((byte) 0x5, 20000, album.getFaceSlot(), album));
|
|
}
|
|
break;
|
|
default:
|
|
chr.chatMessage(Mob, String.format("Cash item %d is not implemented, notify Taiga pls.", itemID));
|
|
return;
|
|
}
|
|
}
|
|
if (itemID != 5040004 && itemID / 10000 != 545) { // TP Rocks and Portable Stores / Storages
|
|
chr.consumeItem(item);
|
|
}
|
|
chr.dispose();
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.USER_ARCANE_SYMBOL_MERGE_REQUEST)
|
|
public static void handleUserArcaneSymbolMergeRequest(Char chr, InPacket inPacket) {
|
|
int type = inPacket.decodeInt();
|
|
int fromPos = inPacket.decodeInt();
|
|
switch (type) {
|
|
case 0:
|
|
// merge
|
|
Equip fromEq = (Equip) chr.getEquipInventory().getItemBySlot(fromPos);
|
|
Equip toEq = (Equip) chr.getEquippedInventory().getItemByItemID(fromEq == null ? 0 : fromEq.getItemId());
|
|
if (fromEq == null || toEq == null || fromEq.getItemId() != toEq.getItemId() || !ItemConstants.isArcaneSymbol(toEq.getItemId())) {
|
|
chr.chatMessage("Could not find one of the symbols.");
|
|
return;
|
|
}
|
|
if (toEq.getSymbolExp() >= ItemConstants.getRequiredSymbolExp(toEq.getSymbolLevel())) {
|
|
chr.chatMessage("Your symbol already is at max exp.");
|
|
return;
|
|
}
|
|
chr.consumeItem(fromEq);
|
|
toEq.setSymbolExp(Math.min(toEq.getSymbolExp() + fromEq.getSymbolExp(), ItemConstants.getRequiredSymbolExp(toEq.getSymbolLevel())));
|
|
toEq.updateToChar(chr);
|
|
break;
|
|
case 1:
|
|
// enhance
|
|
Equip symbol = (Equip) chr.getEquippedInventory().getItemBySlot(fromPos);
|
|
int reqSymbolExp = ItemConstants.getRequiredSymbolExp(symbol.getLevel());
|
|
if (symbol == null || !ItemConstants.isArcaneSymbol(symbol.getItemId())
|
|
|| symbol.getSymbolLevel() >= ItemConstants.MAX_ARCANE_SYMBOL_LEVEL
|
|
|| symbol.getSymbolExp() < reqSymbolExp) {
|
|
chr.chatMessage("Could not find symbol.");
|
|
return;
|
|
}
|
|
long cost = ItemConstants.getSymbolMoneyReqByLevel(symbol.getSymbolLevel());
|
|
if (cost > chr.getMoney()) {
|
|
chr.chatMessage("You do not have enough mesos to level up your symbol.");
|
|
return;
|
|
}
|
|
chr.deductMoney(cost);
|
|
symbol.setSymbolLevel((short) (symbol.getSymbolLevel() + 1));
|
|
symbol.addSymbolExp(-reqSymbolExp);
|
|
symbol.initSymbolStats(symbol.getSymbolLevel(), chr.getJob());
|
|
symbol.updateToChar(chr);
|
|
chr.recalcStats(symbol.getBaseStatFlag());
|
|
break;
|
|
case 2:
|
|
// mass merge
|
|
int itemId = fromPos;
|
|
toEq = (Equip) chr.getEquippedInventory().getItemByItemID(itemId);
|
|
if (!(toEq instanceof Equip) || !ItemConstants.isArcaneSymbol(itemId)) {
|
|
chr.chatMessage("Could not find an arcane symbol to transfer to.");
|
|
return;
|
|
}
|
|
if (toEq.hasSymbolExpForLevelUp()) {
|
|
chr.chatMessage("First level your symbol before trying to add more symbols onto it.");
|
|
return;
|
|
}
|
|
Set<Equip> matchingSymbols = new HashSet<>();
|
|
for (Item item : chr.getEquipInventory().getItems()) {
|
|
if (item.getItemId() == toEq.getItemId()) {
|
|
matchingSymbols.add((Equip) item);
|
|
}
|
|
}
|
|
for (Equip eqSymbol : matchingSymbols) {
|
|
chr.consumeItem(eqSymbol);
|
|
toEq.addSymbolExp(eqSymbol.getTotalSymbolExp());
|
|
if (toEq.hasSymbolExpForLevelUp()) {
|
|
break;
|
|
}
|
|
}
|
|
toEq.updateToChar(chr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.USER_STAT_CHANGE_ITEM_USE_REQUEST)
|
|
public static void handleUserStatChangeItemUseRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
Field field = chr.getField();
|
|
if ((field.getFieldLimit() & FieldOption.StatChangeItemConsumeLimit.getVal()) > 0) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
TemporaryStatManager tsm = chr.getTemporaryStatManager();
|
|
c.verifyTick(inPacket);
|
|
short slot = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(slot);
|
|
if (item == null || item.getItemId() != itemID || !chr.isInValidState()) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
chr.useStatChangeItem(item, true);
|
|
if (field.getConsumeItemCoolTime() > 0) {
|
|
chr.write(UserLocal.consumeItemCooltime());
|
|
}
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.USER_SCRIPT_ITEM_USE_REQUEST)
|
|
public static void handleUserScriptItemUseRequest(Client c, InPacket inPacket) {
|
|
c.verifyTick(inPacket);
|
|
short slot = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
int quant = inPacket.decodeInt();
|
|
Char chr = c.getChr();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(slot);
|
|
if (item == null || item.getItemId() != itemID) {
|
|
item = chr.getCashInventory().getItemBySlot(slot);
|
|
}
|
|
if (item == null || item.getItemId() != itemID || quant < 0 || !chr.isInValidState()) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
String script = String.valueOf(itemID);
|
|
ItemInfo ii = ItemData.getItemInfoByID(itemID);
|
|
if (ii.getScript() != null && !"".equals(ii.getScript())) {
|
|
script = ii.getScript();
|
|
}
|
|
if (item.getItemId() == ItemConstants.GAGAGUCCI) {
|
|
int qid = QuestConstants.PVAC_DATA;
|
|
if (chr.getRecordFromQuestEx(qid, "vac") == 0) {
|
|
chr.setQuestRecordEx(qid, "vac", 1);
|
|
chr.chatMessage("Pvac has been enabled");
|
|
} else {
|
|
chr.setQuestRecordEx(qid, "vac", 0);
|
|
chr.chatMessage("Pvac has been disabled");
|
|
}
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
|
|
chr.getScriptManager().startScript(itemID, script, ScriptType.Item);
|
|
chr.dispose();
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.USER_EQUIPMENT_ENCHANT_WITH_SINGLE_UI_REQUEST)
|
|
public static void handleUserEquipmentEnchantWithSingleUIRequest(Client c, InPacket inPacket) {
|
|
byte equipmentEnchantType = inPacket.decodeByte();
|
|
|
|
Char chr = c.getChr();
|
|
EquipmentEnchantType eeType = EquipmentEnchantType.getByVal(equipmentEnchantType);
|
|
|
|
if (eeType == null) {
|
|
log.error(String.format("Unknown enchant UI request %d", equipmentEnchantType));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
|
|
switch (eeType) {
|
|
case ScrollUpgradeRequest:
|
|
c.verifyTick(inPacket);
|
|
short pos = inPacket.decodeShort();
|
|
int scrollID = inPacket.decodeInt();
|
|
Inventory inv = pos < 0 ? chr.getEquippedInventory() : chr.getEquipInventory();
|
|
pos = (short) Math.abs(pos);
|
|
Equip equip = (Equip) inv.getItemBySlot(pos);
|
|
if (equip == null || equip.hasSpecialAttribute(EquipSpecialAttribute.Vestige)) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to enchant a non-scrollable equip (pos %d, itemid %d).",
|
|
chr.getId(), pos, equip == null ? 0 : equip.getItemId()));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
Equip prevEquip = equip.deepCopy();
|
|
List<ScrollUpgradeInfo> suis = ItemConstants.getScrollUpgradeInfosByEquip(equip);
|
|
if (scrollID < 0 || scrollID >= suis.size()) {
|
|
chr.getOffenseManager().addOffense(String.format("Characer %d tried to spell trace scroll with an invalid scoll ID (%d, "
|
|
+ "itemID %d).", chr.getId(), scrollID, equip.getItemId()));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
ScrollUpgradeInfo sui = suis.get(scrollID);
|
|
if (equip.getBaseStat(tuc) <= 0 && sui.getType() == SpellTraceScrollType.Normal) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to enchant a non-scrollable equip (pos %d, itemid %d).",
|
|
chr.getId(), pos, equip.getItemId()));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
chr.consumeItem(ItemConstants.SPELL_TRACE_ID, sui.getCost());
|
|
boolean success = sui.applyTo(equip);
|
|
equip.recalcEnchantmentStats();
|
|
String desc = success ? "Your item has been upgraded." : "Your upgrade has failed.";
|
|
chr.write(FieldPacket.showScrollUpgradeResult(false, success ? 1 : 0, desc, prevEquip, equip));
|
|
equip.updateToChar(chr);
|
|
if (pos < 0) {
|
|
chr.recalcStats(equip.getBaseStatFlag());
|
|
}
|
|
suis = ItemConstants.getScrollUpgradeInfosByEquip(equip);
|
|
c.write(FieldPacket.scrollUpgradeDisplay(false, suis));
|
|
break;
|
|
case HyperUpgradeResult:
|
|
c.verifyTick(inPacket);
|
|
int eqpPos = inPacket.decodeShort();
|
|
boolean extraChanceFromMiniGame = inPacket.decodeByte() != 0;
|
|
equip = (Equip) chr.getEquipInventory().getItemBySlot(eqpPos);
|
|
if (extraChanceFromMiniGame) {
|
|
inPacket.decodeInt();
|
|
}
|
|
inPacket.decodeInt();
|
|
inPacket.decodeInt();
|
|
boolean safeGuard = inPacket.decodeByte() != 0;
|
|
boolean equippedInv = eqpPos < 0;
|
|
inv = equippedInv ? chr.getEquippedInventory() : chr.getEquipInventory();
|
|
equip = (Equip) inv.getItemBySlot(Math.abs(eqpPos));
|
|
if (equip == null) {
|
|
chr.chatMessage("Could not find the given equip.");
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
if (!ItemConstants.isUpgradable(equip.getItemId())
|
|
|| (equip.getBaseStat(tuc) != 0 && !c.getWorld().isReboot())
|
|
|| chr.getEquipInventory().getEmptySlots() == 0
|
|
|| equip.getChuc() >= GameConstants.getMaxStars(equip)
|
|
|| equip.hasSpecialAttribute(EquipSpecialAttribute.Vestige)) {
|
|
chr.chatMessage("Equipment cannot be enhanced.");
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
long cost = GameConstants.getEnchantmentMesoCost(equip.getrLevel() + equip.getiIncReq(), equip.getChuc(), equip.isSuperiorEqp());
|
|
if (chr.getMoney() < cost) {
|
|
chr.chatMessage("Mesos required: " + NumberFormat.getNumberInstance(Locale.US).format(cost));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
Equip oldEquip = equip.deepCopy();
|
|
int successProp = GameConstants.getEnchantmentSuccessRate(equip);
|
|
if (extraChanceFromMiniGame) {
|
|
successProp *= 1.045;
|
|
}
|
|
int destroyProp = safeGuard && equip.canSafeguardHyperUpgrade() ? 0 : GameConstants.getEnchantmentDestroyRate(equip);
|
|
if (equippedInv && destroyProp > 0 && chr.getEquipInventory().getEmptySlots() == 0) {
|
|
c.write(WvsContext.broadcastMsg(BroadcastMsg.popUpMessage("You do not have enough space in your "
|
|
+ "equip inventory in case your item gets destroyed.")));
|
|
return;
|
|
}
|
|
success = Util.succeedProp(successProp, 1000);
|
|
boolean boom = false;
|
|
boolean canDegrade = equip.isSuperiorEqp() ? equip.getChuc() > 0 : equip.getChuc() > 5 && equip.getChuc() % 5 != 0;
|
|
if (success) {
|
|
equip.setChuc((short) (equip.getChuc() + 1));
|
|
equip.setDropStreak(0);
|
|
} else if (Util.succeedProp(destroyProp, 1000)) {
|
|
equip.setChuc((short) 0);
|
|
equip.makeVestige();
|
|
boom = true;
|
|
if (equippedInv) {
|
|
chr.unequip(equip);
|
|
equip.setBagIndex(chr.getEquipInventory().getFirstOpenSlot());
|
|
equip.updateToChar(chr);
|
|
c.write(WvsContext.inventoryOperation(true, false, Move, (short) eqpPos, (short) equip.getBagIndex(), 0, equip));
|
|
}
|
|
if (!equip.isSuperiorEqp()) {
|
|
equip.setChuc((short) Math.min(12, equip.getChuc()));
|
|
} else {
|
|
equip.setChuc((short) 0);
|
|
}
|
|
} else if (canDegrade) {
|
|
equip.setChuc((short) (equip.getChuc() - 1));
|
|
equip.setDropStreak(equip.getDropStreak() + 1);
|
|
}
|
|
chr.deductMoney(cost);
|
|
equip.recalcEnchantmentStats();
|
|
oldEquip.recalcEnchantmentStats();
|
|
equip.updateToChar(chr);
|
|
if (equippedInv) {
|
|
chr.recalcStats(equip.getBaseStatFlag());
|
|
}
|
|
c.write(FieldPacket.showUpgradeResult(oldEquip, equip, success, boom, canDegrade));
|
|
chr.dispose();
|
|
break;
|
|
case TransmissionResult:
|
|
c.verifyTick(inPacket);
|
|
short toPos = inPacket.decodeShort();
|
|
short fromPos = inPacket.decodeShort();
|
|
Equip fromEq = (Equip) chr.getEquipInventory().getItemBySlot(fromPos);
|
|
Equip toEq = (Equip) chr.getEquipInventory().getItemBySlot(toPos);
|
|
if (fromEq == null || toEq == null || fromEq.getItemId() != toEq.getItemId()
|
|
|| !fromEq.hasSpecialAttribute(EquipSpecialAttribute.Vestige)) {
|
|
log.error(String.format("Equip transmission failed: from = %s, to = %s", fromEq, toEq));
|
|
c.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
fromEq.removeVestige();
|
|
fromEq.setChuc((short) 0);
|
|
chr.consumeItem(toEq);
|
|
fromEq.updateToChar(chr);
|
|
c.write(FieldPacket.showTranmissionResult(fromEq, toEq));
|
|
break;
|
|
case ScrollUpgradeDisplay:
|
|
int ePos = inPacket.decodeInt();
|
|
inv = ePos < 0 ? chr.getEquippedInventory() : chr.getEquipInventory();
|
|
ePos = Math.abs(ePos);
|
|
equip = (Equip) inv.getItemBySlot(ePos);
|
|
if (c.getWorld().isReboot()) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d attempted to scroll in reboot world (pos %d, itemid %d).",
|
|
chr.getId(), ePos, equip == null ? 0 : equip.getItemId()));
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
if (equip == null || equip.hasSpecialAttribute(EquipSpecialAttribute.Vestige) || !ItemConstants.isUpgradable(equip.getItemId())) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to scroll a non-scrollable equip (pos %d, itemid %d).",
|
|
chr.getId(), ePos, equip == null ? 0 : equip.getItemId()));
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
suis = ItemConstants.getScrollUpgradeInfosByEquip(equip);
|
|
c.write(FieldPacket.scrollUpgradeDisplay(false, suis));
|
|
break;
|
|
/*case ScrollTimerEffective:
|
|
break;*/
|
|
case HyperUpgradeDisplay:
|
|
ePos = inPacket.decodeInt();
|
|
safeGuard = inPacket.decodeByte() != 0;
|
|
inv = ePos < 0 ? chr.getEquippedInventory() : chr.getEquipInventory();
|
|
ePos = Math.abs(ePos);
|
|
equip = (Equip) inv.getItemBySlot(ePos);
|
|
if (equip == null || equip.hasSpecialAttribute(EquipSpecialAttribute.Vestige) || !ItemConstants.isUpgradable(equip.getItemId())) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d tried to enchant a non-enchantable equip (pos %d, itemid %d).",
|
|
chr.getId(), ePos, equip == null ? 0 : equip.getItemId()));
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
return;
|
|
}
|
|
cost = GameConstants.getEnchantmentMesoCost(equip.getrLevel() + equip.getiIncReq(), equip.getChuc(), equip.isSuperiorEqp());
|
|
destroyProp = GameConstants.getEnchantmentDestroyRate(equip);
|
|
if (safeGuard && equip.canSafeguardHyperUpgrade()) {
|
|
cost *= 2;
|
|
}
|
|
c.write(FieldPacket.hyperUpgradeDisplay(equip, equip.isSuperiorEqp() ? equip.getChuc() > 0 : equip.getChuc() > 5 && equip.getChuc() % 5 != 0,
|
|
cost, 0, 0, GameConstants.getEnchantmentSuccessRate(equip), 0,
|
|
destroyProp, 0, equip.getDropStreak() >= 2));
|
|
break;
|
|
case MiniGameDisplay:
|
|
c.write(FieldPacket.miniGameDisplay(eeType));
|
|
break;
|
|
//case ShowScrollUpgradeResult:
|
|
case ScrollTimerEffective:
|
|
case ShowHyperUpgradeResult:
|
|
break;
|
|
/*
|
|
case ShowScrollVestigeCompensationResult:
|
|
case ShowTransmissionResult:
|
|
case ShowUnknownFailResult:
|
|
break;*/
|
|
default:
|
|
log.debug("Unhandled Equipment Enchant Type: " + eeType);
|
|
chr.write(FieldPacket.showUnknownEnchantFailResult((byte) 0));
|
|
break;
|
|
}
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_SKILL_LEARN_ITEM_USE_REQUEST)
|
|
public static void handleUserLearnItemUseRequest(Client c, InPacket inPacket) {
|
|
c.verifyTick(inPacket);
|
|
short pos = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
Char chr = c.getChr();
|
|
|
|
ItemInfo ii = ItemData.getItemInfoByID(itemID);
|
|
Item item = chr.getConsumeInventory().getItemBySlot(pos);
|
|
|
|
if (ii == null || !chr.hasItem(itemID) || item == null || item.getItemId() != itemID || !chr.isInValidState()) {
|
|
chr.chatMessage("Could not find that item.");
|
|
return;
|
|
}
|
|
|
|
int masterLevel = ii.getMasterLv();
|
|
int reqSkillLv = ii.getReqSkillLv();
|
|
int skillid = 0;
|
|
Map<ScrollStat, Integer> vals = ii.getScrollStats();
|
|
int chance = vals.getOrDefault(ScrollStat.success, 100);
|
|
|
|
for (int skill : ii.getSkills()) {
|
|
if (chr.hasSkill(skill)) {
|
|
skillid = skill;
|
|
break;
|
|
}
|
|
}
|
|
Skill skill = chr.getSkill(skillid);
|
|
if (skill == null) {
|
|
chr.chatMessage(Notice2, "An error has occured. Mastery Book ID: " + itemID + ", skill ID: " + skillid + ".");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
if (skillid == 0 || (skill.getMasterLevel() >= masterLevel) || skill.getCurrentLevel() < reqSkillLv) {
|
|
chr.chatMessage(SystemNotice, "You cannot use this Mastery Book.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
|
|
if (skill.getCurrentLevel() > reqSkillLv && skill.getMasterLevel() < masterLevel) {
|
|
chr.chatMessage(Mob, "Success Chance: " + chance + "%.");
|
|
chr.consumeItem(itemID, 1);
|
|
if (Util.succeedProp(chance)) {
|
|
skill.setMasterLevel(masterLevel);
|
|
chr.addSkill(skill);
|
|
chr.write(WvsContext.changeSkillRecordResult(skill));
|
|
chr.chatMessage(Notice2, "[Mastery Book] Item id: " + itemID + " set Skill id: " + skillid + "'s Master Level to: " + masterLevel + ".");
|
|
} else {
|
|
chr.chatMessage(Notice2, "[Mastery Book] Item id: " + itemID + " was used, however it was unsuccessful.");
|
|
}
|
|
}
|
|
chr.dispose();
|
|
}
|
|
|
|
|
|
@Handler(op = InHeader.SOCKET_CREATE_REQUEST)
|
|
public static void handleSocketCreateRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
c.verifyTick(inPacket);
|
|
short uPos = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
short ePos = inPacket.decodeShort();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(uPos);
|
|
Equip equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (equip == null || item == null || item.getItemId() != itemID) {
|
|
log.error("Unknown equip or mismatching use items.");
|
|
return;
|
|
}
|
|
int success = 0;
|
|
if (equip.getSocket(0) == ItemConstants.INACTIVE_SOCKET && ItemConstants.canEquipHavePotential(equip)) {
|
|
chr.consumeItem(item);
|
|
equip.setSocket(0, ItemConstants.EMPTY_SOCKET_ID);
|
|
} else {
|
|
success = 1;
|
|
}
|
|
c.write(FieldPacket.socketCreateResult(success));
|
|
equip.updateToChar(chr);
|
|
}
|
|
|
|
@Handler(op = InHeader.SOCKET_CREATE_RESULT)
|
|
public static void handleSocketCreateResult(Client c, InPacket inPacket) {
|
|
c.write(FieldPacket.socketCreateResult(inPacket.decodeInt() + 2));
|
|
}
|
|
|
|
@Handler(op = InHeader.NEBULITE_INSERT_REQUEST)
|
|
public static void handleNebuliteInsertRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
c.verifyTick(inPacket);
|
|
short nebPos = inPacket.decodeShort();
|
|
int nebID = inPacket.decodeInt();
|
|
Item item = chr.getInstallInventory().getItemBySlot(nebPos);
|
|
short ePos = inPacket.decodeShort();
|
|
Equip equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (item == null || equip == null || item.getItemId() != nebID || !ItemConstants.isNebulite(item.getItemId())) {
|
|
log.error("Nebulite or equip was not found when inserting.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
if (equip.getSocket(0) != ItemConstants.EMPTY_SOCKET_ID) {
|
|
log.error("Tried to Nebulite an item without an empty socket.");
|
|
chr.chatMessage("You can only insert a Nebulite into empty socket slots.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
if (!ItemConstants.nebuliteFitsEquip(equip, item)) {
|
|
chr.getOffenseManager().addOffense(String.format("Character %d attempted to use a nebulite (%d) that doesn't fit an equip (%d).", chr.getId(), item.getItemId(), equip.getItemId()));
|
|
chr.chatMessage("The nebulite cannot be mounted on this equip.");
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
chr.consumeItem(item);
|
|
equip.setSocket(0, nebID % ItemConstants.NEBULITE_BASE_ID);
|
|
equip.updateToChar(chr);
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_ITEM_SKILL_SOCKET_UPGRADE_ITEM_USE_REQUEST)
|
|
public static void handleUserItemSkillSocketUpdateItemUseRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
c.verifyTick(inPacket);
|
|
short uPos = inPacket.decodeShort();
|
|
short ePos = inPacket.decodeShort();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(uPos);
|
|
Equip equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (item == null || equip == null || !ItemConstants.isWeapon(equip.getItemId())
|
|
|| !ItemConstants.isSoulEnchanter(item.getItemId()) || equip.getrLevel() + equip.getiIncReq() < ItemConstants.MIN_LEVEL_FOR_SOUL_SOCKET) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
int successProp = ItemData.getItemInfoByID(item.getItemId()).getScrollStats().get(ScrollStat.success);
|
|
boolean success = Util.succeedProp(successProp);
|
|
if (success) {
|
|
equip.setSoulSocketId((short) (item.getItemId() % ItemConstants.SOUL_ENCHANTER_BASE_ID));
|
|
equip.updateToChar(chr);
|
|
}
|
|
chr.getField().broadcastPacket(UserPacket.showItemSkillSocketUpgradeEffect(chr.getId(), success));
|
|
chr.consumeItem(item);
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_ITEM_SKILL_OPTION_UPGRADE_ITEM_USE_REQUEST)
|
|
public static void handleUserItemSkillOptionUpdateItemUseRequest(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
c.verifyTick(inPacket);
|
|
short uPos = inPacket.decodeShort();
|
|
short ePos = inPacket.decodeShort();
|
|
Item item = chr.getConsumeInventory().getItemBySlot(uPos);
|
|
Equip equip = (Equip) chr.getEquipInventory().getItemBySlot(ePos);
|
|
if (item == null || equip == null || !ItemConstants.isWeapon(equip.getItemId())
|
|
|| !ItemConstants.isSoul(item.getItemId()) || equip.getSoulSocketId() == 0) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
equip.setSoulOptionId((short) (1 + item.getItemId() % ItemConstants.SOUL_ITEM_BASE_ID));
|
|
short option = ItemConstants.getSoulOptionFromSoul(item.getItemId()); //Currently does nothing
|
|
if (option == 0) {
|
|
option = (short) ItemConstants.getRandomSoulOption();
|
|
}
|
|
equip.setSoulOption(option);
|
|
equip.updateToChar(chr);
|
|
chr.consumeItem(item);
|
|
chr.getField().broadcastPacket(UserPacket.showItemSkillOptionUpgradeEffect(chr.getId(), true, false, ePos, uPos));
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_WEAPON_TEMP_ITEM_OPTION_REQUEST)
|
|
public static void handleUserWeaponTempItemOptionRequest(Char chr, InPacket inPacket) {
|
|
TemporaryStatManager tsm = chr.getTemporaryStatManager();
|
|
if (tsm.hasStat(CharacterTemporaryStat.SoulMP)
|
|
&& tsm.getOption(CharacterTemporaryStat.SoulMP).nOption >= ItemConstants.MAX_SOUL_CAPACITY) {
|
|
Option o = new Option();
|
|
o.nOption = tsm.getOption(CharacterTemporaryStat.SoulMP).nOption;
|
|
o.xOption = tsm.getOption(CharacterTemporaryStat.SoulMP).xOption;
|
|
o.rOption = ItemConstants.getSoulSkillFromSoulID(
|
|
((Equip) chr.getEquippedItemByBodyPart(BodyPart.Weapon)).getSoulOptionId()
|
|
);
|
|
tsm.putCharacterStatValue(CharacterTemporaryStat.FullSoulMP, o);
|
|
tsm.sendSetStatPacket();
|
|
}
|
|
chr.dispose();
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_PROTECT_BUFF_DIE_ITEM_REQUEST)
|
|
public static void handleUserProtectBuffDieItemRequest(Char chr, InPacket inPacket) {
|
|
chr.getClient().verifyTick(inPacket);
|
|
boolean used = inPacket.decodeByte() != 0;
|
|
if (used) {
|
|
// grabs the first one from the list of buffItems
|
|
Item buffProtector = chr.getBuffProtectorItem();
|
|
if (buffProtector != null) {
|
|
chr.setBuffProtector(true);
|
|
chr.consumeItem(buffProtector);
|
|
chr.write(UserLocal.setBuffProtector(buffProtector.getItemId(), true));
|
|
} else {
|
|
chr.getOffenseManager().addOffense(String.format("Character id %d tried to use a buff without having the appropriate item.", chr.getId()));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_DEFAULT_WING_ITEM)
|
|
public static void handleUserDefaultWingItem(Char chr, InPacket inPacket) {
|
|
int wingItem = inPacket.decodeInt();
|
|
if (wingItem == 5010093) { // AB
|
|
chr.getAvatarData().getCharacterStat().setWingItem(wingItem);
|
|
chr.getField().broadcastPacket(UserRemote.setDefaultWingItem(chr));
|
|
}
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_RECIPE_OPEN_ITEM_USE_REQUEST)
|
|
public static void handleUserRecipeOpenItemUseRequest(Char chr, InPacket inPacket) {
|
|
chr.getClient().verifyTick(inPacket);
|
|
short pos = inPacket.decodeShort();// // nPOS
|
|
int itemID = inPacket.decodeInt();// nItemID
|
|
|
|
Item item = chr.getInventoryByType(CONSUME).getItemBySlot(pos);
|
|
if (item == null || item.getItemId() != itemID || !chr.isInValidState()) {
|
|
chr.dispose();
|
|
return;
|
|
}
|
|
if (chr != null && chr.getHP() > 0 && ItemConstants.isRecipeOpenItem(itemID)) {
|
|
ItemInfo recipe = ItemData.getItemInfoByID(itemID);
|
|
if (recipe != null) {
|
|
int recipeID = recipe.getSpecStats().getOrDefault(SpecStat.recipe, 0);
|
|
int reqSkillLevel = recipe.getSpecStats().getOrDefault(SpecStat.reqSkillLevel, 0);
|
|
MakingSkillRecipe msr = SkillData.getRecipeById(recipeID);
|
|
if (msr != null && msr.isNeedOpenItem()) {
|
|
if (chr.getSkillLevel(msr.getReqSkillID()) < reqSkillLevel || chr.getSkillLevel(recipeID) > 0) {
|
|
return;
|
|
}
|
|
chr.addSkill(recipeID, 1, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_ACTIVATE_NICK_ITEM)
|
|
public static void handleUserActivateNickItem(Client c, InPacket inPacket) {
|
|
Char chr = c.getChr();
|
|
int nickItem = inPacket.decodeInt();
|
|
if (nickItem == 0 || nickItem / 10000 == 370 && chr.hasItem(nickItem)) {
|
|
chr.setActiveNickItemID(nickItem);
|
|
chr.getField().broadcastPacket(UserRemote.setActiveNickItem(chr, null), chr);
|
|
}
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_CHAR_SLOT_INC_ITEM_USE_REQUEST)
|
|
public static void addChrSlot(Client c, InPacket inPacket) {
|
|
Account user = c.getAccount();
|
|
int currentSlots = user.getCharacterSlots();
|
|
user.setCharacterSlots(currentSlots + 1);
|
|
}
|
|
|
|
@Handler(op = InHeader.USER_LOTTERY_ITEM_USE_REQUEST)
|
|
public static void handleUserLotteryItemUseRequest(Char chr, InPacket inPacket) {
|
|
short pos = inPacket.decodeShort();
|
|
int itemID = inPacket.decodeInt();
|
|
inPacket.decodeByte(); // bSendForUI
|
|
inPacket.decodeByte(); // bLogStart
|
|
inPacket.decodeInt(); // 1
|
|
Item item;
|
|
ItemInfo itemInfo;
|
|
if (itemID / 1000 != 2028 || (item = chr.getConsumeInventory().getItemBySlot(pos)) == null
|
|
|| itemID != item.getItemId() || ((itemInfo = ItemData.getItemInfoByID(itemID)) == null)) {
|
|
chr.dispose("Not found.");
|
|
return;
|
|
}
|
|
Object reward = itemInfo.getRandomReward();
|
|
if (reward instanceof Item) {
|
|
chr.addItemToInventory((Item) reward);
|
|
} else if (reward instanceof Integer && (int) reward != 0) {
|
|
chr.addMoney((int) reward);
|
|
} else {
|
|
chr.chatMessage("Oh, you're unlucky."); // should not happen
|
|
}
|
|
chr.consumeItem(item);
|
|
chr.dispose();
|
|
}
|
|
}
|