package server.quest;
import client.MapleCharacter;
import client.MapleQuestStatus;
import client.MapleStat;
import client.MapleTrait;
import client.Skill;
import client.SkillEntry;
import client.SkillFactory;
import client.inventory.InventoryException;
import client.inventory.MapleInventoryType;
import constants.GameConstants;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import server.MapleInventoryManipulator;
import server.MapleItemInformationProvider;
import server.RandomRewards;
import server.Randomizer;
import tools.FileoutputUtil;
import tools.Pair;
import tools.Triple;
import tools.packet.CField;
import tools.packet.CWvsContext;
public class MapleQuestAction
implements Serializable {
private static final long serialVersionUID = 9179541993413738569L;
private MapleQuestActionType type;
private MapleQuest quest;
private int intStore = 0;
private List<Integer> applicableJobs = new ArrayList();
private List<QuestItem> items = null;
private List<Triple<Integer, Integer, Integer>> skill = null;
private List<Pair<Integer, Integer>> state = null;
public MapleQuestAction(MapleQuestActionType type, ResultSet rse, MapleQuest quest, PreparedStatement pss, PreparedStatement psq, PreparedStatement psi) throws SQLException {
this.type = type;
this.quest = quest;
this.intStore = rse.getInt("intStore");
String[] jobs = rse.getString("applicableJobs").split(", ");
if ((jobs.length <= 0) && (rse.getString("applicableJobs").length() > 0)) {
this.applicableJobs.add(Integer.valueOf(Integer.parseInt(rse.getString("applicableJobs"))));
}
for (String j : jobs) {
if (j.length() > 0) {
this.applicableJobs.add(Integer.valueOf(Integer.parseInt(j)));
}
}
ResultSet rs;
switch (type) {
case item:
this.items = new ArrayList();
psi.setInt(1, rse.getInt("uniqueid"));
rs = psi.executeQuery();
while (rs.next()) {
this.items.add(new QuestItem(rs.getInt("itemid"), rs.getInt("count"), rs.getInt("period"), rs.getInt("gender"), rs.getInt("job"), rs.getInt("jobEx"), rs.getInt("prop")));
}
rs.close();
break;
case quest:
this.state = new ArrayList();
psq.setInt(1, rse.getInt("uniqueid"));
rs = psq.executeQuery();
while (rs.next()) {
this.state.add(new Pair(Integer.valueOf(rs.getInt("quest")), Integer.valueOf(rs.getInt("state"))));
}
rs.close();
break;
case skill:
this.skill = new ArrayList();
pss.setInt(1, rse.getInt("uniqueid"));
rs = pss.executeQuery();
while (rs.next()) {
this.skill.add(new Triple(Integer.valueOf(rs.getInt("skillid")), Integer.valueOf(rs.getInt("skillLevel")), Integer.valueOf(rs.getInt("masterLevel"))));
}
rs.close();
}
}
private static boolean canGetItem(QuestItem item, MapleCharacter c) {
if ((item.gender != 2) && (item.gender >= 0) && (item.gender != c.getGender())) {
return false;
}
if (item.job > 0) {
List code = getJobBy5ByteEncoding(item.job);
boolean jobFound = false;
for (Iterator i$ = code.iterator(); i$.hasNext();) {
int codec = ((Integer) i$.next()).intValue();
if (codec / 100 == c.getJob() / 100) {
jobFound = true;
break;
}
}
Iterator i$;
if ((!jobFound) && (item.jobEx > 0)) {
List codeEx = getJobBySimpleEncoding(item.jobEx);
for (i$ = codeEx.iterator(); i$.hasNext();) {
int codec = ((Integer) i$.next()).intValue();
if (codec / 100 % 10 == c.getJob() / 100 % 10) {
jobFound = true;
break;
}
}
}
return jobFound;
}
return true;
}
public final boolean RestoreLostItem(MapleCharacter c, int itemid) {
if (this.type == MapleQuestActionType.item) {
for (QuestItem item : this.items) {
if (item.itemid == itemid) {
if (!c.haveItem(item.itemid, item.count, true, false)) {
MapleInventoryManipulator.addById(c.getClient(), item.itemid, (short) item.count, "Obtained from quest (Restored) " + this.quest.getId() + " on " + FileoutputUtil.CurrentReadable_Date());
}
return true;
}
}
}
return false;
}
public void runStart(MapleCharacter c, Integer extSelection) {
MapleQuestStatus status;
int selection;
int extNum;
switch (type) {
case exp:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
c.gainExp(this.intStore * GameConstants.getExpRate_Quest(c.getLevel()) * c.getStat().questBonus * (c.getTrait(MapleTrait.MapleTraitType.sense).getLevel() * 3 / 10 + 100) / 100, true, true, true);
}
break;
case item:
Map props = new HashMap();
for (QuestItem item : this.items) {
if ((item.prop > 0) && (canGetItem(item, c))) {
for (int i = 0; i < item.prop; i++) {
props.put(Integer.valueOf(props.size()), Integer.valueOf(item.itemid));
}
}
}
selection = 0;
extNum = 0;
if (props.size() > 0) {
selection = ((Integer) props.get(Integer.valueOf(Randomizer.nextInt(props.size())))).intValue();
}
for (QuestItem item : this.items) {
if (canGetItem(item, c)) {
int id = item.itemid;
if ((item.prop == -2)
|| (item.prop == -1
? (extSelection == null) && (extSelection.intValue() == extNum++)
: id == selection)) {
short count = (short) item.count;
if (count < 0) {
try {
MapleInventoryManipulator.removeById(c.getClient(), GameConstants.getInventoryType(id), id, count * -1, true, false);
} catch (InventoryException ie) {
System.err.println("[h4x] Completing a quest without meeting the requirements" + ie);
}
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowItemGain(id, count, true));
} else {
int period = item.period / 1440;
String name = MapleItemInformationProvider.getInstance().getName(id);
if ((id / 10000 == 114) && (name != null) && (name.length() > 0)) {
String msg = "You have attained title <" + name + ">";
c.dropMessage(-1, msg);
c.dropMessage(5, msg);
}
MapleInventoryManipulator.addById(c.getClient(), id, count, "", null, period, "Obtained from quest " + this.quest.getId() + " on " + FileoutputUtil.CurrentReadable_Date());
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowItemGain(id, count, true));
}
}
}
}
break;
case nextQuest:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
c.getClient().getSession().write(CField.updateQuestFinish(this.quest.getId(), status.getNpc(), this.intStore));
}
break;
case money:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
c.gainMeso(this.intStore, true, true);
}
break;
case quest:
for (Pair q : this.state) {
c.updateQuest(new MapleQuestStatus(MapleQuest.getInstance(((Integer) q.left).intValue()), ((Integer) q.right).intValue()));
}
break;
case skill:
Map sa = new HashMap();
for (Triple skills : this.skill) {
int skillid = ((Integer) skills.left).intValue();
int skillLevel = ((Integer) skills.mid).intValue();
int masterLevel = ((Integer) skills.right).intValue();
Skill skillObject = SkillFactory.getSkill(skillid);
boolean found = false;
for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) {
int applicableJob = ((Integer) i$.next()).intValue();
if (c.getJob() == applicableJob) {
found = true;
break;
}
}
if ((skillObject.isBeginnerSkill()) || (found)) {
sa.put(skillObject, new SkillEntry((byte) Math.max(skillLevel, c.getSkillLevel(skillObject)), (byte) Math.max(masterLevel, c.getMasterLevel(skillObject)), SkillFactory.getDefaultSExpiry(skillObject)));
}
}
c.changeSkillsLevel(sa);
break;
case pop:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
int fameGain = this.intStore;
c.addFame(fameGain);
c.updateSingleStat(MapleStat.FAME, c.getFame());
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowFameGain(fameGain));
}
break;
case buffItemID:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
int tobuff = this.intStore;
if (tobuff > 0) {
MapleItemInformationProvider.getInstance().getItemEffect(tobuff).applyTo(c);
}
}
break;
case infoNumber:
break;
case sp:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
int sp_val = this.intStore;
if (this.applicableJobs.size() > 0) {
int finalJob = 0;
for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) {
int job_val = ((Integer) i$.next()).intValue();
if ((c.getJob() >= job_val) && (job_val > finalJob)) {
finalJob = job_val;
}
}
if (finalJob == 0) {
c.gainSP(sp_val);
} else {
c.gainSP(sp_val, GameConstants.getSkillBook(finalJob));
}
} else {
c.gainSP(sp_val);
}
}
break;
case charmEXP:
case charismaEXP:
case craftEXP:
case insightEXP:
case senseEXP:
case willEXP:
status = c.getQuest(this.quest);
if (status.getForfeited() <= 0) {
c.getTrait(MapleTrait.MapleTraitType.getByQuestName(this.type.name())).addExp(this.intStore, c);
}
break;
}
}
public boolean checkEnd(MapleCharacter c, Integer extSelection) {
switch (this.type) {
case item:
Map props = new HashMap();
for (QuestItem item : this.items) {
if ((item.prop > 0) && (canGetItem(item, c))) {
for (int i = 0; i < item.prop; i++) {
props.put(Integer.valueOf(props.size()), Integer.valueOf(item.itemid));
}
}
}
int selection = 0;
int extNum = 0;
if (props.size() > 0) {
selection = ((Integer) props.get(Integer.valueOf(Randomizer.nextInt(props.size())))).intValue();
}
byte eq = 0;
byte use = 0;
byte setup = 0;
byte etc = 0;
byte cash = 0;
for (QuestItem item : this.items) {
if (canGetItem(item, c)) {
int id = item.itemid;
if ((item.prop == -2)
|| (item.prop == -1
? (extSelection == null) && (extSelection.intValue() == extNum++)
: id == selection)) {
short count = (short) item.count;
if (count < 0) {
if (!c.haveItem(id, count, false, true)) {
c.dropMessage(1, "You are short of some item to complete quest.");
return false;
}
} else {
switch (GameConstants.getInventoryType(id)) {
case EQUIP:
eq = (byte) (eq + 1);
break;
case USE:
use = (byte) (use + 1);
break;
case SETUP:
setup = (byte) (setup + 1);
break;
case ETC:
etc = (byte) (etc + 1);
break;
case CASH:
cash = (byte) (cash + 1);
}
}
}
}
}
if (c.getInventory(MapleInventoryType.EQUIP).getNumFreeSlot() < eq) {
c.dropMessage(1, "Please make space for your Equip inventory.");
return false;
}
if (c.getInventory(MapleInventoryType.USE).getNumFreeSlot() < use) {
c.dropMessage(1, "Please make space for your Use inventory.");
return false;
}
if (c.getInventory(MapleInventoryType.SETUP).getNumFreeSlot() < setup) {
c.dropMessage(1, "Please make space for your Setup inventory.");
return false;
}
if (c.getInventory(MapleInventoryType.ETC).getNumFreeSlot() < etc) {
c.dropMessage(1, "Please make space for your Etc inventory.");
return false;
}
if (c.getInventory(MapleInventoryType.CASH).getNumFreeSlot() < cash) {
c.dropMessage(1, "Please make space for your Cash inventory.");
return false;
}
return true;
case money:
int meso = this.intStore;
if (c.getMeso() + meso < 0L) {
c.dropMessage(1, "Meso exceed the max amount, 2147483647.");
return false;
}
if ((meso < 0) && (c.getMeso() < Math.abs(meso))) {
c.dropMessage(1, "Insufficient meso.");
return false;
}
return true;
}
return true;
}
public void runEnd(MapleCharacter c, Integer extSelection) {
int selection;
int extNum;
switch (type) {
case exp:
c.gainExp(this.intStore * GameConstants.getExpRate_Quest(c.getLevel()) * c.getStat().questBonus * (c.getTrait(MapleTrait.MapleTraitType.sense).getLevel() * 3 / 10 + 100) / 100, true, true, true);
break;
case item:
Map props = new HashMap();
for (QuestItem item : this.items) {
if ((item.prop > 0) && (canGetItem(item, c))) {
for (int i = 0; i < item.prop; i++) {
props.put(Integer.valueOf(props.size()), Integer.valueOf(item.itemid));
}
}
}
selection = 0;
extNum = 0;
if (props.size() > 0) {
selection = ((Integer) props.get(Integer.valueOf(Randomizer.nextInt(props.size())))).intValue();
}
for (QuestItem item : this.items) {
if (canGetItem(item, c)) {
int id = item.itemid;
if ((item.prop == -2)
|| (item.prop == -1
? (extSelection == null) && (extSelection.intValue() == extNum++)
: id == selection)) {
short count = (short) item.count;
if (count < 0) {
MapleInventoryManipulator.removeById(c.getClient(), GameConstants.getInventoryType(id), id, count * -1, true, false);
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowItemGain(id, count, true));
} else {
int period = item.period / 1440;
String name = MapleItemInformationProvider.getInstance().getName(id);
if ((id / 10000 == 114) && (name != null) && (name.length() > 0)) {
String msg = "You have attained title <" + name + ">";
c.dropMessage(-1, msg);
c.dropMessage(5, msg);
}
MapleInventoryManipulator.addById(c.getClient(), id, count, "", null, period + " on " + FileoutputUtil.CurrentReadable_Date());
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowItemGain(id, count, true));
}
}
}
}
break;
case nextQuest:
c.getClient().getSession().write(CField.updateQuestFinish(this.quest.getId(), c.getQuest(this.quest).getNpc(), this.intStore));
break;
case money:
c.gainMeso(this.intStore, true, true);
break;
case quest:
for (Pair<Integer, Integer> q : this.state) {
c.updateQuest(new MapleQuestStatus(MapleQuest.getInstance(((Integer) q.left).intValue()), ((Integer) q.right).intValue()));
}
break;
case skill:
Map sa = new HashMap();
for (Triple skills : this.skill) {
int skillid = ((Integer) skills.left).intValue();
int skillLevel = ((Integer) skills.mid).intValue();
int masterLevel = ((Integer) skills.right).intValue();
Skill skillObject = SkillFactory.getSkill(skillid);
boolean found = false;
for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) {
int applicableJob = ((Integer) i$.next()).intValue();
if (c.getJob() == applicableJob) {
found = true;
break;
}
}
if ((skillObject.isBeginnerSkill()) || (found)) {
sa.put(skillObject, new SkillEntry((byte) Math.max(skillLevel, c.getSkillLevel(skillObject)), (byte) Math.max(masterLevel, c.getMasterLevel(skillObject)), SkillFactory.getDefaultSExpiry(skillObject)));
}
}
c.changeSkillsLevel(sa);
break;
case pop:
int fameGain = this.intStore;
c.addFame(fameGain);
c.updateSingleStat(MapleStat.FAME, c.getFame());
c.getClient().getSession().write(CWvsContext.InfoPacket.getShowFameGain(fameGain));
break;
case buffItemID:
int tobuff = this.intStore;
if (tobuff > 0) {
MapleItemInformationProvider.getInstance().getItemEffect(tobuff).applyTo(c);
}
break;
case infoNumber:
break;
case sp:
int sp_val = this.intStore;
if (this.applicableJobs.size() > 0) {
int finalJob = 0;
for (Iterator i$ = this.applicableJobs.iterator(); i$.hasNext();) {
int job_val = ((Integer) i$.next()).intValue();
if ((c.getJob() >= job_val) && (job_val > finalJob)) {
finalJob = job_val;
}
}
if (finalJob == 0) {
c.gainSP(sp_val);
} else {
c.gainSP(sp_val, GameConstants.getSkillBook(finalJob));
}
} else {
c.gainSP(sp_val);
}
break;
case charmEXP:
case charismaEXP:
case craftEXP:
case insightEXP:
case senseEXP:
case willEXP:
c.getTrait(MapleTrait.MapleTraitType.getByQuestName(this.type.name())).addExp(this.intStore, c);
break;
}
}
private static List<Integer> getJobBy5ByteEncoding(int encoded) {
List ret = new ArrayList();
if ((encoded & 0x1) != 0) {
ret.add(Integer.valueOf(0));
}
if ((encoded & 0x2) != 0) {
ret.add(Integer.valueOf(100));
}
if ((encoded & 0x4) != 0) {
ret.add(Integer.valueOf(200));
}
if ((encoded & 0x8) != 0) {
ret.add(Integer.valueOf(300));
}
if ((encoded & 0x10) != 0) {
ret.add(Integer.valueOf(400));
}
if ((encoded & 0x20) != 0) {
ret.add(Integer.valueOf(500));
}
if ((encoded & 0x400) != 0) {
ret.add(Integer.valueOf(1000));
}
if ((encoded & 0x800) != 0) {
ret.add(Integer.valueOf(1100));
}
if ((encoded & 0x1000) != 0) {
ret.add(Integer.valueOf(1200));
}
if ((encoded & 0x2000) != 0) {
ret.add(Integer.valueOf(1300));
}
if ((encoded & 0x4000) != 0) {
ret.add(Integer.valueOf(1400));
}
if ((encoded & 0x8000) != 0) {
ret.add(Integer.valueOf(1500));
}
if ((encoded & 0x20000) != 0) {
ret.add(Integer.valueOf(2001));
ret.add(Integer.valueOf(2200));
}
if ((encoded & 0x100000) != 0) {
ret.add(Integer.valueOf(2000));
ret.add(Integer.valueOf(2001));
}
if ((encoded & 0x200000) != 0) {
ret.add(Integer.valueOf(2100));
}
if ((encoded & 0x400000) != 0) {
ret.add(Integer.valueOf(2001));
ret.add(Integer.valueOf(2200));
}
if ((encoded & 0x40000000) != 0) {
ret.add(Integer.valueOf(3000));
ret.add(Integer.valueOf(3200));
ret.add(Integer.valueOf(3300));
ret.add(Integer.valueOf(3500));
}
return ret;
}
private static List<Integer> getJobBySimpleEncoding(int encoded) {
List ret = new ArrayList();
if ((encoded & 0x1) != 0) {
ret.add(Integer.valueOf(200));
}
if ((encoded & 0x2) != 0) {
ret.add(Integer.valueOf(300));
}
if ((encoded & 0x4) != 0) {
ret.add(Integer.valueOf(400));
}
if ((encoded & 0x8) != 0) {
ret.add(Integer.valueOf(500));
}
return ret;
}
public MapleQuestActionType getType() {
return this.type;
}
public String toString() {
return this.type.toString();
}
public List<Triple<Integer, Integer, Integer>> getSkills() {
return this.skill;
}
public List<QuestItem> getItems() {
return this.items;
}
public static class QuestItem {
public int itemid;
public int count;
public int period;
public int gender;
public int job;
public int jobEx;
public int prop;
public QuestItem(int itemid, int count, int period, int gender, int job, int jobEx, int prop) {
if (RandomRewards.getTenPercent().contains(Integer.valueOf(itemid))) {
count += Randomizer.nextInt(3);
}
this.itemid = itemid;
this.count = count;
this.period = period;
this.gender = gender;
this.job = job;
this.jobEx = jobEx;
this.prop = prop;
}
}
}