/*
* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010
* 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 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 javastory.game.quest;
import java.io.Serializable;
import java.util.Calendar;
import java.util.List;
import com.google.common.collect.Lists;
import javastory.channel.ChannelCharacter;
import javastory.game.Item;
import javastory.game.data.SkillInfoProvider;
import javastory.wz.WzData;
import javastory.wz.WzDataTool;
public class QuestRequirement implements Serializable {
private static final long serialVersionUID = 9179541993413738569L;
private final int questId;
private final QuestRequirementType type;
private int intStore;
private String stringStore;
private List<Entry> dataStore;
private static class Entry implements Serializable {
/**
*
*/
private static final long serialVersionUID = 5791071340009895274L;
public int Key;
public int Value;
public Entry(final int key, final int value) {
this.Key = key;
this.Value = value;
}
}
/** Creates a new instance of MapleQuestRequirement */
public QuestRequirement(final int questId, final QuestRequirementType type, final WzData data) {
this.type = type;
this.questId = questId;
switch (type) {
case JOB: {
final List<WzData> child = data.getChildren();
this.dataStore = Lists.newLinkedList();
for (int i = 0; i < child.size(); i++) {
final int value = WzDataTool.getInt(child.get(i), -1);
final Entry entry = new Entry(i, value);
this.dataStore.add(entry);
}
break;
}
case SKILL: {
final List<WzData> child = data.getChildren();
this.dataStore = Lists.newLinkedList();
for (int i = 0; i < child.size(); i++) {
final WzData childdata = child.get(i);
this.dataStore.add(new Entry(WzDataTool.getInt(childdata.getChildByPath("id"), 0), WzDataTool.getInt(childdata.getChildByPath("acquire"), 0)));
}
break;
}
case QUEST: {
final List<WzData> child = data.getChildren();
this.dataStore = Lists.newLinkedList();
for (int i = 0; i < child.size(); i++) {
final WzData childdata = child.get(i);
this.dataStore.add(new Entry(WzDataTool.getInt(childdata.getChildByPath("id")), WzDataTool.getInt(childdata.getChildByPath("state"), 0)));
}
break;
}
case ITEM: {
final List<WzData> child = data.getChildren();
this.dataStore = Lists.newLinkedList();
for (int i = 0; i < child.size(); i++) {
final WzData childdata = child.get(i);
this.dataStore.add(new Entry(WzDataTool.getInt(childdata.getChildByPath("id")), WzDataTool.getInt(childdata.getChildByPath("count"), 0)));
}
break;
}
case NPC:
case QUEST_COMPLETED:
case FAME:
case INTERVAL:
case MIN_MONSTER_BOOK:
case MAX_LEVEL:
case MIN_LEVEL: {
this.intStore = WzDataTool.getInt(data, -1);
break;
}
case AVAILABLE_UNTIL: {
this.stringStore = WzDataTool.getString(data, null);
break;
}
case MONSTER: {
final List<WzData> child = data.getChildren();
this.dataStore = Lists.newLinkedList();
for (int i = 0; i < child.size(); i++) {
final WzData childdata = child.get(i);
this.dataStore.add(new Entry(WzDataTool.getInt(childdata.getChildByPath("id"), 0), WzDataTool.getInt(childdata.getChildByPath("count"), 0)));
}
break;
}
case FIELD_ENTER: {
final WzData zeroField = data.getChildByPath("0");
if (zeroField != null) {
this.intStore = WzDataTool.getInt(zeroField);
} else {
this.intStore = -1;
}
break;
}
}
}
public boolean check(final ChannelCharacter c, final Integer npcId) {
switch (this.type) {
case JOB:
for (final Entry entry : this.dataStore) {
if (entry.Value == c.getJobId() || c.isGM()) {
return true;
}
}
return false;
case SKILL: {
for (final Entry entry : this.dataStore) {
final int skill = entry.Key;
final boolean acquire = entry.Value > 0;
final byte masterSkillLevel = c.getMasterSkillLevel(SkillInfoProvider.getSkill(skill));
if (acquire) {
if (masterSkillLevel == 0) {
return false;
}
} else {
if (masterSkillLevel > 0) {
return false;
}
}
}
return true;
}
case QUEST:
for (final Entry entry : this.dataStore) {
final QuestStatus q = c.getQuestStatus(entry.Key);
final int state = entry.Value;
if (state != 0) {
if (q == null && state == 0) {
continue;
}
if (q == null || q.getState() != state) {
return false;
}
}
}
return true;
case ITEM:
for (final Entry entry : this.dataStore) {
final int itemId = entry.Key;
short quantity = 0;
for (final Item item : c.getInventoryForItem(itemId).listById(itemId)) {
quantity += item.getQuantity();
}
final int requiredCount = entry.Value;
// Abort checking if we're lacking items.
if (requiredCount > 0 && quantity < requiredCount) {
return false;
}
// Abort checking if we're expected to NOT HAVE the items and we do.
if (requiredCount <= 0 && quantity > 0) {
return false;
}
}
return true;
case MIN_LEVEL:
return c.getLevel() >= this.intStore;
case MAX_LEVEL:
return c.getLevel() <= this.intStore;
case AVAILABLE_UNTIL:
final String timeStr = this.stringStore;
final Calendar cal = Calendar.getInstance();
cal.set(Integer.parseInt(timeStr.substring(0, 4)), Integer.parseInt(timeStr.substring(4, 6)), Integer.parseInt(timeStr.substring(6, 8)), Integer
.parseInt(timeStr.substring(8, 10)), 0);
return cal.getTimeInMillis() >= System.currentTimeMillis();
case MONSTER:
for (final Entry entry : this.dataStore) {
final int mobId = entry.Key;
final int requiredKillCount = entry.Value;
if (c.getQuestStatus(this.questId).getMobKills(mobId) < requiredKillCount) {
return false;
}
}
return true;
case NPC:
return npcId == null || npcId == this.intStore;
case FIELD_ENTER:
if (this.intStore != -1) {
return this.intStore == c.getMapId();
}
return false;
case MIN_MONSTER_BOOK:
if (c.getMonsterBook().getTotalCards() >= this.intStore) {
return true;
} else {
return false;
}
case FAME:
return c.getFame() <= this.intStore;
case QUEST_COMPLETED:
if (c.getNumQuest() >= this.intStore) {
return true;
} else {
return false;
}
case INTERVAL:
final boolean isCompleted = c.getQuestStatus(this.questId).getState() != 2;
final long startTimestamp = this.intStore * 60 * 1000L;
final long completionTimeLimit = c.getQuestStatus(this.questId).getCompletionTime();
return isCompleted || completionTimeLimit <= System.currentTimeMillis() - startTimestamp;
// case PET:
// case MIN_PET_TAMENESS:
default:
return true;
}
}
public QuestRequirementType getType() {
return this.type;
}
@Override
public String toString() {
return this.type.toString();
}
}